You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

646 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* linux/kernel/sys.c
*
* (C) 1991 Linus Torvalds
*/
#include <stdarg.h>
#include <linux/config.h>
#include <asm/system.h>
#include <asm/io.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <sys/times.h>
#include <sys/utsname.h>
#include <stdarg.h>
#include <new.h>
#include <mm.h>
//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(size<len && buf!=NULL)
{
errno=ERANGE;
return NULL;
}
if(!buf)
buf=(char*)malloc(len);
char *p1=buf;
char *p2=name;
while(len--)
put_fs_byte(*(p2++),p1++);
return buf;
}
//THE END
int sys_getdents(unsigned int fd,struct linux_dirent *dirp,unsigned int count)
{
struct m_inode *filenode =current->filp[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<entries)
{
if ((char *)de >= 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(count<nread)
{
errno=ERANGE;
return -1;
}//printk("%d",nread);
i=nread;
char *p1=dirp;
char *p2=initmp;
while(i--)
put_fs_byte(*(p2++),p1++);
free(initmp);
return nread;
}
int sys_pipe2()
{
return -1;
}
unsigned int sys_sleep(unsigned int seconds)
{
struct sigaction tmp;
tmp.sa_handler = (void (*)(int)) SIG_IGN;
tmp.sa_mask = 0;
tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
tmp.sa_restorer = (void (*)(void)) NULL;
current->sigaction[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 ; i<NR_TASKS ; i++)
if (task[i] && task[i]->pid==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;i<sizeof *name;i++)
put_fs_byte(((char *) &thisname)[i],i+(char *) name);
return 0;
}
int sys_sethostname()
{
return -ENOSYS;
}
int sys_getrlimit()
{
return -ENOSYS;
}
int sys_setrlimit()
{
return -ENOSYS;
}
int sys_getrusage()
{
return -ENOSYS;
}
int sys_gettimeofday()
{
return -ENOSYS;
}
int sys_settimeofday()
{
return -ENOSYS;
}
int sys_umask(int mask)
{
int old = current->umask;
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(address<mmap->endaddr)
{
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;
}