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