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