fix chown; don't steal groups or give away files
[unix-history] / usr / src / sys / kern / vfs_syscalls.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
18b0bce6 6 * @(#)vfs_syscalls.c 7.4 (Berkeley) %G%
da7c5cc6 7 */
6459ebe0 8
94368568
JB
9#include "param.h"
10#include "systm.h"
11#include "dir.h"
12#include "user.h"
13#include "kernel.h"
14#include "file.h"
15#include "stat.h"
16#include "inode.h"
17#include "fs.h"
18#include "buf.h"
19#include "proc.h"
20#include "quota.h"
21#include "uio.h"
22#include "socket.h"
23#include "socketvar.h"
24#include "mount.h"
88a7a62a
SL
25
26extern struct fileops inodeops;
27struct file *getinode();
3e78e260 28
4f083fd7
SL
29/*
30 * Change current working directory (``.'').
31 */
3e78e260
BJ
32chdir()
33{
34
35 chdirec(&u.u_cdir);
36}
37
4f083fd7
SL
38/*
39 * Change notion of root (``/'') directory.
40 */
3e78e260
BJ
41chroot()
42{
43
44 if (suser())
45 chdirec(&u.u_rdir);
46}
47
4f083fd7
SL
48/*
49 * Common routine for chroot and chdir.
50 */
3e78e260 51chdirec(ipp)
528f664c 52 register struct inode **ipp;
3e78e260
BJ
53{
54 register struct inode *ip;
55 struct a {
56 char *fname;
715baff1
KM
57 } *uap = (struct a *)u.u_ap;
58 register struct nameidata *ndp = &u.u_nd;
3e78e260 59
715baff1
KM
60 ndp->ni_nameiop = LOOKUP | FOLLOW;
61 ndp->ni_segflg = UIO_USERSPACE;
62 ndp->ni_dirp = uap->fname;
63 ip = namei(ndp);
4f083fd7 64 if (ip == NULL)
3e78e260 65 return;
4f083fd7 66 if ((ip->i_mode&IFMT) != IFDIR) {
3e78e260
BJ
67 u.u_error = ENOTDIR;
68 goto bad;
69 }
4f083fd7 70 if (access(ip, IEXEC))
3e78e260 71 goto bad;
a388503d 72 IUNLOCK(ip);
8eee8525
KM
73 if (*ipp)
74 irele(*ipp);
3e78e260
BJ
75 *ipp = ip;
76 return;
77
78bad:
79 iput(ip);
80}
81
82/*
83 * Open system call.
84 */
85open()
86{
88a7a62a 87 struct a {
3e78e260 88 char *fname;
528f664c 89 int mode;
88a7a62a
SL
90 int crtmode;
91 } *uap = (struct a *) u.u_ap;
3e78e260 92
715baff1 93 copen(uap->mode-FOPEN, uap->crtmode, uap->fname);
3e78e260
BJ
94}
95
96/*
97 * Creat system call.
98 */
88a7a62a 99creat()
3e78e260 100{
88a7a62a 101 struct a {
3e78e260
BJ
102 char *fname;
103 int fmode;
88a7a62a 104 } *uap = (struct a *)u.u_ap;
3e78e260 105
715baff1 106 copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname);
3e78e260
BJ
107}
108
109/*
110 * Common code for open and creat.
88a7a62a
SL
111 * Check permissions, allocate an open file structure,
112 * and call the device open routine if any.
3e78e260 113 */
715baff1 114copen(mode, arg, fname)
88a7a62a
SL
115 register int mode;
116 int arg;
715baff1 117 caddr_t fname;
3e78e260 118{
88a7a62a 119 register struct inode *ip;
3e78e260 120 register struct file *fp;
715baff1 121 register struct nameidata *ndp = &u.u_nd;
49873122 122 int indx;
3e78e260 123
49873122
KM
124 fp = falloc();
125 if (fp == NULL)
88a7a62a 126 return;
49873122 127 indx = u.u_r.r_val1;
715baff1
KM
128 ndp->ni_segflg = UIO_USERSPACE;
129 ndp->ni_dirp = fname;
88a7a62a 130 if (mode&FCREAT) {
696ccec7
KM
131 if (mode & FEXCL)
132 ndp->ni_nameiop = CREATE;
133 else
134 ndp->ni_nameiop = CREATE | FOLLOW;
715baff1 135 ip = namei(ndp);
88a7a62a
SL
136 if (ip == NULL) {
137 if (u.u_error)
49873122 138 goto bad1;
715baff1 139 ip = maknode(arg&07777&(~ISVTX), ndp);
88a7a62a 140 if (ip == NULL)
49873122 141 goto bad1;
88a7a62a
SL
142 mode &= ~FTRUNC;
143 } else {
144 if (mode&FEXCL) {
145 u.u_error = EEXIST;
49873122 146 goto bad;
88a7a62a
SL
147 }
148 mode &= ~FCREAT;
149 }
150 } else {
715baff1
KM
151 ndp->ni_nameiop = LOOKUP | FOLLOW;
152 ip = namei(ndp);
88a7a62a 153 if (ip == NULL)
49873122 154 goto bad1;
88a7a62a
SL
155 }
156 if ((ip->i_mode & IFMT) == IFSOCK) {
157 u.u_error = EOPNOTSUPP;
158 goto bad;
159 }
160 if ((mode&FCREAT) == 0) {
3e78e260 161 if (mode&FREAD)
528f664c
SL
162 if (access(ip, IREAD))
163 goto bad;
09bf91df 164 if (mode&(FWRITE|FTRUNC)) {
528f664c
SL
165 if (access(ip, IWRITE))
166 goto bad;
167 if ((ip->i_mode&IFMT) == IFDIR) {
3e78e260 168 u.u_error = EISDIR;
528f664c
SL
169 goto bad;
170 }
3e78e260
BJ
171 }
172 }
88a7a62a 173 if (mode&FTRUNC)
4f083fd7 174 itrunc(ip, (u_long)0);
a388503d 175 IUNLOCK(ip);
88a7a62a
SL
176 fp->f_flag = mode&FMASK;
177 fp->f_type = DTYPE_INODE;
178 fp->f_ops = &inodeops;
179 fp->f_data = (caddr_t)ip;
88a7a62a
SL
180 if (setjmp(&u.u_qsave)) {
181 if (u.u_error == 0)
182 u.u_error = EINTR;
49873122 183 u.u_ofile[indx] = NULL;
88a7a62a 184 closef(fp);
3e78e260 185 return;
528f664c 186 }
88a7a62a
SL
187 u.u_error = openi(ip, mode);
188 if (u.u_error == 0)
189 return;
49873122 190 ILOCK(ip);
528f664c
SL
191bad:
192 iput(ip);
49873122
KM
193bad1:
194 u.u_ofile[indx] = NULL;
195 fp->f_count--;
3e78e260
BJ
196}
197
198/*
199 * Mknod system call
200 */
201mknod()
202{
203 register struct inode *ip;
204 register struct a {
205 char *fname;
206 int fmode;
207 int dev;
715baff1
KM
208 } *uap = (struct a *)u.u_ap;
209 register struct nameidata *ndp = &u.u_nd;
3e78e260 210
88a7a62a
SL
211 if (!suser())
212 return;
715baff1
KM
213 ndp->ni_nameiop = CREATE;
214 ndp->ni_segflg = UIO_USERSPACE;
215 ndp->ni_dirp = uap->fname;
216 ip = namei(ndp);
88a7a62a
SL
217 if (ip != NULL) {
218 u.u_error = EEXIST;
219 goto out;
3e78e260
BJ
220 }
221 if (u.u_error)
222 return;
715baff1 223 ip = maknode(uap->fmode, ndp);
3e78e260
BJ
224 if (ip == NULL)
225 return;
88a7a62a
SL
226 switch (ip->i_mode & IFMT) {
227
7bfaea72 228 case IFMT: /* used by badsect to flag bad sectors */
88a7a62a
SL
229 case IFCHR:
230 case IFBLK:
231 if (uap->dev) {
232 /*
233 * Want to be able to use this to make badblock
234 * inodes, so don't truncate the dev number.
235 */
236 ip->i_rdev = uap->dev;
237 ip->i_flag |= IACC|IUPD|ICHG;
238 }
3e78e260
BJ
239 }
240
241out:
242 iput(ip);
243}
244
245/*
246 * link system call
247 */
248link()
249{
250 register struct inode *ip, *xp;
251 register struct a {
252 char *target;
253 char *linkname;
715baff1
KM
254 } *uap = (struct a *)u.u_ap;
255 register struct nameidata *ndp = &u.u_nd;
3e78e260 256
715baff1
KM
257 ndp->ni_nameiop = LOOKUP | FOLLOW;
258 ndp->ni_segflg = UIO_USERSPACE;
259 ndp->ni_dirp = uap->target;
260 ip = namei(ndp); /* well, this routine is doomed anyhow */
3e78e260
BJ
261 if (ip == NULL)
262 return;
4f083fd7 263 if ((ip->i_mode&IFMT) == IFDIR && !suser()) {
f94ceb3b
BJ
264 iput(ip);
265 return;
266 }
3e78e260
BJ
267 ip->i_nlink++;
268 ip->i_flag |= ICHG;
3fd23f5c 269 iupdat(ip, &time, &time, 1);
a388503d 270 IUNLOCK(ip);
715baff1
KM
271 ndp->ni_nameiop = CREATE;
272 ndp->ni_segflg = UIO_USERSPACE;
273 ndp->ni_dirp = (caddr_t)uap->linkname;
274 xp = namei(ndp);
3e78e260
BJ
275 if (xp != NULL) {
276 u.u_error = EEXIST;
277 iput(xp);
278 goto out;
279 }
280 if (u.u_error)
281 goto out;
715baff1
KM
282 if (ndp->ni_pdir->i_dev != ip->i_dev) {
283 iput(ndp->ni_pdir);
3e78e260
BJ
284 u.u_error = EXDEV;
285 goto out;
286 }
715baff1 287 u.u_error = direnter(ip, ndp);
3e78e260
BJ
288out:
289 if (u.u_error) {
290 ip->i_nlink--;
291 ip->i_flag |= ICHG;
292 }
8eee8525 293 irele(ip);
3e78e260
BJ
294}
295
296/*
297 * symlink -- make a symbolic link
298 */
299symlink()
300{
301 register struct a {
302 char *target;
303 char *linkname;
715baff1 304 } *uap = (struct a *)u.u_ap;
3e78e260
BJ
305 register struct inode *ip;
306 register char *tp;
307 register c, nc;
715baff1 308 register struct nameidata *ndp = &u.u_nd;
3e78e260 309
3e78e260
BJ
310 tp = uap->target;
311 nc = 0;
312 while (c = fubyte(tp)) {
313 if (c < 0) {
314 u.u_error = EFAULT;
315 return;
316 }
317 tp++;
318 nc++;
319 }
715baff1
KM
320 ndp->ni_nameiop = CREATE;
321 ndp->ni_segflg = UIO_USERSPACE;
322 ndp->ni_dirp = uap->linkname;
323 ip = namei(ndp);
3e78e260
BJ
324 if (ip) {
325 iput(ip);
326 u.u_error = EEXIST;
327 return;
328 }
329 if (u.u_error)
330 return;
715baff1 331 ip = maknode(IFLNK | 0777, ndp);
3e78e260
BJ
332 if (ip == NULL)
333 return;
8011f5df
MK
334 u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, (off_t)0, 0,
335 (int *)0);
4f083fd7 336 /* handle u.u_error != 0 */
3e78e260
BJ
337 iput(ip);
338}
339
340/*
341 * Unlink system call.
342 * Hard to avoid races here, especially
343 * in unlinking directories.
344 */
345unlink()
346{
3e78e260
BJ
347 struct a {
348 char *fname;
715baff1 349 } *uap = (struct a *)u.u_ap;
4f083fd7 350 register struct inode *ip, *dp;
715baff1 351 register struct nameidata *ndp = &u.u_nd;
3e78e260 352
715baff1
KM
353 ndp->ni_nameiop = DELETE | LOCKPARENT;
354 ndp->ni_segflg = UIO_USERSPACE;
355 ndp->ni_dirp = uap->fname;
356 ip = namei(ndp);
4f083fd7 357 if (ip == NULL)
3e78e260 358 return;
715baff1 359 dp = ndp->ni_pdir;
4f083fd7 360 if ((ip->i_mode&IFMT) == IFDIR && !suser())
3e78e260
BJ
361 goto out;
362 /*
363 * Don't unlink a mounted file.
364 */
4f083fd7 365 if (ip->i_dev != dp->i_dev) {
3e78e260
BJ
366 u.u_error = EBUSY;
367 goto out;
368 }
369 if (ip->i_flag&ITEXT)
370 xrele(ip); /* try once to free text */
715baff1 371 if (dirremove(ndp)) {
64d3a787
BJ
372 ip->i_nlink--;
373 ip->i_flag |= ICHG;
6459ebe0 374 }
3e78e260 375out:
4f083fd7 376 if (dp == ip)
8eee8525
KM
377 irele(ip);
378 else
379 iput(ip);
4f083fd7 380 iput(dp);
3e78e260
BJ
381}
382
383/*
384 * Seek system call
385 */
35e7c31a 386lseek()
3e78e260
BJ
387{
388 register struct file *fp;
389 register struct a {
528f664c 390 int fd;
3e78e260
BJ
391 off_t off;
392 int sbase;
715baff1 393 } *uap = (struct a *)u.u_ap;
3e78e260 394
8462a185
SL
395 GETF(fp, uap->fd);
396 if (fp->f_type != DTYPE_INODE) {
397 u.u_error = ESPIPE;
3e78e260 398 return;
8462a185 399 }
b4d1aee9
SL
400 switch (uap->sbase) {
401
402 case L_INCR:
403 fp->f_offset += uap->off;
404 break;
405
406 case L_XTND:
407 fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size;
408 break;
409
410 case L_SET:
411 fp->f_offset = uap->off;
412 break;
413
414 default:
415 u.u_error = EINVAL;
416 return;
417 }
418 u.u_r.r_off = fp->f_offset;
3e78e260
BJ
419}
420
421/*
422 * Access system call
423 */
424saccess()
425{
426 register svuid, svgid;
427 register struct inode *ip;
428 register struct a {
429 char *fname;
430 int fmode;
715baff1
KM
431 } *uap = (struct a *)u.u_ap;
432 register struct nameidata *ndp = &u.u_nd;
3e78e260 433
3e78e260
BJ
434 svuid = u.u_uid;
435 svgid = u.u_gid;
436 u.u_uid = u.u_ruid;
437 u.u_gid = u.u_rgid;
715baff1
KM
438 ndp->ni_nameiop = LOOKUP | FOLLOW;
439 ndp->ni_segflg = UIO_USERSPACE;
440 ndp->ni_dirp = uap->fname;
441 ip = namei(ndp);
3e78e260 442 if (ip != NULL) {
88a7a62a 443 if ((uap->fmode&R_OK) && access(ip, IREAD))
528f664c 444 goto done;
88a7a62a 445 if ((uap->fmode&W_OK) && access(ip, IWRITE))
528f664c 446 goto done;
88a7a62a 447 if ((uap->fmode&X_OK) && access(ip, IEXEC))
528f664c
SL
448 goto done;
449done:
3e78e260
BJ
450 iput(ip);
451 }
452 u.u_uid = svuid;
453 u.u_gid = svgid;
454}
d67a03eb 455
d67a03eb 456/*
6459ebe0 457 * Stat system call. This version follows links.
d67a03eb
BJ
458 */
459stat()
460{
d67a03eb 461
715baff1 462 stat1(FOLLOW);
d67a03eb
BJ
463}
464
5485e062 465/*
6459ebe0 466 * Lstat system call. This version does not follow links.
5485e062
BJ
467 */
468lstat()
88a7a62a
SL
469{
470
715baff1 471 stat1(NOFOLLOW);
88a7a62a
SL
472}
473
474stat1(follow)
475 int follow;
5485e062
BJ
476{
477 register struct inode *ip;
478 register struct a {
479 char *fname;
88a7a62a 480 struct stat *ub;
715baff1 481 } *uap = (struct a *)u.u_ap;
88a7a62a 482 struct stat sb;
715baff1 483 register struct nameidata *ndp = &u.u_nd;
5485e062 484
715baff1
KM
485 ndp->ni_nameiop = LOOKUP | follow;
486 ndp->ni_segflg = UIO_USERSPACE;
487 ndp->ni_dirp = uap->fname;
488 ip = namei(ndp);
5485e062
BJ
489 if (ip == NULL)
490 return;
0eaf24e3 491 (void) ino_stat(ip, &sb);
5485e062 492 iput(ip);
88a7a62a 493 u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
d67a03eb
BJ
494}
495
496/*
5485e062
BJ
497 * Return target name of a symbolic link
498 */
499readlink()
500{
501 register struct inode *ip;
502 register struct a {
503 char *name;
504 char *buf;
505 int count;
31949305 506 } *uap = (struct a *)u.u_ap;
715baff1 507 register struct nameidata *ndp = &u.u_nd;
31949305 508 int resid;
5485e062 509
715baff1
KM
510 ndp->ni_nameiop = LOOKUP;
511 ndp->ni_segflg = UIO_USERSPACE;
512 ndp->ni_dirp = uap->name;
513 ip = namei(ndp);
5485e062
BJ
514 if (ip == NULL)
515 return;
516 if ((ip->i_mode&IFMT) != IFLNK) {
47af7174 517 u.u_error = EINVAL;
5485e062
BJ
518 goto out;
519 }
8011f5df
MK
520 u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, (off_t)0, 0,
521 &resid);
5485e062
BJ
522out:
523 iput(ip);
31949305 524 u.u_r.r_val1 = uap->count - resid;
5485e062
BJ
525}
526
4f083fd7
SL
527/*
528 * Change mode of a file given path name.
529 */
3e78e260 530chmod()
5485e062 531{
528f664c
SL
532 struct inode *ip;
533 struct a {
3e78e260
BJ
534 char *fname;
535 int fmode;
715baff1 536 } *uap = (struct a *)u.u_ap;
5485e062 537
715baff1 538 if ((ip = owner(uap->fname, FOLLOW)) == NULL)
5485e062 539 return;
47af7174 540 u.u_error = chmod1(ip, uap->fmode);
4f083fd7 541 iput(ip);
528f664c 542}
f94ceb3b 543
4f083fd7
SL
544/*
545 * Change mode of a file given a file descriptor.
546 */
528f664c
SL
547fchmod()
548{
549 struct a {
550 int fd;
551 int fmode;
715baff1 552 } *uap = (struct a *)u.u_ap;
528f664c
SL
553 register struct inode *ip;
554 register struct file *fp;
555
88a7a62a 556 fp = getinode(uap->fd);
528f664c
SL
557 if (fp == NULL)
558 return;
88a7a62a 559 ip = (struct inode *)fp->f_data;
4f083fd7 560 if (u.u_uid != ip->i_uid && !suser())
528f664c 561 return;
a388503d 562 ILOCK(ip);
47af7174 563 u.u_error = chmod1(ip, uap->fmode);
a388503d 564 IUNLOCK(ip);
528f664c
SL
565}
566
4f083fd7
SL
567/*
568 * Change the mode on a file.
569 * Inode must be locked before calling.
570 */
528f664c
SL
571chmod1(ip, mode)
572 register struct inode *ip;
573 register int mode;
574{
197da11b 575
47af7174
KM
576 if (ip->i_fs->fs_ronly)
577 return (EROFS);
3e78e260 578 ip->i_mode &= ~07777;
f94ceb3b 579 if (u.u_uid) {
47af7174
KM
580 if ((ip->i_mode & IFMT) != IFDIR)
581 mode &= ~ISVTX;
bb1b75f4
SL
582 if (!groupmember(ip->i_gid))
583 mode &= ~ISGID;
f94ceb3b 584 }
528f664c 585 ip->i_mode |= mode&07777;
3e78e260
BJ
586 ip->i_flag |= ICHG;
587 if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
588 xrele(ip);
47af7174 589 return (0);
5485e062
BJ
590}
591
4f083fd7
SL
592/*
593 * Set ownership given a path name.
594 */
3e78e260 595chown()
d67a03eb 596{
528f664c
SL
597 struct inode *ip;
598 struct a {
3e78e260
BJ
599 char *fname;
600 int uid;
601 int gid;
715baff1 602 } *uap = (struct a *)u.u_ap;
18b0bce6 603 register struct nameidata *ndp = &u.u_nd;
d67a03eb 604
18b0bce6
KB
605 ndp->ni_nameiop = LOOKUP | NOFOLLOW;
606 ndp->ni_segflg = UIO_USERSPACE;
607 ndp->ni_dirp = uap->fname;
608 ip = namei(ndp);
609 if (ip == NULL)
d67a03eb 610 return;
bb1b75f4 611 u.u_error = chown1(ip, uap->uid, uap->gid);
4f083fd7 612 iput(ip);
528f664c 613}
f94ceb3b 614
4f083fd7
SL
615/*
616 * Set ownership given a file descriptor.
617 */
528f664c
SL
618fchown()
619{
620 struct a {
621 int fd;
622 int uid;
623 int gid;
715baff1 624 } *uap = (struct a *)u.u_ap;
528f664c
SL
625 register struct inode *ip;
626 register struct file *fp;
627
88a7a62a 628 fp = getinode(uap->fd);
528f664c
SL
629 if (fp == NULL)
630 return;
88a7a62a 631 ip = (struct inode *)fp->f_data;
a388503d 632 ILOCK(ip);
bb1b75f4 633 u.u_error = chown1(ip, uap->uid, uap->gid);
a388503d 634 IUNLOCK(ip);
528f664c
SL
635}
636
637/*
638 * Perform chown operation on inode ip;
639 * inode must be locked prior to call.
640 */
641chown1(ip, uid, gid)
642 register struct inode *ip;
643 int uid, gid;
644{
645#ifdef QUOTA
646 register long change;
bb1b75f4 647#endif
528f664c 648
47af7174
KM
649 if (ip->i_fs->fs_ronly)
650 return (EROFS);
bb1b75f4
SL
651 if (uid == -1)
652 uid = ip->i_uid;
653 if (gid == -1)
654 gid = ip->i_gid;
18b0bce6
KB
655 /*
656 * If we don't own the file, are trying to change the owner
657 * of the file, or are not a member of the target group,
658 * the caller must be superuser or the call fails.
659 */
660 if ((u.u_uid != ip->i_uid || uid != ip->i_uid ||
661 !groupmember((gid_t)gid)) && !suser())
c979c6ce 662 return (u.u_error);
bb1b75f4 663#ifdef QUOTA
3809bf69 664 if (ip->i_uid == uid) /* this just speeds things a little */
0a77f278 665 change = 0;
2e073567
SL
666 else
667 change = ip->i_blocks;
668 (void) chkdq(ip, -change, 1);
669 (void) chkiq(ip->i_dev, ip, ip->i_uid, 1);
0a77f278 670 dqrele(ip->i_dquot);
f94ceb3b 671#endif
bb1b75f4
SL
672 ip->i_uid = uid;
673 ip->i_gid = gid;
3e78e260
BJ
674 ip->i_flag |= ICHG;
675 if (u.u_ruid != 0)
676 ip->i_mode &= ~(ISUID|ISGID);
528f664c 677#ifdef QUOTA
0a77f278 678 ip->i_dquot = inoquota(ip);
2e073567 679 (void) chkdq(ip, change, 1);
8011f5df 680 (void) chkiq(ip->i_dev, (struct inode *)NULL, (uid_t)uid, 1);
2e073567
SL
681 return (u.u_error); /* should == 0 ALWAYS !! */
682#else
bb1b75f4 683 return (0);
2e073567 684#endif
d67a03eb
BJ
685}
686
bb1b75f4
SL
687utimes()
688{
689 register struct a {
690 char *fname;
691 struct timeval *tptr;
692 } *uap = (struct a *)u.u_ap;
693 register struct inode *ip;
694 struct timeval tv[2];
695
715baff1 696 if ((ip = owner(uap->fname, FOLLOW)) == NULL)
bb1b75f4 697 return;
47af7174
KM
698 if (ip->i_fs->fs_ronly) {
699 u.u_error = EROFS;
700 iput(ip);
701 return;
702 }
bb1b75f4
SL
703 u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
704 if (u.u_error == 0) {
705 ip->i_flag |= IACC|IUPD|ICHG;
706 iupdat(ip, &tv[0], &tv[1], 0);
707 }
708 iput(ip);
709}
d67a03eb 710
4f083fd7
SL
711/*
712 * Flush any pending I/O.
713 */
3e78e260 714sync()
d67a03eb 715{
d67a03eb 716
3fd23f5c 717 update();
d67a03eb 718}
64d3a787 719
4f083fd7
SL
720/*
721 * Truncate a file given its path name.
722 */
528f664c
SL
723truncate()
724{
725 struct a {
726 char *fname;
c979c6ce 727 off_t length;
31949305 728 } *uap = (struct a *)u.u_ap;
528f664c 729 struct inode *ip;
715baff1 730 register struct nameidata *ndp = &u.u_nd;
528f664c 731
715baff1
KM
732 ndp->ni_nameiop = LOOKUP | FOLLOW;
733 ndp->ni_segflg = UIO_USERSPACE;
734 ndp->ni_dirp = uap->fname;
735 ip = namei(ndp);
528f664c
SL
736 if (ip == NULL)
737 return;
738 if (access(ip, IWRITE))
739 goto bad;
740 if ((ip->i_mode&IFMT) == IFDIR) {
741 u.u_error = EISDIR;
742 goto bad;
743 }
c979c6ce 744 itrunc(ip, (u_long)uap->length);
528f664c
SL
745bad:
746 iput(ip);
747}
748
4f083fd7
SL
749/*
750 * Truncate a file given a file descriptor.
751 */
528f664c
SL
752ftruncate()
753{
754 struct a {
755 int fd;
c979c6ce 756 off_t length;
31949305 757 } *uap = (struct a *)u.u_ap;
528f664c
SL
758 struct inode *ip;
759 struct file *fp;
760
88a7a62a 761 fp = getinode(uap->fd);
528f664c
SL
762 if (fp == NULL)
763 return;
528f664c
SL
764 if ((fp->f_flag&FWRITE) == 0) {
765 u.u_error = EINVAL;
766 return;
767 }
88a7a62a 768 ip = (struct inode *)fp->f_data;
a388503d 769 ILOCK(ip);
c979c6ce 770 itrunc(ip, (u_long)uap->length);
a388503d 771 IUNLOCK(ip);
4f083fd7
SL
772}
773
774/*
775 * Synch an open file.
776 */
777fsync()
778{
779 struct a {
780 int fd;
781 } *uap = (struct a *)u.u_ap;
782 struct inode *ip;
783 struct file *fp;
784
88a7a62a 785 fp = getinode(uap->fd);
4f083fd7
SL
786 if (fp == NULL)
787 return;
88a7a62a 788 ip = (struct inode *)fp->f_data;
a388503d 789 ILOCK(ip);
82252d2b
KM
790 if (fp->f_flag&FWRITE)
791 ip->i_flag |= ICHG;
4f083fd7 792 syncip(ip);
a388503d 793 IUNLOCK(ip);
528f664c
SL
794}
795
4f083fd7
SL
796/*
797 * Rename system call.
798 * rename("foo", "bar");
799 * is essentially
800 * unlink("bar");
801 * link("foo", "bar");
802 * unlink("foo");
803 * but ``atomically''. Can't do full commit without saving state in the
804 * inode on disk which isn't feasible at this time. Best we can do is
805 * always guarantee the target exists.
806 *
807 * Basic algorithm is:
808 *
809 * 1) Bump link count on source while we're linking it to the
810 * target. This also insure the inode won't be deleted out
68f21562
KM
811 * from underneath us while we work (it may be truncated by
812 * a concurrent `trunc' or `open' for creation).
4f083fd7
SL
813 * 2) Link source to destination. If destination already exists,
814 * delete it first.
68f21562
KM
815 * 3) Unlink source reference to inode if still around. If a
816 * directory was moved and the parent of the destination
4f083fd7
SL
817 * is different from the source, patch the ".." entry in the
818 * directory.
819 *
820 * Source and destination must either both be directories, or both
821 * not be directories. If target is a directory, it must be empty.
822 */
528f664c
SL
823rename()
824{
825 struct a {
826 char *from;
827 char *to;
715baff1 828 } *uap = (struct a *)u.u_ap;
4f083fd7 829 register struct inode *ip, *xp, *dp;
68f21562
KM
830 struct dirtemplate dirbuf;
831 int doingdirectory = 0, oldparent = 0, newparent = 0;
715baff1 832 register struct nameidata *ndp = &u.u_nd;
a5390dce 833 int error = 0;
4f083fd7 834
715baff1
KM
835 ndp->ni_nameiop = DELETE | LOCKPARENT;
836 ndp->ni_segflg = UIO_USERSPACE;
837 ndp->ni_dirp = uap->from;
838 ip = namei(ndp);
4f083fd7
SL
839 if (ip == NULL)
840 return;
715baff1 841 dp = ndp->ni_pdir;
4f083fd7
SL
842 if ((ip->i_mode&IFMT) == IFDIR) {
843 register struct direct *d;
844
715baff1 845 d = &ndp->ni_dent;
4f083fd7 846 /*
046f18d1 847 * Avoid ".", "..", and aliases of "." for obvious reasons.
4f083fd7 848 */
046f18d1
SL
849 if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
850 (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
68f21562 851 (dp == ip) || (ip->i_flag & IRENAME)) {
046f18d1
SL
852 iput(dp);
853 if (dp == ip)
854 irele(ip);
855 else
4f083fd7 856 iput(ip);
046f18d1
SL
857 u.u_error = EINVAL;
858 return;
4f083fd7 859 }
68f21562 860 ip->i_flag |= IRENAME;
4f083fd7
SL
861 oldparent = dp->i_number;
862 doingdirectory++;
863 }
046f18d1 864 iput(dp);
4f083fd7
SL
865
866 /*
867 * 1) Bump link count while we're moving stuff
868 * around. If we crash somewhere before
869 * completing our work, the link count
870 * may be wrong, but correctable.
871 */
872 ip->i_nlink++;
873 ip->i_flag |= ICHG;
874 iupdat(ip, &time, &time, 1);
a388503d 875 IUNLOCK(ip);
4f083fd7
SL
876
877 /*
878 * When the target exists, both the directory
879 * and target inodes are returned locked.
880 */
715baff1
KM
881 ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE;
882 ndp->ni_dirp = (caddr_t)uap->to;
883 xp = namei(ndp);
a5390dce
SL
884 if (u.u_error) {
885 error = u.u_error;
4f083fd7 886 goto out;
a5390dce 887 }
715baff1 888 dp = ndp->ni_pdir;
046f18d1
SL
889 /*
890 * If ".." must be changed (ie the directory gets a new
81552f0f
KM
891 * parent) then the source directory must not be in the
892 * directory heirarchy above the target, as this would
893 * orphan everything below the source directory. Also
894 * the user must have write permission in the source so
895 * as to be able to change "..". We must repeat the call
896 * to namei, as the parent directory is unlocked by the
897 * call to checkpath().
046f18d1 898 */
68f21562
KM
899 if (oldparent != dp->i_number)
900 newparent = dp->i_number;
901 if (doingdirectory && newparent) {
81552f0f
KM
902 if (access(ip, IWRITE))
903 goto bad;
904 do {
715baff1 905 dp = ndp->ni_pdir;
81552f0f
KM
906 if (xp != NULL)
907 iput(xp);
908 u.u_error = checkpath(ip, dp);
909 if (u.u_error)
910 goto out;
715baff1 911 xp = namei(ndp);
81552f0f
KM
912 if (u.u_error) {
913 error = u.u_error;
914 goto out;
915 }
715baff1 916 } while (dp != ndp->ni_pdir);
81552f0f 917 }
4f083fd7
SL
918 /*
919 * 2) If target doesn't exist, link the target
920 * to the source and unlink the source.
921 * Otherwise, rewrite the target directory
922 * entry to reference the source inode and
923 * expunge the original entry's existence.
924 */
4f083fd7
SL
925 if (xp == NULL) {
926 if (dp->i_dev != ip->i_dev) {
a5390dce 927 error = EXDEV;
4f083fd7
SL
928 goto bad;
929 }
930 /*
68f21562
KM
931 * Account for ".." in new directory.
932 * When source and destination have the same
933 * parent we don't fool with the link count.
4f083fd7 934 */
68f21562 935 if (doingdirectory && newparent) {
4f083fd7
SL
936 dp->i_nlink++;
937 dp->i_flag |= ICHG;
938 iupdat(dp, &time, &time, 1);
939 }
715baff1 940 error = direnter(ip, ndp);
f2a5ad78 941 if (error)
4f083fd7
SL
942 goto out;
943 } else {
944 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
a5390dce 945 error = EXDEV;
4f083fd7
SL
946 goto bad;
947 }
e69c3c9c
SL
948 /*
949 * Short circuit rename(foo, foo).
950 */
951 if (xp->i_number == ip->i_number)
952 goto bad;
80cee150
JB
953 /*
954 * If the parent directory is "sticky", then the user must
955 * own the parent directory, or the destination of the rename,
956 * otherwise the destination may not be changed (except by
957 * root). This implements append-only directories.
958 */
959 if ((dp->i_mode & ISVTX) && u.u_uid != 0 &&
960 u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) {
961 error = EPERM;
962 goto bad;
963 }
4f083fd7 964 /*
a5390dce
SL
965 * Target must be empty if a directory
966 * and have no links to it.
4f083fd7
SL
967 * Also, insure source and target are
968 * compatible (both directories, or both
969 * not directories).
970 */
971 if ((xp->i_mode&IFMT) == IFDIR) {
68f21562 972 if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) {
a5390dce 973 error = ENOTEMPTY;
4f083fd7
SL
974 goto bad;
975 }
976 if (!doingdirectory) {
a5390dce 977 error = ENOTDIR;
4f083fd7
SL
978 goto bad;
979 }
68f21562 980 cacheinval(dp);
4f083fd7 981 } else if (doingdirectory) {
a5390dce 982 error = EISDIR;
4f083fd7
SL
983 goto bad;
984 }
715baff1 985 dirrewrite(dp, ip, ndp);
a5390dce
SL
986 if (u.u_error) {
987 error = u.u_error;
4f083fd7 988 goto bad1;
a5390dce 989 }
4f083fd7 990 /*
a5390dce
SL
991 * Adjust the link count of the target to
992 * reflect the dirrewrite above. If this is
993 * a directory it is empty and there are
994 * no links to it, so we can squash the inode and
995 * any space associated with it. We disallowed
996 * renaming over top of a directory with links to
68f21562
KM
997 * it above, as the remaining link would point to
998 * a directory without "." or ".." entries.
4f083fd7 999 */
a5390dce 1000 xp->i_nlink--;
4f083fd7 1001 if (doingdirectory) {
a5390dce
SL
1002 if (--xp->i_nlink != 0)
1003 panic("rename: linked directory");
4f083fd7 1004 itrunc(xp, (u_long)0);
a5390dce 1005 }
4f083fd7
SL
1006 xp->i_flag |= ICHG;
1007 iput(xp);
31db12cb 1008 xp = NULL;
4f083fd7
SL
1009 }
1010
1011 /*
1012 * 3) Unlink the source.
1013 */
715baff1
KM
1014 ndp->ni_nameiop = DELETE | LOCKPARENT;
1015 ndp->ni_segflg = UIO_USERSPACE;
1016 ndp->ni_dirp = uap->from;
68f21562 1017 xp = namei(ndp);
4f1a9037
KM
1018 if (xp != NULL)
1019 dp = ndp->ni_pdir;
1020 else
1021 dp = NULL;
4f083fd7 1022 /*
68f21562
KM
1023 * Insure that the directory entry still exists and has not
1024 * changed while the new name has been entered. If the source is
1025 * a file then the entry may have been unlinked or renamed. In
1026 * either case there is no further work to be done. If the source
1027 * is a directory then it cannot have been rmdir'ed; its link
1028 * count of three would cause a rmdir to fail with ENOTEMPTY.
1029 * The IRENAME flag insures that it cannot be moved by another
1030 * rename.
4f083fd7 1031 */
4f1a9037 1032 if (xp != ip) {
68f21562 1033 if (doingdirectory)
4f1a9037 1034 panic("rename: lost dir entry");
68f21562 1035 } else {
4f083fd7 1036 /*
68f21562
KM
1037 * If the source is a directory with a
1038 * new parent, the link count of the old
1039 * parent directory must be decremented
1040 * and ".." set to point to the new parent.
4f083fd7 1041 */
68f21562 1042 if (doingdirectory && newparent) {
4f083fd7
SL
1043 dp->i_nlink--;
1044 dp->i_flag |= ICHG;
68f21562
KM
1045 error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
1046 sizeof (struct dirtemplate), (off_t)0, 1,
1047 (int *)0);
1048 if (error == 0) {
1049 if (dirbuf.dotdot_namlen != 2 ||
1050 dirbuf.dotdot_name[0] != '.' ||
1051 dirbuf.dotdot_name[1] != '.') {
1052 printf("rename: mangled dir\n");
1053 } else {
1054 dirbuf.dotdot_ino = newparent;
1055 (void) rdwri(UIO_WRITE, xp,
1056 (caddr_t)&dirbuf,
1057 sizeof (struct dirtemplate),
1058 (off_t)0, 1, (int *)0);
1059 cacheinval(dp);
1060 }
1061 }
4f083fd7 1062 }
715baff1 1063 if (dirremove(ndp)) {
68f21562
KM
1064 xp->i_nlink--;
1065 xp->i_flag |= ICHG;
4f083fd7 1066 }
68f21562
KM
1067 xp->i_flag &= ~IRENAME;
1068 if (error == 0) /* XXX conservative */
a5390dce 1069 error = u.u_error;
4f083fd7 1070 }
4f083fd7
SL
1071 if (dp)
1072 iput(dp);
68f21562
KM
1073 if (xp)
1074 iput(xp);
1075 irele(ip);
1076 if (error)
1077 u.u_error = error;
1078 return;
a5390dce 1079
4f083fd7 1080bad:
31db12cb 1081 iput(dp);
4f083fd7
SL
1082bad1:
1083 if (xp)
31db12cb 1084 iput(xp);
4f083fd7
SL
1085out:
1086 ip->i_nlink--;
1087 ip->i_flag |= ICHG;
1088 irele(ip);
a5390dce
SL
1089 if (error)
1090 u.u_error = error;
528f664c
SL
1091}
1092
64d3a787
BJ
1093/*
1094 * Make a new file.
1095 */
1096struct inode *
715baff1 1097maknode(mode, ndp)
64d3a787 1098 int mode;
715baff1 1099 register struct nameidata *ndp;
64d3a787
BJ
1100{
1101 register struct inode *ip;
715baff1 1102 register struct inode *pdir = ndp->ni_pdir;
64d3a787
BJ
1103 ino_t ipref;
1104
1105 if ((mode & IFMT) == IFDIR)
715baff1 1106 ipref = dirpref(pdir->i_fs);
64d3a787 1107 else
715baff1
KM
1108 ipref = pdir->i_number;
1109 ip = ialloc(pdir, ipref, mode);
64d3a787 1110 if (ip == NULL) {
715baff1 1111 iput(pdir);
528f664c 1112 return (NULL);
64d3a787 1113 }
528f664c 1114#ifdef QUOTA
64d3a787
BJ
1115 if (ip->i_dquot != NODQUOT)
1116 panic("maknode: dquot");
1117#endif
1118 ip->i_flag |= IACC|IUPD|ICHG;
1119 if ((mode & IFMT) == 0)
1120 mode |= IFREG;
1121 ip->i_mode = mode & ~u.u_cmask;
1122 ip->i_nlink = 1;
1123 ip->i_uid = u.u_uid;
715baff1 1124 ip->i_gid = pdir->i_gid;
67361d54 1125 if (ip->i_mode & ISGID && !groupmember(ip->i_gid) && !suser())
bb1b75f4 1126 ip->i_mode &= ~ISGID;
528f664c 1127#ifdef QUOTA
64d3a787
BJ
1128 ip->i_dquot = inoquota(ip);
1129#endif
1130
1131 /*
1132 * Make sure inode goes to disk before directory entry.
1133 */
3fd23f5c 1134 iupdat(ip, &time, &time, 1);
715baff1 1135 u.u_error = direnter(ip, ndp);
64d3a787
BJ
1136 if (u.u_error) {
1137 /*
f2a5ad78
SL
1138 * Write error occurred trying to update directory
1139 * so must deallocate the inode.
64d3a787
BJ
1140 */
1141 ip->i_nlink = 0;
1142 ip->i_flag |= ICHG;
1143 iput(ip);
528f664c 1144 return (NULL);
64d3a787 1145 }
528f664c 1146 return (ip);
64d3a787 1147}
88a7a62a
SL
1148
1149/*
1150 * A virgin directory (no blushing please).
1151 */
1152struct dirtemplate mastertemplate = {
1153 0, 12, 1, ".",
1154 0, DIRBLKSIZ - 12, 2, ".."
1155};
1156
1157/*
1158 * Mkdir system call
1159 */
1160mkdir()
1161{
1162 struct a {
1163 char *name;
1164 int dmode;
715baff1 1165 } *uap = (struct a *)u.u_ap;
88a7a62a
SL
1166 register struct inode *ip, *dp;
1167 struct dirtemplate dirtemplate;
715baff1 1168 register struct nameidata *ndp = &u.u_nd;
88a7a62a 1169
715baff1
KM
1170 ndp->ni_nameiop = CREATE;
1171 ndp->ni_segflg = UIO_USERSPACE;
1172 ndp->ni_dirp = uap->name;
1173 ip = namei(ndp);
88a7a62a
SL
1174 if (u.u_error)
1175 return;
1176 if (ip != NULL) {
1177 iput(ip);
1178 u.u_error = EEXIST;
1179 return;
1180 }
715baff1 1181 dp = ndp->ni_pdir;
88a7a62a
SL
1182 uap->dmode &= 0777;
1183 uap->dmode |= IFDIR;
1184 /*
1185 * Must simulate part of maknode here
1186 * in order to acquire the inode, but
1187 * not have it entered in the parent
1188 * directory. The entry is made later
1189 * after writing "." and ".." entries out.
1190 */
1191 ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
1192 if (ip == NULL) {
1193 iput(dp);
1194 return;
1195 }
1196#ifdef QUOTA
1197 if (ip->i_dquot != NODQUOT)
1198 panic("mkdir: dquot");
1199#endif
1200 ip->i_flag |= IACC|IUPD|ICHG;
1201 ip->i_mode = uap->dmode & ~u.u_cmask;
1202 ip->i_nlink = 2;
1203 ip->i_uid = u.u_uid;
1204 ip->i_gid = dp->i_gid;
1205#ifdef QUOTA
1206 ip->i_dquot = inoquota(ip);
1207#endif
1208 iupdat(ip, &time, &time, 1);
1209
1210 /*
1211 * Bump link count in parent directory
1212 * to reflect work done below. Should
1213 * be done before reference is created
1214 * so reparation is possible if we crash.
1215 */
1216 dp->i_nlink++;
1217 dp->i_flag |= ICHG;
1218 iupdat(dp, &time, &time, 1);
1219
1220 /*
1221 * Initialize directory with "."
1222 * and ".." from static template.
1223 */
1224 dirtemplate = mastertemplate;
1225 dirtemplate.dot_ino = ip->i_number;
1226 dirtemplate.dotdot_ino = dp->i_number;
1227 u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
1228 sizeof (dirtemplate), (off_t)0, 1, (int *)0);
1229 if (u.u_error) {
1230 dp->i_nlink--;
1231 dp->i_flag |= ICHG;
1232 goto bad;
1233 }
23de9f20
KM
1234 if (DIRBLKSIZ > ip->i_fs->fs_fsize)
1235 panic("mkdir: blksize"); /* XXX - should grow with bmap() */
1236 else
1237 ip->i_size = DIRBLKSIZ;
88a7a62a
SL
1238 /*
1239 * Directory all set up, now
1240 * install the entry for it in
1241 * the parent directory.
1242 */
715baff1 1243 u.u_error = direnter(ip, ndp);
88a7a62a
SL
1244 dp = NULL;
1245 if (u.u_error) {
715baff1
KM
1246 ndp->ni_nameiop = LOOKUP | NOCACHE;
1247 ndp->ni_segflg = UIO_USERSPACE;
1248 ndp->ni_dirp = uap->name;
1249 dp = namei(ndp);
88a7a62a
SL
1250 if (dp) {
1251 dp->i_nlink--;
1252 dp->i_flag |= ICHG;
1253 }
1254 }
1255bad:
1256 /*
1257 * No need to do an explicit itrunc here,
1258 * irele will do this for us because we set
1259 * the link count to 0.
1260 */
1261 if (u.u_error) {
1262 ip->i_nlink = 0;
1263 ip->i_flag |= ICHG;
1264 }
1265 if (dp)
1266 iput(dp);
1267 iput(ip);
1268}
1269
1270/*
1271 * Rmdir system call.
1272 */
1273rmdir()
1274{
1275 struct a {
1276 char *name;
715baff1 1277 } *uap = (struct a *)u.u_ap;
88a7a62a 1278 register struct inode *ip, *dp;
715baff1 1279 register struct nameidata *ndp = &u.u_nd;
88a7a62a 1280
715baff1
KM
1281 ndp->ni_nameiop = DELETE | LOCKPARENT;
1282 ndp->ni_segflg = UIO_USERSPACE;
1283 ndp->ni_dirp = uap->name;
1284 ip = namei(ndp);
88a7a62a
SL
1285 if (ip == NULL)
1286 return;
715baff1 1287 dp = ndp->ni_pdir;
88a7a62a
SL
1288 /*
1289 * No rmdir "." please.
1290 */
1291 if (dp == ip) {
1292 irele(dp);
1293 iput(ip);
1294 u.u_error = EINVAL;
1295 return;
1296 }
1297 if ((ip->i_mode&IFMT) != IFDIR) {
1298 u.u_error = ENOTDIR;
1299 goto out;
1300 }
1301 /*
1302 * Don't remove a mounted on directory.
1303 */
1304 if (ip->i_dev != dp->i_dev) {
1305 u.u_error = EBUSY;
1306 goto out;
1307 }
1308 /*
1309 * Verify the directory is empty (and valid).
1310 * (Rmdir ".." won't be valid since
1311 * ".." will contain a reference to
1312 * the current directory and thus be
1313 * non-empty.)
1314 */
68f21562 1315 if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) {
88a7a62a
SL
1316 u.u_error = ENOTEMPTY;
1317 goto out;
1318 }
1319 /*
1320 * Delete reference to directory before purging
1321 * inode. If we crash in between, the directory
1322 * will be reattached to lost+found,
1323 */
715baff1 1324 if (dirremove(ndp) == 0)
88a7a62a
SL
1325 goto out;
1326 dp->i_nlink--;
1327 dp->i_flag |= ICHG;
68f21562 1328 cacheinval(dp);
88a7a62a
SL
1329 iput(dp);
1330 dp = NULL;
1331 /*
1332 * Truncate inode. The only stuff left
1333 * in the directory is "." and "..". The
1334 * "." reference is inconsequential since
1335 * we're quashing it. The ".." reference
1336 * has already been adjusted above. We've
1337 * removed the "." reference and the reference
1338 * in the parent directory, but there may be
1339 * other hard links so decrement by 2 and
1340 * worry about them later.
1341 */
1342 ip->i_nlink -= 2;
1343 itrunc(ip, (u_long)0);
1d00c1cf 1344 cacheinval(ip);
88a7a62a
SL
1345out:
1346 if (dp)
1347 iput(dp);
1348 iput(ip);
1349}
1350
1351struct file *
1352getinode(fdes)
1353 int fdes;
1354{
8462a185 1355 struct file *fp;
88a7a62a 1356
8462a185
SL
1357 if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
1358 u.u_error = EBADF;
1359 return ((struct file *)0);
1360 }
88a7a62a
SL
1361 if (fp->f_type != DTYPE_INODE) {
1362 u.u_error = EINVAL;
8462a185 1363 return ((struct file *)0);
88a7a62a
SL
1364 }
1365 return (fp);
1366}
1367
1368/*
1369 * mode mask for creation of files
1370 */
1371umask()
1372{
1373 register struct a {
1374 int mask;
715baff1 1375 } *uap = (struct a *)u.u_ap;
88a7a62a 1376
88a7a62a
SL
1377 u.u_r.r_val1 = u.u_cmask;
1378 u.u_cmask = uap->mask & 07777;
1379}