/* * linux/kernel/sys.c * * (C) 1991 Linus Torvalds */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //ADD FOR getcwd long sys_getcwd(char *buf,size_t size) { int block=current->pwd->i_zone[0]; int idev=current->pwd->i_dev; int flag=0; struct buffer_head * bh; struct dir_entry * de; struct m_inode *dir=current->pwd,*rdir=current->root; if(dir==rdir) { flag=1; goto mytag; } unsigned short curinode,finode,tempfi; char name[128],base[128]; int entries,i; if (!(block = current->pwd->i_zone[0])) return NULL; if (!(bh = bread(current->pwd->i_dev,block))) return NULL; de = (struct dir_entry *) bh->b_data; curinode=de->inode; de++; finode=de->inode; while (rdir!=dir) { //update father dir=iget(idev,finode); if (!(block = dir->i_zone[0])) return NULL; if (!(bh = bread(dir->i_dev,block))) return NULL; i = 0; entries = dir->i_size / (sizeof (struct dir_entry)); de = (struct dir_entry *) bh->b_data; tempfi=(de+1)->inode; while (i < entries) { if ((char *)de >= BLOCK_SIZE+bh->b_data) { brelse(bh); bh = NULL; if (!(block = bmap(dir,i/DIR_ENTRIES_PER_BLOCK)) || !(bh = bread(dir->i_dev,block))) { i += DIR_ENTRIES_PER_BLOCK; continue; } de = (struct dir_entry *) bh->b_data; } if(de->inode==curinode) { memset(base,'\0',sizeof(base)); strcat(base,"/"); strcat(base,de->name); strcat(base,name); strcpy(name,base); break; } de++; i++; } curinode=finode; finode=tempfi; } mytag: if(flag) strcpy(name,"/"); size_t len=strlen(name); if(sizefilp[fd]->f_inode; int block,i,entries,sizdir=sizeof(struct dir_entry); struct buffer_head * bh; struct dir_entry * de; struct linux_dirent *initmp,*temp; if(!(temp=(struct linux_dirent *)malloc(count+64))) return -1; initmp=temp; int size=sizeof(long)+sizeof(off_t)+sizeof(unsigned short); if (!(block = filenode->i_zone[0])) return -1; if (!(bh = bread(filenode->i_dev,block))) return -1; de = (struct dir_entry *) bh->b_data; entries=filenode->i_size/(sizeof(struct dir_entry)); i=0; int nread=0,pos=0; while(i= BLOCK_SIZE+bh->b_data) { brelse(bh); bh = NULL; if (!(block = bmap(filenode,i/DIR_ENTRIES_PER_BLOCK)) || !(bh = bread(filenode->i_dev,block))) { i += DIR_ENTRIES_PER_BLOCK; continue; } pos+=((char*) bh->b_data-(char*)(de)); de = (struct dir_entry *) bh->b_data; } temp->d_ino=de->inode; temp->d_off=pos; strcpy(temp->d_name,de->name); temp->d_reclen=sizeof(de); nread+=temp->d_reclen; temp=(struct linux_dirent*)((char*)temp+temp->d_reclen); de++; pos+=sizdir; i++; } if(countsigaction[SIGALRM-1] = tmp; current->alarm=(seconds>0)?(jiffies+HZ*seconds):0; current->state=TASK_INTERRUPTIBLE; current->counter=(current->counter>>1)+current->priority; schedule(); return 0; } int sys_clone() { return -1; } int sys_ftime() { return -ENOSYS; } int sys_break() { return -ENOSYS; } int sys_ptrace() { return -ENOSYS; } int sys_stty() { return -ENOSYS; } int sys_gtty() { return -ENOSYS; } int sys_rename() { return -ENOSYS; } int sys_prof() { return -ENOSYS; } int sys_setregid(int rgid, int egid) { if (rgid>0) { if ((current->gid == rgid) || suser()) current->gid = rgid; else return(-EPERM); } if (egid>0) { if ((current->gid == egid) || (current->egid == egid) || suser()) { current->egid = egid; current->sgid = egid; } else return(-EPERM); } return 0; } int sys_setgid(int gid) { /* return(sys_setregid(gid, gid)); */ if (suser()) current->gid = current->egid = current->sgid = gid; else if ((gid == current->gid) || (gid == current->sgid)) current->egid = gid; else return -EPERM; return 0; } int sys_acct() { return -ENOSYS; } int sys_phys() { return -ENOSYS; } int sys_lock() { return -ENOSYS; } int sys_mpx() { return -ENOSYS; } int sys_ulimit() { return -ENOSYS; } int sys_time(long * tloc) { int i; i = CURRENT_TIME; if (tloc) { verify_area(tloc,4); put_fs_long(i,(unsigned long *)tloc); } return i; } /* * Unprivileged users may change the real user id to the effective uid * or vice versa. */ int sys_setreuid(int ruid, int euid) { int old_ruid = current->uid; if (ruid>0) { if ((current->euid==ruid) || (old_ruid == ruid) || suser()) current->uid = ruid; else return(-EPERM); } if (euid>0) { if ((old_ruid == euid) || (current->euid == euid) || suser()) { current->euid = euid; current->suid = euid; } else { current->uid = old_ruid; return(-EPERM); } } return 0; } int sys_setuid(int uid) { /* return(sys_setreuid(uid, uid)); */ if (suser()) current->uid = current->euid = current->suid = uid; else if ((uid == current->uid) || (uid == current->suid)) current->euid = uid; else return -EPERM; return(0); } int sys_stime(long * tptr) { if (!suser()) return -EPERM; startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ; return 0; } int sys_times(struct tms * tbuf) { if (tbuf) { verify_area(tbuf,sizeof *tbuf); put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime); put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime); put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime); put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime); } return jiffies; } int sys_brk(unsigned long end_data_seg) { if (end_data_seg >= current->end_code && end_data_seg < current->start_stack - 16384) current->brk = end_data_seg; return current->brk; } /* * This needs some heave checking ... * I just haven't get the stomach for it. I also don't fully * understand sessions/pgrp etc. Let somebody who does explain it. */ int sys_setpgid(int pid, int pgid) { int i; if (!pid) pid = current->pid; if (!pgid) pgid = current->pid; for (i=0 ; ipid==pid) { if (task[i]->leader) return -EPERM; if (task[i]->session != current->session) return -EPERM; task[i]->pgrp = pgid; return 0; } return -ESRCH; } int sys_getpgrp(void) { return current->pgrp; } int sys_setsid(void) { if (current->leader && !suser()) return -EPERM; current->leader = 1; current->session = current->pgrp = current->pid; current->tty = -1; return current->pgrp; } int sys_getgroups() { return -ENOSYS; } int sys_setgroups() { return -ENOSYS; } int sys_uname(struct utsname * name) { static struct utsname thisname = { "linux .0","nodename","release ","version ","machine " }; int i; if (!name) return -ERROR; verify_area(name,sizeof *name); for(i=0;iumask; current->umask = mask & 0777; return (old); } static int my_share(unsigned long address, struct task_struct * p) { unsigned long from; unsigned long to; unsigned long from_page; unsigned long to_page; unsigned long phys_addr; from_page = to_page = ((address>>20) & 0xffc); from_page += ((current->start_code>>20) & 0xffc); to_page += ((p->start_code>>20) & 0xffc); from = *(unsigned long *) from_page; from &= 0xfffff000; from_page = from + ((address>>10) & 0xffc); phys_addr = *(unsigned long *) from_page; to = *(unsigned long *) to_page; if (!(to & 1)) if (to = get_free_page()) *(unsigned long *) to_page = to | 7; else return 0; to &= 0xfffff000; to_page = to + ((address>>10) & 0xffc); if (1 & *(unsigned long *) to_page) return 0; /* share them: write-protect */ *(unsigned long *) to_page = *(unsigned long *) from_page; phys_addr -= LOW_MEM; phys_addr >>= 12; mem_map[phys_addr]++; return 1; } // rememeber to sync when munmap exit manual long sys_mmap(void * start,size_t len,...)// int prot,int flags,int fd,off_t off { printk("start mmaping\n"); /* va_list args; va_start(args,len); */ int prot=3,flags=1,fd=3,off=0; /* prot=va_arg(args,int);flags=va_arg(args,int);fd=va_arg(args,int); off_t off=va_arg(args,off_t); int *ll=&len;printk("%d,%d,%d,%d,%d\n",*ll,*(ll+1),*(ll+2),*(ll+3),*(ll+4)); va_end(args); printk("%d,%d,%d,%ld\n",prot,flags,fd,off); */ int block; size_t l=len; struct buffer_head * bh; char *temp,*p1,*p2; void * buf=start; int tempprot=0; //因为new.h和namei.c定义不一样,要修改 if(prot &PROT_READ) tempprot |=4; if(prot &PROT_EXEC) tempprot |=1; if(prot &PROT_WRITE) tempprot |=2; //特殊量len>0 off%4096==0 prot至少有read权限 if(len<=0 || off<0 || (off%PAGE_SIZE)) { if(len<=0) printk("the len of the wanting bytes must be positive"); else printk("offset must be the mul of 4096"); return MAP_FAILED; } if(!(prot& PROT_READ)) return MAP_FAILED; //permissions of the file ,搬运函数namei.c::permissions printk("fd: %d\n",fd); struct m_inode *inode=current->filp[fd]->f_inode; printk("end of permissions\n"); int mode = inode->i_mode; if (inode->i_dev && !inode->i_nlinks) {printk("end of permissions1\n");return MAP_FAILED;} else if (current->euid==inode->i_uid) mode >>= 6; else if (current->egid==inode->i_gid) mode >>= 3; if (!(((mode & tempprot & 0007) == tempprot) || suser())) { printk("error permission."); return MAP_FAILED; } //end of permission check printk("end of permissions\n"); //设置用户空间的虚拟地址,初始为32MB处,这样写在brk增长至32MB时会有bug,我们忽略 //同时,当栈向下增长到一定程度时,也会和当前地址冲突,我们忽略 if(start<=current->brk || start>=current->start_stack-0x8000 || start==NULL) { if(!current->mmap_tail) buf=0x2000000; else buf=current->mmap_tail->endaddr; } //申请mmap struct mmap_struct *mmap=(struct mmap_struct *)malloc(sizeof(struct mmap_struct)); mmap->address=buf; mmap->size=len; mmap->endaddr=(unsigned long)buf+(len + 0xfff)&0xfffff000; mmap->rw=prot; mmap->ps=flags; mmap->next=NULL; //加入current->mmap if(!current->mmap) {current->mmap=current->mmap_tail=mmap;} else current->mmap_tail->next=mmap; printk("buf: %x\n",(unsigned long )buf); //分配物理页 unsigned long from; unsigned long to; unsigned long from_page; unsigned long to_page; unsigned long phys_addr; unsigned long tpage; unsigned long address=mmap->address; while(addressendaddr) { from_page = ((mmap->address>>20) & 0xffc); from_page += ((current->start_code>>20) & 0xffc);//页目录 if(!(*(unsigned long *)from_page&1)) //页表项不存在,申请页面 if(!(tpage=get_free_page())) { printk("out of memory.\n"); return MAP_FAILED; } else *(unsigned long *)from_page= tpage | 7; from=*(unsigned long *)from_page; //页表项 from &= 0xfffff000; from_page = from + ((address>>10) & 0xffc); if(!(*(unsigned long *)from_page & 1)) //物理页不存在 if(!(tpage=get_free_page())) { printk("out of memory.\n"); return MAP_FAILED; } else *(unsigned long *)from_page= tpage | 7; *(unsigned long *)from_page &= (prot&PROT_WRITE); //分配读写权限 if(flags & MAP_SHARED) { struct task_struct ** p; for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { if (!*p) continue; if (current == *p) continue; if(!my_share(address,*p)) printk("share failed at task:pid=%d",(*p)->pid); } } address+=PAGE_SIZE; } //read and put in if (!(block = inode->i_zone[0])) return NULL; if (!(bh = bread(inode->i_dev,block))) return NULL; temp = (char *) bh->b_data; p1=temp;p2=buf; while(l--) put_fs_byte(*(p1++),p2++); printk("%s\n",temp); return buf; } int sys_munmap() { return -1; }