|
|
1.1 ! root 1: /* ! 2: * coh.386/sys5.c ! 3: * ! 4: * System calls introduced when going from COH 286 to COH 386. ! 5: * ! 6: * Revised: Mon Jul 12 12:27:55 1993 CDT ! 7: */ ! 8: #include <sys/coherent.h> ! 9: #include <sys/buf.h> ! 10: #include <sys/errno.h> ! 11: #include <canon.h> ! 12: #include <sys/con.h> ! 13: #include <fcntl.h> ! 14: #include <sys/fd.h> ! 15: #include <sys/filsys.h> ! 16: #include <sys/ino.h> ! 17: #include <sys/inode.h> ! 18: #include <sys/io.h> ! 19: #include <sys/mount.h> ! 20: #include <sys/stat.h> ! 21: #include <dirent.h> ! 22: #include <sys/utsname.h> ! 23: #include <sys/mount.h> ! 24: #include <ustat.h> ! 25: #include <sys/statfs.h> ! 26: #include <sys/sysi86.h> ! 27: #include <sys/file.h> ! 28: #include <ulimit.h> ! 29: ! 30: ! 31: utime(tp) ! 32: long *tp; ! 33: { ! 34: return timer.t_time; ! 35: } ! 36: ! 37: /* ! 38: * Return an unique number. ! 39: */ ! 40: usysi86(f, arg1) ! 41: { ! 42: register MOUNT *mp; ! 43: register struct filsys *fsp; ! 44: extern void (*ndpEmFn)(); ! 45: int fpval; ! 46: extern short ndpType; ! 47: ! 48: switch (f) { ! 49: case SYI86UNEEK: ! 50: if ((mp = getment (rootdev, 1)) == NULL) ! 51: return; ! 52: fsp = & mp->m_super; ! 53: fsp->s_fmod = 1; ! 54: return ++ fsp->s_unique; ! 55: ! 56: case SI86FPHW: ! 57: /* ! 58: * 2's bit: floating point ndp is present (80287/80387/80486dx) ! 59: * 1's bit (when 2's bit = 1): 80387/486dx is present ! 60: */ ! 61: ! 62: if (! useracc (arg1, sizeof (int), 1)) { ! 63: SET_U_ERROR (EFAULT, "sysi386:SI86FPHW"); ! 64: return; ! 65: } ! 66: if (ndpType <= 1) { /* no ndp */ ! 67: fpval = (ndpEmFn) ? FP_SW : FP_NO; ! 68: } else ! 69: fpval = (ndpType > 2) ? FP_387 : FP_287; ! 70: ! 71: putuwd (arg1, fpval); ! 72: return 0; ! 73: ! 74: } ! 75: } ! 76: ! 77: ushmsys(func, arg1, arg2, arg3) ! 78: int func, arg1, arg2, arg3; ! 79: { ! 80: switch(func){ ! 81: case 0: return ushmat(arg1, arg2, arg3); ! 82: case 1: return ushmctl(arg1, arg2, arg3); ! 83: case 2: return ushmdt(arg1); ! 84: case 3: return ushmget(arg1, arg2, arg3); ! 85: default: u.u_error = EINVAL; ! 86: } ! 87: } ! 88: ! 89: usemsys(func, arg1, arg2, arg3, arg4) ! 90: int func, arg1, arg2, arg3, arg4; ! 91: { ! 92: switch(func){ ! 93: case 0: return usemctl(arg1, arg2, arg3, arg4); ! 94: case 1: return usemget(arg1, arg2, arg3); ! 95: case 2: return usemop(arg1, arg2, arg3); ! 96: default: u.u_error = EINVAL; ! 97: } ! 98: } ! 99: ! 100: /* ! 101: * uname and ustat system calls. ! 102: * ! 103: * int uname(struct utsname *name) ! 104: * Before lcall instruction 4(%esp) contains name, 8(%esp) contains ! 105: * an unspecified value, and 12(%esp) contains the value 0. ! 106: * ! 107: * int ustat(int dev, struct ustat *buf) ! 108: * Before lcall instruction 4(%esp) contains buf (REVERSE order of argument) ! 109: * 8(%esp) contains dev, and 12(%esp) contains the value 2. ! 110: */ ! 111: ! 112: uutssys(arg1, arg2, func) ! 113: { ! 114: switch(func) { ! 115: case 0: return uname(arg1); ! 116: case 2: return u_ustat(arg2, arg1); ! 117: default:u.u_error = EINVAL; ! 118: } ! 119: } ! 120: ! 121: /* ! 122: * uname - get name of the current operating system. ! 123: */ ! 124: extern char version[]; /* Defined in main.c */ ! 125: extern char release[]; /* Defined in main.c */ ! 126: ! 127: uname(name) ! 128: struct utsname *name; ! 129: { ! 130: register char *rcp; /**/ ! 131: register int i; /* Counter, loop index */ ! 132: register INODE *ip; /* /etc/uucpname inode */ ! 133: BUF *bp; /* Read buffer */ ! 134: char namebuf[SYS_NMLN]; /* System name */ ! 135: int fl; /* File length*/ ! 136: ! 137: /* Check if *name is an available user area */ ! 138: if (! useracc ((char *) name, sizeof (struct utsname), 1)) { ! 139: u.u_error = EFAULT; ! 140: return 0; ! 141: } ! 142: /* Find the size of the version number */ ! 143: for (rcp = version, i = 0; *rcp != '\0' && i < SYS_NMLN; i++, rcp++) ! 144: /* DO NOTHING */ ; ! 145: ! 146: /* Write version number to user area */ ! 147: if (! kucopy (version, name->version, i)) ! 148: return 0; ! 149: ! 150: /* Find the size of the release number */ ! 151: for (rcp = release, i = 0 ; * rcp != '\0' && i < SYS_NMLN ; ! 152: i ++, rcp ++) ! 153: /* DO NOTHING */ ; ! 154: ! 155: /* Write release number to user area */ ! 156: if (! kucopy (release, name->release, i)) ! 157: return; ! 158: ! 159: /* Write "machine" to user area */ ! 160: if (! kucopy ("i386", name->machine, 4)) ! 161: return; ! 162: /* ! 163: * We supposed that system name and nodename are in /etc/uucpname ! 164: * NIGEL: Set the global io segment to IOSYS so that ftoi () will use ! 165: * the right method of getting at the argument passed to it. ! 166: */ ! 167: ! 168: { ! 169: IO io; ! 170: struct direct dir; ! 171: ! 172: io.io_seg = IOSYS; ! 173: if (ftoi ("/etc/uucpname", 'r', & io, & dir) != 0) ! 174: return sys_unknown (name); ! 175: } ! 176: ! 177: ip = u.u_cdiri; ! 178: if ((fl = ip->i_size) == 0) { ! 179: idetach (ip); ! 180: return sys_unknown (name); ! 181: } ! 182: ! 183: if (iaccess (ip, IPR) == 0) { ! 184: idetach (ip); ! 185: return; ! 186: } ! 187: if ((bp = vread (ip, (daddr_t) 0)) == NULL) { ! 188: brelease (bp); ! 189: idetach (ip); ! 190: return; ! 191: } ! 192: ! 193: /* namebuf should be not more than SYS_NMLN - 1 characters long */ ! 194: fl = fl > SYS_NMLN ? SYS_NMLN : fl; ! 195: memcpy (namebuf, bp->b_vaddr, fl); ! 196: ! 197: brelease (bp); ! 198: idetach (ip); ! 199: ! 200: if (fl == 1 && namebuf [0] == '\n') ! 201: return sys_unknown (name); ! 202: ! 203: for (rcp = namebuf, i = 0 ; i < fl ; rcp ++) { ! 204: i ++; ! 205: if (* rcp == '\n') { ! 206: * rcp = '\0'; ! 207: break; ! 208: } ! 209: } ! 210: namebuf[i - 1] = '\0'; ! 211: ! 212: /* Write system name to user area */ ! 213: if (! kucopy (namebuf, name->sysname, i)) ! 214: return 0; ! 215: ! 216: /* Write system name to user area */ ! 217: if (! kucopy (namebuf, name->nodename, i)) ! 218: return 0; ! 219: return 0; ! 220: } ! 221: ! 222: /* ! 223: * sys_unknown - write name unknown to utsname struct ! 224: */ ! 225: char unknown[] = "UNKNOWN"; ! 226: sys_unknown(name) ! 227: struct utsname *name; ! 228: { ! 229: if (! kucopy (unknown, name->sysname, sizeof (unknown))) ! 230: return; ! 231: if (! kucopy (unknown, name->nodename, sizeof (unknown))) ! 232: return; ! 233: } ! 234: ! 235: /* ! 236: * u_ustat - get file system statistics. (Name ustat in use for stat s.c.) ! 237: */ ! 238: ! 239: u_ustat(dev, buf) ! 240: dev_t dev; ! 241: struct ustat *buf; ! 242: { ! 243: register MOUNT *mp; ! 244: ! 245: /* Check if buf is an available user area. */ ! 246: /* B_READ | B_WRITE is not implemented yet. */ ! 247: if (! useracc ((char *) buf, sizeof (struct ustat), 1)) { ! 248: u.u_error = EFAULT; ! 249: return; ! 250: } ! 251: ! 252: /* Take mount filesystem, check if dev is mounted device */ ! 253: for (mp = mountp ; mp != NULL ; mp = mp->m_next) ! 254: if (mp->m_dev == dev) ! 255: break; ! 256: ! 257: if (mp == NULL) { ! 258: u.u_error = EINVAL; ! 259: return; ! 260: } ! 261: ! 262: /* Pickup information from superblock */ ! 263: /* Number of free blocks */ ! 264: if (! kucopy (& mp->m_super.s_tfree, & buf->f_tfree, ! 265: sizeof (mp->m_super.s_tfree))) ! 266: return; ! 267: ! 268: /* Number of free inodes */ ! 269: if (! kucopy (& mp->m_super.s_tinode, & buf->f_tinode, ! 270: sizeof (mp->m_super.s_tinode))) ! 271: return; ! 272: ! 273: /* File system name */ ! 274: if (! kucopy (mp->m_super.s_fname, buf->f_fname, ! 275: sizeof (mp->m_super.s_fname))) ! 276: return; ! 277: ! 278: /* File system pack name */ ! 279: if (! kucopy (mp->m_super.s_fpack, buf->f_fpack, ! 280: sizeof (mp->m_super.s_fpack))) ! 281: return; ! 282: } ! 283: ! 284: umsgsys(func, arg1, arg2, arg3, arg4, arg5) ! 285: { ! 286: switch (func) { ! 287: case 0: return umsgget (arg1, arg2); ! 288: case 1: return umsgctl (arg1, arg2, arg3); ! 289: case 2: return umsgrcv (arg1, arg2, arg3, arg4, arg5); ! 290: case 3: return umsgsnd (arg1, arg2, arg3, arg4); ! 291: default:u.u_error = EINVAL; ! 292: } ! 293: } ! 294: ! 295: /* Don't tell user process about last remaining 64k of RAM */ ! 296: #define BRK_CUSHION 16 ! 297: ! 298: uulimit(cmd, newlimit) ! 299: { ! 300: int freeClicks; ! 301: ! 302: switch (cmd) { ! 303: case UL_GETFSIZE: /* Get max # of 512-byte blocks per file. */ ! 304: return u.u_bpfmax; ! 305: break; ! 306: ! 307: case UL_SETFSIZE: /* Set max # of 512-byte blocks per file. */ ! 308: /* (only superuser may increase this) */ ! 309: if (newlimit <= u.u_bpfmax || super ()) { ! 310: u.u_bpfmax = newlimit; ! 311: return 0; ! 312: } ! 313: /* else super() will have set u.u_error to EPERM */ ! 314: break; ! 315: ! 316: case UL_GMEMLIM: /* Get max break value. */ ! 317: /* return (current brk value) + (amount of free space) */ ! 318: /* Don't report all free clicks - leave a cushion. */ ! 319: freeClicks = allocno () - BRK_CUSHION; ! 320: if (freeClicks < 0) ! 321: freeClicks = 0; ! 322: return u.u_segl [SIPDATA].sr_base + ! 323: SELF->p_segp [SIPDATA]->s_size + NBPC * freeClicks; ! 324: ! 325: case UL_GDESLIM: ! 326: /* Return configured number of open files per process. */ ! 327: return NOFILE; ! 328: break; ! 329: ! 330: default: ! 331: u.u_error = EINVAL; ! 332: } ! 333: } ! 334: ! 335: /* ! 336: * Change the size of a file. ! 337: */ ! 338: uchsize(fd, size) ! 339: int fd; ! 340: register long size; ! 341: { ! 342: FD *fdp; ! 343: register INODE *ip; ! 344: ! 345: if (size < 0) { ! 346: u.u_error = EINVAL; ! 347: return -1; ! 348: } ! 349: if ((fdp = fdget (fd))==NULL || (fdp->f_flag & IPW) == 0) { ! 350: u.u_error = EBADF; ! 351: return -1; ! 352: } ! 353: ! 354: ip = fdp->f_ip; ! 355: switch (ip->i_mode & IFMT) { ! 356: case IFREG: ! 357: if (size > (long) u.u_bpfmax * BSIZE) { ! 358: u.u_error = EFBIG; ! 359: return -1; ! 360: } ! 361: if (size == ip->i_size) ! 362: break; ! 363: ilock (ip); ! 364: if (size < ip->i_size) ! 365: blclear (ip, __DIVIDE_ROUNDUP (ip->i_size, BSIZE)); ! 366: ip->i_size = size; ! 367: imod (ip); ! 368: icrt (ip); ! 369: iunlock (ip); ! 370: break; ! 371: ! 372: case IFPIPE: ! 373: if (size > PIPSIZE) { ! 374: u.u_error = EFBIG; ! 375: return -1; ! 376: } ! 377: ! 378: ilock(ip); ! 379: ! 380: if (! ip->i_par && ! ip->i_psr) { ! 381: u.u_error = EPIPE; ! 382: sendsig (SIGPIPE, SELF); ! 383: iunlock (ip); ! 384: return -1; ! 385: } ! 386: ip->i_pwx += (size - ip->i_pnc); ! 387: if (size > ip->i_pnc) { ! 388: if (ip->i_pwx >= PIPSIZE) ! 389: ip->i_pwx -= PIPSIZE; ! 390: } else if (size < ip->i_pnc) { ! 391: if (ip->i_pwx < 0) ! 392: ip->i_pwx += PIPSIZE; ! 393: } ! 394: ! 395: ip->i_pnc = size; ! 396: imod (ip); ! 397: icrt (ip); ! 398: ! 399: if (size > 0) ! 400: pwake (ip, 2); /* 2==IFWFW, see pipe.c */ ! 401: if (size < PIPSIZE) ! 402: pwake (ip, 1); /* 1==IFWFR, see pipe.c */ ! 403: iunlock (ip); ! 404: break; ! 405: ! 406: default: ! 407: u.u_error = EBADF; ! 408: return -1; ! 409: } ! 410: return 0; ! 411: } ! 412: ! 413: /* ! 414: * Remove a directory. ! 415: */ ! 416: ! 417: urmdir(path) ! 418: char *path; ! 419: { ! 420: register INODE *ip; ! 421: int iPathLen; /* Size of the string */ ! 422: int isdirempty(); ! 423: extern int strUserAcc(); ! 424: IO io; ! 425: struct direct dir; ! 426: ! 427: /* Check if path points to a valid user buffer.*/ ! 428: if ((iPathLen = strUserAcc (path, 0)) < 0) { ! 429: u.u_error = EFAULT; ! 430: return; ! 431: } ! 432: ! 433: io.io_seg = IOUSR; ! 434: if (ftoi (path, 'r', & io, & dir) != 0) ! 435: return; ! 436: ! 437: ip = u.u_cdiri; ! 438: ! 439: /* Check if path is a directory */ ! 440: if ((ip->i_mode & IFMT) != IFDIR) { ! 441: SET_U_ERROR(ENOTDIR, "rmdir: no such directory"); ! 442: idetach (ip); ! 443: return; ! 444: } ! 445: ! 446: /* We have to check if directory is empty */ ! 447: if (! isdirempty (ip)) { ! 448: SET_U_ERROR (EEXIST, "rmdir: directory is not empty"); ! 449: idetach (ip); ! 450: return; ! 451: } ! 452: idetach (ip); ! 453: removedir (path, iPathLen); ! 454: return 0; ! 455: } ! 456: ! 457: /* ! 458: * Remove a directory. ! 459: * path is a pointer to user area. ! 460: */ ! 461: ! 462: removedir(path, iPathLen) ! 463: char *path; /* Directory name */ ! 464: int iPathLen; /* Path length */ ! 465: { ! 466: char *buf; ! 467: char *cpbuf, /* internal file_name buffer */ ! 468: *cppath; /* user file_name buffer */ ! 469: ! 470: /* ! 471: * Allocate kernel buffer. We need extra space for '/', '.', '..' ! 472: * and '\0' ! 473: */ ! 474: ! 475: if ((buf = kalloc (iPathLen + 4)) == NULL) { ! 476: SET_U_ERROR (ENOSPC, "rmdir: out of kernel space"); ! 477: return; ! 478: } ! 479: cpbuf = buf; ! 480: cppath = path; ! 481: ! 482: /* Copy path to the kernel buffer. */ ! 483: while ((* cpbuf = getubd (cppath)) != '\0') { ! 484: cppath ++; ! 485: cpbuf ++; ! 486: } ! 487: * cpbuf++ = '/'; ! 488: * cpbuf++ = '.'; ! 489: * cpbuf = '\0'; ! 490: ! 491: dunlink (buf); ! 492: if (u.u_error) { ! 493: kfree (buf); ! 494: return; ! 495: } ! 496: ! 497: * cpbuf ++ = '.'; ! 498: * cpbuf = '\0'; ! 499: ! 500: dunlink (buf); ! 501: if (u.u_error) { ! 502: /* We have to link '.' back here. */ ! 503: kfree (buf); ! 504: return; ! 505: } ! 506: ! 507: buf [iPathLen] = '\0'; ! 508: ! 509: dunlink (buf); ! 510: if (u.u_error) { ! 511: /* We have to link '.' and '..' back here. */ ! 512: kfree (buf); ! 513: return; ! 514: } ! 515: kfree(buf); ! 516: return; ! 517: } ! 518: ! 519: ! 520: /* ! 521: * Unlink the given directory. ! 522: */ ! 523: ! 524: dunlink (np) ! 525: char *np; ! 526: { ! 527: register INODE *ip; ! 528: register dev_t dev; ! 529: IO io; ! 530: struct direct dir; ! 531: ! 532: io.io_seg = IOSYS; ! 533: if (file_to_inode (np, 'u', 1, & io, & dir) != 0) ! 534: return; ! 535: ! 536: ip = u.u_pdiri; ! 537: if (iaccess (ip, IPW) == 0) ! 538: goto err; ! 539: ! 540: dev = ip->i_dev; ! 541: if (diucheck (dev, u.u_cdirn) == 0) ! 542: goto err; ! 543: ! 544: idirent (0, & io, & dir); ! 545: idetach (ip); ! 546: ! 547: if ((ip = iattach (dev, u.u_cdirn)) == NULL) ! 548: return; ! 549: ! 550: if (ip->i_nlink > 0) ! 551: -- ip->i_nlink; ! 552: icrt (ip); /* unlink - ctime */ ! 553: ! 554: err: ! 555: idetach (ip); ! 556: return; ! 557: } ! 558: ! 559: /* ! 560: * This is a copy of iucheck. The only one difference is that that allows ! 561: * to remove a directory to a regular user. ! 562: */ ! 563: ! 564: diucheck (dev, ino) ! 565: register dev_t dev; ! 566: register ino_t ino; ! 567: { ! 568: register INODE *ip; ! 569: INODE inode; ! 570: ! 571: for (ip = & inodep [NINODE - 1] ; ip >= inodep ; -- ip) { ! 572: if (ip->i_ino == ino && ip->i_dev == dev) ! 573: break; ! 574: } ! 575: ! 576: if (ip < inodep) { ! 577: ip = & inode; ! 578: ip->i_dev = dev; ! 579: ip->i_ino = ino; ! 580: if (icopydm (ip) == 0) ! 581: return 0; ! 582: } ! 583: return 1; ! 584: } ! 585: ! 586: /* ! 587: * Check if directory is empty. ! 588: */ ! 589: int isdirempty (ip) ! 590: register INODE *ip; ! 591: { ! 592: register char *cp; ! 593: int count; ! 594: BUF *bp; ! 595: ! 596: for (count = 0 ; count < ip->i_size ; count += 512) { ! 597: if ((bp = vread (ip, count)) == NULL) ! 598: break; ! 599: ! 600: for (cp = (char *) bp->b_vaddr ; ! 601: cp < (char *) bp->b_vaddr + BSIZE ; cp += 16) { ! 602: ! 603: if (cp == '\0' && cp [1] == '\0') ! 604: continue; ! 605: if (cp [2] != '.') ! 606: goto bad; ! 607: if (cp [3] == '\0') ! 608: continue; ! 609: if (cp [3] != '.' || cp [4] != '\0') ! 610: goto bad; ! 611: } ! 612: ! 613: brelease (bp); ! 614: } ! 615: return 1; ! 616: ! 617: bad: ! 618: brelease (bp); ! 619: return 0; ! 620: } ! 621: ! 622: /* ! 623: * SysV compatible mkdir() system call. ! 624: * ! 625: * Create a directory of the given "path" and "mode", if possible. ! 626: * Creating the directory is straight forward. Trying to clean ! 627: * up in case we run out of inodes or freee blocks in the process ! 628: * is not trivial. ! 629: * This system call was implemented in very press time. ! 630: * Vlad 6-04-92 ! 631: */ ! 632: ! 633: umkdir(path, mode) ! 634: char *path; ! 635: int mode; ! 636: { ! 637: INODE *dmknod(); /* make directory node */ ! 638: register INODE *pip; /* parent inode pointer */ ! 639: register char *cp_path, ! 640: *cpb_path, ! 641: *cp_dot, ! 642: *cp_dotdot, ! 643: *cp_parent; ! 644: char bufpath[512], ! 645: bufdot[512], ! 646: bufdotdot[512], ! 647: bufparent[512]; ! 648: int uid; ! 649: ! 650: /* Check if path points to a valid user buffer.*/ ! 651: if (strUserAcc (path, 0) < 0) { ! 652: u.u_error = EFAULT; ! 653: return; ! 654: } ! 655: ! 656: /* ! 657: * Create a local copies of "path" which we can use to build up ! 658: * the required directory links: ! 659: * path/. -- bufdot ! 660: * path/..-- bufdotdot ! 661: * Verify that the given path is not too long. ! 662: */ ! 663: cp_path = path; ! 664: cpb_path = bufpath; ! 665: cp_dot = bufdot; ! 666: cp_dotdot = bufdotdot; ! 667: cp_parent = bufparent; ! 668: ! 669: while ((* cpb_path = getubd (cp_path)) != '\0') { ! 670: * cp_dot ++ = * cp_dotdot ++ = * cp_parent ++ = * cpb_path; ! 671: ++ cp_path; ! 672: if (++ cpb_path >= & bufpath [sizeof (bufpath) - 3]) { ! 673: SET_U_ERROR (ENOENT, "sys5: mkdir: path too long"); ! 674: return; ! 675: } ! 676: } ! 677: ! 678: while (-- cp_parent >= bufparent) { ! 679: if (* cp_parent == '/') { ! 680: * ++ cp_parent = '\0'; ! 681: break; ! 682: } ! 683: } ! 684: ! 685: if (cp_parent < bufparent) { ! 686: * ++ cp_parent = '.'; ! 687: * ++ cp_parent = '\0'; ! 688: } ! 689: ! 690: * cp_dotdot ++ = * cp_dot++ = '/'; ! 691: * cp_dotdot ++ = * cp_dot++ = '.'; ! 692: * cp_dotdot ++ = '.'; ! 693: * cp_dotdot = * cp_dot = '\0'; ! 694: ! 695: if ((pip = dmknod (path, mode, IOUSR)) == NULL) ! 696: return; ! 697: ! 698: /* ! 699: * Now we can switch our id to root. It allows to use existing ! 700: * functions. ! 701: */ ! 702: ! 703: uid = u.u_uid; ! 704: u.u_uid = 0; ! 705: ! 706: do_link (bufpath, bufdot, IOSYS); ! 707: ! 708: if (u.u_error) { ! 709: u.u_error = do_unlink (bufpath, IOSYS); ! 710: ! 711: u.u_uid = uid; ! 712: return; ! 713: } ! 714: ! 715: do_link (bufparent, bufdotdot, IOSYS); ! 716: ! 717: if (u.u_error) { ! 718: u.u_error = do_unlink (bufdot, IOSYS); ! 719: u.u_error = do_unlink (bufpath, IOSYS); ! 720: } ! 721: ! 722: u.u_uid = uid; ! 723: return 0; ! 724: } ! 725: ! 726: ! 727: /* ! 728: * Create a directory. ! 729: * ! 730: * We cannot use original ulink because it makes the directories only ! 731: * for superuser. ! 732: */ ! 733: ! 734: INODE * ! 735: dmknod (np, mode, space) ! 736: char *np; /* Direcotory name */ ! 737: int mode; ! 738: int space; ! 739: { ! 740: register INODE *ip, *pip; ! 741: register int type; ! 742: IO io; ! 743: struct direct dir; ! 744: ! 745: type = (mode & ~IFMT); ! 746: type |= S_IFDIR; ! 747: ! 748: /* If ftoi returns nonzero, u.u_error has been set. */ ! 749: io.io_seg = space; ! 750: if (ftoi (np, 'c', & io, & dir) != 0) ! 751: return NULL; ! 752: ! 753: if ((ip = u.u_cdiri) != NULL) { ! 754: SET_U_ERROR (EEXIST, "dmknod: path already exists"); ! 755: idetach (ip); ! 756: return NULL; ! 757: } ! 758: if ((ip = imake (type, (dev_t) 0, & io, & dir)) != NULL) ! 759: idetach (ip); ! 760: pip = u.u_pdiri; /* grab ptr to parent inode */ ! 761: return pip; ! 762: } ! 763: ! 764: ! 765: /* ! 766: * Get directory entry in file system independent format. ! 767: */ ! 768: ! 769: ugetdents(fd, bp, n) ! 770: int fd; /* File descriptor to an open directory */ ! 771: char *bp; /* Buffer where entries should be read */ ! 772: unsigned n; /* Number of bytes to be read */ ! 773: { ! 774: struct direct r_dir; ! 775: unsigned bytes; /* Number of bytes */ ! 776: struct dirent sd; ! 777: ino_t inode; /* Inode number */ ! 778: unsigned short ofnm; /* Offset to file name in dirent */ ! 779: char *cw, ! 780: *cr; ! 781: int minbuf; /* Minimum possible size of the bp */ ! 782: int i, mod; ! 783: int entry; ! 784: char ends[3] = ""; ! 785: int total = 0; ! 786: ! 787: cw = bp; ! 788: ! 789: ofnm = sizeof (sd.d_ino) + sizeof (sd.d_off) + sizeof (sd.d_reclen); ! 790: ! 791: /* ! 792: * Find minimum possible size of bp. It should be enough to contain ! 793: * the header of dirent, file name + '\0', and be on a sizeof(long) ! 794: * boundary. ! 795: */ ! 796: ! 797: entry = ofnm + DIRSIZ + 1; ! 798: mod = entry % sizeof(long); ! 799: minbuf = entry + (mod ? sizeof(long) - mod : 0); ! 800: ! 801: /* Is user buffer available? */ ! 802: if (! useracc (bp, n, 1) || n < minbuf) { ! 803: u.u_error = EFAULT; ! 804: return 0; ! 805: } ! 806: ! 807: while(n - (cw - bp) >= minbuf) { ! 808: /* ! 809: * Read next entry from the directory. ! 810: * inode == 0 for rm(ed) entries ! 811: */ ! 812: ! 813: do { ! 814: if ((bytes = dirio (fd, & r_dir, ! 815: sizeof (struct direct), ! 816: & sd.d_off)) == 0) ! 817: return total; ! 818: ! 819: inode = r_dir.d_ino; ! 820: } while (! inode); ! 821: ! 822: /* Find the size of file name */ ! 823: for (cr = r_dir.d_name, i = 0 ; * cr != '\0' && i < DIRSIZ ; ! 824: i ++, cr ++) ! 825: /* DO NOTHING */ ; ! 826: ! 827: /* Copy file name */ ! 828: if (! kucopy (r_dir.d_name, cw + ofnm, i)) ! 829: return 0; ! 830: ! 831: /* Write '\0' */ ! 832: putubd (cw + ofnm + i ++, '\0'); ! 833: ! 834: /* Round up to long boundary */ ! 835: if (mod = (ofnm + i) % sizeof(long)) ! 836: if (! kucopy (ends, cw + ofnm + i, sizeof ! 837: (long) - mod)) ! 838: return 0; ! 839: ! 840: sd.d_ino = r_dir.d_ino; ! 841: sd.d_reclen = ofnm + i; /* Size of directory entry */ ! 842: if (mod) ! 843: sd.d_reclen += sizeof (long) - mod; ! 844: ! 845: if (! kucopy(& sd, cw, ofnm)) ! 846: return 0; ! 847: ! 848: total += sd.d_reclen; ! 849: cw += sd.d_reclen; ! 850: } ! 851: return total; ! 852: } ! 853: ! 854: /* ! 855: * Read `n' bytes from the directory `fd' using the buffer `bp'. ! 856: */ ! 857: ! 858: dirio(fd, bp, n, offset) ! 859: struct direct *bp; ! 860: unsigned n; ! 861: off_t *offset; ! 862: { ! 863: register FD *fdp; ! 864: register INODE *ip; ! 865: IO io; ! 866: ! 867: /* Check file descriptor */ ! 868: if ((fdp = fdget (fd)) == NULL) ! 869: return 0; ! 870: ! 871: if ((fdp->f_flag & IPR) == 0) { ! 872: u.u_error = EBADF; ! 873: return 0; ! 874: } ! 875: ! 876: ip = fdp->f_ip; ! 877: if ((ip->i_mode & IFMT) != IFDIR) { ! 878: u.u_error = EBADF; ! 879: return 0; ! 880: } ! 881: ! 882: ilock (ip); /* We do not want file changes during the read */ ! 883: ! 884: io.io_seg = IOSYS; ! 885: io.io_seek = fdp->f_seek; ! 886: io.io.vbase = bp; ! 887: io.io_ioc = n; ! 888: io.io_flag = 0; ! 889: ! 890: if ((fdp->f_flag & IPNDLY) != 0) ! 891: io.io_flag |= IONDLY; ! 892: ! 893: if ((fdp->f_flag & IPNONBLOCK) != 0) ! 894: io.io_flag |= IONONBLOCK; ! 895: ! 896: iread (ip, & io); ! 897: iacc (ip); /* read - atime */ ! 898: ! 899: n -= io.io_ioc; ! 900: * offset = fdp->f_seek; ! 901: fdp->f_seek += n; ! 902: ! 903: iunlock (ip); ! 904: return n; ! 905: } ! 906: ! 907: /* ! 908: * Get file system information by file name. ! 909: */ ! 910: ustatfs(path, stfs, len, fstyp) ! 911: char *path; /* File name */ ! 912: struct statfs *stfs; /* Pointer to a user structure */ ! 913: int len; /* Size of the structure */ ! 914: int fstyp; /* File system type */ ! 915: { ! 916: struct filsys *statmount(); /* Get mp for mounted device */ ! 917: struct filsys *statunmount(); /* Get mp for unmounted device */ ! 918: struct filsys *sb; /* Pointer to superblock */ ! 919: int count = 0; /* Number of copied bytes */ ! 920: short systype = 1; /* System type */ ! 921: long bsize = BSIZE; /* Block size */ ! 922: long frsize = 0; /* Fragment size */ ! 923: ! 924: /* Check if stfs is an available user area. */ ! 925: if (! useracc ((char *) stfs, len, 1)) { ! 926: SET_U_ERROR (EFAULT, "ustatfs 0"); ! 927: return; ! 928: } ! 929: ! 930: /* Filesystem type is 1 for 512 bytes blocks. */ ! 931: count += sizeof (systype); ! 932: if (count > len) { ! 933: SET_U_ERROR (EFAULT, "ustatfs 1"); ! 934: return; ! 935: } ! 936: if (! kucopy (& systype, & stfs->f_fstyp, sizeof (systype))) ! 937: return; ! 938: ! 939: /* Block size */ ! 940: count += sizeof (bsize); ! 941: if (count > len) { ! 942: SET_U_ERROR (EFAULT, "ustatfs 2"); ! 943: return; ! 944: } ! 945: if (! kucopy (& bsize, & stfs->f_bsize, sizeof (bsize))) ! 946: return; ! 947: ! 948: /* Fragment size. */ ! 949: count += sizeof (int); ! 950: if (count > len) { ! 951: SET_U_ERROR (EFAULT, "ustatfs 3"); ! 952: return; ! 953: } ! 954: if (! kucopy (& frsize, & stfs->f_frsize, sizeof (frsize))) ! 955: return; ! 956: ! 957: if (! fstyp) { ! 958: if ((sb = statmount (-1, path)) == NULL) ! 959: return; ! 960: devinfo (sb, stfs, len, & count); ! 961: } else { ! 962: if ((sb = statunmount (-1, path)) == NULL) ! 963: return; ! 964: devinfo (sb, stfs, len, & count); ! 965: kfree (sb); ! 966: } ! 967: return 0; ! 968: } ! 969: ! 970: /* ! 971: * statmount - get superblock for mounted file system. ! 972: * fd - file descriptor or -1, path - file name or NULL. ! 973: */ ! 974: struct filsys *statmount(fd, path) ! 975: int fd; ! 976: char *path; ! 977: { ! 978: register INODE *ip; /* Structure inode */ ! 979: register FD *fdp; ! 980: register MOUNT *mp; /* Pointer to device */ ! 981: dev_t device; /* Mounted device */ ! 982: ! 983: /* Find the device */ ! 984: if (path) { /* Find ip by file name */ ! 985: IO io; ! 986: struct direct dir; ! 987: ! 988: io.io_seg = IOUSR; ! 989: if (ftoi (path, 'r', & io, & dir)) { ! 990: /* If ftoi returned nonzero, it also set u.u_error. */ ! 991: return NULL; ! 992: } ! 993: ip = u.u_cdiri; ! 994: device = ip->i_dev; ! 995: idetach(ip); ! 996: } else { /* Find ip by file descriptor */ ! 997: if ((fdp = fdget (fd)) == NULL) ! 998: return NULL; ! 999: if ((fdp->f_flag & IPR) == 0) { ! 1000: SET_U_ERROR (EBADF, "statmount 1"); ! 1001: return NULL; ! 1002: } ! 1003: ip = fdp->f_ip; ! 1004: device = ip->i_dev; ! 1005: } ! 1006: ! 1007: /* Take mount filesystem, check if dev is mounted device */ ! 1008: for (mp = mountp; mp != NULL; mp = mp->m_next) ! 1009: if (mp->m_dev == device) ! 1010: break; ! 1011: ! 1012: if (mp == NULL) { ! 1013: u.u_error = EINVAL; ! 1014: return NULL; ! 1015: } ! 1016: return & mp->m_super; ! 1017: } ! 1018: ! 1019: /* ! 1020: * devinfo() write system information to user area ! 1021: */ ! 1022: devinfo(sb, stfs, len, count) ! 1023: struct filsys *sb; /* File name */ ! 1024: struct statfs *stfs; /* Pointer to a user structure */ ! 1025: int len; /* Size of the structure */ ! 1026: int *count; ! 1027: { ! 1028: long inode; ! 1029: ! 1030: /* Total number of blocks */ ! 1031: * count += sizeof (sb->s_fsize); ! 1032: if (* count > len) ! 1033: return; ! 1034: ! 1035: if (! kucopy (& sb->s_fsize, & stfs->f_blocks, sizeof (sb->s_fsize))) ! 1036: return; ! 1037: ! 1038: /* Count of free blocks */ ! 1039: * count += sizeof (sb->s_tfree); ! 1040: if (* count > len) ! 1041: return; ! 1042: if (! kucopy (& sb->s_tfree, & stfs->f_bfree, sizeof (sb->s_tfree))) ! 1043: return; ! 1044: ! 1045: /* Total number of file inodes */ ! 1046: * count += sizeof (inode); ! 1047: if (* count > len) ! 1048: return; ! 1049: ! 1050: inode = (long) (sb->s_isize - INODEI) * INOPB; ! 1051: if (! kucopy (& inode, & stfs->f_files, sizeof (inode))) ! 1052: return; ! 1053: ! 1054: /* Number of free inodes */ ! 1055: * count += sizeof(inode); ! 1056: if (* count > len) ! 1057: return; ! 1058: inode = sb->s_tinode; ! 1059: if (! kucopy (& inode, & stfs->f_ffree, sizeof (inode))) ! 1060: return; ! 1061: ! 1062: /* Volume name */ ! 1063: * count += sizeof (sb->s_fname); ! 1064: if (* count > len) ! 1065: return; ! 1066: if (! kucopy (sb->s_fname, stfs->f_fname, sizeof (sb->s_fpack))) ! 1067: return; ! 1068: ! 1069: /* Pack name */ ! 1070: * count += sizeof(sb->s_fpack); ! 1071: if (* count > len) ! 1072: return; ! 1073: if (! kucopy (sb->s_fpack, stfs->f_fpack, sizeof (sb->s_fpack))) ! 1074: return; ! 1075: } ! 1076: ! 1077: /* ! 1078: * statunmount - get superblock for unmounted file system. ! 1079: * fd - file descriptor or -1, path - file name or NULL. ! 1080: */ ! 1081: struct filsys *statunmount(fd, path) ! 1082: int fd; /* File descriptor */ ! 1083: char *path; /* File name */ ! 1084: { ! 1085: register INODE *ip; ! 1086: register MOUNT *mp; ! 1087: register dev_t rdev; ! 1088: FD *fdp; ! 1089: int mode; ! 1090: BUF *bp; ! 1091: struct filsys *sb; ! 1092: ! 1093: /* Find the device */ ! 1094: if (path) { /* Find ip by file name */ ! 1095: IO io; ! 1096: struct direct dir; ! 1097: ! 1098: if (ftoi (path, 'r', & io, & dir)) ! 1099: return NULL; ! 1100: ip = u.u_cdiri; ! 1101: mode = ip->i_mode; ! 1102: rdev = ip->i_a.i_rdev; ! 1103: idetach (ip); ! 1104: } else { /* Find ip by file descriptor */ ! 1105: if ((fdp = fdget(fd)) == NULL) ! 1106: return NULL; ! 1107: if ((fdp->f_flag & IPR) == 0) { ! 1108: u.u_error = EBADF; ! 1109: return NULL; ! 1110: } ! 1111: ip = fdp->f_ip; ! 1112: ilock (ip); ! 1113: mode = ip->i_mode; ! 1114: rdev = ip->i_a.i_rdev; ! 1115: iunlock (ip); ! 1116: } ! 1117: ! 1118: /* Check for block special device */ ! 1119: if ((mode & IFMT) != IFBLK) { ! 1120: u.u_error = ENOTBLK; ! 1121: return NULL; ! 1122: } ! 1123: ! 1124: /* Check if device is mounted device */ ! 1125: for (mp = mountp; mp != NULL; mp = mp->m_next) { ! 1126: if (mp->m_dev == rdev) { ! 1127: u.u_error = EBUSY; ! 1128: return NULL; ! 1129: } ! 1130: } ! 1131: ! 1132: dopen (rdev, IPR, DFBLK); ! 1133: if (u.u_error) ! 1134: return NULL; ! 1135: ! 1136: /* ! 1137: * NIGEL: Modified for new dclose (). ! 1138: */ ! 1139: ! 1140: bp = bread (rdev, (daddr_t) SUPERI, BUF_SYNC); ! 1141: dclose (rdev, IPR, DFBLK); ! 1142: ! 1143: if (bp == NULL) ! 1144: return NULL; ! 1145: ! 1146: if ((sb = kalloc (sizeof (struct filsys))) == NULL) ! 1147: return NULL; ! 1148: ! 1149: memcpy (sb, bp->b_vaddr, sizeof (struct filsys)); ! 1150: brelease (bp); ! 1151: ! 1152: cansuper (sb); /* canonicalize superblock */ ! 1153: if (tstf (sb) == 0) { /* check for consistency */ ! 1154: kfree (sb); ! 1155: u.u_error = EINVAL; ! 1156: return NULL; ! 1157: } ! 1158: return sb; ! 1159: } ! 1160: ! 1161: /* ! 1162: * Get file system information by file descriptor ! 1163: */ ! 1164: ufstatfs(fildes, stfs, len, fstyp) ! 1165: int fildes; /* File descriptor */ ! 1166: struct statfs *stfs; /* Pointer to a user structure */ ! 1167: int len; /* Size of the structure */ ! 1168: int fstyp; /* File system type */ ! 1169: { ! 1170: struct filsys *statmount(); /* Get mp for mounted device */ ! 1171: struct filsys *statunmount(); /* Get mp for unmounted device */ ! 1172: struct filsys *sb; /* Pointer to superblock */ ! 1173: int count = 0; /* Number of copied bytes */ ! 1174: short systype = 1; /* System type */ ! 1175: long bsize = BSIZE; /* Block size */ ! 1176: long frsize = 0; /* Fragment size */ ! 1177: ! 1178: /* Check if stfs is an available user area. */ ! 1179: if (! useracc ((char *) stfs, len)) { ! 1180: u.u_error = EFAULT; ! 1181: return; ! 1182: } ! 1183: ! 1184: /* Filesystem type is 1 for 512 bytes blocks. */ ! 1185: count += sizeof (systype); ! 1186: if (count > len) { ! 1187: SET_U_ERROR (EFAULT, "ufstatfs 0"); ! 1188: return; ! 1189: } ! 1190: if (! kucopy (& systype, & stfs->f_fstyp, sizeof (systype))) ! 1191: return; ! 1192: ! 1193: /* Block size */ ! 1194: count += sizeof (bsize); ! 1195: if (count > len) { ! 1196: SET_U_ERROR (EFAULT, "ufstatfs 1"); ! 1197: return; ! 1198: } ! 1199: if (! kucopy (& bsize, & stfs->f_bsize, sizeof (bsize))) ! 1200: return; ! 1201: ! 1202: /* Fragment size. */ ! 1203: count += sizeof (int); ! 1204: if (count > len) { ! 1205: SET_U_ERROR (EFAULT, "ufstatfs 2"); ! 1206: return; ! 1207: } ! 1208: if (! kucopy (& frsize, & stfs->f_frsize, sizeof (frsize))) ! 1209: return; ! 1210: ! 1211: if (! fstyp) { ! 1212: if ((sb = statmount (fildes, NULL)) == NULL) ! 1213: return; ! 1214: devinfo (sb, stfs, len, & count); ! 1215: } else { ! 1216: if ((sb = statunmount (fildes, NULL)) == NULL) ! 1217: return; ! 1218: devinfo (sb, stfs, len, & count); ! 1219: kfree (sb); ! 1220: } ! 1221: return 0; ! 1222: } ! 1223: ! 1224: /* ! 1225: * Check superblock for consistency. ! 1226: */ ! 1227: ! 1228: tstf(fp) ! 1229: register struct filsys *fp; ! 1230: { ! 1231: register daddr_t *dp; ! 1232: register ino_t *ip; ! 1233: register ino_t maxinode; ! 1234: ! 1235: maxinode = (fp->s_isize - INODEI) * INOPB + 1; ! 1236: if (fp->s_isize >= fp->s_fsize) ! 1237: return 0; ! 1238: if (fp->s_tfree < fp->s_nfree || ! 1239: fp->s_tfree >= fp->s_fsize - fp->s_isize + 1) ! 1240: return 0; ! 1241: if (fp->s_tinode < fp->s_ninode || fp->s_tinode >= maxinode - 1) ! 1242: return 0; ! 1243: ! 1244: for (dp = fp->s_free ; dp < fp->s_free + fp->s_nfree ; dp += 1) ! 1245: if (* dp < fp->s_isize || * dp >= fp->s_fsize) ! 1246: return 0; ! 1247: ! 1248: for (ip = fp->s_inode ; ip < fp->s_inode + fp->s_ninode ; ip += 1) ! 1249: if (* ip < 1 || * ip > maxinode) ! 1250: return 0; ! 1251: return 1; ! 1252: } ! 1253: ! 1254: /* the following calls are not in the BCS */ ! 1255: ! 1256: uadmin() ! 1257: { ! 1258: u.u_error = EINVAL; ! 1259: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.