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 53eaea18cbSrsc sys_read(void) 542685309fSrsc { 55eaea18cbSrsc struct file *f; 56eaea18cbSrsc int n; 57eaea18cbSrsc char *cp; 582685309fSrsc 59eaea18cbSrsc if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &cp, n) < 0) 602685309fSrsc return -1; 61eaea18cbSrsc 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*8d2e9a48Srsc sys_dup(void) 782685309fSrsc { 79224f6598Srsc struct file *f; 80*8d2e9a48Srsc int fd; 812685309fSrsc 82*8d2e9a48Srsc if(argfd(0, 0, &f) < 0) 832685309fSrsc return -1; 84*8d2e9a48Srsc if((fd=fdalloc(f)) < 0) 85*8d2e9a48Srsc return -1; 86*8d2e9a48Srsc fileincref(f); 87*8d2e9a48Srsc return fd; 882685309fSrsc } 892685309fSrsc 902685309fSrsc int 912685309fSrsc sys_close(void) 922685309fSrsc { 932685309fSrsc int fd; 94224f6598Srsc struct file *f; 952685309fSrsc 96224f6598Srsc if(argfd(0, &fd, &f) < 0) 972685309fSrsc return -1; 98b6095304Srsc cp->ofile[fd] = 0; 99224f6598Srsc fileclose(f); 1002685309fSrsc return 0; 1012685309fSrsc } 1022685309fSrsc 103*8d2e9a48Srsc int 104*8d2e9a48Srsc sys_fstat(void) 105*8d2e9a48Srsc { 106*8d2e9a48Srsc struct file *f; 107*8d2e9a48Srsc struct stat *st; 108*8d2e9a48Srsc 109*8d2e9a48Srsc if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0) 110*8d2e9a48Srsc return -1; 111*8d2e9a48Srsc return filestat(f, st); 112*8d2e9a48Srsc } 113*8d2e9a48Srsc 114eaea18cbSrsc // Create the path new as a link to the same inode as old. 115eaea18cbSrsc int 116eaea18cbSrsc sys_link(void) 117eaea18cbSrsc { 118eaea18cbSrsc char name[DIRSIZ], *new, *old; 119eaea18cbSrsc struct inode *dp, *ip; 120eaea18cbSrsc 121eaea18cbSrsc if(argstr(0, &old) < 0 || argstr(1, &new) < 0) 122eaea18cbSrsc return -1; 12307090dd7Srsc if((ip = namei(old)) == 0) 124eaea18cbSrsc return -1; 12507090dd7Srsc ilock(ip); 126eaea18cbSrsc if(ip->type == T_DIR){ 12707090dd7Srsc iunlockput(ip); 128eaea18cbSrsc return -1; 129eaea18cbSrsc } 130eaea18cbSrsc ip->nlink++; 131eaea18cbSrsc iupdate(ip); 13207090dd7Srsc iunlock(ip); 133eaea18cbSrsc 13407090dd7Srsc if((dp = nameiparent(new, name)) == 0) 13507090dd7Srsc goto bad; 13607090dd7Srsc ilock(dp); 13707090dd7Srsc if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0) 13807090dd7Srsc goto bad; 13907090dd7Srsc iunlockput(dp); 14007090dd7Srsc iput(ip); 14107090dd7Srsc return 0; 14207090dd7Srsc 14307090dd7Srsc bad: 144eaea18cbSrsc if(dp) 14507090dd7Srsc iunlockput(dp); 14607090dd7Srsc ilock(ip); 147eaea18cbSrsc ip->nlink--; 148eaea18cbSrsc iupdate(ip); 14907090dd7Srsc iunlockput(ip); 150eaea18cbSrsc return -1; 151eaea18cbSrsc } 152eaea18cbSrsc 153eaea18cbSrsc // Is the directory dp empty except for "." and ".." ? 154eaea18cbSrsc static int 155eaea18cbSrsc isdirempty(struct inode *dp) 156eaea18cbSrsc { 157eaea18cbSrsc int off; 158eaea18cbSrsc struct dirent de; 159eaea18cbSrsc 160eaea18cbSrsc for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){ 161eaea18cbSrsc if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 162eaea18cbSrsc panic("isdirempty: readi"); 163eaea18cbSrsc if(de.inum != 0) 164eaea18cbSrsc return 0; 165eaea18cbSrsc } 166eaea18cbSrsc return 1; 167eaea18cbSrsc } 168eaea18cbSrsc 169*8d2e9a48Srsc //PAGEBREAK! 170eaea18cbSrsc int 171eaea18cbSrsc sys_unlink(void) 172eaea18cbSrsc { 173eaea18cbSrsc struct inode *ip, *dp; 174eaea18cbSrsc struct dirent de; 175eaea18cbSrsc char name[DIRSIZ], *path; 176eaea18cbSrsc uint off; 177eaea18cbSrsc 178eaea18cbSrsc if(argstr(0, &path) < 0) 179eaea18cbSrsc return -1; 18007090dd7Srsc if((dp = nameiparent(path, name)) == 0) 181eaea18cbSrsc return -1; 18207090dd7Srsc ilock(dp); 183eaea18cbSrsc 184eaea18cbSrsc // Cannot unlink "." or "..". 185eaea18cbSrsc if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){ 18607090dd7Srsc iunlockput(dp); 187eaea18cbSrsc return -1; 188eaea18cbSrsc } 189eaea18cbSrsc 19007090dd7Srsc if((ip = dirlookup(dp, name, &off)) == 0){ 19107090dd7Srsc iunlockput(dp); 192eaea18cbSrsc return -1; 193eaea18cbSrsc } 19407090dd7Srsc ilock(ip); 195eaea18cbSrsc 196eaea18cbSrsc if(ip->nlink < 1) 197eaea18cbSrsc panic("unlink: nlink < 1"); 198eaea18cbSrsc if(ip->type == T_DIR && !isdirempty(ip)){ 19907090dd7Srsc iunlockput(ip); 20007090dd7Srsc iunlockput(dp); 201eaea18cbSrsc return -1; 202eaea18cbSrsc } 203eaea18cbSrsc 204eaea18cbSrsc memset(&de, 0, sizeof(de)); 205eaea18cbSrsc if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) 206eaea18cbSrsc panic("unlink: writei"); 20707090dd7Srsc iunlockput(dp); 208eaea18cbSrsc 209eaea18cbSrsc ip->nlink--; 210eaea18cbSrsc iupdate(ip); 21107090dd7Srsc iunlockput(ip); 212eaea18cbSrsc return 0; 213eaea18cbSrsc } 214eaea18cbSrsc 215eaea18cbSrsc static struct inode* 216eaea18cbSrsc mkpath(char *path, int canexist, short type, short major, short minor) 217eaea18cbSrsc { 218eaea18cbSrsc uint off; 219eaea18cbSrsc struct inode *ip, *dp; 220eaea18cbSrsc char name[DIRSIZ]; 221eaea18cbSrsc 22207090dd7Srsc if((dp = nameiparent(path, name)) == 0) 223eaea18cbSrsc return 0; 22407090dd7Srsc ilock(dp); 225eaea18cbSrsc 22607090dd7Srsc if(canexist && (ip = dirlookup(dp, name, &off)) != 0){ 22707090dd7Srsc iunlockput(dp); 22807090dd7Srsc ilock(ip); 229eaea18cbSrsc if(ip->type != type || ip->major != major || ip->minor != minor){ 23007090dd7Srsc iunlockput(ip); 231eaea18cbSrsc return 0; 232eaea18cbSrsc } 233eaea18cbSrsc return ip; 234eaea18cbSrsc } 235eaea18cbSrsc 23607090dd7Srsc if((ip = ialloc(dp->dev, type)) == 0){ 23707090dd7Srsc iunlockput(dp); 238eaea18cbSrsc return 0; 239eaea18cbSrsc } 24007090dd7Srsc ilock(ip); 241eaea18cbSrsc ip->major = major; 242eaea18cbSrsc ip->minor = minor; 243eaea18cbSrsc ip->size = 0; 244eaea18cbSrsc ip->nlink = 1; 245eaea18cbSrsc iupdate(ip); 246eaea18cbSrsc 247eaea18cbSrsc if(dirlink(dp, name, ip->inum) < 0){ 248eaea18cbSrsc ip->nlink = 0; 24907090dd7Srsc iunlockput(ip); 25007090dd7Srsc iunlockput(dp); 251eaea18cbSrsc return 0; 252eaea18cbSrsc } 253eaea18cbSrsc 254eaea18cbSrsc if(type == T_DIR){ // Create . and .. entries. 255eaea18cbSrsc dp->nlink++; // for ".." 256eaea18cbSrsc iupdate(dp); 257eaea18cbSrsc // No ip->nlink++ for ".": avoid cyclic ref count. 258eaea18cbSrsc if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0) 259eaea18cbSrsc panic("mkpath dots"); 260eaea18cbSrsc } 26107090dd7Srsc iunlockput(dp); 262eaea18cbSrsc return ip; 263eaea18cbSrsc } 264eaea18cbSrsc 2652685309fSrsc int 2662685309fSrsc sys_open(void) 2672685309fSrsc { 268f32f3638Srsc char *path; 269f32f3638Srsc int fd, omode; 270224f6598Srsc struct file *f; 271f32f3638Srsc struct inode *ip; 2722685309fSrsc 273224f6598Srsc if(argstr(0, &path) < 0 || argint(1, &omode) < 0) 2742685309fSrsc return -1; 2752685309fSrsc 276eaea18cbSrsc if(omode & O_CREATE){ 277eaea18cbSrsc if((ip = mkpath(path, 1, T_FILE, 0, 0)) == 0) 278e2a620daSrsc return -1; 279eaea18cbSrsc }else{ 28007090dd7Srsc if((ip = namei(path)) == 0) 281eaea18cbSrsc return -1; 28207090dd7Srsc ilock(ip); 283f32f3638Srsc if(ip->type == T_DIR && (omode & (O_RDWR|O_WRONLY))){ 28407090dd7Srsc iunlockput(ip); 2852685309fSrsc return -1; 2862685309fSrsc } 287eaea18cbSrsc } 2882685309fSrsc 289eaea18cbSrsc if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){ 290eaea18cbSrsc if(f) 291224f6598Srsc fileclose(f); 29207090dd7Srsc iunlockput(ip); 2932685309fSrsc return -1; 2942685309fSrsc } 29507090dd7Srsc iunlock(ip); 2962685309fSrsc 297eaea18cbSrsc f->type = FD_INODE; 29807090dd7Srsc f->ip = ip; 299eaea18cbSrsc f->off = 0; 300224f6598Srsc if(omode & O_RDWR) { 301224f6598Srsc f->readable = 1; 302224f6598Srsc f->writable = 1; 303224f6598Srsc } else if(omode & O_WRONLY) { 304224f6598Srsc f->readable = 0; 305224f6598Srsc f->writable = 1; 3062685309fSrsc } else { 307224f6598Srsc f->readable = 1; 308224f6598Srsc f->writable = 0; 3092685309fSrsc } 3102685309fSrsc 311224f6598Srsc return fd; 3122685309fSrsc } 3132685309fSrsc 3142685309fSrsc int 3152685309fSrsc sys_mknod(void) 3162685309fSrsc { 317eaea18cbSrsc struct inode *ip; 318224f6598Srsc char *path; 319224f6598Srsc int len; 320aa6824abSrsc int major, minor; 3212685309fSrsc 32207090dd7Srsc if((len=argstr(0, &path)) < 0 || 32307090dd7Srsc argint(1, &major) < 0 || 32407090dd7Srsc argint(2, &minor) < 0 || 32507090dd7Srsc (ip = mkpath(path, 0, T_DEV, major, minor)) == 0) 3262685309fSrsc return -1; 32707090dd7Srsc iunlockput(ip); 328224f6598Srsc return 0; 3292685309fSrsc } 3302685309fSrsc 3312685309fSrsc int 3322685309fSrsc sys_mkdir(void) 3332685309fSrsc { 334f32f3638Srsc char *path; 335eaea18cbSrsc struct inode *ip; 3362685309fSrsc 337eaea18cbSrsc if(argstr(0, &path) < 0 || (ip = mkpath(path, 0, T_DIR, 0, 0)) == 0) 3382685309fSrsc return -1; 33907090dd7Srsc iunlockput(ip); 340eaea18cbSrsc return 0; 3412685309fSrsc } 3422685309fSrsc 3432685309fSrsc int 3442685309fSrsc sys_chdir(void) 3452685309fSrsc { 346eaea18cbSrsc char *path; 3472685309fSrsc struct inode *ip; 3482685309fSrsc 34907090dd7Srsc if(argstr(0, &path) < 0 || (ip = namei(path)) == 0) 3502685309fSrsc return -1; 35107090dd7Srsc ilock(ip); 3522685309fSrsc if(ip->type != T_DIR) { 35307090dd7Srsc iunlockput(ip); 3542685309fSrsc return -1; 3552685309fSrsc } 35607090dd7Srsc iunlock(ip); 357eaea18cbSrsc iput(cp->cwd); 35807090dd7Srsc cp->cwd = ip; 3592685309fSrsc return 0; 3602685309fSrsc } 3612685309fSrsc 3622685309fSrsc int 3632685309fSrsc sys_exec(void) 3642685309fSrsc { 365eaea18cbSrsc char *path, *argv[20]; 366f32f3638Srsc int i; 367f32f3638Srsc uint uargv, uarg; 3682685309fSrsc 369f32f3638Srsc if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0) 3702685309fSrsc return -1; 371eaea18cbSrsc memset(argv, 0, sizeof(argv)); 3722685309fSrsc for(i=0;; i++){ 373eaea18cbSrsc if(i >= NELEM(argv)) 3742685309fSrsc return -1; 375f32f3638Srsc if(fetchint(cp, uargv+4*i, (int*)&uarg) < 0) 376f32f3638Srsc return -1; 377f32f3638Srsc if(uarg == 0){ 378f32f3638Srsc argv[i] = 0; 379f32f3638Srsc break; 3802685309fSrsc } 381f32f3638Srsc if(fetchstr(cp, uarg, &argv[i]) < 0) 382f32f3638Srsc return -1; 383f32f3638Srsc } 384f32f3638Srsc return exec(path, argv); 385f32f3638Srsc } 386f32f3638Srsc 387eaea18cbSrsc int 388eaea18cbSrsc sys_pipe(void) 389eaea18cbSrsc { 390eaea18cbSrsc int *fd; 391eaea18cbSrsc struct file *rf, *wf; 392eaea18cbSrsc int fd0, fd1; 393eaea18cbSrsc 394eaea18cbSrsc if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0) 395eaea18cbSrsc return -1; 396eaea18cbSrsc if(pipe_alloc(&rf, &wf) < 0) 397eaea18cbSrsc return -1; 398eaea18cbSrsc fd0 = -1; 399eaea18cbSrsc if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){ 400eaea18cbSrsc if(fd0 >= 0) 401eaea18cbSrsc cp->ofile[fd0] = 0; 402eaea18cbSrsc fileclose(rf); 403eaea18cbSrsc fileclose(wf); 404eaea18cbSrsc return -1; 405eaea18cbSrsc } 406eaea18cbSrsc fd[0] = fd0; 407eaea18cbSrsc fd[1] = fd1; 408eaea18cbSrsc return 0; 409eaea18cbSrsc } 410