1*6423Sroot /* vfs_syscalls.c 4.22 82/04/01 */ 237Sbill 337Sbill #include "../h/param.h" 437Sbill #include "../h/systm.h" 537Sbill #include "../h/dir.h" 637Sbill #include "../h/user.h" 76254Sroot #include "../h/reg.h" 86254Sroot #include "../h/file.h" 937Sbill #include "../h/inode.h" 106254Sroot #include "../h/ino.h" 116254Sroot #include "../h/pte.h" 126254Sroot #include "../h/vm.h" 136254Sroot #include "../h/buf.h" 146254Sroot #include "../h/mtpr.h" 156254Sroot #include "../h/proc.h" 166254Sroot #include "../h/inline.h" 1737Sbill #include "../h/conf.h" 184918Swnj #include "../h/socket.h" 194918Swnj #include "../h/socketvar.h" 206254Sroot #include "../h/stat.h" 2137Sbill 226254Sroot chdir() 236254Sroot { 246254Sroot 256254Sroot chdirec(&u.u_cdir); 266254Sroot } 276254Sroot 286254Sroot chroot() 296254Sroot { 306254Sroot 316254Sroot if (suser()) 326254Sroot chdirec(&u.u_rdir); 336254Sroot } 346254Sroot 356254Sroot chdirec(ipp) 366254Sroot register struct inode **ipp; 376254Sroot { 386254Sroot register struct inode *ip; 396254Sroot struct a { 406254Sroot char *fname; 416254Sroot }; 426254Sroot 436254Sroot ip = namei(uchar, 0, 1); 446254Sroot if(ip == NULL) 456254Sroot return; 466254Sroot if((ip->i_mode&IFMT) != IFDIR) { 476254Sroot u.u_error = ENOTDIR; 486254Sroot goto bad; 496254Sroot } 506254Sroot if(access(ip, IEXEC)) 516254Sroot goto bad; 526254Sroot irele(ip); 536254Sroot if (*ipp) { 546254Sroot ilock(*ipp); 556254Sroot iput(*ipp); 566254Sroot } 576254Sroot *ipp = ip; 586254Sroot return; 596254Sroot 606254Sroot bad: 616254Sroot iput(ip); 626254Sroot } 636254Sroot 6437Sbill /* 656254Sroot * Open system call. 666254Sroot */ 676254Sroot open() 686254Sroot { 696254Sroot register struct inode *ip; 706254Sroot register struct a { 716254Sroot char *fname; 726254Sroot int rwmode; 736254Sroot } *uap; 746254Sroot 756254Sroot uap = (struct a *)u.u_ap; 766254Sroot ip = namei(uchar, 0, 1); 776254Sroot if (ip == NULL) 786254Sroot return; 796254Sroot open1(ip, ++uap->rwmode, 0); 806254Sroot } 816254Sroot 826254Sroot /* 836254Sroot * Creat system call. 846254Sroot */ 856254Sroot creat() 866254Sroot { 876254Sroot register struct inode *ip; 886254Sroot register struct a { 896254Sroot char *fname; 906254Sroot int fmode; 916254Sroot } *uap; 926254Sroot 936254Sroot uap = (struct a *)u.u_ap; 946254Sroot ip = namei(uchar, 1, 1); 956254Sroot if (ip == NULL) { 966254Sroot if (u.u_error) 976254Sroot return; 986254Sroot ip = maknode(uap->fmode&07777&(~ISVTX)); 996254Sroot if (ip==NULL) 1006254Sroot return; 1016254Sroot open1(ip, FWRITE, 2); 1026254Sroot } else 1036254Sroot open1(ip, FWRITE, 1); 1046254Sroot } 1056254Sroot 1066254Sroot /* 1076254Sroot * Common code for open and creat. 1086254Sroot * Check permissions, allocate an open file structure, 1096254Sroot * and call the device open routine if any. 1106254Sroot */ 1116254Sroot open1(ip, mode, trf) 1126254Sroot register struct inode *ip; 1136254Sroot register mode; 1146254Sroot { 1156254Sroot register struct file *fp; 1166254Sroot int i; 1176254Sroot 1186254Sroot if (trf != 2) { 1196254Sroot if (mode&FREAD) 1206254Sroot (void) access(ip, IREAD); 1216254Sroot if (mode&FWRITE) { 1226254Sroot (void) access(ip, IWRITE); 1236254Sroot if ((ip->i_mode&IFMT) == IFDIR) 1246254Sroot u.u_error = EISDIR; 1256254Sroot } 1266254Sroot } 1276254Sroot if (u.u_error) 1286254Sroot goto out; 1296254Sroot if (trf == 1) 1306254Sroot itrunc(ip); 1316254Sroot irele(ip); 1326254Sroot if ((fp = falloc()) == NULL) 1336254Sroot goto out; 1346254Sroot fp->f_flag = mode&(FREAD|FWRITE); 1356254Sroot i = u.u_r.r_val1; 1366254Sroot fp->f_inode = ip; 1376254Sroot openi(ip, mode&(FREAD|FWRITE)); 1386254Sroot if (u.u_error == 0) 1396254Sroot return; 1406254Sroot u.u_ofile[i] = NULL; 1416254Sroot fp->f_count--; 1426254Sroot out: 1436254Sroot if (ip != NULL) 1446254Sroot iput(ip); 1456254Sroot } 1466254Sroot 1476254Sroot /* 1486254Sroot * Mknod system call 1496254Sroot */ 1506254Sroot mknod() 1516254Sroot { 1526254Sroot register struct inode *ip; 1536254Sroot register struct a { 1546254Sroot char *fname; 1556254Sroot int fmode; 1566254Sroot int dev; 1576254Sroot } *uap; 1586254Sroot 1596254Sroot uap = (struct a *)u.u_ap; 1606254Sroot if (suser()) { 1616254Sroot ip = namei(uchar, 1, 0); 1626254Sroot if (ip != NULL) { 1636254Sroot u.u_error = EEXIST; 1646254Sroot goto out; 1656254Sroot } 1666254Sroot } 1676254Sroot if (u.u_error) 1686254Sroot return; 1696254Sroot ip = maknode(uap->fmode); 1706254Sroot if (ip == NULL) 1716254Sroot return; 1726254Sroot if (uap->dev) { 1736254Sroot /* 1746254Sroot * Want to be able to use this to make badblock 1756254Sroot * inodes, so don't truncate the dev number. 1766254Sroot */ 1776254Sroot ip->i_un.i_rdev = uap->dev; 1786254Sroot ip->i_flag |= IACC|IUPD|ICHG; 1796254Sroot } 1806254Sroot 1816254Sroot out: 1826254Sroot iput(ip); 1836254Sroot } 1846254Sroot 1856254Sroot /* 1866254Sroot * link system call 1876254Sroot */ 1886254Sroot link() 1896254Sroot { 1906254Sroot register struct inode *ip, *xp; 1916254Sroot register struct a { 1926254Sroot char *target; 1936254Sroot char *linkname; 1946254Sroot } *uap; 1956254Sroot 1966254Sroot uap = (struct a *)u.u_ap; 1976254Sroot ip = namei(uchar, 0, 1); /* well, this routine is doomed anyhow */ 1986254Sroot if (ip == NULL) 1996254Sroot return; 2006254Sroot if ((ip->i_mode&IFMT)==IFDIR && !suser()) 2016254Sroot goto out1; 2026254Sroot ip->i_nlink++; 2036254Sroot ip->i_flag |= ICHG; 2046254Sroot iupdat(ip, &time, &time, 1); 2056254Sroot irele(ip); 2066254Sroot u.u_dirp = (caddr_t)uap->linkname; 2076254Sroot xp = namei(uchar, 1, 0); 2086254Sroot if (xp != NULL) { 2096254Sroot u.u_error = EEXIST; 2106254Sroot iput(xp); 2116254Sroot goto out; 2126254Sroot } 2136254Sroot if (u.u_error) 2146254Sroot goto out; 2156254Sroot if (u.u_pdir->i_dev != ip->i_dev) { 2166254Sroot iput(u.u_pdir); 2176254Sroot u.u_error = EXDEV; 2186254Sroot goto out; 2196254Sroot } 2206254Sroot wdir(ip); 2216254Sroot out: 2226254Sroot if (u.u_error) { 2236254Sroot ip->i_nlink--; 2246254Sroot ip->i_flag |= ICHG; 2256254Sroot } 2266254Sroot out1: 2276254Sroot iput(ip); 2286254Sroot } 2296254Sroot 2306254Sroot /* 2316254Sroot * symlink -- make a symbolic link 2326254Sroot */ 2336254Sroot symlink() 2346254Sroot { 2356254Sroot register struct a { 2366254Sroot char *target; 2376254Sroot char *linkname; 2386254Sroot } *uap; 2396254Sroot register struct inode *ip; 2406254Sroot register char *tp; 2416254Sroot register c, nc; 2426254Sroot 2436254Sroot uap = (struct a *)u.u_ap; 2446254Sroot tp = uap->target; 2456254Sroot nc = 0; 2466254Sroot while (c = fubyte(tp)) { 2476254Sroot if (c < 0) { 2486254Sroot u.u_error = EFAULT; 2496254Sroot return; 2506254Sroot } 2516254Sroot tp++; 2526254Sroot nc++; 2536254Sroot } 2546254Sroot u.u_dirp = uap->linkname; 2556254Sroot ip = namei(uchar, 1, 0); 2566254Sroot if (ip) { 2576254Sroot iput(ip); 2586254Sroot u.u_error = EEXIST; 2596254Sroot return; 2606254Sroot } 2616254Sroot if (u.u_error) 2626254Sroot return; 2636254Sroot ip = maknode(IFLNK | 0777); 2646254Sroot if (ip == NULL) 2656254Sroot return; 2666254Sroot u.u_base = uap->target; 2676254Sroot u.u_count = nc; 2686254Sroot u.u_offset = 0; 2696254Sroot u.u_segflg = 0; 2706254Sroot writei(ip); 2716254Sroot iput(ip); 2726254Sroot } 2736254Sroot 2746254Sroot /* 2756254Sroot * Unlink system call. 2766254Sroot * Hard to avoid races here, especially 2776254Sroot * in unlinking directories. 2786254Sroot */ 2796254Sroot unlink() 2806254Sroot { 2816254Sroot register struct inode *ip, *pp; 2826254Sroot struct a { 2836254Sroot char *fname; 2846254Sroot }; 2856254Sroot 2866254Sroot pp = namei(uchar, 2, 0); 2876254Sroot if(pp == NULL) 2886254Sroot return; 2896254Sroot /* 2906254Sroot * Check for unlink(".") 2916254Sroot * to avoid hanging on the iget 2926254Sroot */ 2936254Sroot if (pp->i_number == u.u_dent.d_ino) { 2946254Sroot ip = pp; 2956254Sroot ip->i_count++; 2966254Sroot } else 2976254Sroot ip = iget(pp->i_dev, u.u_dent.d_ino); 2986254Sroot if(ip == NULL) 2996254Sroot goto out1; 3006254Sroot if((ip->i_mode&IFMT)==IFDIR && !suser()) 3016254Sroot goto out; 3026254Sroot /* 3036254Sroot * Don't unlink a mounted file. 3046254Sroot */ 3056254Sroot if (ip->i_dev != pp->i_dev) { 3066254Sroot u.u_error = EBUSY; 3076254Sroot goto out; 3086254Sroot } 3096254Sroot if (ip->i_flag&ITEXT) 3106254Sroot xrele(ip); /* try once to free text */ 3116254Sroot /* 3126254Sroot if ((ip->i_flag&ITEXT) && ip->i_nlink==1) { 3136254Sroot u.u_error = ETXTBSY; 3146254Sroot goto out; 3156254Sroot } 3166254Sroot */ 3176254Sroot u.u_offset -= sizeof(struct direct); 3186254Sroot u.u_base = (caddr_t)&u.u_dent; 3196254Sroot u.u_count = sizeof(struct direct); 3206254Sroot u.u_dent.d_ino = 0; 3216254Sroot writei(pp); 3226254Sroot ip->i_nlink--; 3236254Sroot ip->i_flag |= ICHG; 3246254Sroot 3256254Sroot out: 3266254Sroot iput(ip); 3276254Sroot out1: 3286254Sroot iput(pp); 3296254Sroot } 3306254Sroot 3316254Sroot /* 3326254Sroot * Seek system call 3336254Sroot */ 3346254Sroot seek() 3356254Sroot { 3366254Sroot register struct file *fp; 3376254Sroot register struct a { 3386254Sroot int fdes; 3396254Sroot off_t off; 3406254Sroot int sbase; 3416254Sroot } *uap; 3426254Sroot 3436254Sroot uap = (struct a *)u.u_ap; 3446254Sroot fp = getf(uap->fdes); 3456254Sroot if (fp == NULL) 3466254Sroot return; 3476254Sroot if (fp->f_flag&FSOCKET) { 3486254Sroot u.u_error = ESPIPE; 3496254Sroot return; 3506254Sroot } 3516254Sroot if (uap->sbase == 1) 3526254Sroot uap->off += fp->f_offset; 3536254Sroot else if (uap->sbase == 2) 3546254Sroot uap->off += fp->f_inode->i_size; 3556254Sroot fp->f_offset = uap->off; 3566254Sroot u.u_r.r_off = uap->off; 3576254Sroot } 3586254Sroot 3596254Sroot /* 3606254Sroot * Access system call 3616254Sroot */ 3626254Sroot saccess() 3636254Sroot { 3646254Sroot register svuid, svgid; 3656254Sroot register struct inode *ip; 3666254Sroot register struct a { 3676254Sroot char *fname; 3686254Sroot int fmode; 3696254Sroot } *uap; 3706254Sroot 3716254Sroot uap = (struct a *)u.u_ap; 3726254Sroot svuid = u.u_uid; 3736254Sroot svgid = u.u_gid; 3746254Sroot u.u_uid = u.u_ruid; 3756254Sroot u.u_gid = u.u_rgid; 3766254Sroot ip = namei(uchar, 0, 1); 3776254Sroot if (ip != NULL) { 3786254Sroot if (uap->fmode&(IREAD>>6)) 3796254Sroot (void) access(ip, IREAD); 3806254Sroot if (uap->fmode&(IWRITE>>6)) 3816254Sroot (void) access(ip, IWRITE); 3826254Sroot if (uap->fmode&(IEXEC>>6)) 3836254Sroot (void) access(ip, IEXEC); 3846254Sroot iput(ip); 3856254Sroot } 3866254Sroot u.u_uid = svuid; 3876254Sroot u.u_gid = svgid; 3886254Sroot } 3896254Sroot 3906254Sroot /* 39137Sbill * the fstat system call. 39237Sbill */ 39337Sbill fstat() 39437Sbill { 39537Sbill register struct file *fp; 39637Sbill register struct a { 39737Sbill int fdes; 39837Sbill struct stat *sb; 39937Sbill } *uap; 40037Sbill 40137Sbill uap = (struct a *)u.u_ap; 40237Sbill fp = getf(uap->fdes); 4034828Swnj if (fp == NULL) 40437Sbill return; 4054828Swnj if (fp->f_flag & FSOCKET) 4064891Swnj u.u_error = sostat(fp->f_socket, uap->sb); 4074828Swnj else 4084828Swnj stat1(fp->f_inode, uap->sb); 40937Sbill } 41037Sbill 41137Sbill /* 412*6423Sroot * Stat system call; this follows links. 41337Sbill */ 41437Sbill stat() 41537Sbill { 41637Sbill register struct inode *ip; 41737Sbill register struct a { 41837Sbill char *fname; 41937Sbill struct stat *sb; 42037Sbill } *uap; 42137Sbill 42237Sbill uap = (struct a *)u.u_ap; 423*6423Sroot ip = namei(uchar, 0, 1); 4244828Swnj if (ip == NULL) 42537Sbill return; 4263624Sroot stat1(ip, uap->sb); 42737Sbill iput(ip); 42837Sbill } 42937Sbill 43037Sbill /* 431*6423Sroot * Lstat system call; like stat but doesn't follow links. 4325992Swnj */ 4335992Swnj lstat() 4345992Swnj { 4355992Swnj register struct inode *ip; 4365992Swnj register struct a { 4375992Swnj char *fname; 4385992Swnj struct stat *sb; 4395992Swnj } *uap; 4405992Swnj 4415992Swnj uap = (struct a *)u.u_ap; 442*6423Sroot ip = namei(uchar, 0, 0); 4435992Swnj if (ip == NULL) 4445992Swnj return; 4456153Ssam stat1(ip, uap->sb); 4465992Swnj iput(ip); 4475992Swnj } 4485992Swnj 4495992Swnj /* 45037Sbill * The basic routine for fstat and stat: 45137Sbill * get the inode and pass appropriate parts back. 45237Sbill */ 4533624Sroot stat1(ip, ub) 4544828Swnj register struct inode *ip; 4554828Swnj struct stat *ub; 45637Sbill { 45737Sbill register struct dinode *dp; 45837Sbill register struct buf *bp; 45937Sbill struct stat ds; 46037Sbill 4611204Sbill IUPDAT(ip, &time, &time, 0); 46237Sbill /* 4634828Swnj * First copy from inode table 46437Sbill */ 46537Sbill ds.st_dev = ip->i_dev; 46637Sbill ds.st_ino = ip->i_number; 46737Sbill ds.st_mode = ip->i_mode; 46837Sbill ds.st_nlink = ip->i_nlink; 46937Sbill ds.st_uid = ip->i_uid; 47037Sbill ds.st_gid = ip->i_gid; 47137Sbill ds.st_rdev = (dev_t)ip->i_un.i_rdev; 4723624Sroot ds.st_size = ip->i_size; 47337Sbill /* 4745992Swnj * next the dates in the disk 47537Sbill */ 47637Sbill bp = bread(ip->i_dev, itod(ip->i_number)); 47737Sbill dp = bp->b_un.b_dino; 47837Sbill dp += itoo(ip->i_number); 47937Sbill ds.st_atime = dp->di_atime; 48037Sbill ds.st_mtime = dp->di_mtime; 48137Sbill ds.st_ctime = dp->di_ctime; 48237Sbill brelse(bp); 48337Sbill if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0) 48437Sbill u.u_error = EFAULT; 48537Sbill } 48637Sbill 48737Sbill /* 4885992Swnj * Return target name of a symbolic link 48937Sbill */ 4905992Swnj readlink() 4915992Swnj { 4925992Swnj register struct inode *ip; 4935992Swnj register struct a { 4945992Swnj char *name; 4955992Swnj char *buf; 4965992Swnj int count; 4975992Swnj } *uap; 4985992Swnj 4995992Swnj ip = namei(uchar, 0, 0); 5005992Swnj if (ip == NULL) 5015992Swnj return; 5025992Swnj if ((ip->i_mode&IFMT) != IFLNK) { 5035992Swnj u.u_error = ENXIO; 5045992Swnj goto out; 5055992Swnj } 5065992Swnj uap = (struct a *)u.u_ap; 5075992Swnj u.u_offset = 0; 5085992Swnj u.u_base = uap->buf; 5095992Swnj u.u_count = uap->count; 5105992Swnj u.u_segflg = 0; 5115992Swnj readi(ip); 5125992Swnj out: 5135992Swnj iput(ip); 5145992Swnj u.u_r.r_val1 = uap->count - u.u_count; 5155992Swnj } 5165992Swnj 5176254Sroot chmod() 5185992Swnj { 5196254Sroot register struct inode *ip; 5205992Swnj register struct a { 5216254Sroot char *fname; 5226254Sroot int fmode; 5235992Swnj } *uap; 5245992Swnj 5255992Swnj uap = (struct a *)u.u_ap; 5266254Sroot if ((ip = owner(1)) == NULL) 5275992Swnj return; 5286254Sroot ip->i_mode &= ~07777; 5296254Sroot if (u.u_uid) 5306254Sroot uap->fmode &= ~ISVTX; 5316254Sroot ip->i_mode |= uap->fmode&07777; 5326254Sroot ip->i_flag |= ICHG; 5336254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 5346254Sroot xrele(ip); 5355992Swnj iput(ip); 5365992Swnj } 5375992Swnj 5386254Sroot chown() 53937Sbill { 5406254Sroot register struct inode *ip; 54137Sbill register struct a { 5426254Sroot char *fname; 5436254Sroot int uid; 5446254Sroot int gid; 54537Sbill } *uap; 54637Sbill 54737Sbill uap = (struct a *)u.u_ap; 5486254Sroot if (!suser() || (ip = owner(0)) == NULL) 54937Sbill return; 5506254Sroot ip->i_uid = uap->uid; 5516254Sroot ip->i_gid = uap->gid; 5526254Sroot ip->i_flag |= ICHG; 5536254Sroot if (u.u_ruid != 0) 5546254Sroot ip->i_mode &= ~(ISUID|ISGID); 5556254Sroot iput(ip); 55637Sbill } 55737Sbill 55837Sbill /* 5596254Sroot * Set IUPD and IACC times on file. 5606254Sroot * Can't set ICHG. 56137Sbill */ 5626254Sroot utime() 5634828Swnj { 56437Sbill register struct a { 5656254Sroot char *fname; 5666254Sroot time_t *tptr; 56737Sbill } *uap; 5686254Sroot register struct inode *ip; 5696254Sroot time_t tv[2]; 57037Sbill 57137Sbill uap = (struct a *)u.u_ap; 5726254Sroot if ((ip = owner(1)) == NULL) 57337Sbill return; 5746254Sroot if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) { 5756254Sroot u.u_error = EFAULT; 5766254Sroot } else { 5776254Sroot ip->i_flag |= IACC|IUPD|ICHG; 5786254Sroot iupdat(ip, &tv[0], &tv[1], 0); 57937Sbill } 58037Sbill iput(ip); 58137Sbill } 58237Sbill 5836254Sroot sync() 58437Sbill { 58537Sbill 5865416Swnj update(0); 58737Sbill } 588