xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 7439)
1 /*	vfs_syscalls.c	4.28	82/07/15	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/dir.h"
6 #include "../h/user.h"
7 #include "../h/file.h"
8 #include "../h/stat.h"
9 #include "../h/inode.h"
10 #include "../h/fs.h"
11 #include "../h/buf.h"
12 #include "../h/proc.h"
13 #include "../h/inline.h"
14 #ifdef EFS
15 #include "../net/in.h"
16 #include "../h/efs.h"
17 #endif
18 
19 chdir()
20 {
21 
22 	chdirec(&u.u_cdir);
23 }
24 
25 chroot()
26 {
27 
28 	if (suser())
29 		chdirec(&u.u_rdir);
30 }
31 
32 chdirec(ipp)
33 register struct inode **ipp;
34 {
35 	register struct inode *ip;
36 	struct a {
37 		char	*fname;
38 	};
39 
40 	ip = namei(uchar, 0, 1);
41 	if(ip == NULL)
42 		return;
43 	if((ip->i_mode&IFMT) != IFDIR) {
44 		u.u_error = ENOTDIR;
45 		goto bad;
46 	}
47 	if(access(ip, IEXEC))
48 		goto bad;
49 	iunlock(ip);
50 	if (*ipp)
51 		irele(*ipp);
52 	*ipp = ip;
53 	return;
54 
55 bad:
56 	iput(ip);
57 }
58 
59 /*
60  * Open system call.
61  */
62 open()
63 {
64 	register struct inode *ip;
65 	register struct a {
66 		char	*fname;
67 		int	rwmode;
68 	} *uap;
69 
70 	uap = (struct a *)u.u_ap;
71 	ip = namei(uchar, 0, 1);
72 	if (ip == NULL)
73 		return;
74 	open1(ip, ++uap->rwmode, 0);
75 }
76 
77 /*
78  * Creat system call.
79  */
80 creat()
81 {
82 	register struct inode *ip;
83 	register struct a {
84 		char	*fname;
85 		int	fmode;
86 	} *uap;
87 
88 	uap = (struct a *)u.u_ap;
89 	ip = namei(uchar, 1, 1);
90 	if (ip == NULL) {
91 		if (u.u_error)
92 			return;
93 		ip = maknode(uap->fmode&07777&(~ISVTX));
94 		if (ip==NULL)
95 			return;
96 		open1(ip, FWRITE, 2);
97 	} else
98 		open1(ip, FWRITE, 1);
99 }
100 
101 /*
102  * Common code for open and creat.
103  * Check permissions, allocate an open file structure,
104  * and call the device open routine if any.
105  */
106 open1(ip, mode, trf)
107 	register struct inode *ip;
108 	register mode;
109 {
110 	register struct file *fp;
111 	int i;
112 
113 	if (trf != 2) {
114 		if (mode&FREAD)
115 			(void) access(ip, IREAD);
116 		if (mode&FWRITE) {
117 			(void) access(ip, IWRITE);
118 			if ((ip->i_mode&IFMT) == IFDIR)
119 				u.u_error = EISDIR;
120 		}
121 	}
122 	if (u.u_error) {
123 		iput(ip);
124 		return;
125 	}
126 	if (trf == 1)
127 		itrunc(ip);
128 	iunlock(ip);
129 	if ((fp = falloc()) == NULL)
130 		goto out;
131 	fp->f_flag = mode&(FREAD|FWRITE);
132 	i = u.u_r.r_val1;
133 	fp->f_inode = ip;
134 #ifdef EFS
135 	openi(ip, mode&(FREAD|FWRITE), trf);
136 #else
137 	openi(ip, mode&(FREAD|FWRITE));
138 #endif
139 	if (u.u_error == 0)
140 		return;
141 	u.u_ofile[i] = NULL;
142 	fp->f_count--;
143 out:
144 	irele(ip);
145 }
146 
147 /*
148  * Mknod system call
149  */
150 mknod()
151 {
152 	register struct inode *ip;
153 	register struct a {
154 		char	*fname;
155 		int	fmode;
156 		int	dev;
157 	} *uap;
158 
159 	uap = (struct a *)u.u_ap;
160 	if (suser()) {
161 		ip = namei(uchar, 1, 0);
162 		if (ip != NULL) {
163 			u.u_error = EEXIST;
164 			goto out;
165 		}
166 	}
167 	if (u.u_error)
168 		return;
169 	ip = maknode(uap->fmode);
170 	if (ip == NULL)
171 		return;
172 	if (uap->dev) {
173 		/*
174 		 * Want to be able to use this to make badblock
175 		 * inodes, so don't truncate the dev number.
176 		 */
177 		ip->i_rdev = uap->dev;
178 		ip->i_flag |= IACC|IUPD|ICHG;
179 	}
180 
181 out:
182 	iput(ip);
183 }
184 
185 /*
186  * link system call
187  */
188 link()
189 {
190 	register struct inode *ip, *xp;
191 	register struct a {
192 		char	*target;
193 		char	*linkname;
194 	} *uap;
195 
196 	uap = (struct a *)u.u_ap;
197 	ip = namei(uchar, 0, 1);    /* well, this routine is doomed anyhow */
198 	if (ip == NULL)
199 		return;
200 	if ((ip->i_mode&IFMT)==IFDIR && !suser()) {
201 		iput(ip);
202 		return;
203 	}
204 	ip->i_nlink++;
205 	ip->i_flag |= ICHG;
206 	iupdat(ip, &time, &time, 1);
207 	iunlock(ip);
208 	u.u_dirp = (caddr_t)uap->linkname;
209 	xp = namei(uchar, 1, 0);
210 	if (xp != NULL) {
211 		u.u_error = EEXIST;
212 		iput(xp);
213 		goto out;
214 	}
215 	if (u.u_error)
216 		goto out;
217 	if (u.u_pdir->i_dev != ip->i_dev) {
218 		iput(u.u_pdir);
219 		u.u_error = EXDEV;
220 		goto out;
221 	}
222 	wdir(ip);
223 out:
224 	if (u.u_error) {
225 		ip->i_nlink--;
226 		ip->i_flag |= ICHG;
227 	}
228 out1:
229 	irele(ip);
230 }
231 
232 /*
233  * symlink -- make a symbolic link
234  */
235 symlink()
236 {
237 	register struct a {
238 		char	*target;
239 		char	*linkname;
240 	} *uap;
241 	register struct inode *ip;
242 	register char *tp;
243 	register c, nc;
244 
245 	uap = (struct a *)u.u_ap;
246 	tp = uap->target;
247 	nc = 0;
248 	while (c = fubyte(tp)) {
249 		if (c < 0) {
250 			u.u_error = EFAULT;
251 			return;
252 		}
253 		tp++;
254 		nc++;
255 	}
256 	u.u_dirp = uap->linkname;
257 	ip = namei(uchar, 1, 0);
258 	if (ip) {
259 		iput(ip);
260 		u.u_error = EEXIST;
261 		return;
262 	}
263 	if (u.u_error)
264 		return;
265 	ip = maknode(IFLNK | 0777);
266 	if (ip == NULL)
267 		return;
268 	u.u_base = uap->target;
269 	u.u_count = nc;
270 	u.u_offset = 0;
271 	u.u_segflg = 0;
272 	writei(ip);
273 	iput(ip);
274 }
275 
276 /*
277  * Unlink system call.
278  * Hard to avoid races here, especially
279  * in unlinking directories.
280  */
281 unlink()
282 {
283 	register struct inode *ip, *pp;
284 	struct a {
285 		char	*fname;
286 	};
287 	struct fs *fs;
288 	struct buf *bp;
289 	int lbn, bn, base;
290 	int unlinkingdot = 0;
291 
292 	pp = namei(uchar, 2, 0);
293 	if(pp == NULL)
294 		return;
295 #ifdef EFS
296 	/* divert to extended file system if off machine. */
297 	if (efsinode(pp)) {
298 		dev_t ndev = pp->i_rdev;
299 
300 		iput(pp);	/* avoid recursive hang on inode */
301 		efsunlink(ndev);
302 		if (u.u_error != EEXIST)
303 			return;
304 
305 		/*
306 		 * If a null pathname remainder, then do
307 		 * the unlink locally after restoring state.
308 		 */
309 		u.u_error = 0;
310 		u.u_dirp = (caddr_t)u.u_arg[0];
311 		pp = namei(uchar, 2, 0);
312 	}
313 #endif
314 
315 	/*
316 	 * Check for unlink(".")
317 	 * to avoid hanging on the iget
318 	 */
319 	if (pp->i_number == u.u_dent.d_ino) {
320 		ip = pp;
321 		ip->i_count++;
322 		unlinkingdot++;
323 	} else
324 		ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino);
325 	if(ip == NULL)
326 		goto out1;
327 	if((ip->i_mode&IFMT)==IFDIR && !suser())
328 		goto out;
329 	/*
330 	 * Don't unlink a mounted file.
331 	 */
332 	if (ip->i_dev != pp->i_dev) {
333 		u.u_error = EBUSY;
334 		goto out;
335 	}
336 	if (ip->i_flag&ITEXT)
337 		xrele(ip);	/* try once to free text */
338 /*
339 	if ((ip->i_flag&ITEXT) && ip->i_nlink==1) {
340  		u.u_error = ETXTBSY;
341 		goto out;
342 	}
343 */
344 	if (u.u_count == 0) {
345 		/*
346 		 * first entry in block, so set d_ino to zero.
347 		 */
348 		u.u_base = (caddr_t)&u.u_dent;
349 		u.u_count = DIRSIZ(&u.u_dent);
350 		u.u_dent.d_ino = 0;
351 		writei(pp);
352 	} else {
353 		/*
354 		 * updating preceeding entry to skip over current entry.
355 		 */
356 		fs = pp->i_fs;
357 		lbn = lblkno(fs, u.u_offset);
358 		base = blkoff(fs, u.u_offset);
359 		bn = fsbtodb(fs, bmap(pp, lbn, B_WRITE, base + u.u_count));
360 		bp = bread(pp->i_dev, bn, blksize(fs, pp, lbn));
361 		if (bp->b_flags & B_ERROR) {
362 			brelse(bp);
363 			goto out;
364 		}
365 		((struct direct *)(bp->b_un.b_addr + base))->d_reclen +=
366 		    u.u_dent.d_reclen;
367 		bwrite(bp);
368 		pp->i_flag |= IUPD|ICHG;
369 	}
370 	ip->i_nlink--;
371 	ip->i_flag |= ICHG;
372 
373 out:
374 	if (unlinkingdot)
375 		irele(ip);
376 	else
377 		iput(ip);
378 out1:
379 	iput(pp);
380 }
381 
382 /*
383  * Seek system call
384  */
385 seek()
386 {
387 	register struct file *fp;
388 	register struct a {
389 		int	fdes;
390 		off_t	off;
391 		int	sbase;
392 	} *uap;
393 
394 	uap = (struct a *)u.u_ap;
395 	fp = getf(uap->fdes);
396 	if (fp == NULL)
397 		return;
398 	if (fp->f_flag&FSOCKET) {
399 		u.u_error = ESPIPE;
400 		return;
401 	}
402 	if (uap->sbase == 1)
403 		uap->off += fp->f_offset;
404 	else if (uap->sbase == 2) {
405 #ifdef EFS
406 		struct inode *ip = fp->f_inode;
407 		uap->off += efsinode(ip) ? efsfilesize(fp) : ip->i_size;
408 #else
409 		uap->off += fp->f_inode->i_size;
410 #endif
411 	}
412 	fp->f_offset = uap->off;
413 	u.u_r.r_off = uap->off;
414 }
415 
416 /*
417  * Access system call
418  */
419 saccess()
420 {
421 	register svuid, svgid;
422 	register struct inode *ip;
423 	register struct a {
424 		char	*fname;
425 		int	fmode;
426 	} *uap;
427 
428 	uap = (struct a *)u.u_ap;
429 	svuid = u.u_uid;
430 	svgid = u.u_gid;
431 	u.u_uid = u.u_ruid;
432 	u.u_gid = u.u_rgid;
433 	ip = namei(uchar, 0, 1);
434 #ifdef EFS
435 	if (efsinode(ip)) {
436 		dev_t ndev = ip->i_rdev;
437 
438 		iput(ip);
439 		efssaccess(ndev);
440 		if (u.u_error != EEXIST)
441 			return;
442 		u.u_error = 0;
443 		u.u_dirp = (caddr_t)u.u_arg[0];
444 		ip = namei(uchar, 0, 1);
445 	}
446 #endif
447 	if (ip != NULL) {
448 		if (uap->fmode&(IREAD>>6))
449 			(void) access(ip, IREAD);
450 		if (uap->fmode&(IWRITE>>6))
451 			(void) access(ip, IWRITE);
452 		if (uap->fmode&(IEXEC>>6))
453 			(void) access(ip, IEXEC);
454 		iput(ip);
455 	}
456 	u.u_uid = svuid;
457 	u.u_gid = svgid;
458 }
459 
460 /*
461  * the fstat system call.
462  */
463 fstat()
464 {
465 	register struct file *fp;
466 	register struct a {
467 		int	fdes;
468 		struct stat *sb;
469 	} *uap;
470 
471 	uap = (struct a *)u.u_ap;
472 	fp = getf(uap->fdes);
473 	if (fp == NULL)
474 		return;
475 #ifdef EFS
476 	if (efsinode(fp->f_inode)) {
477 		efsfstat(fp->f_inode->i_rdev, fp);
478 		return;
479 	}
480 #endif
481 	if (fp->f_flag & FSOCKET)
482 		u.u_error = sostat(fp->f_socket, uap->sb);
483 	else
484 		stat1(fp->f_inode, uap->sb);
485 }
486 
487 /*
488  * Stat system call.  This version follows links.
489  */
490 stat()
491 {
492 	register struct inode *ip;
493 	register struct a {
494 		char	*fname;
495 		struct stat *sb;
496 	} *uap;
497 
498 	uap = (struct a *)u.u_ap;
499 	ip = namei(uchar, 0, 1);
500 	if (ip == NULL)
501 		return;
502 #ifdef EFS
503 	if (efsinode(ip)) {
504 		dev_t ndev = ip->i_rdev;
505 
506 		iput(ip);
507 		efsstat(ndev);
508 		if (u.u_error != EEXIST)
509 			return;
510 		u.u_error = 0;
511 		u.u_dirp = (caddr_t)u.u_arg[0];
512 		ip = namei(uchar, 0, 1);
513 	}
514 #endif
515 	stat1(ip, uap->sb);
516 	iput(ip);
517 }
518 
519 /*
520  * Lstat system call.  This version does not follow links.
521  */
522 lstat()
523 {
524 	register struct inode *ip;
525 	register struct a {
526 		char	*fname;
527 		struct stat *sb;
528 	} *uap;
529 
530 	uap = (struct a *)u.u_ap;
531 	ip = namei(uchar, 0, 0);
532 	if (ip == NULL)
533 		return;
534 #ifdef EFS
535 	if (efsinode(ip)) {
536 		dev_t ndev = ip->i_rdev;
537 
538 		iput(ip);
539 		efslstat(ndev);
540 		if (u.u_error != EEXIST)
541 			return;
542 		u.u_error = 0;
543 		u.u_dirp = (caddr_t)u.u_arg[0];
544 		ip = namei(uchar, 0, 0);
545 	}
546 #endif
547 	stat1(ip, uap->sb);
548 	iput(ip);
549 }
550 
551 /*
552  * The basic routine for fstat and stat:
553  * get the inode and pass appropriate parts back.
554  */
555 stat1(ip, ub)
556 	register struct inode *ip;
557 	struct stat *ub;
558 {
559 	struct stat ds;
560 
561 	IUPDAT(ip, &time, &time, 0);
562 	/*
563 	 * Copy from inode table
564 	 */
565 	ds.st_dev = ip->i_dev;
566 	ds.st_ino = ip->i_number;
567 	ds.st_mode = ip->i_mode;
568 	ds.st_nlink = ip->i_nlink;
569 	ds.st_uid = ip->i_uid;
570 	ds.st_gid = ip->i_gid;
571 	ds.st_rdev = (dev_t)ip->i_rdev;
572 	ds.st_size = ip->i_size;
573 	ds.st_atime = ip->i_atime;
574 	ds.st_mtime = ip->i_mtime;
575 	ds.st_ctime = ip->i_ctime;
576 	ds.st_blksize = ip->i_fs->fs_bsize;
577 	if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
578 		u.u_error = EFAULT;
579 }
580 
581 /*
582  * Return target name of a symbolic link
583  */
584 readlink()
585 {
586 	register struct inode *ip;
587 	register struct a {
588 		char	*name;
589 		char	*buf;
590 		int	count;
591 	} *uap;
592 
593 	ip = namei(uchar, 0, 0);
594 	if (ip == NULL)
595 		return;
596 #ifdef EFS
597 	if (efsinode(ip)) {
598 		dev_t ndev = ip->i_rdev;
599 
600 		iput(ip);
601 		efsreadlink(ndev);
602 		if (u.u_error != EEXIST)
603 			return;
604 		u.u_error = 0;
605 		u.u_dirp = (caddr_t)u.u_arg[0];
606 		ip = namei(uchar, 0, 0);
607 		return (0);
608 	}
609 #endif
610 	if ((ip->i_mode&IFMT) != IFLNK) {
611 		u.u_error = ENXIO;
612 		goto out;
613 	}
614 	uap = (struct a *)u.u_ap;
615 	u.u_offset = 0;
616 	u.u_base = uap->buf;
617 	u.u_count = uap->count;
618 	u.u_segflg = 0;
619 	readi(ip);
620 out:
621 	iput(ip);
622 	u.u_r.r_val1 = uap->count - u.u_count;
623 }
624 
625 chmod()
626 {
627 	register struct inode *ip;
628 	register struct a {
629 		char	*fname;
630 		int	fmode;
631 	} *uap;
632 
633 	uap = (struct a *)u.u_ap;
634 	if ((ip = owner(1)) == NULL)
635 		return;
636 #ifdef EFS
637 	if (efsinode(ip)) {
638 		dev_t ndev = ip->i_rdev;
639 
640 		iput(ip);
641 		efschmod(ndev);
642 		if (u.u_error != EEXIST)
643 			return;
644 		u.u_error = 0;
645 		u.u_dirp = (caddr_t)u.u_arg[0];
646 		ip = owner(1);
647 	}
648 #endif
649 	ip->i_mode &= ~07777;
650 	if (u.u_uid) {
651 		uap->fmode &= ~ISVTX;
652 		if (ip->i_gid >= NGRPS ||
653 		    (u.u_grps[ip->i_gid/(sizeof(int)*8)] &
654 		     (1 << ip->i_gid%(sizeof(int)*8))) == 0)
655 			uap->fmode &= ~ISGID;
656 	}
657 	ip->i_mode |= uap->fmode&07777;
658 	ip->i_flag |= ICHG;
659 	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
660 		xrele(ip);
661 	iput(ip);
662 }
663 
664 chown()
665 {
666 	register struct inode *ip;
667 	register struct a {
668 		char	*fname;
669 		int	uid;
670 		int	gid;
671 	} *uap;
672 
673 	uap = (struct a *)u.u_ap;
674 	if (!suser() || (ip = owner(0)) == NULL)
675 		return;
676 #ifdef EFS
677 	if (efsinode(ip)) {
678 		dev_t ndev = ip->i_rdev;
679 
680 		iput(ip);
681 		efschown(ndev);
682 		if (u.u_error != EEXIST)
683 			return;
684 		u.u_error = 0;
685 		u.u_dirp = (caddr_t)u.u_arg[0];
686 		ip = owner(0);
687 	}
688 #endif
689 	/*
690 	 * keep uid/gid's in sane range - no err, so chown(file, uid, -1)
691 	 * will do something useful
692 	 */
693 	if (uap->uid >= 0 && uap->uid <= 32767)	/* should have a const	*/
694 		ip->i_uid = uap->uid;
695 	if (uap->gid >= 0 && uap->gid <= 32767)	/* same here		*/
696 		ip->i_gid = uap->gid;
697 	ip->i_flag |= ICHG;
698 	if (u.u_ruid != 0)
699 		ip->i_mode &= ~(ISUID|ISGID);
700 	iput(ip);
701 }
702 
703 /*
704  * Set IUPD and IACC times on file.
705  * Can't set ICHG.
706  */
707 utime()
708 {
709 	register struct a {
710 		char	*fname;
711 		time_t	*tptr;
712 	} *uap;
713 	register struct inode *ip;
714 	time_t tv[2];
715 
716 	uap = (struct a *)u.u_ap;
717 	if ((ip = owner(1)) == NULL)
718 		return;
719 	if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
720 		u.u_error = EFAULT;
721 	} else {
722 #ifdef EFS
723 		if (efsinode(ip)) {
724 			dev_t ndev = ip->i_rdev;
725 
726 			iput(ip);
727 			efsutime(ndev, uap->fname, tv);
728 			if (u.u_error != EEXIST)
729 				return;
730 			u.u_error = 0;
731 			u.u_dirp = (caddr_t)u.u_arg[0];
732 			ip = owner(1);
733 		}
734 #endif
735 		ip->i_flag |= IACC|IUPD|ICHG;
736 		iupdat(ip, &tv[0], &tv[1], 0);
737 	}
738 	iput(ip);
739 }
740 
741 sync()
742 {
743 
744 	update(0);
745 }
746