xref: /xv6-public/sysfile.c (revision e2a620da)
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;
25224f6598Srsc 
26224f6598Srsc   if(argint(argno, &fd) < 0)
27224f6598Srsc     return -1;
289583b476Srsc   if(fd < 0 || fd >= NOFILE || (f=cp->ofile[fd]) == 0)
29224f6598Srsc     return -1;
30224f6598Srsc   if(pfd)
31224f6598Srsc     *pfd = fd;
32224f6598Srsc   if(pf)
33224f6598Srsc     *pf = f;
34224f6598Srsc   return 0;
35224f6598Srsc }
36224f6598Srsc 
37224f6598Srsc // Allocate a file descriptor for the given file.
38224f6598Srsc // Takes over file reference from caller on success.
39224f6598Srsc static int
40224f6598Srsc fdalloc(struct file *f)
41224f6598Srsc {
42224f6598Srsc   int fd;
439583b476Srsc 
44224f6598Srsc   for(fd = 0; fd < NOFILE; fd++){
459583b476Srsc     if(cp->ofile[fd] == 0){
469583b476Srsc       cp->ofile[fd] = f;
47224f6598Srsc       return fd;
48224f6598Srsc     }
49224f6598Srsc   }
50224f6598Srsc   return -1;
51224f6598Srsc }
52224f6598Srsc 
532685309fSrsc int
542685309fSrsc sys_pipe(void)
552685309fSrsc {
56224f6598Srsc   int *fd;
57dca5b5caSrsc   struct file *rf, *wf;
58224f6598Srsc   int fd0, fd1;
592685309fSrsc 
60224f6598Srsc   if(argptr(0, (void*)&fd, 2*sizeof fd[0]) < 0)
612685309fSrsc     return -1;
62224f6598Srsc   if(pipe_alloc(&rf, &wf) < 0)
63224f6598Srsc     return -1;
64224f6598Srsc   fd0 = -1;
65224f6598Srsc   if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
66224f6598Srsc     if(fd0 >= 0)
679583b476Srsc       cp->ofile[fd0] = 0;
68224f6598Srsc     fileclose(rf);
69224f6598Srsc     fileclose(wf);
70224f6598Srsc     return -1;
71224f6598Srsc   }
7270c3260dSrsc   fd[0] = fd0;
7370c3260dSrsc   fd[1] = fd1;
74224f6598Srsc   return 0;
752685309fSrsc }
762685309fSrsc 
772685309fSrsc int
782685309fSrsc sys_write(void)
792685309fSrsc {
80224f6598Srsc   struct file *f;
81224f6598Srsc   int n;
82224f6598Srsc   char *cp;
832685309fSrsc 
84224f6598Srsc   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0)
852685309fSrsc     return -1;
86224f6598Srsc   return filewrite(f, cp, n);
872685309fSrsc }
882685309fSrsc 
892685309fSrsc int
902685309fSrsc sys_read(void)
912685309fSrsc {
92224f6598Srsc   struct file *f;
93224f6598Srsc   int n;
94224f6598Srsc   char *cp;
952685309fSrsc 
96224f6598Srsc   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0)
972685309fSrsc     return -1;
98224f6598Srsc   return fileread(f, cp, n);
992685309fSrsc }
1002685309fSrsc 
1012685309fSrsc int
1022685309fSrsc sys_close(void)
1032685309fSrsc {
1042685309fSrsc   int fd;
105224f6598Srsc   struct file *f;
1062685309fSrsc 
107224f6598Srsc   if(argfd(0, &fd, &f) < 0)
1082685309fSrsc     return -1;
109b6095304Srsc   cp->ofile[fd] = 0;
110224f6598Srsc   fileclose(f);
1112685309fSrsc   return 0;
1122685309fSrsc }
1132685309fSrsc 
1142685309fSrsc int
1152685309fSrsc sys_open(void)
1162685309fSrsc {
1172685309fSrsc   struct inode *ip, *dp;
118*e2a620daSrsc   char *path, *name;
119*e2a620daSrsc   int namelen;
120224f6598Srsc   int omode;
121*e2a620daSrsc   int fd, dev;
122*e2a620daSrsc   uint inum;
123224f6598Srsc   struct file *f;
1242685309fSrsc 
125224f6598Srsc   if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
1262685309fSrsc     return -1;
1272685309fSrsc 
128*e2a620daSrsc   switch(omode & O_CREATE){
129*e2a620daSrsc   default:
130*e2a620daSrsc   case 0: // regular open
131*e2a620daSrsc     if((ip = namei(path)) == 0)
132*e2a620daSrsc       return -1;
133*e2a620daSrsc     break;
134*e2a620daSrsc 
135*e2a620daSrsc   case O_CREATE:
136*e2a620daSrsc     if((dp = nameiparent(path, &name, &namelen)) == 0)
137*e2a620daSrsc       return -1;
138*e2a620daSrsc     if(dirlookup(dp, name, namelen, 0, &inum) >= 0){
139*e2a620daSrsc       dev = dp->dev;
1402685309fSrsc       iput(dp);
141*e2a620daSrsc       ip = iget(dev, inum);
1422685309fSrsc     }else{
143*e2a620daSrsc       if((ip = dircreat(dp, name, namelen, T_FILE, 0, 0)) == 0){
144*e2a620daSrsc         iput(dp);
1452685309fSrsc         return -1;
1462685309fSrsc       }
147*e2a620daSrsc       iput(dp);
148*e2a620daSrsc     }
149*e2a620daSrsc     break;
150*e2a620daSrsc   }
151*e2a620daSrsc 
152*e2a620daSrsc   if(ip->type == T_DIR && (omode & (O_RDWR|O_WRONLY|O_CREATE))){
1532685309fSrsc     iput(ip);
1542685309fSrsc     return -1;
1552685309fSrsc   }
1562685309fSrsc 
157224f6598Srsc   if((f = filealloc()) == 0){
1582685309fSrsc     iput(ip);
1592685309fSrsc     return -1;
1602685309fSrsc   }
161224f6598Srsc   if((fd = fdalloc(f)) < 0){
1622685309fSrsc     iput(ip);
163224f6598Srsc     fileclose(f);
1642685309fSrsc     return -1;
1652685309fSrsc   }
1662685309fSrsc 
1672685309fSrsc   iunlock(ip);
168224f6598Srsc   f->type = FD_FILE;
169224f6598Srsc   if(omode & O_RDWR) {
170224f6598Srsc     f->readable = 1;
171224f6598Srsc     f->writable = 1;
172224f6598Srsc   } else if(omode & O_WRONLY) {
173224f6598Srsc     f->readable = 0;
174224f6598Srsc     f->writable = 1;
1752685309fSrsc   } else {
176224f6598Srsc     f->readable = 1;
177224f6598Srsc     f->writable = 0;
1782685309fSrsc   }
179224f6598Srsc   f->ip = ip;
180224f6598Srsc   f->off = 0;
1812685309fSrsc 
182224f6598Srsc   return fd;
1832685309fSrsc }
1842685309fSrsc 
1852685309fSrsc int
1862685309fSrsc sys_mknod(void)
1872685309fSrsc {
1882685309fSrsc   struct inode *nip;
189224f6598Srsc   char *path;
190224f6598Srsc   int len;
191224f6598Srsc   int type, major, minor;
1922685309fSrsc 
193224f6598Srsc   if((len=argstr(0, &path)) < 0 || argint(1, &type) < 0 ||
194224f6598Srsc      argint(2, &major) < 0 || argint(3, &minor) < 0)
1952685309fSrsc     return -1;
1962685309fSrsc 
197224f6598Srsc   if(len >= DIRSIZ)
1982685309fSrsc     return -1;
1992685309fSrsc 
200224f6598Srsc   if((nip = mknod(path, type, major, minor)) == 0)
2012685309fSrsc     return -1;
2022685309fSrsc   iput(nip);
203224f6598Srsc   return 0;
2042685309fSrsc }
2052685309fSrsc 
2062685309fSrsc int
2072685309fSrsc sys_mkdir(void)
2082685309fSrsc {
2092685309fSrsc   struct inode *nip;
2102685309fSrsc   struct inode *dp;
211*e2a620daSrsc   char *name, *path;
2122685309fSrsc   struct dirent de;
213*e2a620daSrsc   int namelen;
2142685309fSrsc 
215224f6598Srsc   if(argstr(0, &path) < 0)
2162685309fSrsc     return -1;
2172685309fSrsc 
218*e2a620daSrsc   dp = nameiparent(path, &name, &namelen);
2192685309fSrsc   if(dp == 0)
2202685309fSrsc     return -1;
221*e2a620daSrsc   if(dirlookup(dp, name, namelen, 0, 0) >= 0){
222*e2a620daSrsc     iput(dp);
223*e2a620daSrsc     return -1;
224*e2a620daSrsc   }
2252685309fSrsc 
226*e2a620daSrsc   nip = dircreat(dp, name, namelen, T_DIR, 0, 0);
2272685309fSrsc   if(nip == 0){
2282685309fSrsc     iput(dp);
2292685309fSrsc     return -1;
2302685309fSrsc   }
2312685309fSrsc 
23219297cafSrsc   dp->nlink++;
2332685309fSrsc   iupdate(dp);
2342685309fSrsc 
2352685309fSrsc   memset(de.name, '\0', DIRSIZ);
2362685309fSrsc   de.name[0] = '.';
2372685309fSrsc   de.inum = nip->inum;
2382685309fSrsc   writei(nip, (char*) &de, 0, sizeof(de));
2392685309fSrsc 
2402685309fSrsc   de.inum = dp->inum;
2412685309fSrsc   de.name[1] = '.';
2422685309fSrsc   writei(nip, (char*) &de, sizeof(de), sizeof(de));
2432685309fSrsc 
2442685309fSrsc   iput(dp);
2452685309fSrsc   iput(nip);
2462685309fSrsc 
2472685309fSrsc   return 0;
2482685309fSrsc }
2492685309fSrsc 
2502685309fSrsc int
2512685309fSrsc sys_chdir(void)
2522685309fSrsc {
2532685309fSrsc   struct inode *ip;
254224f6598Srsc   char *path;
2552685309fSrsc 
256224f6598Srsc   if(argstr(0, &path) < 0)
2572685309fSrsc     return -1;
2582685309fSrsc 
259*e2a620daSrsc   if((ip = namei(path)) == 0)
2602685309fSrsc     return -1;
2612685309fSrsc 
2622685309fSrsc   if(ip->type != T_DIR) {
2632685309fSrsc     iput(ip);
2642685309fSrsc     return -1;
2652685309fSrsc   }
2662685309fSrsc 
267*e2a620daSrsc   iunlock(ip);
2689583b476Srsc   idecref(cp->cwd);
2699583b476Srsc   cp->cwd = ip;
2702685309fSrsc   return 0;
2712685309fSrsc }
2722685309fSrsc 
2732685309fSrsc int
2742685309fSrsc sys_unlink(void)
2752685309fSrsc {
276224f6598Srsc   char *path;
2772685309fSrsc 
278224f6598Srsc   if(argstr(0, &path) < 0)
2792685309fSrsc     return -1;
280224f6598Srsc   return unlink(path);
2812685309fSrsc }
2822685309fSrsc 
2832685309fSrsc int
2842685309fSrsc sys_fstat(void)
2852685309fSrsc {
286224f6598Srsc   struct file *f;
287224f6598Srsc   struct stat *st;
2882685309fSrsc 
289224f6598Srsc   if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof *st) < 0)
2902685309fSrsc     return -1;
291224f6598Srsc   return filestat(f, st);
2922685309fSrsc }
2932685309fSrsc 
2942685309fSrsc int
2952685309fSrsc sys_dup(void)
2962685309fSrsc {
297224f6598Srsc   struct file *f;
298224f6598Srsc   int fd;
2992685309fSrsc 
300224f6598Srsc   if(argfd(0, 0, &f) < 0)
3012685309fSrsc     return -1;
302224f6598Srsc   if((fd=fdalloc(f)) < 0)
3032685309fSrsc     return -1;
304224f6598Srsc   fileincref(f);
305224f6598Srsc   return fd;
3062685309fSrsc }
3072685309fSrsc 
3082685309fSrsc int
3092685309fSrsc sys_link(void)
3102685309fSrsc {
311224f6598Srsc   char *old, *new;
3122685309fSrsc 
313224f6598Srsc   if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
3142685309fSrsc     return -1;
315224f6598Srsc   return link(old, new);
3162685309fSrsc }
3172685309fSrsc 
3182685309fSrsc int
3192685309fSrsc sys_exec(void)
3202685309fSrsc {
321224f6598Srsc   uint sz=0, ap, sp, p1, p2;
3222685309fSrsc   int i, nargs, argbytes, len;
3232685309fSrsc   struct inode *ip;
3242685309fSrsc   struct elfhdr elf;
3252685309fSrsc   struct proghdr ph;
3262685309fSrsc   char *mem = 0;
3277366e042Srsc   char *path, *s, *last;
328224f6598Srsc   uint argv;
3292685309fSrsc 
330224f6598Srsc   if(argstr(0, &path) < 0 || argint(1, (int*)&argv) < 0)
3312685309fSrsc     return -1;
332224f6598Srsc 
333*e2a620daSrsc   if((ip = namei(path)) == 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