xref: /xv6-public/sysfile.c (revision 9936bffa)
12685309fSrsc #include "types.h"
22685309fSrsc #include "stat.h"
32685309fSrsc #include "param.h"
42685309fSrsc #include "mmu.h"
52685309fSrsc #include "proc.h"
62685309fSrsc #include "defs.h"
72685309fSrsc #include "x86.h"
82685309fSrsc #include "traps.h"
92685309fSrsc #include "syscall.h"
102685309fSrsc #include "spinlock.h"
112685309fSrsc #include "buf.h"
122685309fSrsc #include "fs.h"
132685309fSrsc #include "fsvar.h"
142685309fSrsc #include "elf.h"
15*9936bffaSrsc #include "file.h"
162685309fSrsc #include "fcntl.h"
172685309fSrsc 
182685309fSrsc int
192685309fSrsc sys_pipe(void)
202685309fSrsc {
2139593d2fSrsc   struct file *rfd = 0, *wfd = 0;
222685309fSrsc   int f1 = -1, f2 = -1;
232685309fSrsc   struct proc *p = curproc[cpu()];
242685309fSrsc   uint fdp;
252685309fSrsc 
262685309fSrsc   if(pipe_alloc(&rfd, &wfd) < 0)
272685309fSrsc     goto oops;
282685309fSrsc   if((f1 = fd_ualloc()) < 0)
292685309fSrsc     goto oops;
3039593d2fSrsc   p->ofile[f1] = rfd;
312685309fSrsc   if((f2 = fd_ualloc()) < 0)
322685309fSrsc     goto oops;
3339593d2fSrsc   p->ofile[f2] = wfd;
342685309fSrsc   if(fetcharg(0, &fdp) < 0)
352685309fSrsc     goto oops;
362685309fSrsc   if(putint(p, fdp, f1) < 0)
372685309fSrsc     goto oops;
382685309fSrsc   if(putint(p, fdp+4, f2) < 0)
392685309fSrsc     goto oops;
402685309fSrsc   return 0;
412685309fSrsc 
422685309fSrsc  oops:
432685309fSrsc   if(rfd)
442685309fSrsc     fd_close(rfd);
452685309fSrsc   if(wfd)
462685309fSrsc     fd_close(wfd);
472685309fSrsc   if(f1 >= 0)
4839593d2fSrsc     p->ofile[f1] = 0;
492685309fSrsc   if(f2 >= 0)
5039593d2fSrsc     p->ofile[f2] = 0;
512685309fSrsc   return -1;
522685309fSrsc }
532685309fSrsc 
542685309fSrsc int
552685309fSrsc sys_write(void)
562685309fSrsc {
572685309fSrsc   int fd, n, ret;
582685309fSrsc   uint addr;
592685309fSrsc   struct proc *p = curproc[cpu()];
602685309fSrsc 
612685309fSrsc   if(fetcharg(0, &fd) < 0 || fetcharg(1, &addr) < 0 || fetcharg(2, &n) < 0)
622685309fSrsc     return -1;
632685309fSrsc   if(fd < 0 || fd >= NOFILE)
642685309fSrsc     return -1;
6539593d2fSrsc   if(p->ofile[fd] == 0)
662685309fSrsc     return -1;
672685309fSrsc   if(addr + n > p->sz)
682685309fSrsc     return -1;
692685309fSrsc 
7039593d2fSrsc   ret = fd_write(p->ofile[fd], p->mem + addr, n);
712685309fSrsc   return ret;
722685309fSrsc }
732685309fSrsc 
742685309fSrsc int
752685309fSrsc sys_read(void)
762685309fSrsc {
772685309fSrsc   int fd, n, ret;
782685309fSrsc   uint addr;
792685309fSrsc   struct proc *p = curproc[cpu()];
802685309fSrsc 
812685309fSrsc   if(fetcharg(0, &fd) < 0 || fetcharg(1, &addr) < 0 || fetcharg(2, &n) < 0)
822685309fSrsc     return -1;
832685309fSrsc   if(fd < 0 || fd >= NOFILE)
842685309fSrsc     return -1;
8539593d2fSrsc   if(p->ofile[fd] == 0)
862685309fSrsc     return -1;
872685309fSrsc   if(addr + n > p->sz)
882685309fSrsc     return -1;
8939593d2fSrsc   ret = fd_read(p->ofile[fd], p->mem + addr, n);
902685309fSrsc   return ret;
912685309fSrsc }
922685309fSrsc 
932685309fSrsc int
942685309fSrsc sys_close(void)
952685309fSrsc {
962685309fSrsc   int fd;
972685309fSrsc   struct proc *p = curproc[cpu()];
982685309fSrsc 
992685309fSrsc   if(fetcharg(0, &fd) < 0)
1002685309fSrsc     return -1;
1012685309fSrsc   if(fd < 0 || fd >= NOFILE)
1022685309fSrsc     return -1;
10339593d2fSrsc   if(p->ofile[fd] == 0)
1042685309fSrsc     return -1;
10539593d2fSrsc   fd_close(p->ofile[fd]);
10639593d2fSrsc   p->ofile[fd] = 0;
1072685309fSrsc   return 0;
1082685309fSrsc }
1092685309fSrsc 
1102685309fSrsc int
1112685309fSrsc sys_open(void)
1122685309fSrsc {
1132685309fSrsc   struct proc *cp = curproc[cpu()];
1142685309fSrsc   struct inode *ip, *dp;
1152685309fSrsc   uint arg0, arg1;
1162685309fSrsc   int ufd;
11739593d2fSrsc   struct file *fd;
1182685309fSrsc   int l;
1192685309fSrsc   char *last;
1202685309fSrsc 
1212685309fSrsc   if(fetcharg(0, &arg0) < 0 || fetcharg(1, &arg1) < 0)
1222685309fSrsc     return -1;
1232685309fSrsc   if((l = checkstring(arg0)) < 0)
1242685309fSrsc     return -1;
1252685309fSrsc 
1262685309fSrsc   if(arg1 & O_CREATE){
1272685309fSrsc     dp = namei(cp->mem + arg0, NAMEI_CREATE, 0, &last, &ip);
1282685309fSrsc     if(dp){
1292685309fSrsc       ip = mknod1(dp, last, T_FILE, 0, 0);
1302685309fSrsc       iput(dp);
1312685309fSrsc       if(ip == 0)
1322685309fSrsc         return -1;
1332685309fSrsc     } else if(ip == 0){
1342685309fSrsc       return -1;
1352685309fSrsc     } else if(ip->type == T_DIR){
1362685309fSrsc       iput(ip);
1372685309fSrsc       return -1;
1382685309fSrsc     }
1392685309fSrsc   } else {
1402685309fSrsc     ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0, 0, 0);
1412685309fSrsc     if(ip == 0)
1422685309fSrsc       return -1;
1432685309fSrsc   }
1442685309fSrsc   if(ip->type == T_DIR && ((arg1 & O_RDWR) || (arg1 & O_WRONLY))){
1452685309fSrsc     iput(ip);
1462685309fSrsc     return -1;
1472685309fSrsc   }
1482685309fSrsc 
1492685309fSrsc   if((fd = fd_alloc()) == 0){
1502685309fSrsc     iput(ip);
1512685309fSrsc     return -1;
1522685309fSrsc   }
1532685309fSrsc   if((ufd = fd_ualloc()) < 0){
1542685309fSrsc     iput(ip);
1552685309fSrsc     fd_close(fd);
1562685309fSrsc     return -1;
1572685309fSrsc   }
1582685309fSrsc 
1592685309fSrsc   iunlock(ip);
1602685309fSrsc   fd->type = FD_FILE;
1612685309fSrsc   if(arg1 & O_RDWR) {
1622685309fSrsc     fd->readable = 1;
1632685309fSrsc     fd->writable = 1;
1642685309fSrsc   } else if(arg1 & O_WRONLY) {
1652685309fSrsc     fd->readable = 0;
1662685309fSrsc     fd->writable = 1;
1672685309fSrsc   } else {
1682685309fSrsc     fd->readable = 1;
1692685309fSrsc     fd->writable = 0;
1702685309fSrsc   }
1712685309fSrsc   fd->ip = ip;
1722685309fSrsc   fd->off = 0;
17339593d2fSrsc   cp->ofile[ufd] = fd;
1742685309fSrsc 
1752685309fSrsc   return ufd;
1762685309fSrsc }
1772685309fSrsc 
1782685309fSrsc int
1792685309fSrsc sys_mknod(void)
1802685309fSrsc {
1812685309fSrsc   struct proc *cp = curproc[cpu()];
1822685309fSrsc   struct inode *nip;
1832685309fSrsc   uint arg0, arg1, arg2, arg3;
1842685309fSrsc   int l;
1852685309fSrsc 
1862685309fSrsc   if(fetcharg(0, &arg0) < 0 || fetcharg(1, &arg1) < 0 ||
1872685309fSrsc      fetcharg(2, &arg2) < 0 || fetcharg(3, &arg3) < 0)
1882685309fSrsc     return -1;
1892685309fSrsc 
1902685309fSrsc   if((l = checkstring(arg0)) < 0)
1912685309fSrsc     return -1;
1922685309fSrsc 
1932685309fSrsc   if(l >= DIRSIZ)
1942685309fSrsc     return -1;
1952685309fSrsc 
1962685309fSrsc   nip = mknod(cp->mem + arg0, (short) arg1, (short) arg2, (short) arg3);
1972685309fSrsc   if(nip)
1982685309fSrsc     iput(nip);
1992685309fSrsc   return (nip == 0) ? -1 : 0;
2002685309fSrsc }
2012685309fSrsc 
2022685309fSrsc int
2032685309fSrsc sys_mkdir(void)
2042685309fSrsc {
2052685309fSrsc   struct proc *cp = curproc[cpu()];
2062685309fSrsc   struct inode *nip;
2072685309fSrsc   struct inode *dp;
2082685309fSrsc   uint arg0;
2092685309fSrsc   int l;
2102685309fSrsc   struct dirent de;
2112685309fSrsc   char *last;
2122685309fSrsc 
2132685309fSrsc   if(fetcharg(0, &arg0) < 0)
2142685309fSrsc     return -1;
2152685309fSrsc 
2162685309fSrsc   if((l = checkstring(arg0)) < 0)
2172685309fSrsc     return -1;
2182685309fSrsc 
2192685309fSrsc   dp = namei(cp->mem + arg0, NAMEI_CREATE, 0, &last, 0);
2202685309fSrsc   if(dp == 0)
2212685309fSrsc     return -1;
2222685309fSrsc 
2232685309fSrsc   nip = mknod1(dp, last, T_DIR, 0, 0);
2242685309fSrsc   if(nip == 0){
2252685309fSrsc     iput(dp);
2262685309fSrsc     return -1;
2272685309fSrsc   }
2282685309fSrsc 
2292685309fSrsc   dp->nlink += 1;
2302685309fSrsc   iupdate(dp);
2312685309fSrsc 
2322685309fSrsc   memset(de.name, '\0', DIRSIZ);
2332685309fSrsc   de.name[0] = '.';
2342685309fSrsc   de.inum = nip->inum;
2352685309fSrsc   writei(nip, (char*) &de, 0, sizeof(de));
2362685309fSrsc 
2372685309fSrsc   de.inum = dp->inum;
2382685309fSrsc   de.name[1] = '.';
2392685309fSrsc   writei(nip, (char*) &de, sizeof(de), sizeof(de));
2402685309fSrsc 
2412685309fSrsc   iput(dp);
2422685309fSrsc   iput(nip);
2432685309fSrsc 
2442685309fSrsc   return 0;
2452685309fSrsc }
2462685309fSrsc 
2472685309fSrsc 
2482685309fSrsc int
2492685309fSrsc sys_chdir(void)
2502685309fSrsc {
2512685309fSrsc   struct proc *cp = curproc[cpu()];
2522685309fSrsc   struct inode *ip;
2532685309fSrsc     uint arg0;
2542685309fSrsc   int l;
2552685309fSrsc 
2562685309fSrsc   if(fetcharg(0, &arg0) < 0)
2572685309fSrsc     return -1;
2582685309fSrsc 
2592685309fSrsc   if((l = checkstring(arg0)) < 0)
2602685309fSrsc     return -1;
2612685309fSrsc 
2622685309fSrsc   if((ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0, 0, 0)) == 0)
2632685309fSrsc     return -1;
2642685309fSrsc 
2652685309fSrsc   if(ip == cp->cwd) {
2662685309fSrsc     iput(ip);
2672685309fSrsc     return 0;
2682685309fSrsc   }
2692685309fSrsc 
2702685309fSrsc   if(ip->type != T_DIR) {
2712685309fSrsc     iput(ip);
2722685309fSrsc     return -1;
2732685309fSrsc   }
2742685309fSrsc 
2752685309fSrsc   idecref(cp->cwd);
2762685309fSrsc   cp->cwd = ip;
2772685309fSrsc   iunlock(cp->cwd);
2782685309fSrsc   return 0;
2792685309fSrsc }
2802685309fSrsc 
2812685309fSrsc int
2822685309fSrsc sys_unlink(void)
2832685309fSrsc {
2842685309fSrsc   struct proc *cp = curproc[cpu()];
2852685309fSrsc   uint arg0;
2862685309fSrsc   int r;
2872685309fSrsc 
2882685309fSrsc   if(fetcharg(0, &arg0) < 0)
2892685309fSrsc     return -1;
2902685309fSrsc   if(checkstring(arg0) < 0)
2912685309fSrsc     return -1;
2922685309fSrsc   r = unlink(cp->mem + arg0);
2932685309fSrsc   return r;
2942685309fSrsc }
2952685309fSrsc 
2962685309fSrsc int
2972685309fSrsc sys_fstat(void)
2982685309fSrsc {
2992685309fSrsc   struct proc *cp = curproc[cpu()];
3002685309fSrsc   uint fd, addr;
3012685309fSrsc   int r;
3022685309fSrsc 
3032685309fSrsc   if(fetcharg(0, &fd) < 0)
3042685309fSrsc     return -1;
3052685309fSrsc   if(fetcharg(1, &addr) < 0)
3062685309fSrsc     return -1;
3072685309fSrsc   if(fd < 0 || fd >= NOFILE)
3082685309fSrsc     return -1;
30939593d2fSrsc   if(cp->ofile[fd] == 0)
3102685309fSrsc     return -1;
3112685309fSrsc   if(addr + sizeof(struct stat) > cp->sz)
3122685309fSrsc     return -1;
31339593d2fSrsc   r = fd_stat(cp->ofile[fd], (struct stat*)(cp->mem + addr));
3142685309fSrsc   return r;
3152685309fSrsc }
3162685309fSrsc 
3172685309fSrsc int
3182685309fSrsc sys_dup(void)
3192685309fSrsc {
3202685309fSrsc   struct proc *cp = curproc[cpu()];
3212685309fSrsc   uint fd, ufd1;
3222685309fSrsc 
3232685309fSrsc   if(fetcharg(0, &fd) < 0)
3242685309fSrsc     return -1;
3252685309fSrsc   if(fd < 0 || fd >= NOFILE)
3262685309fSrsc     return -1;
32739593d2fSrsc   if(cp->ofile[fd] == 0)
3282685309fSrsc     return -1;
3292685309fSrsc   if((ufd1 = fd_ualloc()) < 0)
3302685309fSrsc     return -1;
33139593d2fSrsc   cp->ofile[ufd1] = cp->ofile[fd];
33239593d2fSrsc   fd_incref(cp->ofile[ufd1]);
3332685309fSrsc   return ufd1;
3342685309fSrsc }
3352685309fSrsc 
3362685309fSrsc int
3372685309fSrsc sys_link(void)
3382685309fSrsc {
3392685309fSrsc   struct proc *cp = curproc[cpu()];
3402685309fSrsc   uint name1, name2;
3412685309fSrsc   int r;
3422685309fSrsc 
3432685309fSrsc   if(fetcharg(0, &name1) < 0 || checkstring(name1) < 0)
3442685309fSrsc     return -1;
3452685309fSrsc   if(fetcharg(1, &name2) < 0 || checkstring(name2) < 0)
3462685309fSrsc     return -1;
3472685309fSrsc   r = link(cp->mem + name1, cp->mem + name2);
3482685309fSrsc   return r;
3492685309fSrsc }
3502685309fSrsc 
3512685309fSrsc int
3522685309fSrsc sys_exec(void)
3532685309fSrsc {
3542685309fSrsc   struct proc *cp = curproc[cpu()];
3552685309fSrsc   uint arg0, arg1, sz=0, ap, sp, p1, p2;
3562685309fSrsc   int i, nargs, argbytes, len;
3572685309fSrsc   struct inode *ip;
3582685309fSrsc   struct elfhdr elf;
3592685309fSrsc   struct proghdr ph;
3602685309fSrsc   char *mem = 0;
3612685309fSrsc 
3622685309fSrsc   if(fetcharg(0, &arg0) < 0)
3632685309fSrsc     return -1;
3642685309fSrsc   if(fetcharg(1, &arg1) < 0)
3652685309fSrsc     return -1;
3662685309fSrsc   if(checkstring(arg0) < 0)
3672685309fSrsc     return -1;
3682685309fSrsc   ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0, 0, 0);
3692685309fSrsc   if(ip == 0)
3702685309fSrsc     return -1;
3712685309fSrsc 
3722685309fSrsc   if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))
3732685309fSrsc     goto bad;
3742685309fSrsc 
3752685309fSrsc   if(elf.magic != ELF_MAGIC)
3762685309fSrsc     goto bad;
3772685309fSrsc 
3782685309fSrsc   sz = 0;
3792685309fSrsc   for(i = 0; i < elf.phnum; i++){
3802685309fSrsc     if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
3812685309fSrsc              sizeof(ph)) != sizeof(ph))
3822685309fSrsc       goto bad;
3832685309fSrsc     if(ph.type != ELF_PROG_LOAD)
3842685309fSrsc       continue;
3852685309fSrsc     if(ph.memsz < ph.filesz)
3862685309fSrsc       goto bad;
3872685309fSrsc     sz += ph.memsz;
3882685309fSrsc   }
3892685309fSrsc 
3902685309fSrsc   sz += 4096 - (sz % 4096);
3912685309fSrsc   sz += 4096;
3922685309fSrsc 
3932685309fSrsc   mem = kalloc(sz);
3942685309fSrsc   if(mem == 0)
3952685309fSrsc     goto bad;
3962685309fSrsc   memset(mem, 0, sz);
3972685309fSrsc 
3982685309fSrsc   // arg1 is a pointer to an array of pointers to string.
3992685309fSrsc   nargs = 0;
4002685309fSrsc   argbytes = 0;
4012685309fSrsc   for(i = 0; ; i++){
4022685309fSrsc     if(fetchint(cp, arg1 + 4*i, &ap) < 0)
4032685309fSrsc       goto bad;
4042685309fSrsc     if(ap == 0)
4052685309fSrsc       break;
4062685309fSrsc     len = checkstring(ap);
4072685309fSrsc     if(len < 0)
4082685309fSrsc       goto bad;
4092685309fSrsc     nargs++;
4102685309fSrsc     argbytes += len + 1;
4112685309fSrsc   }
4122685309fSrsc 
4132685309fSrsc   // argn\0
4142685309fSrsc   // ...
4152685309fSrsc   // arg0\0
4162685309fSrsc   // 0
4172685309fSrsc   // ptr to argn
4182685309fSrsc   // ...
4192685309fSrsc   // 12: ptr to arg0
4202685309fSrsc   //  8: argv (points to ptr to arg0)
4212685309fSrsc   //  4: argc
4222685309fSrsc   //  0: fake return pc
4232685309fSrsc   sp = sz - argbytes - (nargs+1)*4 - 4 - 4 - 4;
4242685309fSrsc   *(uint*)(mem + sp) = 0xffffffff;
4252685309fSrsc   *(uint*)(mem + sp + 4) = nargs;
4262685309fSrsc   *(uint*)(mem + sp + 8) = (uint)(sp + 12);
4272685309fSrsc 
4282685309fSrsc   p1 = sp + 12;
4292685309fSrsc   p2 = sp + 12 + (nargs + 1) * 4;
4302685309fSrsc   for(i = 0; i < nargs; i++){
4312685309fSrsc     fetchint(cp, arg1 + 4*i, &ap);
4322685309fSrsc     len = checkstring(ap);
4332685309fSrsc     memmove(mem + p2, cp->mem + ap, len + 1);
4342685309fSrsc     *(uint*)(mem + p1) = p2;
4352685309fSrsc     p1 += 4;
4362685309fSrsc     p2 += len + 1;
4372685309fSrsc   }
4382685309fSrsc   *(uint*)(mem + p1) = 0;
4392685309fSrsc 
4402685309fSrsc   // commit to the new image.
4412685309fSrsc   kfree(cp->mem, cp->sz);
4422685309fSrsc   cp->sz = sz;
4432685309fSrsc   cp->mem = mem;
4442685309fSrsc   mem = 0;
4452685309fSrsc 
4462685309fSrsc   for(i = 0; i < elf.phnum; i++){
4472685309fSrsc     if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
4482685309fSrsc              sizeof(ph)) != sizeof(ph))
4492685309fSrsc       goto bad2;
4502685309fSrsc     if(ph.type != ELF_PROG_LOAD)
4512685309fSrsc       continue;
4522685309fSrsc     if(ph.va + ph.memsz > sz)
4532685309fSrsc       goto bad2;
4542685309fSrsc     if(readi(ip, cp->mem + ph.va, ph.offset, ph.filesz) != ph.filesz)
4552685309fSrsc       goto bad2;
4562685309fSrsc     memset(cp->mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz);
4572685309fSrsc   }
4582685309fSrsc 
4592685309fSrsc   iput(ip);
4602685309fSrsc 
4612685309fSrsc   cp->tf->eip = elf.entry;
4622685309fSrsc   cp->tf->esp = sp;
4632685309fSrsc   setupsegs(cp);
4642685309fSrsc 
4652685309fSrsc   return 0;
4662685309fSrsc 
4672685309fSrsc  bad:
4682685309fSrsc   if(mem)
4692685309fSrsc     kfree(mem, sz);
4702685309fSrsc   iput(ip);
4712685309fSrsc   return -1;
4722685309fSrsc 
4732685309fSrsc  bad2:
4742685309fSrsc   iput(ip);
4752685309fSrsc   proc_exit();
4762685309fSrsc   return 0;
4772685309fSrsc }
478