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" 149936bffaSrsc #include "file.h" 152685309fSrsc #include "fcntl.h" 162685309fSrsc 17224f6598Srsc // Fetch the nth word-sized system call argument as a file descriptor 18224f6598Srsc // and return both the descriptor and the corresponding struct file. 19224f6598Srsc static int 20224f6598Srsc argfd(int argno, int *pfd, struct file **pf) 21224f6598Srsc { 22224f6598Srsc int fd; 23224f6598Srsc struct file *f; 24224f6598Srsc 25224f6598Srsc if(argint(argno, &fd) < 0) 26224f6598Srsc return -1; 279583b476Srsc if(fd < 0 || fd >= NOFILE || (f=cp->ofile[fd]) == 0) 28224f6598Srsc return -1; 29224f6598Srsc if(pfd) 30224f6598Srsc *pfd = fd; 31224f6598Srsc if(pf) 32224f6598Srsc *pf = f; 33224f6598Srsc return 0; 34224f6598Srsc } 35224f6598Srsc 36224f6598Srsc // Allocate a file descriptor for the given file. 37224f6598Srsc // Takes over file reference from caller on success. 38224f6598Srsc static int 39224f6598Srsc fdalloc(struct file *f) 40224f6598Srsc { 41224f6598Srsc int fd; 429583b476Srsc 43224f6598Srsc for(fd = 0; fd < NOFILE; fd++){ 449583b476Srsc if(cp->ofile[fd] == 0){ 459583b476Srsc cp->ofile[fd] = f; 46224f6598Srsc return fd; 47224f6598Srsc } 48224f6598Srsc } 49224f6598Srsc return -1; 50224f6598Srsc } 51224f6598Srsc 522685309fSrsc int 53*eaea18cbSrsc sys_read(void) 542685309fSrsc { 55*eaea18cbSrsc struct file *f; 56*eaea18cbSrsc int n; 57*eaea18cbSrsc char *cp; 582685309fSrsc 59*eaea18cbSrsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0) 602685309fSrsc return -1; 61*eaea18cbSrsc return fileread(f, cp, n); 622685309fSrsc } 632685309fSrsc 642685309fSrsc int 652685309fSrsc sys_write(void) 662685309fSrsc { 67224f6598Srsc struct file *f; 68224f6598Srsc int n; 69224f6598Srsc char *cp; 702685309fSrsc 71224f6598Srsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0) 722685309fSrsc return -1; 73224f6598Srsc return filewrite(f, cp, n); 742685309fSrsc } 752685309fSrsc 762685309fSrsc int 77*eaea18cbSrsc sys_fstat(void) 782685309fSrsc { 79224f6598Srsc struct file *f; 80*eaea18cbSrsc struct stat *st; 812685309fSrsc 82*eaea18cbSrsc if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0) 832685309fSrsc return -1; 84*eaea18cbSrsc return filestat(f, st); 852685309fSrsc } 862685309fSrsc 872685309fSrsc int 882685309fSrsc sys_close(void) 892685309fSrsc { 902685309fSrsc int fd; 91224f6598Srsc struct file *f; 922685309fSrsc 93224f6598Srsc if(argfd(0, &fd, &f) < 0) 942685309fSrsc return -1; 95b6095304Srsc cp->ofile[fd] = 0; 96224f6598Srsc fileclose(f); 972685309fSrsc return 0; 982685309fSrsc } 992685309fSrsc 100*eaea18cbSrsc // Create the path new as a link to the same inode as old. 101*eaea18cbSrsc int 102*eaea18cbSrsc sys_link(void) 103*eaea18cbSrsc { 104*eaea18cbSrsc char name[DIRSIZ], *new, *old; 105*eaea18cbSrsc struct inode *dp, *ip; 106*eaea18cbSrsc struct uinode *ipu; 107*eaea18cbSrsc 108*eaea18cbSrsc if(argstr(0, &old) < 0 || argstr(1, &new) < 0) 109*eaea18cbSrsc return -1; 110*eaea18cbSrsc if((ip = ilock(namei(old))) == 0) 111*eaea18cbSrsc return -1; 112*eaea18cbSrsc if(ip->type == T_DIR){ 113*eaea18cbSrsc iput(iunlock(ip)); 114*eaea18cbSrsc return -1; 115*eaea18cbSrsc } 116*eaea18cbSrsc ip->nlink++; 117*eaea18cbSrsc iupdate(ip); 118*eaea18cbSrsc ipu = iunlock(ip); ip = 0; 119*eaea18cbSrsc 120*eaea18cbSrsc if((dp = ilock(nameiparent(new, name))) == 0 || 121*eaea18cbSrsc dp->dev != ipu->dev || dirlink(dp, name, ipu->inum) < 0){ 122*eaea18cbSrsc if(dp) 123*eaea18cbSrsc iput(iunlock(dp)); 124*eaea18cbSrsc ip = ilock(ipu); 125*eaea18cbSrsc ip->nlink--; 126*eaea18cbSrsc iupdate(ip); 127*eaea18cbSrsc iput(iunlock(ip)); 128*eaea18cbSrsc return -1; 129*eaea18cbSrsc } 130*eaea18cbSrsc iput(iunlock(dp)); 131*eaea18cbSrsc iput(ipu); 132*eaea18cbSrsc return 0; 133*eaea18cbSrsc } 134*eaea18cbSrsc 135*eaea18cbSrsc // Is the directory dp empty except for "." and ".." ? 136*eaea18cbSrsc static int 137*eaea18cbSrsc isdirempty(struct inode *dp) 138*eaea18cbSrsc { 139*eaea18cbSrsc int off; 140*eaea18cbSrsc struct dirent de; 141*eaea18cbSrsc 142*eaea18cbSrsc for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){ 143*eaea18cbSrsc if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 144*eaea18cbSrsc panic("isdirempty: readi"); 145*eaea18cbSrsc if(de.inum != 0) 146*eaea18cbSrsc return 0; 147*eaea18cbSrsc } 148*eaea18cbSrsc return 1; 149*eaea18cbSrsc } 150*eaea18cbSrsc 151*eaea18cbSrsc int 152*eaea18cbSrsc sys_unlink(void) 153*eaea18cbSrsc { 154*eaea18cbSrsc struct inode *ip, *dp; 155*eaea18cbSrsc struct dirent de; 156*eaea18cbSrsc char name[DIRSIZ], *path; 157*eaea18cbSrsc uint off; 158*eaea18cbSrsc 159*eaea18cbSrsc if(argstr(0, &path) < 0) 160*eaea18cbSrsc return -1; 161*eaea18cbSrsc if((dp = ilock(nameiparent(path, name))) == 0) 162*eaea18cbSrsc return -1; 163*eaea18cbSrsc 164*eaea18cbSrsc // Cannot unlink "." or "..". 165*eaea18cbSrsc if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){ 166*eaea18cbSrsc iput(iunlock(dp)); 167*eaea18cbSrsc return -1; 168*eaea18cbSrsc } 169*eaea18cbSrsc 170*eaea18cbSrsc if((ip = ilock(dirlookup(dp, name, &off))) == 0){ 171*eaea18cbSrsc iput(iunlock(dp)); 172*eaea18cbSrsc return -1; 173*eaea18cbSrsc } 174*eaea18cbSrsc 175*eaea18cbSrsc if(ip->nlink < 1) 176*eaea18cbSrsc panic("unlink: nlink < 1"); 177*eaea18cbSrsc if(ip->type == T_DIR && !isdirempty(ip)){ 178*eaea18cbSrsc iput(iunlock(ip)); 179*eaea18cbSrsc iput(iunlock(dp)); 180*eaea18cbSrsc return -1; 181*eaea18cbSrsc } 182*eaea18cbSrsc 183*eaea18cbSrsc memset(&de, 0, sizeof(de)); 184*eaea18cbSrsc if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 185*eaea18cbSrsc panic("unlink: writei"); 186*eaea18cbSrsc iput(iunlock(dp)); 187*eaea18cbSrsc 188*eaea18cbSrsc ip->nlink--; 189*eaea18cbSrsc iupdate(ip); 190*eaea18cbSrsc iput(iunlock(ip)); 191*eaea18cbSrsc return 0; 192*eaea18cbSrsc } 193*eaea18cbSrsc 194*eaea18cbSrsc // Create the path and return its unlocked inode structure. 195*eaea18cbSrsc static struct inode* 196*eaea18cbSrsc mkpath(char *path, int canexist, short type, short major, short minor) 197*eaea18cbSrsc { 198*eaea18cbSrsc uint off; 199*eaea18cbSrsc struct inode *ip, *dp; 200*eaea18cbSrsc struct uinode *ipu; 201*eaea18cbSrsc char name[DIRSIZ]; 202*eaea18cbSrsc 203*eaea18cbSrsc if((dp = ilock(nameiparent(path, name))) == 0) 204*eaea18cbSrsc return 0; 205*eaea18cbSrsc 206*eaea18cbSrsc if(canexist && (ipu = dirlookup(dp, name, &off)) != 0){ 207*eaea18cbSrsc iput(iunlock(dp)); 208*eaea18cbSrsc ip = ilock(ipu); 209*eaea18cbSrsc if(ip->type != type || ip->major != major || ip->minor != minor){ 210*eaea18cbSrsc iput(iunlock(ip)); 211*eaea18cbSrsc return 0; 212*eaea18cbSrsc } 213*eaea18cbSrsc return ip; 214*eaea18cbSrsc } 215*eaea18cbSrsc 216*eaea18cbSrsc if((ip = ilock(ialloc(dp->dev, type))) == 0){ 217*eaea18cbSrsc iput(iunlock(dp)); 218*eaea18cbSrsc return 0; 219*eaea18cbSrsc } 220*eaea18cbSrsc ip->major = major; 221*eaea18cbSrsc ip->minor = minor; 222*eaea18cbSrsc ip->size = 0; 223*eaea18cbSrsc ip->nlink = 1; 224*eaea18cbSrsc iupdate(ip); 225*eaea18cbSrsc 226*eaea18cbSrsc if(dirlink(dp, name, ip->inum) < 0){ 227*eaea18cbSrsc ip->nlink = 0; 228*eaea18cbSrsc iput(iunlock(ip)); 229*eaea18cbSrsc iput(iunlock(dp)); 230*eaea18cbSrsc return 0; 231*eaea18cbSrsc } 232*eaea18cbSrsc 233*eaea18cbSrsc if(type == T_DIR){ // Create . and .. entries. 234*eaea18cbSrsc dp->nlink++; // for ".." 235*eaea18cbSrsc iupdate(dp); 236*eaea18cbSrsc // No ip->nlink++ for ".": avoid cyclic ref count. 237*eaea18cbSrsc if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) 238*eaea18cbSrsc panic("mkpath dots"); 239*eaea18cbSrsc } 240*eaea18cbSrsc iput(iunlock(dp)); 241*eaea18cbSrsc return ip; 242*eaea18cbSrsc } 243*eaea18cbSrsc 2442685309fSrsc int 2452685309fSrsc sys_open(void) 2462685309fSrsc { 247f32f3638Srsc char *path; 248f32f3638Srsc int fd, omode; 249224f6598Srsc struct file *f; 250f32f3638Srsc struct inode *ip; 2512685309fSrsc 252224f6598Srsc if(argstr(0, &path) < 0 || argint(1, &omode) < 0) 2532685309fSrsc return -1; 2542685309fSrsc 255*eaea18cbSrsc if(omode & O_CREATE){ 256*eaea18cbSrsc if((ip = mkpath(path, 1, T_FILE, 0, 0)) == 0) 257e2a620daSrsc return -1; 258*eaea18cbSrsc }else{ 259*eaea18cbSrsc if((ip = ilock(namei(path))) == 0) 260*eaea18cbSrsc return -1; 261f32f3638Srsc if(ip->type == T_DIR && (omode & (O_RDWR|O_WRONLY))){ 262*eaea18cbSrsc iput(iunlock(ip)); 2632685309fSrsc return -1; 2642685309fSrsc } 265*eaea18cbSrsc } 2662685309fSrsc 267*eaea18cbSrsc if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ 268*eaea18cbSrsc if(f) 269224f6598Srsc fileclose(f); 270*eaea18cbSrsc iput(iunlock(ip)); 2712685309fSrsc return -1; 2722685309fSrsc } 2732685309fSrsc 274*eaea18cbSrsc f->type = FD_INODE; 275*eaea18cbSrsc f->ip = iunlock(ip); 276*eaea18cbSrsc f->off = 0; 277224f6598Srsc if(omode & O_RDWR) { 278224f6598Srsc f->readable = 1; 279224f6598Srsc f->writable = 1; 280224f6598Srsc } else if(omode & O_WRONLY) { 281224f6598Srsc f->readable = 0; 282224f6598Srsc f->writable = 1; 2832685309fSrsc } else { 284224f6598Srsc f->readable = 1; 285224f6598Srsc f->writable = 0; 2862685309fSrsc } 2872685309fSrsc 288224f6598Srsc return fd; 2892685309fSrsc } 2902685309fSrsc 2912685309fSrsc int 2922685309fSrsc sys_mknod(void) 2932685309fSrsc { 294*eaea18cbSrsc struct inode *ip; 295224f6598Srsc char *path; 296224f6598Srsc int len; 297224f6598Srsc int type, major, minor; 2982685309fSrsc 299224f6598Srsc if((len=argstr(0, &path)) < 0 || argint(1, &type) < 0 || 300224f6598Srsc argint(2, &major) < 0 || argint(3, &minor) < 0) 3012685309fSrsc return -1; 302*eaea18cbSrsc // XXX check that type == T_DEV or eliminate type arg? 303*eaea18cbSrsc if((ip = mkpath(path, 0, type, major, minor)) == 0) 3042685309fSrsc return -1; 305*eaea18cbSrsc iput(iunlock(ip)); 306224f6598Srsc return 0; 3072685309fSrsc } 3082685309fSrsc 3092685309fSrsc int 3102685309fSrsc sys_mkdir(void) 3112685309fSrsc { 312f32f3638Srsc char *path; 313*eaea18cbSrsc struct inode *ip; 3142685309fSrsc 315*eaea18cbSrsc if(argstr(0, &path) < 0 || (ip = mkpath(path, 0, T_DIR, 0, 0)) == 0) 3162685309fSrsc return -1; 317*eaea18cbSrsc iput(iunlock(ip)); 318*eaea18cbSrsc return 0; 3192685309fSrsc } 3202685309fSrsc 3212685309fSrsc int 3222685309fSrsc sys_chdir(void) 3232685309fSrsc { 324*eaea18cbSrsc char *path; 3252685309fSrsc struct inode *ip; 3262685309fSrsc 327*eaea18cbSrsc if(argstr(0, &path) < 0 || (ip = ilock(namei(path))) == 0) 3282685309fSrsc return -1; 3292685309fSrsc if(ip->type != T_DIR) { 330*eaea18cbSrsc iput(iunlock(ip)); 3312685309fSrsc return -1; 3322685309fSrsc } 333*eaea18cbSrsc iput(cp->cwd); 334*eaea18cbSrsc cp->cwd = iunlock(ip); 3352685309fSrsc return 0; 3362685309fSrsc } 3372685309fSrsc 3382685309fSrsc int 3392685309fSrsc sys_dup(void) 3402685309fSrsc { 341224f6598Srsc struct file *f; 342224f6598Srsc int fd; 3432685309fSrsc 344224f6598Srsc if(argfd(0, 0, &f) < 0) 3452685309fSrsc return -1; 346224f6598Srsc if((fd=fdalloc(f)) < 0) 3472685309fSrsc return -1; 348224f6598Srsc fileincref(f); 349224f6598Srsc return fd; 3502685309fSrsc } 3512685309fSrsc 3522685309fSrsc int 3532685309fSrsc sys_exec(void) 3542685309fSrsc { 355*eaea18cbSrsc char *path, *argv[20]; 356f32f3638Srsc int i; 357f32f3638Srsc uint uargv, uarg; 3582685309fSrsc 359f32f3638Srsc if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0) 3602685309fSrsc return -1; 361*eaea18cbSrsc memset(argv, 0, sizeof(argv)); 3622685309fSrsc for(i=0;; i++){ 363*eaea18cbSrsc if(i >= NELEM(argv)) 3642685309fSrsc return -1; 365f32f3638Srsc if(fetchint(cp, uargv+4*i, (int*)&uarg) < 0) 366f32f3638Srsc return -1; 367f32f3638Srsc if(uarg == 0){ 368f32f3638Srsc argv[i] = 0; 369f32f3638Srsc break; 3702685309fSrsc } 371f32f3638Srsc if(fetchstr(cp, uarg, &argv[i]) < 0) 372f32f3638Srsc return -1; 373f32f3638Srsc } 374f32f3638Srsc return exec(path, argv); 375f32f3638Srsc } 376f32f3638Srsc 377*eaea18cbSrsc int 378*eaea18cbSrsc sys_pipe(void) 379*eaea18cbSrsc { 380*eaea18cbSrsc int *fd; 381*eaea18cbSrsc struct file *rf, *wf; 382*eaea18cbSrsc int fd0, fd1; 383*eaea18cbSrsc 384*eaea18cbSrsc if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0) 385*eaea18cbSrsc return -1; 386*eaea18cbSrsc if(pipe_alloc(&rf, &wf) < 0) 387*eaea18cbSrsc return -1; 388*eaea18cbSrsc fd0 = -1; 389*eaea18cbSrsc if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ 390*eaea18cbSrsc if(fd0 >= 0) 391*eaea18cbSrsc cp->ofile[fd0] = 0; 392*eaea18cbSrsc fileclose(rf); 393*eaea18cbSrsc fileclose(wf); 394*eaea18cbSrsc return -1; 395*eaea18cbSrsc } 396*eaea18cbSrsc fd[0] = fd0; 397*eaea18cbSrsc fd[1] = fd1; 398*eaea18cbSrsc return 0; 399*eaea18cbSrsc } 400