xref: /xv6-public/sysfile.c (revision 224f6598)
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"
159936bffaSrsc #include "file.h"
162685309fSrsc #include "fcntl.h"
172685309fSrsc 
18*224f6598Srsc // Fetch the nth word-sized system call argument as a file descriptor
19*224f6598Srsc // and return both the descriptor and the corresponding struct file.
20*224f6598Srsc static int
21*224f6598Srsc argfd(int argno, int *pfd, struct file **pf)
22*224f6598Srsc {
23*224f6598Srsc   int fd;
24*224f6598Srsc   struct file *f;
25*224f6598Srsc   struct proc *p = curproc[cpu()];
26*224f6598Srsc 
27*224f6598Srsc   if(argint(argno, &fd) < 0)
28*224f6598Srsc     return -1;
29*224f6598Srsc   if(fd < 0 || fd >= NOFILE || (f=p->ofile[fd]) == 0)
30*224f6598Srsc     return -1;
31*224f6598Srsc   if(pfd)
32*224f6598Srsc     *pfd = fd;
33*224f6598Srsc   if(pf)
34*224f6598Srsc     *pf = f;
35*224f6598Srsc   return 0;
36*224f6598Srsc }
37*224f6598Srsc 
38*224f6598Srsc // Allocate a file descriptor for the given file.
39*224f6598Srsc // Takes over file reference from caller on success.
40*224f6598Srsc static int
41*224f6598Srsc fdalloc(struct file *f)
42*224f6598Srsc {
43*224f6598Srsc   int fd;
44*224f6598Srsc   struct proc *p = curproc[cpu()];
45*224f6598Srsc   for(fd = 0; fd < NOFILE; fd++){
46*224f6598Srsc     if(p->ofile[fd] == 0){
47*224f6598Srsc       p->ofile[fd] = f;
48*224f6598Srsc       return fd;
49*224f6598Srsc     }
50*224f6598Srsc   }
51*224f6598Srsc   return -1;
52*224f6598Srsc }
53*224f6598Srsc 
542685309fSrsc int
552685309fSrsc sys_pipe(void)
562685309fSrsc {
57*224f6598Srsc   int *fd;
58*224f6598Srsc   struct file *rf = 0, *wf = 0;
59*224f6598Srsc   int fd0, fd1;
602685309fSrsc   struct proc *p = curproc[cpu()];
612685309fSrsc 
62*224f6598Srsc   if(argptr(0, (void*)&fd, 2*sizeof fd[0]) < 0)
632685309fSrsc     return -1;
64*224f6598Srsc   if(pipe_alloc(&rf, &wf) < 0)
65*224f6598Srsc     return -1;
66*224f6598Srsc   fd0 = -1;
67*224f6598Srsc   if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
68*224f6598Srsc     if(fd0 >= 0)
69*224f6598Srsc       p->ofile[fd0] = 0;
70*224f6598Srsc     fileclose(rf);
71*224f6598Srsc     fileclose(wf);
72*224f6598Srsc     return -1;
73*224f6598Srsc   }
74*224f6598Srsc   return 0;
752685309fSrsc }
762685309fSrsc 
772685309fSrsc int
782685309fSrsc sys_write(void)
792685309fSrsc {
80*224f6598Srsc   struct file *f;
81*224f6598Srsc   int n;
82*224f6598Srsc   char *cp;
832685309fSrsc 
84*224f6598Srsc   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0)
852685309fSrsc     return -1;
86*224f6598Srsc   return filewrite(f, cp, n);
872685309fSrsc }
882685309fSrsc 
892685309fSrsc int
902685309fSrsc sys_read(void)
912685309fSrsc {
92*224f6598Srsc   struct file *f;
93*224f6598Srsc   int n;
94*224f6598Srsc   char *cp;
952685309fSrsc 
96*224f6598Srsc   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0)
972685309fSrsc     return -1;
98*224f6598Srsc   return fileread(f, cp, n);
992685309fSrsc }
1002685309fSrsc 
1012685309fSrsc int
1022685309fSrsc sys_close(void)
1032685309fSrsc {
1042685309fSrsc   int fd;
105*224f6598Srsc   struct file *f;
1062685309fSrsc 
107*224f6598Srsc   if(argfd(0, &fd, &f) < 0)
1082685309fSrsc     return -1;
109*224f6598Srsc   curproc[cpu()]->ofile[fd] = 0;
110*224f6598Srsc   fileclose(f);
1112685309fSrsc   return 0;
1122685309fSrsc }
1132685309fSrsc 
1142685309fSrsc int
1152685309fSrsc sys_open(void)
1162685309fSrsc {
1172685309fSrsc   struct inode *ip, *dp;
118*224f6598Srsc   char *path;
119*224f6598Srsc   int omode;
120*224f6598Srsc   int fd;
121*224f6598Srsc   struct file *f;
1222685309fSrsc   char *last;
1232685309fSrsc 
124*224f6598Srsc   if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
1252685309fSrsc     return -1;
1262685309fSrsc 
127*224f6598Srsc   if(omode & O_CREATE){
128*224f6598Srsc     dp = namei(path, NAMEI_CREATE, 0, &last, &ip);
1292685309fSrsc     if(dp){
1302685309fSrsc       ip = mknod1(dp, last, T_FILE, 0, 0);
1312685309fSrsc       iput(dp);
1322685309fSrsc       if(ip == 0)
1332685309fSrsc         return -1;
1342685309fSrsc     } else if(ip == 0){
1352685309fSrsc       return -1;
1362685309fSrsc     } else if(ip->type == T_DIR){
1372685309fSrsc       iput(ip);
1382685309fSrsc       return -1;
1392685309fSrsc     }
1402685309fSrsc   } else {
141*224f6598Srsc     ip = namei(path, NAMEI_LOOKUP, 0, 0, 0);
1422685309fSrsc     if(ip == 0)
1432685309fSrsc       return -1;
1442685309fSrsc   }
145*224f6598Srsc   if(ip->type == T_DIR && ((omode & O_RDWR) || (omode & O_WRONLY))){
1462685309fSrsc     iput(ip);
1472685309fSrsc     return -1;
1482685309fSrsc   }
1492685309fSrsc 
150*224f6598Srsc   if((f = filealloc()) == 0){
1512685309fSrsc     iput(ip);
1522685309fSrsc     return -1;
1532685309fSrsc   }
154*224f6598Srsc   if((fd = fdalloc(f)) < 0){
1552685309fSrsc     iput(ip);
156*224f6598Srsc     fileclose(f);
1572685309fSrsc     return -1;
1582685309fSrsc   }
1592685309fSrsc 
1602685309fSrsc   iunlock(ip);
161*224f6598Srsc   f->type = FD_FILE;
162*224f6598Srsc   if(omode & O_RDWR) {
163*224f6598Srsc     f->readable = 1;
164*224f6598Srsc     f->writable = 1;
165*224f6598Srsc   } else if(omode & O_WRONLY) {
166*224f6598Srsc     f->readable = 0;
167*224f6598Srsc     f->writable = 1;
1682685309fSrsc   } else {
169*224f6598Srsc     f->readable = 1;
170*224f6598Srsc     f->writable = 0;
1712685309fSrsc   }
172*224f6598Srsc   f->ip = ip;
173*224f6598Srsc   f->off = 0;
1742685309fSrsc 
175*224f6598Srsc   return fd;
1762685309fSrsc }
1772685309fSrsc 
1782685309fSrsc int
1792685309fSrsc sys_mknod(void)
1802685309fSrsc {
1812685309fSrsc   struct inode *nip;
182*224f6598Srsc   char *path;
183*224f6598Srsc   int len;
184*224f6598Srsc   int type, major, minor;
1852685309fSrsc 
186*224f6598Srsc   if((len=argstr(0, &path)) < 0 || argint(1, &type) < 0 ||
187*224f6598Srsc      argint(2, &major) < 0 || argint(3, &minor) < 0)
1882685309fSrsc     return -1;
1892685309fSrsc 
190*224f6598Srsc   if(len >= DIRSIZ)
1912685309fSrsc     return -1;
1922685309fSrsc 
193*224f6598Srsc   if((nip = mknod(path, type, major, minor)) == 0)
1942685309fSrsc     return -1;
1952685309fSrsc   iput(nip);
196*224f6598Srsc   return 0;
1972685309fSrsc }
1982685309fSrsc 
1992685309fSrsc int
2002685309fSrsc sys_mkdir(void)
2012685309fSrsc {
2022685309fSrsc   struct inode *nip;
2032685309fSrsc   struct inode *dp;
204*224f6598Srsc   char *path;
2052685309fSrsc   struct dirent de;
2062685309fSrsc   char *last;
2072685309fSrsc 
208*224f6598Srsc   if(argstr(0, &path) < 0)
2092685309fSrsc     return -1;
2102685309fSrsc 
211*224f6598Srsc   dp = namei(path, NAMEI_CREATE, 0, &last, 0);
2122685309fSrsc   if(dp == 0)
2132685309fSrsc     return -1;
2142685309fSrsc 
2152685309fSrsc   nip = mknod1(dp, last, T_DIR, 0, 0);
2162685309fSrsc   if(nip == 0){
2172685309fSrsc     iput(dp);
2182685309fSrsc     return -1;
2192685309fSrsc   }
2202685309fSrsc 
2212685309fSrsc   dp->nlink += 1;
2222685309fSrsc   iupdate(dp);
2232685309fSrsc 
2242685309fSrsc   memset(de.name, '\0', DIRSIZ);
2252685309fSrsc   de.name[0] = '.';
2262685309fSrsc   de.inum = nip->inum;
2272685309fSrsc   writei(nip, (char*) &de, 0, sizeof(de));
2282685309fSrsc 
2292685309fSrsc   de.inum = dp->inum;
2302685309fSrsc   de.name[1] = '.';
2312685309fSrsc   writei(nip, (char*) &de, sizeof(de), sizeof(de));
2322685309fSrsc 
2332685309fSrsc   iput(dp);
2342685309fSrsc   iput(nip);
2352685309fSrsc 
2362685309fSrsc   return 0;
2372685309fSrsc }
2382685309fSrsc 
2392685309fSrsc int
2402685309fSrsc sys_chdir(void)
2412685309fSrsc {
242*224f6598Srsc   struct proc *p = curproc[cpu()];
2432685309fSrsc   struct inode *ip;
244*224f6598Srsc   char *path;
2452685309fSrsc 
246*224f6598Srsc   if(argstr(0, &path) < 0)
2472685309fSrsc     return -1;
2482685309fSrsc 
249*224f6598Srsc   if((ip = namei(path, NAMEI_LOOKUP, 0, 0, 0)) == 0)
2502685309fSrsc     return -1;
2512685309fSrsc 
252*224f6598Srsc   if(ip == p->cwd) {
2532685309fSrsc     iput(ip);
2542685309fSrsc     return 0;
2552685309fSrsc   }
2562685309fSrsc 
2572685309fSrsc   if(ip->type != T_DIR) {
2582685309fSrsc     iput(ip);
2592685309fSrsc     return -1;
2602685309fSrsc   }
2612685309fSrsc 
262*224f6598Srsc   idecref(p->cwd);
263*224f6598Srsc   p->cwd = ip;
264*224f6598Srsc   iunlock(p->cwd);
2652685309fSrsc   return 0;
2662685309fSrsc }
2672685309fSrsc 
2682685309fSrsc int
2692685309fSrsc sys_unlink(void)
2702685309fSrsc {
271*224f6598Srsc   char *path;
2722685309fSrsc 
273*224f6598Srsc   if(argstr(0, &path) < 0)
2742685309fSrsc     return -1;
275*224f6598Srsc   return unlink(path);
2762685309fSrsc }
2772685309fSrsc 
2782685309fSrsc int
2792685309fSrsc sys_fstat(void)
2802685309fSrsc {
281*224f6598Srsc   struct file *f;
282*224f6598Srsc   struct stat *st;
2832685309fSrsc 
284*224f6598Srsc   if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof *st) < 0)
2852685309fSrsc     return -1;
286*224f6598Srsc   return filestat(f, st);
2872685309fSrsc }
2882685309fSrsc 
2892685309fSrsc int
2902685309fSrsc sys_dup(void)
2912685309fSrsc {
292*224f6598Srsc   struct file *f;
293*224f6598Srsc   int fd;
2942685309fSrsc 
295*224f6598Srsc   if(argfd(0, 0, &f) < 0)
2962685309fSrsc     return -1;
297*224f6598Srsc   if((fd=fdalloc(f)) < 0)
2982685309fSrsc     return -1;
299*224f6598Srsc   fileincref(f);
300*224f6598Srsc   return fd;
3012685309fSrsc }
3022685309fSrsc 
3032685309fSrsc int
3042685309fSrsc sys_link(void)
3052685309fSrsc {
306*224f6598Srsc   char *old, *new;
3072685309fSrsc 
308*224f6598Srsc   if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
3092685309fSrsc     return -1;
310*224f6598Srsc   return link(old, new);
3112685309fSrsc }
3122685309fSrsc 
3132685309fSrsc int
3142685309fSrsc sys_exec(void)
3152685309fSrsc {
3162685309fSrsc   struct proc *cp = curproc[cpu()];
317*224f6598Srsc   uint sz=0, ap, sp, p1, p2;
3182685309fSrsc   int i, nargs, argbytes, len;
3192685309fSrsc   struct inode *ip;
3202685309fSrsc   struct elfhdr elf;
3212685309fSrsc   struct proghdr ph;
3222685309fSrsc   char *mem = 0;
323*224f6598Srsc   char *path, *s;
324*224f6598Srsc   uint argv;
3252685309fSrsc 
326*224f6598Srsc   if(argstr(0, &path) < 0 || argint(1, (int*)&argv) < 0)
3272685309fSrsc     return -1;
328*224f6598Srsc 
329*224f6598Srsc   ip = namei(path, NAMEI_LOOKUP, 0, 0, 0);
3302685309fSrsc   if(ip == 0)
3312685309fSrsc     return -1;
3322685309fSrsc 
3332685309fSrsc   if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))
3342685309fSrsc     goto bad;
3352685309fSrsc 
3362685309fSrsc   if(elf.magic != ELF_MAGIC)
3372685309fSrsc     goto bad;
3382685309fSrsc 
3392685309fSrsc   sz = 0;
3402685309fSrsc   for(i = 0; i < elf.phnum; i++){
3412685309fSrsc     if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
3422685309fSrsc              sizeof(ph)) != sizeof(ph))
3432685309fSrsc       goto bad;
3442685309fSrsc     if(ph.type != ELF_PROG_LOAD)
3452685309fSrsc       continue;
3462685309fSrsc     if(ph.memsz < ph.filesz)
3472685309fSrsc       goto bad;
3482685309fSrsc     sz += ph.memsz;
3492685309fSrsc   }
3502685309fSrsc 
3512685309fSrsc   sz += 4096 - (sz % 4096);
3522685309fSrsc   sz += 4096;
3532685309fSrsc 
3542685309fSrsc   mem = kalloc(sz);
3552685309fSrsc   if(mem == 0)
3562685309fSrsc     goto bad;
3572685309fSrsc   memset(mem, 0, sz);
3582685309fSrsc 
3592685309fSrsc   nargs = 0;
3602685309fSrsc   argbytes = 0;
3612685309fSrsc   for(i = 0;; i++){
362*224f6598Srsc     if(fetchint(cp, argv + 4*i, (int*)&ap) < 0)
3632685309fSrsc       goto bad;
3642685309fSrsc     if(ap == 0)
3652685309fSrsc       break;
366*224f6598Srsc     len = fetchstr(cp, ap, &s);
3672685309fSrsc     if(len < 0)
3682685309fSrsc       goto bad;
3692685309fSrsc     nargs++;
3702685309fSrsc     argbytes += len + 1;
3712685309fSrsc   }
3722685309fSrsc 
3732685309fSrsc   // argn\0
3742685309fSrsc   // ...
3752685309fSrsc   // arg0\0
3762685309fSrsc   // 0
3772685309fSrsc   // ptr to argn
3782685309fSrsc   // ...
3792685309fSrsc   // 12: ptr to arg0
3802685309fSrsc   //  8: argv (points to ptr to arg0)
3812685309fSrsc   //  4: argc
3822685309fSrsc   //  0: fake return pc
3832685309fSrsc   sp = sz - argbytes - (nargs+1)*4 - 4 - 4 - 4;
3842685309fSrsc   *(uint*)(mem + sp) = 0xffffffff;
3852685309fSrsc   *(uint*)(mem + sp + 4) = nargs;
3862685309fSrsc   *(uint*)(mem + sp + 8) = (uint)(sp + 12);
3872685309fSrsc 
3882685309fSrsc   p1 = sp + 12;
3892685309fSrsc   p2 = sp + 12 + (nargs + 1) * 4;
3902685309fSrsc   for(i = 0; i < nargs; i++){
391*224f6598Srsc     fetchint(cp, argv + 4*i, (int*)&ap);
392*224f6598Srsc     len = fetchstr(cp, ap, &s);
393*224f6598Srsc     memmove(mem + p2, s, len + 1);
3942685309fSrsc     *(uint*)(mem + p1) = p2;
3952685309fSrsc     p1 += 4;
3962685309fSrsc     p2 += len + 1;
3972685309fSrsc   }
3982685309fSrsc   *(uint*)(mem + p1) = 0;
3992685309fSrsc 
4002685309fSrsc   // commit to the new image.
4012685309fSrsc   kfree(cp->mem, cp->sz);
4022685309fSrsc   cp->sz = sz;
4032685309fSrsc   cp->mem = mem;
4042685309fSrsc   mem = 0;
4052685309fSrsc 
4062685309fSrsc   for(i = 0; i < elf.phnum; i++){
4072685309fSrsc     if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
4082685309fSrsc              sizeof(ph)) != sizeof(ph))
4092685309fSrsc       goto bad2;
4102685309fSrsc     if(ph.type != ELF_PROG_LOAD)
4112685309fSrsc       continue;
4122685309fSrsc     if(ph.va + ph.memsz > sz)
4132685309fSrsc       goto bad2;
4142685309fSrsc     if(readi(ip, cp->mem + ph.va, ph.offset, ph.filesz) != ph.filesz)
4152685309fSrsc       goto bad2;
4162685309fSrsc     memset(cp->mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz);
4172685309fSrsc   }
4182685309fSrsc 
4192685309fSrsc   iput(ip);
4202685309fSrsc 
4212685309fSrsc   cp->tf->eip = elf.entry;
4222685309fSrsc   cp->tf->esp = sp;
4232685309fSrsc   setupsegs(cp);
4242685309fSrsc 
4252685309fSrsc   return 0;
4262685309fSrsc 
4272685309fSrsc  bad:
4282685309fSrsc   if(mem)
4292685309fSrsc     kfree(mem, sz);
4302685309fSrsc   iput(ip);
4312685309fSrsc   return -1;
4322685309fSrsc 
4332685309fSrsc  bad2:
4342685309fSrsc   iput(ip);
4352685309fSrsc   proc_exit();
4362685309fSrsc   return 0;
4372685309fSrsc }
438