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.

545 lines
10 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);
}
// 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;
//特殊量
if(!len || off<0 || (off%PAGE_SIZE)) return MAP_FAILED;
if(!(prot& PROT_READ)) return MAP_FAILED;
//permissions of the file
printk("end of permissions0\n");
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");
if(start<=current->brk || start>=current->start_stack-0x8000 || start==NULL)
{
if(!current->mmap_tail)
buf=0x2000000;
else
buf=current->mmap_tail->endaddr;
}
struct mmap_struct *mmap=(struct mmap_struct *)malloc(sizeof(struct mmap_struct));
mmap->address=buf;mmap->size=len;
mmap->endaddr=buf+(len + 0xfff)&0xfffff000;
mmap->rw=prot;mmap->ps=flags;
mmap->next=NULL;
if(!current->mmap)
{current->mmap=current->mapp_tail=mapp;}
else
current->mmap_tail->next=mapp;
printk("buf: %x\n",(unsigned long )buf);
//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;
printk("end of mmap\n");
p1=temp;p2=buf;
while(l--)
put_fs_byte(*(p1++),p2++);
printk("%s\n",temp);
return buf;
}
int sys_munmap()
{
return -1;
}