xref: /xv6-public/sysfile.c (revision 9583b476)
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 
18224f6598Srsc // Fetch the nth word-sized system call argument as a file descriptor
19224f6598Srsc // and return both the descriptor and the corresponding struct file.
20224f6598Srsc static int
21224f6598Srsc argfd(int argno, int *pfd, struct file **pf)
22224f6598Srsc {
23224f6598Srsc   int fd;
24224f6598Srsc   struct file *f;
25*9583b476Srsc   struct proc *cp = curproc[cpu()];
26224f6598Srsc 
27224f6598Srsc   if(argint(argno, &fd) < 0)
28224f6598Srsc     return -1;
29*9583b476Srsc   if(fd < 0 || fd >= NOFILE || (f=cp->ofile[fd]) == 0)
30224f6598Srsc     return -1;
31224f6598Srsc   if(pfd)
32224f6598Srsc     *pfd = fd;
33224f6598Srsc   if(pf)
34224f6598Srsc     *pf = f;
35224f6598Srsc   return 0;
36224f6598Srsc }
37224f6598Srsc 
38224f6598Srsc // Allocate a file descriptor for the given file.
39224f6598Srsc // Takes over file reference from caller on success.
40224f6598Srsc static int
41224f6598Srsc fdalloc(struct file *f)
42224f6598Srsc {
43224f6598Srsc   int fd;
44*9583b476Srsc   struct proc *cp = curproc[cpu()];
45*9583b476Srsc 
46224f6598Srsc   for(fd = 0; fd < NOFILE; fd++){
47*9583b476Srsc     if(cp->ofile[fd] == 0){
48*9583b476Srsc       cp->ofile[fd] = f;
49224f6598Srsc       return fd;
50224f6598Srsc     }
51224f6598Srsc   }
52224f6598Srsc   return -1;
53224f6598Srsc }
54224f6598Srsc 
552685309fSrsc int
562685309fSrsc sys_pipe(void)
572685309fSrsc {
58224f6598Srsc   int *fd;
59224f6598Srsc   struct file *rf = 0, *wf = 0;
60224f6598Srsc   int fd0, fd1;
61*9583b476Srsc   struct proc *cp = curproc[cpu()];
622685309fSrsc 
63224f6598Srsc   if(argptr(0, (void*)&fd, 2*sizeof fd[0]) < 0)
642685309fSrsc     return -1;
65224f6598Srsc   if(pipe_alloc(&rf, &wf) < 0)
66224f6598Srsc     return -1;
67224f6598Srsc   fd0 = -1;
68224f6598Srsc   if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
69224f6598Srsc     if(fd0 >= 0)
70*9583b476Srsc       cp->ofile[fd0] = 0;
71224f6598Srsc     fileclose(rf);
72224f6598Srsc     fileclose(wf);
73224f6598Srsc     return -1;
74224f6598Srsc   }
7570c3260dSrsc   fd[0] = fd0;
7670c3260dSrsc   fd[1] = fd1;
77224f6598Srsc   return 0;
782685309fSrsc }
792685309fSrsc 
802685309fSrsc int
812685309fSrsc sys_write(void)
822685309fSrsc {
83224f6598Srsc   struct file *f;
84224f6598Srsc   int n;
85224f6598Srsc   char *cp;
862685309fSrsc 
87224f6598Srsc   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0)
882685309fSrsc     return -1;
89224f6598Srsc   return filewrite(f, cp, n);
902685309fSrsc }
912685309fSrsc 
922685309fSrsc int
932685309fSrsc sys_read(void)
942685309fSrsc {
95224f6598Srsc   struct file *f;
96224f6598Srsc   int n;
97224f6598Srsc   char *cp;
982685309fSrsc 
99224f6598Srsc   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0)
1002685309fSrsc     return -1;
101224f6598Srsc   return fileread(f, cp, n);
1022685309fSrsc }
1032685309fSrsc 
1042685309fSrsc int
1052685309fSrsc sys_close(void)
1062685309fSrsc {
1072685309fSrsc   int fd;
108224f6598Srsc   struct file *f;
1092685309fSrsc 
110224f6598Srsc   if(argfd(0, &fd, &f) < 0)
1112685309fSrsc     return -1;
112224f6598Srsc   curproc[cpu()]->ofile[fd] = 0;
113224f6598Srsc   fileclose(f);
1142685309fSrsc   return 0;
1152685309fSrsc }
1162685309fSrsc 
1172685309fSrsc int
1182685309fSrsc sys_open(void)
1192685309fSrsc {
1202685309fSrsc   struct inode *ip, *dp;
121224f6598Srsc   char *path;
122224f6598Srsc   int omode;
123224f6598Srsc   int fd;
124224f6598Srsc   struct file *f;
1252685309fSrsc   char *last;
1262685309fSrsc 
127224f6598Srsc   if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
1282685309fSrsc     return -1;
1292685309fSrsc 
130224f6598Srsc   if(omode & O_CREATE){
131224f6598Srsc     dp = namei(path, NAMEI_CREATE, 0, &last, &ip);
1322685309fSrsc     if(dp){
1332685309fSrsc       ip = mknod1(dp, last, T_FILE, 0, 0);
1342685309fSrsc       iput(dp);
1352685309fSrsc       if(ip == 0)
1362685309fSrsc         return -1;
1372685309fSrsc     } else if(ip == 0){
1382685309fSrsc       return -1;
1392685309fSrsc     } else if(ip->type == T_DIR){
1402685309fSrsc       iput(ip);
1412685309fSrsc       return -1;
1422685309fSrsc     }
1432685309fSrsc   } else {
144224f6598Srsc     ip = namei(path, NAMEI_LOOKUP, 0, 0, 0);
1452685309fSrsc     if(ip == 0)
1462685309fSrsc       return -1;
1472685309fSrsc   }
148224f6598Srsc   if(ip->type == T_DIR && ((omode & O_RDWR) || (omode & O_WRONLY))){
1492685309fSrsc     iput(ip);
1502685309fSrsc     return -1;
1512685309fSrsc   }
1522685309fSrsc 
153224f6598Srsc   if((f = filealloc()) == 0){
1542685309fSrsc     iput(ip);
1552685309fSrsc     return -1;
1562685309fSrsc   }
157224f6598Srsc   if((fd = fdalloc(f)) < 0){
1582685309fSrsc     iput(ip);
159224f6598Srsc     fileclose(f);
1602685309fSrsc     return -1;
1612685309fSrsc   }
1622685309fSrsc 
1632685309fSrsc   iunlock(ip);
164224f6598Srsc   f->type = FD_FILE;
165224f6598Srsc   if(omode & O_RDWR) {
166224f6598Srsc     f->readable = 1;
167224f6598Srsc     f->writable = 1;
168224f6598Srsc   } else if(omode & O_WRONLY) {
169224f6598Srsc     f->readable = 0;
170224f6598Srsc     f->writable = 1;
1712685309fSrsc   } else {
172224f6598Srsc     f->readable = 1;
173224f6598Srsc     f->writable = 0;
1742685309fSrsc   }
175224f6598Srsc   f->ip = ip;
176224f6598Srsc   f->off = 0;
1772685309fSrsc 
178224f6598Srsc   return fd;
1792685309fSrsc }
1802685309fSrsc 
1812685309fSrsc int
1822685309fSrsc sys_mknod(void)
1832685309fSrsc {
1842685309fSrsc   struct inode *nip;
185224f6598Srsc   char *path;
186224f6598Srsc   int len;
187224f6598Srsc   int type, major, minor;
1882685309fSrsc 
189224f6598Srsc   if((len=argstr(0, &path)) < 0 || argint(1, &type) < 0 ||
190224f6598Srsc      argint(2, &major) < 0 || argint(3, &minor) < 0)
1912685309fSrsc     return -1;
1922685309fSrsc 
193224f6598Srsc   if(len >= DIRSIZ)
1942685309fSrsc     return -1;
1952685309fSrsc 
196224f6598Srsc   if((nip = mknod(path, type, major, minor)) == 0)
1972685309fSrsc     return -1;
1982685309fSrsc   iput(nip);
199224f6598Srsc   return 0;
2002685309fSrsc }
2012685309fSrsc 
2022685309fSrsc int
2032685309fSrsc sys_mkdir(void)
2042685309fSrsc {
2052685309fSrsc   struct inode *nip;
2062685309fSrsc   struct inode *dp;
207224f6598Srsc   char *path;
2082685309fSrsc   struct dirent de;
2092685309fSrsc   char *last;
2102685309fSrsc 
211224f6598Srsc   if(argstr(0, &path) < 0)
2122685309fSrsc     return -1;
2132685309fSrsc 
214224f6598Srsc   dp = namei(path, NAMEI_CREATE, 0, &last, 0);
2152685309fSrsc   if(dp == 0)
2162685309fSrsc     return -1;
2172685309fSrsc 
2182685309fSrsc   nip = mknod1(dp, last, T_DIR, 0, 0);
2192685309fSrsc   if(nip == 0){
2202685309fSrsc     iput(dp);
2212685309fSrsc     return -1;
2222685309fSrsc   }
2232685309fSrsc 
22419297cafSrsc   dp->nlink++;
2252685309fSrsc   iupdate(dp);
2262685309fSrsc 
2272685309fSrsc   memset(de.name, '\0', DIRSIZ);
2282685309fSrsc   de.name[0] = '.';
2292685309fSrsc   de.inum = nip->inum;
2302685309fSrsc   writei(nip, (char*) &de, 0, sizeof(de));
2312685309fSrsc 
2322685309fSrsc   de.inum = dp->inum;
2332685309fSrsc   de.name[1] = '.';
2342685309fSrsc   writei(nip, (char*) &de, sizeof(de), sizeof(de));
2352685309fSrsc 
2362685309fSrsc   iput(dp);
2372685309fSrsc   iput(nip);
2382685309fSrsc 
2392685309fSrsc   return 0;
2402685309fSrsc }
2412685309fSrsc 
2422685309fSrsc int
2432685309fSrsc sys_chdir(void)
2442685309fSrsc {
245*9583b476Srsc   struct proc *cp = curproc[cpu()];
2462685309fSrsc   struct inode *ip;
247224f6598Srsc   char *path;
2482685309fSrsc 
249224f6598Srsc   if(argstr(0, &path) < 0)
2502685309fSrsc     return -1;
2512685309fSrsc 
252224f6598Srsc   if((ip = namei(path, NAMEI_LOOKUP, 0, 0, 0)) == 0)
2532685309fSrsc     return -1;
2542685309fSrsc 
255224f6598Srsc   if(ip == p->cwd) {
2562685309fSrsc     iput(ip);
2572685309fSrsc     return 0;
2582685309fSrsc   }
2592685309fSrsc 
2602685309fSrsc   if(ip->type != T_DIR) {
2612685309fSrsc     iput(ip);
2622685309fSrsc     return -1;
2632685309fSrsc   }
2642685309fSrsc 
265*9583b476Srsc   idecref(cp->cwd);
266*9583b476Srsc   cp->cwd = ip;
267*9583b476Srsc   iunlock(cp->cwd);
2682685309fSrsc   return 0;
2692685309fSrsc }
2702685309fSrsc 
2712685309fSrsc int
2722685309fSrsc sys_unlink(void)
2732685309fSrsc {
274224f6598Srsc   char *path;
2752685309fSrsc 
276224f6598Srsc   if(argstr(0, &path) < 0)
2772685309fSrsc     return -1;
278224f6598Srsc   return unlink(path);
2792685309fSrsc }
2802685309fSrsc 
2812685309fSrsc int
2822685309fSrsc sys_fstat(void)
2832685309fSrsc {
284224f6598Srsc   struct file *f;
285224f6598Srsc   struct stat *st;
2862685309fSrsc 
287224f6598Srsc   if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof *st) < 0)
2882685309fSrsc     return -1;
289224f6598Srsc   return filestat(f, st);
2902685309fSrsc }
2912685309fSrsc 
2922685309fSrsc int
2932685309fSrsc sys_dup(void)
2942685309fSrsc {
295224f6598Srsc   struct file *f;
296224f6598Srsc   int fd;
2972685309fSrsc 
298224f6598Srsc   if(argfd(0, 0, &f) < 0)
2992685309fSrsc     return -1;
300224f6598Srsc   if((fd=fdalloc(f)) < 0)
3012685309fSrsc     return -1;
302224f6598Srsc   fileincref(f);
303224f6598Srsc   return fd;
3042685309fSrsc }
3052685309fSrsc 
3062685309fSrsc int
3072685309fSrsc sys_link(void)
3082685309fSrsc {
309224f6598Srsc   char *old, *new;
3102685309fSrsc 
311224f6598Srsc   if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
3122685309fSrsc     return -1;
313224f6598Srsc   return link(old, new);
3142685309fSrsc }
3152685309fSrsc 
3162685309fSrsc int
3172685309fSrsc sys_exec(void)
3182685309fSrsc {
3192685309fSrsc   struct proc *cp = curproc[cpu()];
320224f6598Srsc   uint sz=0, ap, sp, p1, p2;
3212685309fSrsc   int i, nargs, argbytes, len;
3222685309fSrsc   struct inode *ip;
3232685309fSrsc   struct elfhdr elf;
3242685309fSrsc   struct proghdr ph;
3252685309fSrsc   char *mem = 0;
3267366e042Srsc   char *path, *s, *last;
327224f6598Srsc   uint argv;
3282685309fSrsc 
329224f6598Srsc   if(argstr(0, &path) < 0 || argint(1, (int*)&argv) < 0)
3302685309fSrsc     return -1;
331224f6598Srsc 
332224f6598Srsc   ip = namei(path, NAMEI_LOOKUP, 0, 0, 0);
3332685309fSrsc   if(ip == 0)
3342685309fSrsc     return -1;
3352685309fSrsc 
3362685309fSrsc   if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))
3372685309fSrsc     goto bad;
3382685309fSrsc 
3392685309fSrsc   if(elf.magic != ELF_MAGIC)
3402685309fSrsc     goto bad;
3412685309fSrsc 
3422685309fSrsc   sz = 0;
3432685309fSrsc   for(i = 0; i < elf.phnum; i++){
3442685309fSrsc     if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
3452685309fSrsc              sizeof(ph)) != sizeof(ph))
3462685309fSrsc       goto bad;
3472685309fSrsc     if(ph.type != ELF_PROG_LOAD)
3482685309fSrsc       continue;
3492685309fSrsc     if(ph.memsz < ph.filesz)
3502685309fSrsc       goto bad;
3512685309fSrsc     sz += ph.memsz;
3522685309fSrsc   }
3532685309fSrsc 
3542685309fSrsc   sz += 4096 - (sz % 4096);
3552685309fSrsc   sz += 4096;
3562685309fSrsc 
3572685309fSrsc   mem = kalloc(sz);
3582685309fSrsc   if(mem == 0)
3592685309fSrsc     goto bad;
3602685309fSrsc   memset(mem, 0, sz);
3612685309fSrsc 
3622685309fSrsc   nargs = 0;
3632685309fSrsc   argbytes = 0;
3642685309fSrsc   for(i = 0;; i++){
365224f6598Srsc     if(fetchint(cp, argv + 4*i, (int*)&ap) < 0)
3662685309fSrsc       goto bad;
3672685309fSrsc     if(ap == 0)
3682685309fSrsc       break;
369224f6598Srsc     len = fetchstr(cp, ap, &s);
3702685309fSrsc     if(len < 0)
3712685309fSrsc       goto bad;
3722685309fSrsc     nargs++;
3732685309fSrsc     argbytes += len + 1;
3742685309fSrsc   }
3752685309fSrsc 
3762685309fSrsc   // argn\0
3772685309fSrsc   // ...
3782685309fSrsc   // arg0\0
3792685309fSrsc   // 0
3802685309fSrsc   // ptr to argn
3812685309fSrsc   // ...
3822685309fSrsc   // 12: ptr to arg0
3832685309fSrsc   //  8: argv (points to ptr to arg0)
3842685309fSrsc   //  4: argc
3852685309fSrsc   //  0: fake return pc
3862685309fSrsc   sp = sz - argbytes - (nargs+1)*4 - 4 - 4 - 4;
3872685309fSrsc   *(uint*)(mem + sp) = 0xffffffff;
3882685309fSrsc   *(uint*)(mem + sp + 4) = nargs;
3892685309fSrsc   *(uint*)(mem + sp + 8) = (uint)(sp + 12);
3902685309fSrsc 
3912685309fSrsc   p1 = sp + 12;
3922685309fSrsc   p2 = sp + 12 + (nargs + 1) * 4;
3932685309fSrsc   for(i = 0; i < nargs; i++){
394224f6598Srsc     fetchint(cp, argv + 4*i, (int*)&ap);
395224f6598Srsc     len = fetchstr(cp, ap, &s);
396224f6598Srsc     memmove(mem + p2, s, len + 1);
3972685309fSrsc     *(uint*)(mem + p1) = p2;
3982685309fSrsc     p1 += 4;
3992685309fSrsc     p2 += len + 1;
4002685309fSrsc   }
4012685309fSrsc   *(uint*)(mem + p1) = 0;
4022685309fSrsc 
4037366e042Srsc   // Save name for debugging.
4047366e042Srsc   for(last=s=path; *s; s++)
4057366e042Srsc     if(*s == '/')
4067366e042Srsc       last = s+1;
4077366e042Srsc   safestrcpy(cp->name, last, sizeof cp->name);
4087366e042Srsc 
4092685309fSrsc   // commit to the new image.
4102685309fSrsc   kfree(cp->mem, cp->sz);
4112685309fSrsc   cp->sz = sz;
4122685309fSrsc   cp->mem = mem;
4132685309fSrsc   mem = 0;
4142685309fSrsc 
4152685309fSrsc   for(i = 0; i < elf.phnum; i++){
4162685309fSrsc     if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
4172685309fSrsc              sizeof(ph)) != sizeof(ph))
4182685309fSrsc       goto bad2;
4192685309fSrsc     if(ph.type != ELF_PROG_LOAD)
4202685309fSrsc       continue;
4212685309fSrsc     if(ph.va + ph.memsz > sz)
4222685309fSrsc       goto bad2;
4232685309fSrsc     if(readi(ip, cp->mem + ph.va, ph.offset, ph.filesz) != ph.filesz)
4242685309fSrsc       goto bad2;
4252685309fSrsc     memset(cp->mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz);
4262685309fSrsc   }
4272685309fSrsc 
4282685309fSrsc   iput(ip);
4292685309fSrsc 
4302685309fSrsc   cp->tf->eip = elf.entry;
4312685309fSrsc   cp->tf->esp = sp;
4322685309fSrsc   setupsegs(cp);
4332685309fSrsc 
4342685309fSrsc   return 0;
4352685309fSrsc 
4362685309fSrsc  bad:
4372685309fSrsc   if(mem)
4382685309fSrsc     kfree(mem, sz);
4392685309fSrsc   iput(ip);
4402685309fSrsc   return -1;
4412685309fSrsc 
4422685309fSrsc  bad2:
4432685309fSrsc   iput(ip);
4442685309fSrsc   proc_exit();
4452685309fSrsc   return 0;
4462685309fSrsc }
447