1*7142Smckusick /* vfs_syscalls.c 4.26 82/06/10 */ 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; 487122Smckusick iunlock(ip); 49*7142Smckusick if (*ipp) 50*7142Smckusick irele(*ipp); 516254Sroot *ipp = ip; 526254Sroot return; 536254Sroot 546254Sroot bad: 556254Sroot iput(ip); 566254Sroot } 576254Sroot 5837Sbill /* 596254Sroot * Open system call. 606254Sroot */ 616254Sroot open() 626254Sroot { 636254Sroot register struct inode *ip; 646254Sroot register struct a { 656254Sroot char *fname; 666254Sroot int rwmode; 676254Sroot } *uap; 686254Sroot 696254Sroot uap = (struct a *)u.u_ap; 706254Sroot ip = namei(uchar, 0, 1); 716254Sroot if (ip == NULL) 726254Sroot return; 736254Sroot open1(ip, ++uap->rwmode, 0); 746254Sroot } 756254Sroot 766254Sroot /* 776254Sroot * Creat system call. 786254Sroot */ 796254Sroot creat() 806254Sroot { 816254Sroot register struct inode *ip; 826254Sroot register struct a { 836254Sroot char *fname; 846254Sroot int fmode; 856254Sroot } *uap; 866254Sroot 876254Sroot uap = (struct a *)u.u_ap; 886254Sroot ip = namei(uchar, 1, 1); 896254Sroot if (ip == NULL) { 906254Sroot if (u.u_error) 916254Sroot return; 926254Sroot ip = maknode(uap->fmode&07777&(~ISVTX)); 936254Sroot if (ip==NULL) 946254Sroot return; 956254Sroot open1(ip, FWRITE, 2); 966254Sroot } else 976254Sroot open1(ip, FWRITE, 1); 986254Sroot } 996254Sroot 1006254Sroot /* 1016254Sroot * Common code for open and creat. 1026254Sroot * Check permissions, allocate an open file structure, 1036254Sroot * and call the device open routine if any. 1046254Sroot */ 1056254Sroot open1(ip, mode, trf) 1066254Sroot register struct inode *ip; 1076254Sroot register mode; 1086254Sroot { 1096254Sroot register struct file *fp; 1106254Sroot int i; 1116254Sroot 1126254Sroot if (trf != 2) { 1136254Sroot if (mode&FREAD) 1146254Sroot (void) access(ip, IREAD); 1156254Sroot if (mode&FWRITE) { 1166254Sroot (void) access(ip, IWRITE); 1176254Sroot if ((ip->i_mode&IFMT) == IFDIR) 1186254Sroot u.u_error = EISDIR; 1196254Sroot } 1206254Sroot } 121*7142Smckusick if (u.u_error) { 122*7142Smckusick iput(ip); 123*7142Smckusick return; 124*7142Smckusick } 1256254Sroot if (trf == 1) 1266254Sroot itrunc(ip); 1277122Smckusick iunlock(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: 139*7142Smckusick irele(ip); 1406254Sroot } 1416254Sroot 1426254Sroot /* 1436254Sroot * Mknod system call 1446254Sroot */ 1456254Sroot mknod() 1466254Sroot { 1476254Sroot register struct inode *ip; 1486254Sroot register struct a { 1496254Sroot char *fname; 1506254Sroot int fmode; 1516254Sroot int dev; 1526254Sroot } *uap; 1536254Sroot 1546254Sroot uap = (struct a *)u.u_ap; 1556254Sroot if (suser()) { 1566254Sroot ip = namei(uchar, 1, 0); 1576254Sroot if (ip != NULL) { 1586254Sroot u.u_error = EEXIST; 1596254Sroot goto out; 1606254Sroot } 1616254Sroot } 1626254Sroot if (u.u_error) 1636254Sroot return; 1646254Sroot ip = maknode(uap->fmode); 1656254Sroot if (ip == NULL) 1666254Sroot return; 1676254Sroot if (uap->dev) { 1686254Sroot /* 1696254Sroot * Want to be able to use this to make badblock 1706254Sroot * inodes, so don't truncate the dev number. 1716254Sroot */ 1726574Smckusic ip->i_rdev = uap->dev; 1736254Sroot ip->i_flag |= IACC|IUPD|ICHG; 1746254Sroot } 1756254Sroot 1766254Sroot out: 1776254Sroot iput(ip); 1786254Sroot } 1796254Sroot 1806254Sroot /* 1816254Sroot * link system call 1826254Sroot */ 1836254Sroot link() 1846254Sroot { 1856254Sroot register struct inode *ip, *xp; 1866254Sroot register struct a { 1876254Sroot char *target; 1886254Sroot char *linkname; 1896254Sroot } *uap; 1906254Sroot 1916254Sroot uap = (struct a *)u.u_ap; 1926254Sroot ip = namei(uchar, 0, 1); /* well, this routine is doomed anyhow */ 1936254Sroot if (ip == NULL) 1946254Sroot return; 1956254Sroot if ((ip->i_mode&IFMT)==IFDIR && !suser()) 1966254Sroot goto out1; 1976254Sroot ip->i_nlink++; 1986254Sroot ip->i_flag |= ICHG; 1996254Sroot iupdat(ip, &time, &time, 1); 2007122Smckusick iunlock(ip); 2016254Sroot u.u_dirp = (caddr_t)uap->linkname; 2026254Sroot xp = namei(uchar, 1, 0); 2036254Sroot if (xp != NULL) { 2046254Sroot u.u_error = EEXIST; 2056254Sroot iput(xp); 2066254Sroot goto out; 2076254Sroot } 2086254Sroot if (u.u_error) 2096254Sroot goto out; 2106254Sroot if (u.u_pdir->i_dev != ip->i_dev) { 2116254Sroot iput(u.u_pdir); 2126254Sroot u.u_error = EXDEV; 2136254Sroot goto out; 2146254Sroot } 2156254Sroot wdir(ip); 2166254Sroot out: 2176254Sroot if (u.u_error) { 2186254Sroot ip->i_nlink--; 2196254Sroot ip->i_flag |= ICHG; 2206254Sroot } 2216254Sroot out1: 222*7142Smckusick irele(ip); 2236254Sroot } 2246254Sroot 2256254Sroot /* 2266254Sroot * symlink -- make a symbolic link 2276254Sroot */ 2286254Sroot symlink() 2296254Sroot { 2306254Sroot register struct a { 2316254Sroot char *target; 2326254Sroot char *linkname; 2336254Sroot } *uap; 2346254Sroot register struct inode *ip; 2356254Sroot register char *tp; 2366254Sroot register c, nc; 2376254Sroot 2386254Sroot uap = (struct a *)u.u_ap; 2396254Sroot tp = uap->target; 2406254Sroot nc = 0; 2416254Sroot while (c = fubyte(tp)) { 2426254Sroot if (c < 0) { 2436254Sroot u.u_error = EFAULT; 2446254Sroot return; 2456254Sroot } 2466254Sroot tp++; 2476254Sroot nc++; 2486254Sroot } 2496254Sroot u.u_dirp = uap->linkname; 2506254Sroot ip = namei(uchar, 1, 0); 2516254Sroot if (ip) { 2526254Sroot iput(ip); 2536254Sroot u.u_error = EEXIST; 2546254Sroot return; 2556254Sroot } 2566254Sroot if (u.u_error) 2576254Sroot return; 2586254Sroot ip = maknode(IFLNK | 0777); 2596254Sroot if (ip == NULL) 2606254Sroot return; 2616254Sroot u.u_base = uap->target; 2626254Sroot u.u_count = nc; 2636254Sroot u.u_offset = 0; 2646254Sroot u.u_segflg = 0; 2656254Sroot writei(ip); 2666254Sroot iput(ip); 2676254Sroot } 2686254Sroot 2696254Sroot /* 2706254Sroot * Unlink system call. 2716254Sroot * Hard to avoid races here, especially 2726254Sroot * in unlinking directories. 2736254Sroot */ 2746254Sroot unlink() 2756254Sroot { 2766254Sroot register struct inode *ip, *pp; 2776254Sroot struct a { 2786254Sroot char *fname; 2796254Sroot }; 2806574Smckusic struct fs *fs; 2816574Smckusic struct buf *bp; 2826574Smckusic int lbn, bn, base; 283*7142Smckusick int unlinkingdot = 0; 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++; 295*7142Smckusick unlinkingdot++; 2966254Sroot } else 2976574Smckusic ip = iget(pp->i_dev, pp->i_fs, 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 */ 3176574Smckusic if (u.u_count == 0) { 3186574Smckusic /* 3196574Smckusic * first entry in block, so set d_ino to zero. 3206574Smckusic */ 3216574Smckusic u.u_base = (caddr_t)&u.u_dent; 3226574Smckusic u.u_count = DIRSIZ(&u.u_dent); 3236574Smckusic u.u_dent.d_ino = 0; 3246574Smckusic writei(pp); 3256574Smckusic } else { 3266574Smckusic /* 3276574Smckusic * updating preceeding entry to skip over current entry. 3286574Smckusic */ 3296574Smckusic fs = pp->i_fs; 3306574Smckusic lbn = lblkno(fs, u.u_offset); 3316574Smckusic base = blkoff(fs, u.u_offset); 3326574Smckusic bn = fsbtodb(fs, bmap(pp, lbn, B_WRITE, base + u.u_count)); 3336574Smckusic bp = bread(pp->i_dev, bn, blksize(fs, pp, lbn)); 3346574Smckusic if (bp->b_flags & B_ERROR) { 3356574Smckusic brelse(bp); 3366574Smckusic goto out; 3376574Smckusic } 3386574Smckusic ((struct direct *)(bp->b_un.b_addr + base))->d_reclen += 3396574Smckusic u.u_dent.d_reclen; 3406574Smckusic bwrite(bp); 3416574Smckusic pp->i_flag |= IUPD|ICHG; 3426574Smckusic } 3436254Sroot ip->i_nlink--; 3446254Sroot ip->i_flag |= ICHG; 3456254Sroot 3466254Sroot out: 347*7142Smckusick if (unlinkingdot) 348*7142Smckusick irele(ip); 349*7142Smckusick else 350*7142Smckusick iput(ip); 3516254Sroot out1: 3526254Sroot iput(pp); 3536254Sroot } 3546254Sroot 3556254Sroot /* 3566254Sroot * Seek system call 3576254Sroot */ 3586254Sroot seek() 3596254Sroot { 3606254Sroot register struct file *fp; 3616254Sroot register struct a { 3626254Sroot int fdes; 3636254Sroot off_t off; 3646254Sroot int sbase; 3656254Sroot } *uap; 3666254Sroot 3676254Sroot uap = (struct a *)u.u_ap; 3686254Sroot fp = getf(uap->fdes); 3696254Sroot if (fp == NULL) 3706254Sroot return; 3716254Sroot if (fp->f_flag&FSOCKET) { 3726254Sroot u.u_error = ESPIPE; 3736254Sroot return; 3746254Sroot } 3756254Sroot if (uap->sbase == 1) 3766254Sroot uap->off += fp->f_offset; 3776254Sroot else if (uap->sbase == 2) 3786254Sroot uap->off += fp->f_inode->i_size; 3796254Sroot fp->f_offset = uap->off; 3806254Sroot u.u_r.r_off = uap->off; 3816254Sroot } 3826254Sroot 3836254Sroot /* 3846254Sroot * Access system call 3856254Sroot */ 3866254Sroot saccess() 3876254Sroot { 3886254Sroot register svuid, svgid; 3896254Sroot register struct inode *ip; 3906254Sroot register struct a { 3916254Sroot char *fname; 3926254Sroot int fmode; 3936254Sroot } *uap; 3946254Sroot 3956254Sroot uap = (struct a *)u.u_ap; 3966254Sroot svuid = u.u_uid; 3976254Sroot svgid = u.u_gid; 3986254Sroot u.u_uid = u.u_ruid; 3996254Sroot u.u_gid = u.u_rgid; 4006254Sroot ip = namei(uchar, 0, 1); 4016254Sroot if (ip != NULL) { 4026254Sroot if (uap->fmode&(IREAD>>6)) 4036254Sroot (void) access(ip, IREAD); 4046254Sroot if (uap->fmode&(IWRITE>>6)) 4056254Sroot (void) access(ip, IWRITE); 4066254Sroot if (uap->fmode&(IEXEC>>6)) 4076254Sroot (void) access(ip, IEXEC); 4086254Sroot iput(ip); 4096254Sroot } 4106254Sroot u.u_uid = svuid; 4116254Sroot u.u_gid = svgid; 4126254Sroot } 4136254Sroot 4146254Sroot /* 41537Sbill * the fstat system call. 41637Sbill */ 41737Sbill fstat() 41837Sbill { 41937Sbill register struct file *fp; 42037Sbill register struct a { 42137Sbill int fdes; 42237Sbill struct stat *sb; 42337Sbill } *uap; 42437Sbill 42537Sbill uap = (struct a *)u.u_ap; 42637Sbill fp = getf(uap->fdes); 4274828Swnj if (fp == NULL) 42837Sbill return; 4294828Swnj if (fp->f_flag & FSOCKET) 4304891Swnj u.u_error = sostat(fp->f_socket, uap->sb); 4314828Swnj else 4324828Swnj stat1(fp->f_inode, uap->sb); 43337Sbill } 43437Sbill 43537Sbill /* 4366574Smckusic * Stat system call. This version follows links. 43737Sbill */ 43837Sbill stat() 43937Sbill { 44037Sbill register struct inode *ip; 44137Sbill register struct a { 44237Sbill char *fname; 44337Sbill struct stat *sb; 44437Sbill } *uap; 44537Sbill 44637Sbill uap = (struct a *)u.u_ap; 4476423Sroot ip = namei(uchar, 0, 1); 4484828Swnj if (ip == NULL) 44937Sbill return; 4503624Sroot stat1(ip, uap->sb); 45137Sbill iput(ip); 45237Sbill } 45337Sbill 45437Sbill /* 4556574Smckusic * Lstat system call. This version does not follow links. 4565992Swnj */ 4575992Swnj lstat() 4585992Swnj { 4595992Swnj register struct inode *ip; 4605992Swnj register struct a { 4615992Swnj char *fname; 4625992Swnj struct stat *sb; 4635992Swnj } *uap; 4645992Swnj 4655992Swnj uap = (struct a *)u.u_ap; 4666423Sroot ip = namei(uchar, 0, 0); 4675992Swnj if (ip == NULL) 4685992Swnj return; 4696153Ssam stat1(ip, uap->sb); 4705992Swnj iput(ip); 4715992Swnj } 4725992Swnj 4735992Swnj /* 47437Sbill * The basic routine for fstat and stat: 47537Sbill * get the inode and pass appropriate parts back. 47637Sbill */ 4773624Sroot stat1(ip, ub) 4784828Swnj register struct inode *ip; 4794828Swnj struct stat *ub; 48037Sbill { 48137Sbill struct stat ds; 48237Sbill 4831204Sbill IUPDAT(ip, &time, &time, 0); 48437Sbill /* 4857023Smckusick * Copy from inode table 48637Sbill */ 48737Sbill ds.st_dev = ip->i_dev; 48837Sbill ds.st_ino = ip->i_number; 48937Sbill ds.st_mode = ip->i_mode; 49037Sbill ds.st_nlink = ip->i_nlink; 49137Sbill ds.st_uid = ip->i_uid; 49237Sbill ds.st_gid = ip->i_gid; 4936574Smckusic ds.st_rdev = (dev_t)ip->i_rdev; 4943624Sroot ds.st_size = ip->i_size; 4956574Smckusic ds.st_atime = ip->i_atime; 4966574Smckusic ds.st_mtime = ip->i_mtime; 4976574Smckusic ds.st_ctime = ip->i_ctime; 4987023Smckusick ds.st_blksize = ip->i_fs->fs_bsize; 49937Sbill if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0) 50037Sbill u.u_error = EFAULT; 50137Sbill } 50237Sbill 50337Sbill /* 5045992Swnj * Return target name of a symbolic link 50537Sbill */ 5065992Swnj readlink() 5075992Swnj { 5085992Swnj register struct inode *ip; 5095992Swnj register struct a { 5105992Swnj char *name; 5115992Swnj char *buf; 5125992Swnj int count; 5135992Swnj } *uap; 5145992Swnj 5155992Swnj ip = namei(uchar, 0, 0); 5165992Swnj if (ip == NULL) 5175992Swnj return; 5185992Swnj if ((ip->i_mode&IFMT) != IFLNK) { 5195992Swnj u.u_error = ENXIO; 5205992Swnj goto out; 5215992Swnj } 5225992Swnj uap = (struct a *)u.u_ap; 5235992Swnj u.u_offset = 0; 5245992Swnj u.u_base = uap->buf; 5255992Swnj u.u_count = uap->count; 5265992Swnj u.u_segflg = 0; 5275992Swnj readi(ip); 5285992Swnj out: 5295992Swnj iput(ip); 5305992Swnj u.u_r.r_val1 = uap->count - u.u_count; 5315992Swnj } 5325992Swnj 5336254Sroot chmod() 5345992Swnj { 5356254Sroot register struct inode *ip; 5365992Swnj register struct a { 5376254Sroot char *fname; 5386254Sroot int fmode; 5395992Swnj } *uap; 5405992Swnj 5415992Swnj uap = (struct a *)u.u_ap; 5426254Sroot if ((ip = owner(1)) == NULL) 5435992Swnj return; 5446254Sroot ip->i_mode &= ~07777; 5456254Sroot if (u.u_uid) 5466254Sroot uap->fmode &= ~ISVTX; 5476254Sroot ip->i_mode |= uap->fmode&07777; 5486254Sroot ip->i_flag |= ICHG; 5496254Sroot if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0) 5506254Sroot xrele(ip); 5515992Swnj iput(ip); 5525992Swnj } 5535992Swnj 5546254Sroot chown() 55537Sbill { 5566254Sroot register struct inode *ip; 55737Sbill register struct a { 5586254Sroot char *fname; 5596254Sroot int uid; 5606254Sroot int gid; 56137Sbill } *uap; 56237Sbill 56337Sbill uap = (struct a *)u.u_ap; 5646254Sroot if (!suser() || (ip = owner(0)) == NULL) 56537Sbill return; 5666254Sroot ip->i_uid = uap->uid; 5676254Sroot ip->i_gid = uap->gid; 5686254Sroot ip->i_flag |= ICHG; 5696254Sroot if (u.u_ruid != 0) 5706254Sroot ip->i_mode &= ~(ISUID|ISGID); 5716254Sroot iput(ip); 57237Sbill } 57337Sbill 57437Sbill /* 5756254Sroot * Set IUPD and IACC times on file. 5766254Sroot * Can't set ICHG. 57737Sbill */ 5786254Sroot utime() 5794828Swnj { 58037Sbill register struct a { 5816254Sroot char *fname; 5826254Sroot time_t *tptr; 58337Sbill } *uap; 5846254Sroot register struct inode *ip; 5856254Sroot time_t tv[2]; 58637Sbill 58737Sbill uap = (struct a *)u.u_ap; 5886254Sroot if ((ip = owner(1)) == NULL) 58937Sbill return; 5906254Sroot if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) { 5916254Sroot u.u_error = EFAULT; 5926254Sroot } else { 5936254Sroot ip->i_flag |= IACC|IUPD|ICHG; 5946254Sroot iupdat(ip, &tv[0], &tv[1], 0); 59537Sbill } 59637Sbill iput(ip); 59737Sbill } 59837Sbill 5996254Sroot sync() 60037Sbill { 60137Sbill 6025416Swnj update(0); 60337Sbill } 604