|
|
1.1 root 1: /* $Header: /kernel/kersrc/coh.386/RCS/sys2.c,v 1.2 92/08/04 12:34:59 bin Exp Locker: bin $ */
2: /* (lgl-
3: * The information contained herein is a trade secret of Mark Williams
4: * Company, and is confidential information. It is provided under a
5: * license agreement, and may be copied or disclosed only under the
6: * terms of that agreement. Any reproduction or disclosure of this
7: * material without the express written authorization of Mark Williams
8: * Company or pursuant to the license agreement is unlawful.
9: *
10: * COHERENT Version 4.0
11: * Copyright (c) 1982, 1992.
12: * All rights reserved.
13: -lgl) */
14: /*
15: * Coherent.
16: * System calls (filesystem related).
17: *
18: * $Log: sys2.c,v $
19: * Revision 1.2 92/08/04 12:34:59 bin
20: * changed for ker 59
21: *
22: * Revision 1.9 92/06/11 18:25:58 root
23: * Add close on exec code.
24: *
25: * Revision 1.8 92/06/10 12:53:14 hal
26: * Initial record locking. Ker #55.
27: *
28: * Revision 1.6 92/03/16 16:05:39 hal
29: * upoll(): fix control logic and two getuwd's from short values.
30: *
31: * Revision 1.5 92/03/13 14:46:35 hal
32: * Three argument open.
33: * Fix upoll().
34: *
35: * Revision 1.3 92/01/06 12:00:42 hal
36: * Compile with cc.mwc.
37: *
38: * Revision 1.2 91/12/10 15:58:13 hal
39: * Allow apparently negative net offsets to lseek.
40: *
41: * Revision 1.2 88/08/02 15:00:22 src
42: * O_APPEND flag now supported on open/fcntl system calls.
43: *
44: * Revision 1.1 88/03/24 16:14:31 src
45: * Initial revision
46: *
47: * 87/08/13 Allan Cornish /usr/src/sys/coh/sys2.c
48: * upoll() now initiates/cancels poll timers which use cprocp->p_polltim.
49: *
50: * 87/03/27 Allan Cornish /usr/src/sys/coh/sys2.c
51: * upoll() does more argument validation, and more comments.
52: *
53: * 86/12/14 Allan Cornish /usr/src/sys/coh/sys2.c
54: * upoll() now calls msgpoll() with 3 arguments, new arg means blocking poll
55: *
56: * 86/12/12 Allan Cornish /usr/src/sys/coh/sys2.c
57: * upoll() now calls dpoll() with 3 arguments, new arg indicating blocking poll
58: *
59: * 86/11/19 Allan Cornish /usr/src/sys/coh/sys2.c
60: * ufcntl() and upoll() system call handlers added, to support
61: * non-blocking reads/writes, and System V.3 compatible multi-event waits.
62: *
63: * 85/01/11 Allan Cornish /usr/src/sys/coh/sys2.c
64: * ucreat() on block/char devices works even if the file system is readonly.
65: */
66: #include <sys/coherent.h>
67: #include <errno.h>
68: #include <fcntl.h>
69: #include <sys/fd.h>
70: #include <sys/ino.h>
71: #include <sys/inode.h>
72: #include <sys/mount.h>
73: #include <sys/sched.h>
74: #include <sys/stat.h>
75:
76: /*
77: * Determine accessibility of the given file.
78: */
79: uaccess(np, mode)
80: char *np;
81: register int mode;
82: {
83: register INODE *ip;
84: register int r;
85:
86: schizo();
87: r = ftoi(np, 'r');
88: schizo();
89: if (r != 0)
90: return;
91: ip = u.u_cdiri;
92: if ((mode&imode(ip, u.u_ruid, u.u_rgid)) != mode)
93: u.u_error = EACCES;
94: idetach(ip);
95: return (0);
96: }
97:
98: /*
99: * Schizo - swap real and effective id's.
100: */
101: schizo()
102: {
103: register int t;
104:
105: t = u.u_uid;
106: u.u_uid = u.u_ruid;
107: u.u_ruid = t;
108: t = u.u_gid;
109: u.u_gid = u.u_rgid;
110: u.u_rgid = t;
111: }
112:
113: /*
114: * Turn accounting on or off.
115: */
116: uacct(np)
117: register char *np;
118: {
119: register INODE *ip;
120:
121: if (super() == 0)
122: return;
123: if (np == NULL) {
124: if (acctip == NULL) {
125: u.u_error = EINVAL;
126: return;
127: }
128: ldetach(acctip);
129: acctip = NULL;
130: } else {
131: if (acctip != NULL) {
132: u.u_error = EINVAL;
133: return;
134: }
135: if (ftoi(np, 'r') != 0)
136: return;
137: ip = u.u_cdiri;
138: if ((ip->i_mode&IFMT) != IFREG) {
139: u.u_error = EINVAL;
140: idetach(ip);
141: return;
142: }
143: iunlock(ip);
144: acctip = ip;
145: }
146: return (0);
147: }
148:
149: /*
150: * Set current directory.
151: */
152: uchdir(np)
153: char *np;
154: {
155: setcdir(np, &u.u_cdir);
156: return (0);
157: }
158:
159: /*
160: * Given a directory name and a pointer to a working directory pointer,
161: * Save the inode associated with the directory name in the working
162: * directory pointer and release the old one. This is used to change
163: * working and root directories.
164: */
165: setcdir(np, ipp)
166: char *np;
167: register INODE **ipp;
168: {
169: register INODE *ip;
170:
171: if (ftoi(np, 'r') != 0)
172: return;
173: ip = u.u_cdiri;
174: if ((ip->i_mode&IFMT) != IFDIR) {
175: u.u_error = ENOTDIR;
176: idetach(ip);
177: return;
178: }
179: if (iaccess(ip, IPE) == 0) {
180: u.u_error = EACCES;
181: idetach(ip);
182: return;
183: }
184: iunlock(ip);
185: ldetach(*ipp);
186: *ipp = ip;
187: }
188:
189: /*
190: * Change the mode of a file.
191: */
192: uchmod(np, mode)
193: char *np;
194: {
195: register INODE *ip;
196:
197: if (ftoi(np, 'r') != 0)
198: return;
199: ip = u.u_cdiri;
200: if (owner(ip->i_uid)) {
201: if (u.u_uid != 0)
202: mode &= ~ISVTXT;
203: ip->i_mode &= IFMT;
204: ip->i_mode |= mode&~IFMT;
205: icrt(ip); /* chmod - ctime */
206: }
207: idetach(ip);
208: return (0);
209: }
210:
211: /*
212: * Change owner and group of a file.
213: */
214: uchown(np, uid, gid)
215: char *np;
216: {
217: register INODE *ip;
218:
219: if (ftoi(np, 'r') != 0)
220: return;
221: ip = u.u_cdiri;
222: if (super()) {
223: ip->i_mode &= ~(ISUID | ISGID); /* clear any setuid/setgid */
224: ip->i_uid = uid;
225: ip->i_gid = gid;
226: icrt(ip); /* chown - ctime */
227: }
228: idetach(ip);
229: return (0);
230: }
231:
232: /*
233: * Set root directory.
234: */
235: uchroot(np)
236: register char *np;
237: {
238: if (super())
239: setcdir(np, &u.u_rdir);
240: return (0);
241: }
242:
243: /*
244: * Close the given file descriptor.
245: */
246: uclose(fd)
247: {
248: fdclose(fd);
249: return (0);
250: }
251:
252: /*
253: * Create a file with the given mode.
254: */
255: ucreat(np, mode)
256: char *np;
257: register int mode;
258: {
259: return(uopen(np, O_WRONLY|O_CREAT|O_TRUNC, mode));
260: }
261:
262: /*
263: * Duplicate a file descriptor.
264: */
265: udup(ofd)
266: {
267: return ufcntl(ofd, F_DUPFD, 0);
268: }
269:
270: /*
271: * Given a file descriptor, return a status structure.
272: */
273: ufstat(fd, stp)
274: struct stat *stp;
275: {
276: register INODE *ip;
277: register FD *fdp;
278: struct stat stat;
279:
280: if ((fdp=fdget(fd)) == NULL)
281: return;
282: ip = fdp->f_ip;
283: istat(ip, &stat);
284: kucopy(&stat, stp, sizeof(stat));
285: return (0);
286: }
287:
288: /*
289: * File control.
290: */
291: ufcntl( fd, cmd, arg )
292: int fd, cmd, arg;
293: {
294: register FD * fdp;
295: FLOCK sfl;
296:
297: T_VLAD(2, printf("fcntl(%d,%x,%x) ", fd, cmd, arg));
298:
299: /*
300: * Validate file descriptor.
301: */
302: if ( (fd < 0) || (fd >= NUFILE) || ((fdp = u.u_filep[fd]) == 0) ) {
303: u.u_error = EBADF;
304: return;
305: }
306:
307: switch ( cmd ) {
308:
309: case F_DUPFD:
310: /*
311: * Validate base file descriptor.
312: */
313: if ( (arg < 0) || (arg >= NUFILE) ) {
314: u.u_error = EINVAL;
315: return;
316: }
317:
318: /*
319: * Search for next available file descriptor.
320: */
321: do {
322: if ( u.u_filep[arg] == 0 ) {
323: u.u_filep[arg] = fdp;
324: fdp->f_refc++;
325: return arg;
326: }
327: } while ( ++arg < NUFILE );
328:
329: u.u_error = EMFILE;
330: return;
331:
332: case F_SETFL:
333: fdp->f_flag &= ~IPNDLY;
334: if ( arg & O_NDELAY )
335: fdp->f_flag |= IPNDLY;
336: if ( arg & O_APPEND )
337: fdp->f_flag |= IPAPPEND;
338: /* no break */
339:
340: case F_GETFL:
341: switch ( fdp->f_flag & (IPR+IPW) ) {
342: case IPR: arg = O_RDONLY; break;
343: case IPW: arg = O_WRONLY; break;
344: default: arg = O_RDWR; break;
345: }
346: if ( fdp->f_flag & IPNDLY )
347: arg |= O_NDELAY;
348: if ( fdp->f_flag & IPAPPEND )
349: arg |= O_APPEND;
350: return arg;
351:
352: case F_GETLK:
353: case F_SETLK:
354: case F_SETLKW:
355: ukcopy(*(FLOCK **)&arg, &sfl, sizeof(FLOCK));
356: if (u.u_error)
357: return -1;
358: if (rlock(fdp, cmd, &sfl))
359: return -1;
360: if (cmd == F_GETLK) {
361: kucopy(&sfl, *(FLOCK **)&arg, sizeof(FLOCK));
362: if (u.u_error)
363: return -1;
364: }
365: return 0;
366:
367: case F_GETFD:
368: return fdp->f_flag2 & FD_CLOEXEC;
369:
370: case F_SETFD:
371: if (arg & FD_CLOEXEC)
372: fdp->f_flag2 |= FD_CLOEXEC;
373: else
374: fdp->f_flag2 &= ~FD_CLOEXEC;
375: return 0;
376:
377: default:
378: T_VLAD(0x02,
379: printf("'fcntl - unknown cmd=%d arg=0x0%x' ", cmd, arg));
380: u.u_error = EINVAL;
381: }
382: }
383:
384: /*
385: * Device control information.
386: */
387: uioctl(fd, r, argp)
388: struct sgttyb *argp;
389: {
390: register FD *fdp;
391: register INODE *ip;
392: register int mode;
393:
394:
395: T_PIGGY( 0x8, printf("uioctl(%d, 0x%x, 0x%x)", fd, r, argp); );
396:
397: if ((fdp=fdget(fd)) == NULL)
398: return;
399: ip = fdp->f_ip;
400: mode = ip->i_mode&IFMT;
401: if (mode!=IFCHR && mode!=IFBLK) {
402: u.u_error = ENOTTY;
403: return;
404: }
405: dioctl(ip->i_a.i_rdev, r, argp);
406: return (0);
407: }
408:
409: /*
410: * Create a link, `np2' to the already existing file `np1'.
411: */
412: ulink(np1, np2)
413: char *np1;
414: char *np2;
415: {
416: register INODE *ip1;
417:
418: if (ftoi(np1, 'r') != 0)
419: return;
420: ip1 = u.u_cdiri;
421: if ((ip1->i_mode&IFMT)==IFDIR && super()==0) {
422: idetach(ip1);
423: return;
424: }
425: iunlock(ip1);
426: if (ftoi(np2, 'c') != 0) {
427: ldetach(ip1);
428: return;
429: }
430: if (u.u_cdiri != NULL) {
431: u.u_error = EEXIST;
432: idetach(u.u_cdiri);
433: ldetach(ip1);
434: return;
435: }
436: if (ip1->i_dev != u.u_pdiri->i_dev) {
437: u.u_error = EXDEV;
438: idetach(u.u_pdiri);
439: ldetach(ip1);
440: return;
441: }
442: if (iaccess(u.u_pdiri, IPW) == 0) {
443: idetach(u.u_pdiri);
444: ldetach(ip1);
445: return;
446: }
447: idirent(ip1->i_ino);
448: idetach(u.u_pdiri);
449: ilock(ip1);
450: /* idirent() can fail during iwrite. In this case we should not
451: * increase link count.
452: * As result of this old bug, 286 mkdir utility destroys file
453: * system when runs out of free blocks.
454: */
455: if (!u.u_error)
456: ip1->i_nlink++;
457: icrt(ip1); /* link - ctime */
458: idetach(ip1);
459: return (0);
460: }
461:
462: /*
463: * Seek on the given file descriptor.
464: */
465: off_t
466: ulseek(fd, off, w)
467: register off_t off;
468: {
469: register FD *fdp;
470: register INODE *ip;
471:
472: if ((fdp=fdget(fd)) == NULL)
473: return;
474: ip = fdp->f_ip;
475: if ((ip->i_mode&IFMT) == IFPIPE) {
476: u.u_error = ESPIPE;
477: return;
478: }
479: switch (w) {
480: case 0:
481: break;
482: case 1:
483: off += fdp->f_seek;
484: break;
485: case 2:
486: off += ip->i_size;
487: break;
488: default:
489: u.u_error = EINVAL;
490: return;
491: }
492: /*
493: * The following test is no longer reasonable.
494: * May want to seek to kernel text, which is in range 0xFFxxyyyy.
495: */
496: #if 0
497: if (off < 0) {
498: u.u_error = EINVAL;
499: return;
500: }
501: #endif
502: fdp->f_seek = off;
503: return (off);
504: }
505:
506: /*
507: * Create a special file.
508: */
509: umknod(np, mode, rdev)
510: char *np;
511: dev_t rdev;
512: {
513: register INODE *ip;
514: register int type;
515:
516: type = mode&IFMT;
517: if (type!=IFPIPE && super()==0)
518: return;
519: if (type!=IFBLK && type!=IFCHR)
520: rdev = 0;
521: if (ftoi(np, 'c') != 0)
522: return;
523: if ((ip=u.u_cdiri) != NULL) {
524: u.u_error = EEXIST;
525: idetach(ip);
526: return;
527: }
528: if ((ip=imake(mode, rdev)) != NULL)
529: idetach(ip);
530: return (0);
531: }
532:
533: /*
534: * Mount the device `sp' on the pathname `np'. The flag, `f',
535: * indicates that the device is to be mounted read only.
536: */
537: umount(sp, np, f)
538: char *sp;
539: char *np;
540: {
541: register INODE *ip;
542: register MOUNT *mp;
543: register dev_t rdev;
544: register int mode;
545:
546: if (ftoi(sp, 'r') != 0)
547: return;
548: ip = u.u_cdiri;
549: if (iaccess(ip, IPR|IPW) == 0)
550: goto err;
551: mode = ip->i_mode;
552: rdev = ip->i_a.i_rdev;
553: if ((mode&IFMT) != IFBLK) {
554: u.u_error = ENOTBLK;
555: goto err;
556: }
557: idetach(ip);
558: if (ftoi(np, 'r') != 0)
559: return;
560: ip = u.u_cdiri;
561: if (iaccess(ip, IPR) == 0)
562: goto err;
563: if ((ip->i_mode&IFMT) != IFDIR) {
564: u.u_error = ENOTDIR;
565: goto err;
566: }
567: /* Check for current directory, open, or mount directory */
568: if (ip->i_refc > 1 || ip->i_ino == ROOTIN) {
569: u.u_error = EBUSY;
570: goto err;
571: }
572: for (mp=mountp; mp!=NULL; mp=mp->m_next) {
573: if (mp->m_dev == rdev) {
574: u.u_error = EBUSY;
575: goto err;
576: }
577: }
578: if ((mp=fsmount(rdev, f)) == NULL)
579: goto err;
580: mp->m_ip = ip;
581: ip->i_flag |= IFMNT;
582: ip->i_refc++;
583: err:
584: idetach(ip);
585: return (0);
586: }
587:
588: /*
589: * Poll devices for input/output events.
590: */
591: int
592: upoll(pollfds, npoll, msec)
593: struct pollfd * pollfds;
594: unsigned long npoll;
595: int msec;
596: {
597: register struct pollfd * pollp; /* current poll pointer */
598: register FD * fdp; /* current file descriptor ptr */
599: auto int fd; /* current file descriptor */
600: auto int rev; /* last event report received */
601: auto int nev; /* number non-zero event reports */
602: auto int i;
603: char * cp;
604: int ret = -1;
605:
606: /*
607: * Validate number of polls.
608: */
609: if ((npoll < 0) || (npoll > NUFILE)) {
610: u.u_error = EINVAL;
611: goto poll_done;
612: }
613:
614: /*
615: * Validate address of polling information.
616: */
617: if ((pollfds == NULL)
618: || !useracc(pollfds, npoll*sizeof(struct pollfd))) {
619: u.u_error = EFAULT;
620: goto poll_done;
621: }
622:
623: do {
624: /*
625: * Service each poll in turn.
626: */
627: for (nev=0, i=npoll, pollp = pollfds; i > 0; --i, pollp++) {
628:
629: /*
630: * Fetch file descriptor.
631: */
632: fd = getuwd(&pollp->fd);
633:
634: /*
635: * Ignore negative file descriptors.
636: */
637: if (fd < 0) {
638: rev = 0;
639: goto remember;
640: }
641:
642: /*
643: * Poll message queue.
644: */
645: if (fd >= NUFILE) {
646: rev = msgpoll(fd, getusd(&pollp->events), msec);
647: goto remember;
648: }
649:
650: /*
651: * Validate file descriptor.
652: */
653: if ((fdp = u.u_filep[fd]) == 0) {
654: rev = POLLNVAL;
655: goto remember;
656: }
657:
658: /*
659: * Non-character device.
660: */
661: if ((fdp->f_ip->i_mode & IFMT) != IFCHR) {
662: printf("polling non-CHR device: fd=%d mode=%x\n", fd, fdp->f_ip->i_mode);
663: rev = POLLNVAL;
664: goto remember;
665: }
666:
667: /*
668: * Poll character device driver.
669: */
670: rev = dpoll(fdp->f_ip->i_a.i_rdev,
671: getusd(&pollp->events)&0xffff, msec);
672:
673: /*
674: * Remember reponses.
675: */
676: remember:
677: cp = (char *)(&pollp->revents);
678: putusd(cp, rev);
679:
680: /*
681: * Record number of non-zero responses.
682: */
683: if (rev != 0) {
684: msec = 0;
685: nev++;
686: }
687: }
688:
689: /*
690: * Non-blocking poll or poll response received.
691: */
692: if (msec == 0) {
693: pollexit();
694: ret = nev;
695: goto poll_done;
696: }
697:
698: /*
699: * Schedule wakeup timer if positive delay interval given.
700: */
701: if (msec > 0) {
702: /*
703: * Convert milliseconds to clock ticks.
704: */
705: msec += (1000 / HZ) - 1;
706: msec /= (1000 / HZ);
707: timeout(&cprocp->p_polltim, msec,
708: wakeup, &cprocp->p_polls);
709: }
710:
711: /*
712: * Wake for polled event, poll timeout, or signal.
713: */
714: v_sleep(&cprocp->p_polls, CVTTOUT, IVTTOUT, SVTTOUT, "poll");
715: /* Wake for polled event, poll timeout, or signal. */
716:
717: /*
718: * Terminate event monitoring.
719: */
720: pollexit();
721:
722: /*
723: * Perform non-blocking poll after first poll timeout.
724: */
725: if (msec > 0) {
726: timeout(&cprocp->p_polltim, 0, NULL, NULL);
727: msec = 0;
728: }
729:
730: /*
731: * Signal woke us up.
732: */
733: if (nondsig()) {
734: u.u_error = EINTR;
735: goto poll_done;
736: }
737:
738: } while (msec != 0);
739:
740: ret = 0;
741:
742: poll_done:
743: return ret;
744: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.