|
|
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.