1*7023Smckusick /* vfs_syscalls.c 4.24 82/06/04 */ 237Sbill 36574Smckusic #ifdef SIMFS 46574Smckusic #include "../h/sysrenam.h" 56574Smckusic #endif 637Sbill #include "../h/param.h" 737Sbill #include "../h/systm.h" 837Sbill #include "../h/dir.h" 937Sbill #include "../h/user.h" 106254Sroot #include "../h/file.h" 116574Smckusic #include "../h/stat.h" 1237Sbill #include "../h/inode.h" 136574Smckusic #include "../h/fs.h" 146254Sroot #include "../h/buf.h" 156254Sroot #include "../h/proc.h" 166254Sroot #include "../h/inline.h" 1737Sbill 186254Sroot chdir() 196254Sroot { 206254Sroot 216254Sroot chdirec(&u.u_cdir); 226254Sroot } 236254Sroot 246254Sroot chroot() 256254Sroot { 266254Sroot 276254Sroot if (suser()) 286254Sroot chdirec(&u.u_rdir); 296254Sroot } 306254Sroot 316254Sroot chdirec(ipp) 326254Sroot register struct inode **ipp; 336254Sroot { 346254Sroot register struct inode *ip; 356254Sroot struct a { 366254Sroot char *fname; 376254Sroot }; 386254Sroot 396254Sroot ip = namei(uchar, 0, 1); 406254Sroot if(ip == NULL) 416254Sroot return; 426254Sroot if((ip->i_mode&IFMT) != IFDIR) { 436254Sroot u.u_error = ENOTDIR; 446254Sroot goto bad; 456254Sroot } 466254Sroot if(access(ip, IEXEC)) 476254Sroot goto bad; 486254Sroot irele(ip); 496254Sroot if (*ipp) { 506254Sroot ilock(*ipp); 516254Sroot iput(*ipp); 526254Sroot } 536254Sroot *ipp = ip; 546254Sroot return; 556254Sroot 566254Sroot bad: 576254Sroot iput(ip); 586254Sroot } 596254Sroot 6037Sbill /* 616254Sroot * Open system call. 626254Sroot */ 636254Sroot open() 646254Sroot { 656254Sroot register struct inode *ip; 666254Sroot register struct a { 676254Sroot char *fname; 686254Sroot int rwmode; 696254Sroot } *uap; 706254Sroot 716254Sroot uap = (struct a *)u.u_ap; 726254Sroot ip = namei(uchar, 0, 1); 736254Sroot if (ip == NULL) 746254Sroot return; 756254Sroot open1(ip, ++uap->rwmode, 0); 766254Sroot } 776254Sroot 786254Sroot /* 796254Sroot * Creat system call. 806254Sroot */ 816254Sroot creat() 826254Sroot { 836254Sroot register struct inode *ip; 846254Sroot register struct a { 856254Sroot char *fname; 866254Sroot int fmode; 876254Sroot } *uap; 886254Sroot 896254Sroot uap = (struct a *)u.u_ap; 906254Sroot ip = namei(uchar, 1, 1); 916254Sroot if (ip == NULL) { 926254Sroot if (u.u_error) 936254Sroot return; 946254Sroot ip = maknode(uap->fmode&07777&(~ISVTX)); 956254Sroot if (ip==NULL) 966254Sroot return; 976254Sroot open1(ip, FWRITE, 2); 986254Sroot } else 996254Sroot open1(ip, FWRITE, 1); 1006254Sroot } 1016254Sroot 1026254Sroot /* 1036254Sroot * Common code for open and creat. 1046254Sroot * Check permissions, allocate an open file structure, 1056254Sroot * and call the device open routine if any. 1066254Sroot */ 1076254Sroot open1(ip, mode, trf) 1086254Sroot register struct inode *ip; 1096254Sroot register mode; 1106254Sroot { 1116254Sroot register struct file *fp; 1126254Sroot int i; 1136254Sroot 1146254Sroot if (trf != 2) { 1156254Sroot if (mode&FREAD) 1166254Sroot (void) access(ip, IREAD); 1176254Sroot if (mode&FWRITE) { 1186254Sroot (void) access(ip, IWRITE); 1196254Sroot if ((ip->i_mode&IFMT) == IFDIR) 1206254Sroot u.u_error = EISDIR; 1216254Sroot } 1226254Sroot } 1236254Sroot if (u.u_error) 1246254Sroot goto out; 1256254Sroot if (trf == 1) 1266254Sroot itrunc(ip); 1276254Sroot irele(ip); 1286254Sroot if ((fp = falloc()) == NULL) 1296254Sroot goto out; 1306254Sroot fp->f_flag = mode&(FREAD|FWRITE); 1316254Sroot i = u.u_r.r_val1; 1326254Sroot fp->f_inode = ip; 1336254Sroot openi(ip, mode&(FREAD|FWRITE)); 1346254Sroot if (u.u_error == 0) 1356254Sroot return; 1366254Sroot u.u_ofile[i] = NULL; 1376254Sroot fp->f_count--; 1386254Sroot out: 1396254Sroot if (ip != NULL) 1406254Sroot iput(ip); 1416254Sroot } 1426254Sroot 1436254Sroot /* 1446254Sroot * Mknod system call 1456254Sroot */ 1466254Sroot mknod() 1476254Sroot { 1486254Sroot register struct inode *ip; 1496254Sroot register struct a { 1506254Sroot char *fname; 1516254Sroot int fmode; 1526254Sroot int dev; 1536254Sroot } *uap; 1546254Sroot 1556254Sroot uap = (struct a *)u.u_ap; 1566254Sroot if (suser()) { 1576254Sroot ip = namei(uchar, 1, 0); 1586254Sroot if (ip != NULL) { 1596254Sroot u.u_error = EEXIST; 1606254Sroot goto out; 1616254Sroot } 1626254Sroot } 1636254Sroot if (u.u_error) 1646254Sroot return; 1656254Sroot ip = maknode(uap->fmode); 1666254Sroot if (ip == NULL) 1676254Sroot return; 1686254Sroot if (uap->dev) { 1696254Sroot /* 1706254Sroot * Want to be able to use this to make badblock 1716254Sroot * inodes, so don't truncate the dev number. 1726254Sroot */ 1736574Smckusic ip->i_rdev = uap->dev; 1746254Sroot ip->i_flag |= IACC|IUPD|ICHG; 1756254Sroot } 1766254Sroot 1776254Sroot out: 1786254Sroot iput(ip); 1796254Sroot } 1806254Sroot 1816254Sroot /* 1826254Sroot * link system call 1836254Sroot */ 1846254Sroot link() 1856254Sroot { 1866254Sroot register struct inode *ip, *xp; 1876254Sroot register struct a { 1886254Sroot char *target; 1896254Sroot char *linkname; 1906254Sroot } *uap; 1916254Sroot 1926254Sroot uap = (struct a *)u.u_ap; 1936254Sroot ip = namei(uchar, 0, 1); /* well, this routine is doomed anyhow */ 1946254Sroot if (ip == NULL) 1956254Sroot return; 1966254Sroot if ((ip->i_mode&IFMT)==IFDIR && !suser()) 1976254Sroot goto out1; 1986254Sroot ip->i_nlink++; 1996254Sroot ip->i_flag |= ICHG; 2006254Sroot iupdat(ip, &time, &time, 1); 2016254Sroot irele(ip); 2026254Sroot u.u_dirp = (caddr_t)uap->linkname; 2036254Sroot xp = namei(uchar, 1, 0); 2046254Sroot if (xp != NULL) { 2056254Sroot u.u_error = EEXIST; 2066254Sroot iput(xp); 2076254Sroot goto out; 2086254Sroot } 2096254Sroot if (u.u_error) 2106254Sroot goto out; 2116254Sroot if (u.u_pdir->i_dev != ip->i_dev) { 2126254Sroot iput(u.u_pdir); 2136254Sroot u.u_error = EXDEV; 2146254Sroot goto out; 2156254Sroot } 2166254Sroot wdir(ip); 2176254Sroot out: 2186254Sroot if (u.u_error) { 2196254Sroot ip->i_nlink--; 2206254Sroot ip->i_flag |= ICHG; 2216254Sroot } 2226254Sroot out1: 2236254Sroot iput(ip); 2246254Sroot } 2256254Sroot 2266254Sroot /* 2276254Sroot * symlink -- make a symbolic link 2286254Sroot */ 2296254Sroot symlink() 2306254Sroot { 2316254Sroot register struct a { 2326254Sroot char *target; 2336254Sroot char *linkname; 2346254Sroot } *uap; 2356254Sroot register struct inode *ip; 2366254Sroot register char *tp; 2376254Sroot register c, nc; 2386254Sroot 2396254Sroot uap = (struct a *)u.u_ap; 2406254Sroot tp = uap->target; 2416254Sroot nc = 0; 2426254Sroot while (c = fubyte(tp)) { 2436254Sroot if (c < 0) { 2446254Sroot u.u_error = EFAULT; 2456254Sroot return; 2466254Sroot } 2476254Sroot tp++; 2486254Sroot nc++; 2496254Sroot } 2506254Sroot u.u_dirp = uap->linkname; 2516254Sroot ip = namei(uchar, 1, 0); 2526254Sroot if (ip) { 2536254Sroot iput(ip); 2546254Sroot u.u_error = EEXIST; 2556254Sroot return; 2566254Sroot } 2576254Sroot if (u.u_error) 2586254Sroot return; 2596254Sroot ip = maknode(IFLNK | 0777); 2606254Sroot if (ip == NULL) 2616254Sroot return; 2626254Sroot u.u_base = uap->target; 2636254Sroot u.u_count = nc; 2646254Sroot u.u_offset = 0; 2656254Sroot u.u_segflg = 0; 2666254Sroot writei(ip); 2676254Sroot iput(ip); 2686254Sroot } 2696254Sroot 2706254Sroot /* 2716254Sroot * Unlink system call. 2726254Sroot * Hard to avoid races here, especially 2736254Sroot * in unlinking directories. 2746254Sroot */ 2756254Sroot unlink() 2766254Sroot { 2776254Sroot register struct inode *ip, *pp; 2786254Sroot struct a { 2796254Sroot char *fname; 2806254Sroot }; 2816574Smckusic struct fs *fs; 2826574Smckusic struct buf *bp; 2836574Smckusic int lbn, bn, base; 2846254Sroot 2856254Sroot pp = namei(uchar, 2, 0); 2866254Sroot if(pp == NULL) 2876254Sroot return; 2886254Sroot /* 2896254Sroot * Check for unlink(".") 2906254Sroot * to avoid hanging on the iget 2916254Sroot */ 2926254Sroot if (pp->i_number == u.u_dent.d_ino) { 2936254Sroot ip = pp; 2946254Sroot ip->i_count++; 2956254Sroot } else 2966574Smckusic ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino); 2976254Sroot if(ip == NULL) 2986254Sroot goto out1; 2996254Sroot if((ip->i_mode&IFMT)==IFDIR && !suser()) 3006254Sroot goto out; 3016254Sroot /* 3026254Sroot * Don't unlink a mounted file. 3036254Sroot */ 3046254Sroot if (ip->i_dev != pp->i_dev) { 3056254Sroot u.u_error = EBUSY; 3066254Sroot goto out; 3076254Sroot } 3086254Sroot if (ip->i_flag&ITEXT) 3096254Sroot xrele(ip); /* try once to free text */ 3106254Sroot /* 3116254Sroot if ((ip->i_flag&ITEXT) && ip->i_nlink==1) { 3126254Sroot u.u_error = ETXTBSY; 3136254Sroot goto out; 3146254Sroot } 3156254Sroot */ 3166574Smckusic if (u.u_count == 0) { 3176574Smckusic /* 3186574Smckusic * first entry in block, so set d_ino to zero. 3196574Smckusic */ 3206574Smckusic u.u_base = (caddr_t)&u.u_dent; 3216574Smckusic u.u_count = DIRSIZ(&u.u_dent); 3226574Smckusic u.u_dent.d_ino = 0; 3236574Smckusic writei(pp); 3246574Smckusic } else { 3256574Smckusic /* 3266574Smckusic * updating preceeding entry to skip over current entry. 3276574Smckusic */ 3286574Smckusic fs = pp->i_fs; 3296574Smckusic lbn = lblkno(fs, u.u_offset); 3306574Smckusic base = blkoff(fs, u.u_offset); 3316574Smckusic bn = fsbtodb(fs, bmap(pp, lbn, B_WRITE, base + u.u_count)); 3326574Smckusic bp = bread(pp->i_dev, bn, blksize(fs, pp, lbn)); 3336574Smckusic if (bp->b_flags & B_ERROR) { 3346574Smckusic brelse(bp); 3356574Smckusic goto out; 3366574Smckusic } 3376574Smckusic ((struct direct *)(bp->b_un.b_addr + base))->d_reclen += 3386574Smckusic u.u_dent.d_reclen; 3396574Smckusic bwrite(bp); 3406574Smckusic pp->i_flag |= IUPD|ICHG; 3416574Smckusic } 3426254Sroot ip->i_nlink--; 3436254Sroot ip->i_flag |= ICHG; 3446254Sroot 3456254Sroot out: 3466254Sroot iput(ip); 3476254Sroot out1: 3486254Sroot iput(pp); 3496254Sroot } 3506254Sroot 3516254Sroot /* 3526254Sroot * Seek system call 3536254Sroot */ 3546254Sroot seek() 3556254Sroot { 3566254Sroot register struct file *fp; 3576254Sroot register struct a { 3586254Sroot int fdes; 3596254Sroot off_t off; 3606254Sroot int sbase; 3616254Sroot } *uap; 3626254Sroot 3636254Sroot uap = (struct a *)u.u_ap; 3646254Sroot fp = getf(uap->fdes); 3656254Sroot if (fp == NULL) 3666254Sroot return; 3676254Sroot if (fp->f_flag&FSOCKET) { 3686254Sroot u.u_error = ESPIPE; 3696254Sroot return; 3706254Sroot } 3716254Sroot if (uap->sbase == 1) 3726254Sroot uap->off += fp->f_offset; 3736254Sroot else if (uap->sbase == 2) 3746254Sroot uap->off += fp->f_inode->i_size; 3756254Sroot fp->f_offset = uap->off; 3766254Sroot u.u_r.r_off = uap->off; 3776254Sroot } 3786254Sroot 3796254Sroot /* 3806254Sroot * Access system call 3816254Sroot */ 3826254Sroot saccess() 3836254Sroot { 3846254Sroot register svuid, svgid; 3856254Sroot register struct inode *ip; 3866254Sroot register struct a { 3876254Sroot char *fname; 3886254Sroot int fmode; 3896254Sroot } *uap; 3906254Sroot 3916254Sroot uap = (struct a *)u.u_ap; 3926254Sroot svuid = u.u_uid; 3936254Sroot svgid = u.u_gid; 3946254Sroot u.u_uid = u.u_ruid; 3956254Sroot u.u_gid = u.u_rgid; 3966254Sroot ip = namei(uchar, 0, 1); 3976254Sroot if (ip != NULL) { 3986254Sroot if (uap->fmode&(IREAD>>6)) 3996254Sroot (void) access(ip, IREAD); 4006254Sroot if (uap->fmode&(IWRITE>>6)) 4016254Sroot (void) access(ip, IWRITE); 4026254Sroot if (uap->fmode&(IEXEC>>6)) 4036254Sroot (void) access(ip, IEXEC); 4046254Sroot iput(ip); 4056254Sroot } 4066254Sroot u.u_uid = svuid; 4076254Sroot u.u_gid = svgid; 4086254Sroot } 4096254Sroot 4106254Sroot /* 41137Sbill * the fstat system call. 41237Sbill */ 41337Sbill fstat() 41437Sbill { 41537Sbill register struct file *fp; 41637Sbill register struct a { 41737Sbill int fdes; 41837Sbill struct stat *sb; 41937Sbill } *uap; 42037Sbill 42137Sbill uap = (struct a *)u.u_ap; 42237Sbill fp = getf(uap->fdes); 4234828Swnj if (fp == NULL) 42437Sbill return; 4254828Swnj if (fp->f_flag & FSOCKET) 4264891Swnj u.u_error = sostat(fp->f_socket, uap->sb); 4274828Swnj else 4284828Swnj stat1(fp->f_inode, uap->sb); 42937Sbill } 43037Sbill 43137Sbill /* 4326574Smckusic * Stat system call. This version follows links. 43337Sbill */ 43437Sbill stat() 43537Sbill { 43637Sbill register struct inode *ip; 43737Sbill register struct a { 43837Sbill char *fname; 43937Sbill struct stat *sb; 44037Sbill } *uap; 44137Sbill 44237Sbill uap = (struct a *)u.u_ap; 4436423Sroot ip = namei(uchar, 0, 1); 4444828Swnj if (ip == NULL) 44537Sbill return; 4463624Sroot stat1(ip, uap->sb); 44737Sbill iput(ip); 44837Sbill } 44937Sbill 45037Sbill /* 4516574Smckusic * Lstat system call. This version does not follow links. 4525992Swnj */ 4535992Swnj lstat() 4545992Swnj { 4555992Swnj register struct inode *ip; 4565992Swnj register struct a { 4575992Swnj char *fname; 4585992Swnj struct stat *sb; 4595992Swnj } *uap; 4605992Swnj 4615992Swnj uap = (struct a *)u.u_ap; 4626423Sroot ip = namei(uchar, 0, 0); 4635992Swnj if (ip == NULL) 4645992Swnj return; 4656153Ssam stat1(ip, uap->sb); 4665992Swnj iput(ip); 4675992Swnj } 4685992Swnj 4695992Swnj /* 47037Sbill * The basic routine for fstat and stat: 47137Sbill * get the inode and pass appropriate parts back. 47237Sbill */ 4733624Sroot stat1(ip, ub) 4744828Swnj register struct inode *ip; 4754828Swnj struct stat *ub; 47637Sbill { 47737Sbill struct stat ds; 47837Sbill 4791204Sbill IUPDAT(ip, &time, &time, 0); 48037Sbill /* 481*7023Smckusick * Copy from inode table 48237Sbill */ 48337Sbill ds.st_dev = ip->i_dev; 48437Sbill ds.st_ino = ip->i_number; 48537Sbill ds.st_mode = ip->i_mode; 48637Sbill ds.st_nlink = ip->i_nlink; 48737Sbill ds.st_uid = ip->i_uid; 48837Sbill ds.st_gid = ip->i_gid; 4896574Smckusic ds.st_rdev = (dev_t)ip->i_rdev; 4903624Sroot ds.st_size = ip->i_size; 4916574Smckusic ds.st_atime = ip->i_atime; 4926574Smckusic ds.st_mtime = ip->i_mtime; 4936574Smckusic ds.st_ctime = ip->i_ctime; 494*7023Smckusick ds.st_blksize = ip->i_fs->fs_bsize; 49537Sbill if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0) 49637Sbill u.u_error = EFAULT; 49737Sbill } 49837Sbill 49937Sbill /* 5005992Swnj * Return target name of a symbolic link 50137Sbill */ 5025992Swnj readlink() 5035992Swnj { 5045992Swnj register struct inode *ip; 5055992Swnj register struct a { 5065992Swnj char *name; 5075992Swnj char *buf; 5085992Swnj int count; 5095992Swnj } *uap; 5105992Swnj 5115992Swnj ip = namei(uchar, 0, 0); 5125992Swnj if (ip == NULL) 5135992Swnj return; 5145992Swnj if ((ip->i_mode&IFMT) != IFLNK) { 5155992Swnj u.u_error = ENXIO; 5165992Swnj goto out; 5175992Swnj } 5185992Swnj uap = (struct a *)u.u_ap; 5195992Swnj u.u_offset = 0; 5205992Swnj u.u_base = uap->buf; 5215992Swnj u.u_count = uap->count; 5225992Swnj u.u_segflg = 0; 5235992Swnj readi(ip); 5245992Swnj out: 5255992Swnj iput(ip); 5265992Swnj u.u_r.r_val1 = uap->count - u.u_count; 5275992Swnj } 5285992Swnj 5296254Sroot chmod() 5305992Swnj { 5316254Sroot register struct inode *ip; 5325992Swnj register struct a { 5336254Sroot char *fname; 5346254Sroot int fmode; 5355992Swnj } *uap; 5365992Swnj 5375992Swnj uap = (struct a *)u.u_ap; 5386254Sroot if ((ip = owner(1)) == NULL) 5395992Swnj return; 5406254Sroot ip->i_mode &= ~07777; 5416254Sroot if (u.u_uid) 5426254Sroot uap->fmode &= ~ISVTX; 5436254Sroot ip->i_mode |= uap->fmode&07777; 5446254Sroot ip->i_flag |= ICHG; 5456254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 5466254Sroot xrele(ip); 5475992Swnj iput(ip); 5485992Swnj } 5495992Swnj 5506254Sroot chown() 55137Sbill { 5526254Sroot register struct inode *ip; 55337Sbill register struct a { 5546254Sroot char *fname; 5556254Sroot int uid; 5566254Sroot int gid; 55737Sbill } *uap; 55837Sbill 55937Sbill uap = (struct a *)u.u_ap; 5606254Sroot if (!suser() || (ip = owner(0)) == NULL) 56137Sbill return; 5626254Sroot ip->i_uid = uap->uid; 5636254Sroot ip->i_gid = uap->gid; 5646254Sroot ip->i_flag |= ICHG; 5656254Sroot if (u.u_ruid != 0) 5666254Sroot ip->i_mode &= ~(ISUID|ISGID); 5676254Sroot iput(ip); 56837Sbill } 56937Sbill 57037Sbill /* 5716254Sroot * Set IUPD and IACC times on file. 5726254Sroot * Can't set ICHG. 57337Sbill */ 5746254Sroot utime() 5754828Swnj { 57637Sbill register struct a { 5776254Sroot char *fname; 5786254Sroot time_t *tptr; 57937Sbill } *uap; 5806254Sroot register struct inode *ip; 5816254Sroot time_t tv[2]; 58237Sbill 58337Sbill uap = (struct a *)u.u_ap; 5846254Sroot if ((ip = owner(1)) == NULL) 58537Sbill return; 5866254Sroot if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) { 5876254Sroot u.u_error = EFAULT; 5886254Sroot } else { 5896254Sroot ip->i_flag |= IACC|IUPD|ICHG; 5906254Sroot iupdat(ip, &tv[0], &tv[1], 0); 59137Sbill } 59237Sbill iput(ip); 59337Sbill } 59437Sbill 5956254Sroot sync() 59637Sbill { 59737Sbill 5985416Swnj update(0); 59937Sbill } 600