ifdef openlog for 4.2BSD systems
[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 *
67361d54 6 * @(#)vfs_syscalls.c 7.3 (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;
d67a03eb 603
c979c6ce 604 if ((ip = owner(uap->fname, NOFOLLOW)) == NULL)
d67a03eb 605 return;
bb1b75f4 606 u.u_error = chown1(ip, uap->uid, uap->gid);
4f083fd7 607 iput(ip);
528f664c 608}
f94ceb3b 609
4f083fd7
SL
610/*
611 * Set ownership given a file descriptor.
612 */
528f664c
SL
613fchown()
614{
615 struct a {
616 int fd;
617 int uid;
618 int gid;
715baff1 619 } *uap = (struct a *)u.u_ap;
528f664c
SL
620 register struct inode *ip;
621 register struct file *fp;
622
88a7a62a 623 fp = getinode(uap->fd);
528f664c
SL
624 if (fp == NULL)
625 return;
88a7a62a 626 ip = (struct inode *)fp->f_data;
a388503d 627 ILOCK(ip);
bb1b75f4 628 u.u_error = chown1(ip, uap->uid, uap->gid);
a388503d 629 IUNLOCK(ip);
528f664c
SL
630}
631
632/*
633 * Perform chown operation on inode ip;
634 * inode must be locked prior to call.
635 */
636chown1(ip, uid, gid)
637 register struct inode *ip;
638 int uid, gid;
639{
640#ifdef QUOTA
641 register long change;
bb1b75f4 642#endif
528f664c 643
47af7174
KM
644 if (ip->i_fs->fs_ronly)
645 return (EROFS);
bb1b75f4
SL
646 if (uid == -1)
647 uid = ip->i_uid;
648 if (gid == -1)
649 gid = ip->i_gid;
c979c6ce
MK
650 if (uid != ip->i_uid && !suser())
651 return (u.u_error);
652 if (gid != ip->i_gid && !groupmember((gid_t)gid) && !suser())
653 return (u.u_error);
bb1b75f4 654#ifdef QUOTA
3809bf69 655 if (ip->i_uid == uid) /* this just speeds things a little */
0a77f278 656 change = 0;
2e073567
SL
657 else
658 change = ip->i_blocks;
659 (void) chkdq(ip, -change, 1);
660 (void) chkiq(ip->i_dev, ip, ip->i_uid, 1);
0a77f278 661 dqrele(ip->i_dquot);
f94ceb3b 662#endif
bb1b75f4
SL
663 ip->i_uid = uid;
664 ip->i_gid = gid;
3e78e260
BJ
665 ip->i_flag |= ICHG;
666 if (u.u_ruid != 0)
667 ip->i_mode &= ~(ISUID|ISGID);
528f664c 668#ifdef QUOTA
0a77f278 669 ip->i_dquot = inoquota(ip);
2e073567 670 (void) chkdq(ip, change, 1);
8011f5df 671 (void) chkiq(ip->i_dev, (struct inode *)NULL, (uid_t)uid, 1);
2e073567
SL
672 return (u.u_error); /* should == 0 ALWAYS !! */
673#else
bb1b75f4 674 return (0);
2e073567 675#endif
d67a03eb
BJ
676}
677
bb1b75f4
SL
678utimes()
679{
680 register struct a {
681 char *fname;
682 struct timeval *tptr;
683 } *uap = (struct a *)u.u_ap;
684 register struct inode *ip;
685 struct timeval tv[2];
686
715baff1 687 if ((ip = owner(uap->fname, FOLLOW)) == NULL)
bb1b75f4 688 return;
47af7174
KM
689 if (ip->i_fs->fs_ronly) {
690 u.u_error = EROFS;
691 iput(ip);
692 return;
693 }
bb1b75f4
SL
694 u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
695 if (u.u_error == 0) {
696 ip->i_flag |= IACC|IUPD|ICHG;
697 iupdat(ip, &tv[0], &tv[1], 0);
698 }
699 iput(ip);
700}
d67a03eb 701
4f083fd7
SL
702/*
703 * Flush any pending I/O.
704 */
3e78e260 705sync()
d67a03eb 706{
d67a03eb 707
3fd23f5c 708 update();
d67a03eb 709}
64d3a787 710
4f083fd7
SL
711/*
712 * Truncate a file given its path name.
713 */
528f664c
SL
714truncate()
715{
716 struct a {
717 char *fname;
c979c6ce 718 off_t length;
31949305 719 } *uap = (struct a *)u.u_ap;
528f664c 720 struct inode *ip;
715baff1 721 register struct nameidata *ndp = &u.u_nd;
528f664c 722
715baff1
KM
723 ndp->ni_nameiop = LOOKUP | FOLLOW;
724 ndp->ni_segflg = UIO_USERSPACE;
725 ndp->ni_dirp = uap->fname;
726 ip = namei(ndp);
528f664c
SL
727 if (ip == NULL)
728 return;
729 if (access(ip, IWRITE))
730 goto bad;
731 if ((ip->i_mode&IFMT) == IFDIR) {
732 u.u_error = EISDIR;
733 goto bad;
734 }
c979c6ce 735 itrunc(ip, (u_long)uap->length);
528f664c
SL
736bad:
737 iput(ip);
738}
739
4f083fd7
SL
740/*
741 * Truncate a file given a file descriptor.
742 */
528f664c
SL
743ftruncate()
744{
745 struct a {
746 int fd;
c979c6ce 747 off_t length;
31949305 748 } *uap = (struct a *)u.u_ap;
528f664c
SL
749 struct inode *ip;
750 struct file *fp;
751
88a7a62a 752 fp = getinode(uap->fd);
528f664c
SL
753 if (fp == NULL)
754 return;
528f664c
SL
755 if ((fp->f_flag&FWRITE) == 0) {
756 u.u_error = EINVAL;
757 return;
758 }
88a7a62a 759 ip = (struct inode *)fp->f_data;
a388503d 760 ILOCK(ip);
c979c6ce 761 itrunc(ip, (u_long)uap->length);
a388503d 762 IUNLOCK(ip);
4f083fd7
SL
763}
764
765/*
766 * Synch an open file.
767 */
768fsync()
769{
770 struct a {
771 int fd;
772 } *uap = (struct a *)u.u_ap;
773 struct inode *ip;
774 struct file *fp;
775
88a7a62a 776 fp = getinode(uap->fd);
4f083fd7
SL
777 if (fp == NULL)
778 return;
88a7a62a 779 ip = (struct inode *)fp->f_data;
a388503d 780 ILOCK(ip);
82252d2b
KM
781 if (fp->f_flag&FWRITE)
782 ip->i_flag |= ICHG;
4f083fd7 783 syncip(ip);
a388503d 784 IUNLOCK(ip);
528f664c
SL
785}
786
4f083fd7
SL
787/*
788 * Rename system call.
789 * rename("foo", "bar");
790 * is essentially
791 * unlink("bar");
792 * link("foo", "bar");
793 * unlink("foo");
794 * but ``atomically''. Can't do full commit without saving state in the
795 * inode on disk which isn't feasible at this time. Best we can do is
796 * always guarantee the target exists.
797 *
798 * Basic algorithm is:
799 *
800 * 1) Bump link count on source while we're linking it to the
801 * target. This also insure the inode won't be deleted out
68f21562
KM
802 * from underneath us while we work (it may be truncated by
803 * a concurrent `trunc' or `open' for creation).
4f083fd7
SL
804 * 2) Link source to destination. If destination already exists,
805 * delete it first.
68f21562
KM
806 * 3) Unlink source reference to inode if still around. If a
807 * directory was moved and the parent of the destination
4f083fd7
SL
808 * is different from the source, patch the ".." entry in the
809 * directory.
810 *
811 * Source and destination must either both be directories, or both
812 * not be directories. If target is a directory, it must be empty.
813 */
528f664c
SL
814rename()
815{
816 struct a {
817 char *from;
818 char *to;
715baff1 819 } *uap = (struct a *)u.u_ap;
4f083fd7 820 register struct inode *ip, *xp, *dp;
68f21562
KM
821 struct dirtemplate dirbuf;
822 int doingdirectory = 0, oldparent = 0, newparent = 0;
715baff1 823 register struct nameidata *ndp = &u.u_nd;
a5390dce 824 int error = 0;
4f083fd7 825
715baff1
KM
826 ndp->ni_nameiop = DELETE | LOCKPARENT;
827 ndp->ni_segflg = UIO_USERSPACE;
828 ndp->ni_dirp = uap->from;
829 ip = namei(ndp);
4f083fd7
SL
830 if (ip == NULL)
831 return;
715baff1 832 dp = ndp->ni_pdir;
4f083fd7
SL
833 if ((ip->i_mode&IFMT) == IFDIR) {
834 register struct direct *d;
835
715baff1 836 d = &ndp->ni_dent;
4f083fd7 837 /*
046f18d1 838 * Avoid ".", "..", and aliases of "." for obvious reasons.
4f083fd7 839 */
046f18d1
SL
840 if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
841 (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
68f21562 842 (dp == ip) || (ip->i_flag & IRENAME)) {
046f18d1
SL
843 iput(dp);
844 if (dp == ip)
845 irele(ip);
846 else
4f083fd7 847 iput(ip);
046f18d1
SL
848 u.u_error = EINVAL;
849 return;
4f083fd7 850 }
68f21562 851 ip->i_flag |= IRENAME;
4f083fd7
SL
852 oldparent = dp->i_number;
853 doingdirectory++;
854 }
046f18d1 855 iput(dp);
4f083fd7
SL
856
857 /*
858 * 1) Bump link count while we're moving stuff
859 * around. If we crash somewhere before
860 * completing our work, the link count
861 * may be wrong, but correctable.
862 */
863 ip->i_nlink++;
864 ip->i_flag |= ICHG;
865 iupdat(ip, &time, &time, 1);
a388503d 866 IUNLOCK(ip);
4f083fd7
SL
867
868 /*
869 * When the target exists, both the directory
870 * and target inodes are returned locked.
871 */
715baff1
KM
872 ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE;
873 ndp->ni_dirp = (caddr_t)uap->to;
874 xp = namei(ndp);
a5390dce
SL
875 if (u.u_error) {
876 error = u.u_error;
4f083fd7 877 goto out;
a5390dce 878 }
715baff1 879 dp = ndp->ni_pdir;
046f18d1
SL
880 /*
881 * If ".." must be changed (ie the directory gets a new
81552f0f
KM
882 * parent) then the source directory must not be in the
883 * directory heirarchy above the target, as this would
884 * orphan everything below the source directory. Also
885 * the user must have write permission in the source so
886 * as to be able to change "..". We must repeat the call
887 * to namei, as the parent directory is unlocked by the
888 * call to checkpath().
046f18d1 889 */
68f21562
KM
890 if (oldparent != dp->i_number)
891 newparent = dp->i_number;
892 if (doingdirectory && newparent) {
81552f0f
KM
893 if (access(ip, IWRITE))
894 goto bad;
895 do {
715baff1 896 dp = ndp->ni_pdir;
81552f0f
KM
897 if (xp != NULL)
898 iput(xp);
899 u.u_error = checkpath(ip, dp);
900 if (u.u_error)
901 goto out;
715baff1 902 xp = namei(ndp);
81552f0f
KM
903 if (u.u_error) {
904 error = u.u_error;
905 goto out;
906 }
715baff1 907 } while (dp != ndp->ni_pdir);
81552f0f 908 }
4f083fd7
SL
909 /*
910 * 2) If target doesn't exist, link the target
911 * to the source and unlink the source.
912 * Otherwise, rewrite the target directory
913 * entry to reference the source inode and
914 * expunge the original entry's existence.
915 */
4f083fd7
SL
916 if (xp == NULL) {
917 if (dp->i_dev != ip->i_dev) {
a5390dce 918 error = EXDEV;
4f083fd7
SL
919 goto bad;
920 }
921 /*
68f21562
KM
922 * Account for ".." in new directory.
923 * When source and destination have the same
924 * parent we don't fool with the link count.
4f083fd7 925 */
68f21562 926 if (doingdirectory && newparent) {
4f083fd7
SL
927 dp->i_nlink++;
928 dp->i_flag |= ICHG;
929 iupdat(dp, &time, &time, 1);
930 }
715baff1 931 error = direnter(ip, ndp);
f2a5ad78 932 if (error)
4f083fd7
SL
933 goto out;
934 } else {
935 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
a5390dce 936 error = EXDEV;
4f083fd7
SL
937 goto bad;
938 }
e69c3c9c
SL
939 /*
940 * Short circuit rename(foo, foo).
941 */
942 if (xp->i_number == ip->i_number)
943 goto bad;
80cee150
JB
944 /*
945 * If the parent directory is "sticky", then the user must
946 * own the parent directory, or the destination of the rename,
947 * otherwise the destination may not be changed (except by
948 * root). This implements append-only directories.
949 */
950 if ((dp->i_mode & ISVTX) && u.u_uid != 0 &&
951 u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) {
952 error = EPERM;
953 goto bad;
954 }
4f083fd7 955 /*
a5390dce
SL
956 * Target must be empty if a directory
957 * and have no links to it.
4f083fd7
SL
958 * Also, insure source and target are
959 * compatible (both directories, or both
960 * not directories).
961 */
962 if ((xp->i_mode&IFMT) == IFDIR) {
68f21562 963 if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) {
a5390dce 964 error = ENOTEMPTY;
4f083fd7
SL
965 goto bad;
966 }
967 if (!doingdirectory) {
a5390dce 968 error = ENOTDIR;
4f083fd7
SL
969 goto bad;
970 }
68f21562 971 cacheinval(dp);
4f083fd7 972 } else if (doingdirectory) {
a5390dce 973 error = EISDIR;
4f083fd7
SL
974 goto bad;
975 }
715baff1 976 dirrewrite(dp, ip, ndp);
a5390dce
SL
977 if (u.u_error) {
978 error = u.u_error;
4f083fd7 979 goto bad1;
a5390dce 980 }
4f083fd7 981 /*
a5390dce
SL
982 * Adjust the link count of the target to
983 * reflect the dirrewrite above. If this is
984 * a directory it is empty and there are
985 * no links to it, so we can squash the inode and
986 * any space associated with it. We disallowed
987 * renaming over top of a directory with links to
68f21562
KM
988 * it above, as the remaining link would point to
989 * a directory without "." or ".." entries.
4f083fd7 990 */
a5390dce 991 xp->i_nlink--;
4f083fd7 992 if (doingdirectory) {
a5390dce
SL
993 if (--xp->i_nlink != 0)
994 panic("rename: linked directory");
4f083fd7 995 itrunc(xp, (u_long)0);
a5390dce 996 }
4f083fd7
SL
997 xp->i_flag |= ICHG;
998 iput(xp);
31db12cb 999 xp = NULL;
4f083fd7
SL
1000 }
1001
1002 /*
1003 * 3) Unlink the source.
1004 */
715baff1
KM
1005 ndp->ni_nameiop = DELETE | LOCKPARENT;
1006 ndp->ni_segflg = UIO_USERSPACE;
1007 ndp->ni_dirp = uap->from;
68f21562 1008 xp = namei(ndp);
4f1a9037
KM
1009 if (xp != NULL)
1010 dp = ndp->ni_pdir;
1011 else
1012 dp = NULL;
4f083fd7 1013 /*
68f21562
KM
1014 * Insure that the directory entry still exists and has not
1015 * changed while the new name has been entered. If the source is
1016 * a file then the entry may have been unlinked or renamed. In
1017 * either case there is no further work to be done. If the source
1018 * is a directory then it cannot have been rmdir'ed; its link
1019 * count of three would cause a rmdir to fail with ENOTEMPTY.
1020 * The IRENAME flag insures that it cannot be moved by another
1021 * rename.
4f083fd7 1022 */
4f1a9037 1023 if (xp != ip) {
68f21562 1024 if (doingdirectory)
4f1a9037 1025 panic("rename: lost dir entry");
68f21562 1026 } else {
4f083fd7 1027 /*
68f21562
KM
1028 * If the source is a directory with a
1029 * new parent, the link count of the old
1030 * parent directory must be decremented
1031 * and ".." set to point to the new parent.
4f083fd7 1032 */
68f21562 1033 if (doingdirectory && newparent) {
4f083fd7
SL
1034 dp->i_nlink--;
1035 dp->i_flag |= ICHG;
68f21562
KM
1036 error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
1037 sizeof (struct dirtemplate), (off_t)0, 1,
1038 (int *)0);
1039 if (error == 0) {
1040 if (dirbuf.dotdot_namlen != 2 ||
1041 dirbuf.dotdot_name[0] != '.' ||
1042 dirbuf.dotdot_name[1] != '.') {
1043 printf("rename: mangled dir\n");
1044 } else {
1045 dirbuf.dotdot_ino = newparent;
1046 (void) rdwri(UIO_WRITE, xp,
1047 (caddr_t)&dirbuf,
1048 sizeof (struct dirtemplate),
1049 (off_t)0, 1, (int *)0);
1050 cacheinval(dp);
1051 }
1052 }
4f083fd7 1053 }
715baff1 1054 if (dirremove(ndp)) {
68f21562
KM
1055 xp->i_nlink--;
1056 xp->i_flag |= ICHG;
4f083fd7 1057 }
68f21562
KM
1058 xp->i_flag &= ~IRENAME;
1059 if (error == 0) /* XXX conservative */
a5390dce 1060 error = u.u_error;
4f083fd7 1061 }
4f083fd7
SL
1062 if (dp)
1063 iput(dp);
68f21562
KM
1064 if (xp)
1065 iput(xp);
1066 irele(ip);
1067 if (error)
1068 u.u_error = error;
1069 return;
a5390dce 1070
4f083fd7 1071bad:
31db12cb 1072 iput(dp);
4f083fd7
SL
1073bad1:
1074 if (xp)
31db12cb 1075 iput(xp);
4f083fd7
SL
1076out:
1077 ip->i_nlink--;
1078 ip->i_flag |= ICHG;
1079 irele(ip);
a5390dce
SL
1080 if (error)
1081 u.u_error = error;
528f664c
SL
1082}
1083
64d3a787
BJ
1084/*
1085 * Make a new file.
1086 */
1087struct inode *
715baff1 1088maknode(mode, ndp)
64d3a787 1089 int mode;
715baff1 1090 register struct nameidata *ndp;
64d3a787
BJ
1091{
1092 register struct inode *ip;
715baff1 1093 register struct inode *pdir = ndp->ni_pdir;
64d3a787
BJ
1094 ino_t ipref;
1095
1096 if ((mode & IFMT) == IFDIR)
715baff1 1097 ipref = dirpref(pdir->i_fs);
64d3a787 1098 else
715baff1
KM
1099 ipref = pdir->i_number;
1100 ip = ialloc(pdir, ipref, mode);
64d3a787 1101 if (ip == NULL) {
715baff1 1102 iput(pdir);
528f664c 1103 return (NULL);
64d3a787 1104 }
528f664c 1105#ifdef QUOTA
64d3a787
BJ
1106 if (ip->i_dquot != NODQUOT)
1107 panic("maknode: dquot");
1108#endif
1109 ip->i_flag |= IACC|IUPD|ICHG;
1110 if ((mode & IFMT) == 0)
1111 mode |= IFREG;
1112 ip->i_mode = mode & ~u.u_cmask;
1113 ip->i_nlink = 1;
1114 ip->i_uid = u.u_uid;
715baff1 1115 ip->i_gid = pdir->i_gid;
67361d54 1116 if (ip->i_mode & ISGID && !groupmember(ip->i_gid) && !suser())
bb1b75f4 1117 ip->i_mode &= ~ISGID;
528f664c 1118#ifdef QUOTA
64d3a787
BJ
1119 ip->i_dquot = inoquota(ip);
1120#endif
1121
1122 /*
1123 * Make sure inode goes to disk before directory entry.
1124 */
3fd23f5c 1125 iupdat(ip, &time, &time, 1);
715baff1 1126 u.u_error = direnter(ip, ndp);
64d3a787
BJ
1127 if (u.u_error) {
1128 /*
f2a5ad78
SL
1129 * Write error occurred trying to update directory
1130 * so must deallocate the inode.
64d3a787
BJ
1131 */
1132 ip->i_nlink = 0;
1133 ip->i_flag |= ICHG;
1134 iput(ip);
528f664c 1135 return (NULL);
64d3a787 1136 }
528f664c 1137 return (ip);
64d3a787 1138}
88a7a62a
SL
1139
1140/*
1141 * A virgin directory (no blushing please).
1142 */
1143struct dirtemplate mastertemplate = {
1144 0, 12, 1, ".",
1145 0, DIRBLKSIZ - 12, 2, ".."
1146};
1147
1148/*
1149 * Mkdir system call
1150 */
1151mkdir()
1152{
1153 struct a {
1154 char *name;
1155 int dmode;
715baff1 1156 } *uap = (struct a *)u.u_ap;
88a7a62a
SL
1157 register struct inode *ip, *dp;
1158 struct dirtemplate dirtemplate;
715baff1 1159 register struct nameidata *ndp = &u.u_nd;
88a7a62a 1160
715baff1
KM
1161 ndp->ni_nameiop = CREATE;
1162 ndp->ni_segflg = UIO_USERSPACE;
1163 ndp->ni_dirp = uap->name;
1164 ip = namei(ndp);
88a7a62a
SL
1165 if (u.u_error)
1166 return;
1167 if (ip != NULL) {
1168 iput(ip);
1169 u.u_error = EEXIST;
1170 return;
1171 }
715baff1 1172 dp = ndp->ni_pdir;
88a7a62a
SL
1173 uap->dmode &= 0777;
1174 uap->dmode |= IFDIR;
1175 /*
1176 * Must simulate part of maknode here
1177 * in order to acquire the inode, but
1178 * not have it entered in the parent
1179 * directory. The entry is made later
1180 * after writing "." and ".." entries out.
1181 */
1182 ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
1183 if (ip == NULL) {
1184 iput(dp);
1185 return;
1186 }
1187#ifdef QUOTA
1188 if (ip->i_dquot != NODQUOT)
1189 panic("mkdir: dquot");
1190#endif
1191 ip->i_flag |= IACC|IUPD|ICHG;
1192 ip->i_mode = uap->dmode & ~u.u_cmask;
1193 ip->i_nlink = 2;
1194 ip->i_uid = u.u_uid;
1195 ip->i_gid = dp->i_gid;
1196#ifdef QUOTA
1197 ip->i_dquot = inoquota(ip);
1198#endif
1199 iupdat(ip, &time, &time, 1);
1200
1201 /*
1202 * Bump link count in parent directory
1203 * to reflect work done below. Should
1204 * be done before reference is created
1205 * so reparation is possible if we crash.
1206 */
1207 dp->i_nlink++;
1208 dp->i_flag |= ICHG;
1209 iupdat(dp, &time, &time, 1);
1210
1211 /*
1212 * Initialize directory with "."
1213 * and ".." from static template.
1214 */
1215 dirtemplate = mastertemplate;
1216 dirtemplate.dot_ino = ip->i_number;
1217 dirtemplate.dotdot_ino = dp->i_number;
1218 u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
1219 sizeof (dirtemplate), (off_t)0, 1, (int *)0);
1220 if (u.u_error) {
1221 dp->i_nlink--;
1222 dp->i_flag |= ICHG;
1223 goto bad;
1224 }
23de9f20
KM
1225 if (DIRBLKSIZ > ip->i_fs->fs_fsize)
1226 panic("mkdir: blksize"); /* XXX - should grow with bmap() */
1227 else
1228 ip->i_size = DIRBLKSIZ;
88a7a62a
SL
1229 /*
1230 * Directory all set up, now
1231 * install the entry for it in
1232 * the parent directory.
1233 */
715baff1 1234 u.u_error = direnter(ip, ndp);
88a7a62a
SL
1235 dp = NULL;
1236 if (u.u_error) {
715baff1
KM
1237 ndp->ni_nameiop = LOOKUP | NOCACHE;
1238 ndp->ni_segflg = UIO_USERSPACE;
1239 ndp->ni_dirp = uap->name;
1240 dp = namei(ndp);
88a7a62a
SL
1241 if (dp) {
1242 dp->i_nlink--;
1243 dp->i_flag |= ICHG;
1244 }
1245 }
1246bad:
1247 /*
1248 * No need to do an explicit itrunc here,
1249 * irele will do this for us because we set
1250 * the link count to 0.
1251 */
1252 if (u.u_error) {
1253 ip->i_nlink = 0;
1254 ip->i_flag |= ICHG;
1255 }
1256 if (dp)
1257 iput(dp);
1258 iput(ip);
1259}
1260
1261/*
1262 * Rmdir system call.
1263 */
1264rmdir()
1265{
1266 struct a {
1267 char *name;
715baff1 1268 } *uap = (struct a *)u.u_ap;
88a7a62a 1269 register struct inode *ip, *dp;
715baff1 1270 register struct nameidata *ndp = &u.u_nd;
88a7a62a 1271
715baff1
KM
1272 ndp->ni_nameiop = DELETE | LOCKPARENT;
1273 ndp->ni_segflg = UIO_USERSPACE;
1274 ndp->ni_dirp = uap->name;
1275 ip = namei(ndp);
88a7a62a
SL
1276 if (ip == NULL)
1277 return;
715baff1 1278 dp = ndp->ni_pdir;
88a7a62a
SL
1279 /*
1280 * No rmdir "." please.
1281 */
1282 if (dp == ip) {
1283 irele(dp);
1284 iput(ip);
1285 u.u_error = EINVAL;
1286 return;
1287 }
1288 if ((ip->i_mode&IFMT) != IFDIR) {
1289 u.u_error = ENOTDIR;
1290 goto out;
1291 }
1292 /*
1293 * Don't remove a mounted on directory.
1294 */
1295 if (ip->i_dev != dp->i_dev) {
1296 u.u_error = EBUSY;
1297 goto out;
1298 }
1299 /*
1300 * Verify the directory is empty (and valid).
1301 * (Rmdir ".." won't be valid since
1302 * ".." will contain a reference to
1303 * the current directory and thus be
1304 * non-empty.)
1305 */
68f21562 1306 if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) {
88a7a62a
SL
1307 u.u_error = ENOTEMPTY;
1308 goto out;
1309 }
1310 /*
1311 * Delete reference to directory before purging
1312 * inode. If we crash in between, the directory
1313 * will be reattached to lost+found,
1314 */
715baff1 1315 if (dirremove(ndp) == 0)
88a7a62a
SL
1316 goto out;
1317 dp->i_nlink--;
1318 dp->i_flag |= ICHG;
68f21562 1319 cacheinval(dp);
88a7a62a
SL
1320 iput(dp);
1321 dp = NULL;
1322 /*
1323 * Truncate inode. The only stuff left
1324 * in the directory is "." and "..". The
1325 * "." reference is inconsequential since
1326 * we're quashing it. The ".." reference
1327 * has already been adjusted above. We've
1328 * removed the "." reference and the reference
1329 * in the parent directory, but there may be
1330 * other hard links so decrement by 2 and
1331 * worry about them later.
1332 */
1333 ip->i_nlink -= 2;
1334 itrunc(ip, (u_long)0);
1d00c1cf 1335 cacheinval(ip);
88a7a62a
SL
1336out:
1337 if (dp)
1338 iput(dp);
1339 iput(ip);
1340}
1341
1342struct file *
1343getinode(fdes)
1344 int fdes;
1345{
8462a185 1346 struct file *fp;
88a7a62a 1347
8462a185
SL
1348 if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
1349 u.u_error = EBADF;
1350 return ((struct file *)0);
1351 }
88a7a62a
SL
1352 if (fp->f_type != DTYPE_INODE) {
1353 u.u_error = EINVAL;
8462a185 1354 return ((struct file *)0);
88a7a62a
SL
1355 }
1356 return (fp);
1357}
1358
1359/*
1360 * mode mask for creation of files
1361 */
1362umask()
1363{
1364 register struct a {
1365 int mask;
715baff1 1366 } *uap = (struct a *)u.u_ap;
88a7a62a 1367
88a7a62a
SL
1368 u.u_r.r_val1 = u.u_cmask;
1369 u.u_cmask = uap->mask & 07777;
1370}