|
|
1.1 ! root 1: /* ! 2: * uumkdir.c ! 3: * ! 4: * Makes directories for uucico to write in. ! 5: * ! 6: */ ! 7: ! 8: #include <sys/stat.h> ! 9: #include <sys/dir.h> ! 10: #include <sys/ino.h> ! 11: #include <pwd.h> ! 12: #include <signal.h> ! 13: #include <errno.h> ! 14: #include "dcp.h" ! 15: ! 16: #ifndef NULL ! 17: #define NULL ((char*) 0) ! 18: #endif ! 19: ! 20: #ifndef TRUE ! 21: #define TRUE (0 == 0) ! 22: #endif ! 23: ! 24: #define MAXDIR 32 ! 25: #define equal(s1, s2) (strcmp(s1, s2) == 0) ! 26: ! 27: /* ! 28: * Masks by types of permissions. ! 29: */ ! 30: #define AEXEC (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)) ! 31: #define AREAD (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6)) ! 32: #define AWRITE (S_IWRITE|(S_IWRITE>>3)|(S_IWRITE>>6)) ! 33: #define ASUID (S_ISUID|S_ISGID) ! 34: #define ATEXT S_ISVTX ! 35: ! 36: /* ! 37: * Masks by types of users. ! 38: */ ! 39: #define AOWN (S_ISUID|S_ISVTX|S_IREAD|S_IWRITE|S_IEXEC) ! 40: #define AGRP (S_ISGID|S_ISVTX|(S_IREAD>>3)|(S_IWRITE>>3)|(S_IEXEC>>3)) ! 41: #define AOTH (S_ISVTX|(S_IREAD>>6)|(S_IWRITE>>6)|(S_IEXEC>>6)) ! 42: #define AALL (AOWN|AGRP|AOTH) ! 43: ! 44: typedef ! 45: struct inpdir_s { ! 46: char * dir; /* dir string entered */ ! 47: char * start; /* start of new dir in string */ ! 48: char * end; /* end of dir string */ ! 49: char * p; /* end of current parent string */ ! 50: char * c; /* end of current child string */ ! 51: } inpdir_t; ! 52: ! 53: char usage[] = "Usage: uumkdir [ -m mode ] [ -p ] dir ...\n"; ! 54: char badsm[] = "uumkdir: badly formed symbolic mode\n"; ! 55: char badom[] = "uumkdir: badly formed octal mode\n"; ! 56: ! 57: long int new; /* bit-wise child dir condition */ ! 58: short uid; /* user ID */ ! 59: int interrupted; /* interrupt flag */ ! 60: int endflag; /* end od dir string flag */ ! 61: int pflag; /* p option flag */ ! 62: int mflag; /* m option flag */ ! 63: int mode = 0755; /* initial mode setup for m option */ ! 64: ! 65: extern char *malloc(); ! 66: extern char *strcpy(); ! 67: extern char *strncpy(); ! 68: extern char *strcat(); ! 69: ! 70: /* ! 71: * Interrupts are handled to prevent the formation of mangled directories. ! 72: */ ! 73: ! 74: main(argc, argv) ! 75: int argc; ! 76: register char ** argv; ! 77: ! 78: { ! 79: register int status = 0; /* condition of mkdir: ! 80: 0 - success, 1 - error */ ! 81: inpdir_t dirs; /* structure with dir string info */ ! 82: char * end; /* pointer to end of dir string */ ! 83: ! 84: extern void fatal(); ! 85: extern int catch(); ! 86: extern int readmode(); ! 87: extern int mkpath(); ! 88: extern int error(); ! 89: ! 90: if ( (setuid(0) < 0) || (setgid(0) < 0) ) ! 91: fatal("uumkdir must be executed setuid root\n"); ! 92: ! 93: catch(SIGINT); ! 94: catch(SIGHUP); ! 95: signal(SIGQUIT, SIG_IGN); ! 96: ! 97: while((--argc > 0) && ((*++argv)[0] == '-')) { ! 98: switch((*argv)[1]) { ! 99: case 'p': ! 100: if (pflag) ! 101: fatal(usage); ! 102: pflag = TRUE; ! 103: break; ! 104: case 'm': ! 105: if (mflag || (--argc <= 0)) ! 106: fatal(usage); ! 107: uid = getuid(); ! 108: mflag = TRUE; ! 109: mode = readmode(*++argv, mode); ! 110: break; ! 111: case 'v': ! 112: case 'V': ! 113: fatal("uumkdir: Version %s", VERSION); ! 114: default: ! 115: fatal(usage); ! 116: } ! 117: } ! 118: if (argc <= 0) ! 119: fatal(usage); ! 120: else { ! 121: for(; *argv ; ++argv) { ! 122: if (dirs.dir) ! 123: free(dirs.dir); ! 124: for(end = *argv ; *end != '\0' ; ++end) ! 125: ; ! 126: do { ! 127: if (end == *argv) { ! 128: error("bad argument (empty string)", 0); ! 129: exit(1); ! 130: } ! 131: } while(*--end == '/'); ! 132: *++end = '\0'; ! 133: if ((dirs.dir = malloc(end - *argv + 1)) == NULL) { ! 134: error("out of memory ", 0); ! 135: exit(1); ! 136: } ! 137: strcpy(dirs.dir, *argv); ! 138: dirs.end = dirs.dir + (end - *argv); ! 139: if (mkpath(&dirs) < 0) ! 140: status = 1; /* error */ ! 141: if (interrupted) ! 142: exit(1); ! 143: } ! 144: } ! 145: exit(status); ! 146: } ! 147: ! 148: /** ! 149: * int ! 150: * mkpath(pdir) ! 151: * inpdir_t * pdir; ! 152: * ! 153: * Input: pdir - pointer to structure. ! 154: * ! 155: * Action: Create new directory and all necessary directories ! 156: * to new directory. ! 157: * ! 158: * Return: 0 if all directory creations are successful, else -1. ! 159: * ! 160: * Note: All directories created before an error is ! 161: * encountered are not removed from user's file. ! 162: */ ! 163: ! 164: int ! 165: mkpath(pdir) ! 166: inpdir_t * pdir; ! 167: { ! 168: register char * childnam; /* dir name of child */ ! 169: register char * child; /* path name of child */ ! 170: register char * parent; /* path name of parent */ ! 171: register int n; ! 172: int err; /* error response from dir creation */ ! 173: int numdir; /* number of directories minus first ! 174: parent specified in full path name */ ! 175: extern char * getparent(); ! 176: extern char * getchild(); ! 177: extern char * getpath(); ! 178: extern int mkdir(); ! 179: extern int setmod(); ! 180: extern int error(); ! 181: ! 182: numdir = 0; ! 183: new = 0L; ! 184: endflag = !TRUE; ! 185: ! 186: if ((child = malloc(pdir->end - pdir->dir + 1)) == NULL) ! 187: return(error("out of memory ", 0)); ! 188: parent = getparent(pdir); ! 189: n = pdir->start - pdir->dir; ! 190: strncpy(child, pdir->dir, n); ! 191: child[n] = '\0'; ! 192: do { ! 193: ++numdir; ! 194: if ((int)(childnam = getchild(pdir)) < 0) { ! 195: error("can't get dir name ", pdir->dir, 0); ! 196: break; ! 197: } ! 198: child = getpath(pdir, child); ! 199: if (pdir->c == pdir->end) { ! 200: /* Last child declared cannot be "." or "..". */ ! 201: if (equal(childnam, ".") || equal(childnam, "..")) { ! 202: error(pdir->dir," not allowed", 0); ! 203: break; ! 204: } ! 205: /* Signal end of dir string. */ ! 206: endflag = TRUE; ! 207: if (mkdir(parent, child) == -1) ! 208: break; ! 209: /* Signal new dir. */ ! 210: new = (new << 1) | 1L; ! 211: numdir += MAXDIR; ! 212: } else { ! 213: new = (new << 1) | 0L; ! 214: if (!equal(childnam, ".") && !equal(childnam, "..")) { ! 215: if ((err = mkdir(parent, child)) == -1) ! 216: break; ! 217: else if (err == 0) ! 218: new |= 1L; ! 219: } ! 220: } ! 221: /* Get next parent. */ ! 222: parent = getpath(pdir, parent); ! 223: pdir->p = pdir->c; ! 224: } while(numdir <= MAXDIR); ! 225: /* Set user-selected mode if available. */ ! 226: if (mflag) { ! 227: if (setmod(parent, numdir, pdir->start, (pdir->p - 1)) < 0) ! 228: return(-1); ! 229: } ! 230: if (numdir > MAXDIR) ! 231: return(0); ! 232: else ! 233: return(-1); ! 234: } ! 235: ! 236: /** ! 237: * int ! 238: * setmod(ch, ndir, start, p) ! 239: * char * ch; ! 240: * char * start; ! 241: * char * p; ! 242: * int ndir; ! 243: * ! 244: * Input: ch - string holding all new dir names. ! 245: * start - start of new dir. ! 246: * p - end of new dir. ! 247: * ndir - number of directories tested. ! 248: * ! 249: * Action: Set mode of all new directories created. ! 250: * ! 251: * Return: 0 if all mode setups are successful, else -1. ! 252: * ! 253: * Note: None. ! 254: */ ! 255: ! 256: int ! 257: setmod(ch, ndir, start, p) ! 258: char * ch; ! 259: char * start; ! 260: char * p; ! 261: int ndir; ! 262: { ! 263: char * c; /* pointer to end of dir string */ ! 264: /* Get pointer to end of string. */ ! 265: for(c = ch ; *c != '\0' ; ++c) ! 266: ; ! 267: if (ndir > MAXDIR) ! 268: ndir -= (MAXDIR - 1); ! 269: /* Reset to mode desired. */ ! 270: while(--ndir > 0) { ! 271: /* Change dir mode if new directory. */ ! 272: if ((new & 01L) == 1L) ! 273: if (chmod(ch, mode) < 0) { ! 274: write(2, ch, (c - ch)); ! 275: write(2, ": ", 2); ! 276: write(2, sys_errlist[ errno ], ! 277: strlen(sys_errlist[ errno ])); ! 278: write(2, "\n", 1); ! 279: return(-1); ! 280: } ! 281: new = new >> 1; ! 282: /* Remove current dir name from string. */ ! 283: for(++p ; (--p >= start) && (*p != '/') ; *--c = '\0') ! 284: ; ! 285: /* Remove trailing slashes. */ ! 286: for(++p ; (--p >= start) && (*p == '/') ; *--c = '\0') ! 287: ; ! 288: } ! 289: return(0); ! 290: } ! 291: ! 292: /** ! 293: * char * ! 294: * getparent(pdir) ! 295: * inpdir_t * pdir; ! 296: * ! 297: * Input: pdir - pointer to structure. ! 298: * ! 299: * Action: Get parent to directory currently working on. ! 300: * ! 301: * Return: Pointer to parent string. ! 302: * ! 303: * Note: None. ! 304: */ ! 305: ! 306: char * ! 307: getparent(pdir) ! 308: inpdir_t * pdir; ! 309: { ! 310: int found; /* 0: parent found, -1: parent not found */ ! 311: int size; /* size of dir string in structure */ ! 312: char * par; /* pointer to parent string */ ! 313: char * tail; /* pointer to end of parent string */ ! 314: extern int error(); ! 315: ! 316: size = pdir->end - pdir->dir; ! 317: if ((par = malloc(size + 3)) == NULL) { ! 318: error("out of memory ", 0); ! 319: exit(1); ! 320: } ! 321: /* Copy structure string to parent and set tail to end of ! 322: * parent string. ! 323: */ ! 324: strcpy(par, pdir->dir); ! 325: tail = par + size; ! 326: /* Search for parent string. */ ! 327: do { ! 328: /* Remove last dir name in string. */ ! 329: for(; (--tail >= par) && (*tail != '/') ; *tail = '\0') ! 330: ; ! 331: /* Remove trailing slashes. */ ! 332: for(++tail ; (--tail > par) && (*tail == '/') ; *tail = '\0') ! 333: ; ! 334: /** Substitute "." for null path. */ ! 335: if (++tail == par) { ! 336: *tail = '.'; ! 337: *(tail + 1) = '/'; ! 338: } ! 339: if ((found = access(par, 03)) == -1) ! 340: switch(errno) { ! 341: case ENOENT: ! 342: break; ! 343: case EACCES: ! 344: error("no permission to mkdir in ", par, 0); ! 345: exit(1); ! 346: default: ! 347: error("can't make ", pdir->dir, 0); ! 348: exit(1); ! 349: } ! 350: } while((found == -1) && pflag); ! 351: /* Set start of first child and pointer to end of first parent. */ ! 352: pdir->start = pdir->p = pdir->dir + (tail - par); ! 353: return(par); ! 354: } ! 355: ! 356: /** ! 357: * char * ! 358: * getchild(pdir) ! 359: * inpdir_t * pdir; ! 360: * ! 361: * Input: pdir - pointer to structure. ! 362: * ! 363: * Action: Get current child dir name. ! 364: * ! 365: * Return: Pointer to child dir name. ! 366: * ! 367: * Note: If dir name found exceeds DIRSIZ in length, it will be ! 368: * truncated to DIRSIZ. ! 369: */ ! 370: ! 371: char * ! 372: getchild(pdir) ! 373: inpdir_t * pdir; ! 374: { ! 375: static char nam[ DIRSIZ + 1 ]; /* dir name of child */ ! 376: char * c; /* pointer to end of child name */ ! 377: int i, j; /* working counters */ ! 378: /* Increment to start of next dir name. */ ! 379: for(i = 0, c = pdir->p ; (c < pdir->end) && (*c == '/') ; ++i, ++c) ! 380: ; ! 381: /* Increment to end of dir name. */ ! 382: for(j = 0 ; (c < pdir->end) && (*c != '/') ; ++j, ++c) ! 383: ; ! 384: pdir->c = c; ! 385: /* Copy up to DIRSIZ length of child dir name to static memory. */ ! 386: if (j > DIRSIZ) ! 387: j = DIRSIZ; ! 388: strncpy(nam, pdir->p + i, j); ! 389: nam[j] = '\0'; ! 390: return(nam); ! 391: } ! 392: ! 393: /** ! 394: * char * ! 395: * getpath(pdir, dir) ! 396: * inpdir_t * pdir; ! 397: * char * dir; ! 398: * ! 399: * Input: pdir - pointer to structure. ! 400: * dir - current path name. ! 401: * Action: Get current path name of child. ! 402: * Return: Pointer to current path name. ! 403: * Note: None. ! 404: */ ! 405: ! 406: char * ! 407: getpath(pdir, dir) ! 408: inpdir_t * pdir; ! 409: char * dir; ! 410: { ! 411: strncat(dir, pdir->p, (pdir->c - pdir->p)); ! 412: return(strcat(dir, "\0")); ! 413: } ! 414: ! 415: /** ! 416: * int ! 417: * mkdir(parent, child) ! 418: * char * parent; ! 419: * char * child; ! 420: * ! 421: * Input: parent - pointer to dir path name to parent. ! 422: * child - pointer to dir path name to child. ! 423: * Action: Make a directory. If the parent exists and is writeable, ! 424: * the directory and its "." and ".." links are created. ! 425: * Return: 0 if successful, 1 if dir existed already and dir is ! 426: * not the last dir in string. Else -1. ! 427: * Note: None. ! 428: */ ! 429: ! 430: int ! 431: mkdir(parent, child) ! 432: char * parent; ! 433: char * child; ! 434: { ! 435: extern char * concat(); ! 436: extern int linkerr(); ! 437: extern int error(); ! 438: struct passwd *pw; ! 439: ! 440: /* Test if parent file is accessible by user. */ ! 441: if (access(parent, 03)) ! 442: switch(errno) { ! 443: case ENOENT: ! 444: error("parent dir ", parent, " doesn't exist", 0); ! 445: return(-1); ! 446: case EACCES: ! 447: error("no permission to mkdir in ", parent, 0); ! 448: return(-1); ! 449: default: ! 450: return(error("can't make ", child, 0)); ! 451: } ! 452: /* Creat new directory. */ ! 453: if (mknod(child, IFDIR | 0777, 0)) { ! 454: switch(errno) { ! 455: case EEXIST: ! 456: if (endflag) ! 457: return(error(child, " already exists", 0)); ! 458: else ! 459: return(1); ! 460: case EPERM: ! 461: return(error("not the super-user", 0)); ! 462: default: ! 463: return(error("can't make ", child, 0)); ! 464: } ! 465: } ! 466: if (link(child, concat(child, "/."))) ! 467: return(linkerr(child, ".")); ! 468: if (link(parent, concat(child, "/.."))) ! 469: return(linkerr(child, "..")); ! 470: /* Set ownership of directory to user. */ ! 471: if ((pw = getpwnam("uucp")) == NULL) ! 472: return -1; ! 473: if (chown(child, pw->pw_uid, pw->pw_gid) < 0) ! 474: return -1; ! 475: return(0); ! 476: } ! 477: ! 478: /** ! 479: * char * ! 480: * concat(s1, s2) ! 481: * char * s1, * s2; ! 482: * Input: s1, s2 - strings to be concatenated. ! 483: * Action: Join string s2 to string s1 to form a new string. ! 484: * Return: Pointer to start of concatenation of `s1' and `s2'. ! 485: * Note: None. ! 486: */ ! 487: ! 488: char * ! 489: concat(s1, s2) ! 490: char * s1; ! 491: char * s2; ! 492: { ! 493: static char * str; ! 494: if (str) ! 495: free(str); ! 496: /* Allocate memory space for concatenated string. */ ! 497: if ((str = malloc(strlen(s1) + strlen(s2) + 1)) == NULL) { ! 498: error("out of memory", 0); ! 499: exit(1); ! 500: } ! 501: strcpy(str, s1); ! 502: return(strcat(str, s2)); ! 503: } ! 504: ! 505: /** ! 506: * int ! 507: * linkerr(dir, name) ! 508: * char * dir; ! 509: * char * name; ! 510: * ! 511: * input: dir - directory where linking failed. ! 512: * name - type of link failed, "." or "..". ! 513: * Action: Recover from link failure. In the event that "." or ".." ! 514: * cannot be created, remove all traces of the directory. ! 515: * return: -1. ! 516: * Note: none. ! 517: */ ! 518: ! 519: int ! 520: linkerr(dir, name) ! 521: char * dir; ! 522: char * name; ! 523: { ! 524: extern char * concat(); ! 525: extern int error(); ! 526: ! 527: unlink(concat(dir, "/.")); ! 528: unlink(concat(dir, "/..")); ! 529: unlink(dir); ! 530: return(error("link to '", name, "' failed", 0)); ! 531: } ! 532: ! 533: /** ! 534: * int ! 535: * onintr() ! 536: * ! 537: * Input: None. ! 538: * Action: Reset SIGINT and SIGHUP and set interrupt counter. ! 539: * Return: Pointer to previous action on success, else -1. ! 540: * Note: None. ! 541: */ ! 542: ! 543: int ! 544: onintr() ! 545: { ! 546: signal(SIGINT, SIG_IGN); ! 547: signal(SIGHUP, SIG_IGN); ! 548: ++interrupted; ! 549: } ! 550: ! 551: /** ! 552: * int ! 553: * catch(sig) ! 554: * ! 555: * Input: sig - signal caught. ! 556: * Action: Reset signals. ! 557: * Return: Pointer to previous action on success, else -1. ! 558: * Note: None. ! 559: */ ! 560: ! 561: int ! 562: catch(sig) ! 563: { ! 564: extern int onintr(); ! 565: if (signal(sig, SIG_IGN) == SIG_DFL) ! 566: signal(sig, onintr); ! 567: } ! 568: ! 569: /** ! 570: * int ! 571: * error(arg1) ! 572: * char * arg1; ! 573: * ! 574: * Input: arg1 - error message string. ! 575: * Action: Display error message. ! 576: * Return: -1. ! 577: * Note: None. ! 578: */ ! 579: ! 580: int ! 581: error(arg1) ! 582: char * arg1; ! 583: { ! 584: register char ** p; ! 585: write(2, "mkdir: ", 7); ! 586: for(p = &arg1 ; *p != 0 ; ++p) ! 587: write(2, *p, strlen(*p)); ! 588: write(2, "\n", 1); ! 589: return(-1); ! 590: } ! 591: ! 592: /** ! 593: * int ! 594: * readmode(s, mode) ! 595: * char * s; ! 596: * int mode; ! 597: * ! 598: * Input: s - string containing setting changes. ! 599: * mode - current setting of permission. ! 600: * Action: Read in the symbolic mode and set the variables `who', `op', ! 601: * and `mode'. Knows about the old octal modes as well. ! 602: * Return: New mode. ! 603: * Note: None. ! 604: */ ! 605: ! 606: int ! 607: readmode(s, mode) ! 608: register char * s; ! 609: int mode; ! 610: { ! 611: register int c; ! 612: register int op; ! 613: register int m1, m2; ! 614: extern void fatal(); ! 615: extern void checkmode(); ! 616: extern int getumask(); ! 617: extern int mrepl(); ! 618: ! 619: if ((*s >= '0') && (*s <= '7')) { ! 620: mode = 0; ! 621: while(*s != '\0') { ! 622: if ((*s < '0') || (*s > '7')) ! 623: fatal(badom); ! 624: mode = (mode << 3) | (*s++)-'0'; ! 625: } ! 626: checkmode(mode); ! 627: return(mode); ! 628: } ! 629: newsym: ! 630: for(m1 = 0 ;;) { ! 631: switch(*s++) { ! 632: case 'u': m1 |= AOWN; continue; ! 633: case 'g': m1 |= AGRP; continue; ! 634: case 'o': m1 |= AOTH; continue; ! 635: case 'a': m1 |= AALL; continue; ! 636: default : s--; break; ! 637: } ! 638: break; ! 639: } ! 640: if (m1 == 0) ! 641: m1 = AALL & ~getumask(); ! 642: newop: ! 643: if (((c = *s++) == '=') || (c == '+') || (c == '-')) ! 644: op = c; ! 645: else ! 646: fatal(badsm); ! 647: for(m2 = 0 ;;) { ! 648: switch(*s++) { ! 649: case 'r': m2 |= AREAD; continue; ! 650: case 'w': m2 |= AWRITE; continue; ! 651: case 'x': m2 |= AEXEC; continue; ! 652: case 's': m2 |= ASUID; continue; ! 653: case 't': m2 |= ATEXT; continue; ! 654: case 'u': m2 |= mrepl(mode & AOWN); continue; ! 655: case 'g': m2 |= mrepl((mode & AGRP) << 3); continue; ! 656: case 'o': m2 |= mrepl((mode & AOTH) << 6); continue; ! 657: default : s--; break; ! 658: } ! 659: break; ! 660: } ! 661: switch(op) { ! 662: case '-': mode &= ~(m1 & m2); break; ! 663: case '+': mode |= m1 & m2; break; ! 664: case '=': mode = (mode & ~m1) | (m1 & m2); break; ! 665: } ! 666: if (*s == '\0') { ! 667: checkmode(mode); ! 668: return(mode); ! 669: } ! 670: if ((*s == '+') || (*s == '-') || (*s == '=')) ! 671: goto newop; ! 672: if (*s++ == ',') ! 673: goto newsym; ! 674: fatal(badsm); ! 675: } ! 676: ! 677: /** ! 678: * int ! 679: * getumask() ! 680: * ! 681: * Input: None. ! 682: * ! 683: * Action: Get the value of the umask setting. ! 684: * ! 685: * Return: ???? ! 686: * ! 687: * Note: None. ! 688: */ ! 689: ! 690: int ! 691: getumask() ! 692: ! 693: { ! 694: register int omask; ! 695: ! 696: omask = umask(0); ! 697: umask(omask); ! 698: return(omask); ! 699: } ! 700: ! 701: /** ! 702: * void ! 703: * checkmode(mode) ! 704: * int mode; ! 705: * ! 706: * Input: mode - current setup of permission. ! 707: * Action: Check the mode to see if any problem bits are on. ! 708: * For now, this is S_ISVTX for non-super-users. ! 709: * Return: None. ! 710: * Note: None. ! 711: */ ! 712: ! 713: void ! 714: checkmode(mode) ! 715: register int mode; ! 716: { ! 717: static char stickwarn[] = ! 718: "mkdir: Warning: non-super user may not set sticky bit\n"; ! 719: if ((uid != 0) && (mode & S_ISVTX)) { ! 720: write(2, stickwarn, 54); ! 721: exit(1); ! 722: } ! 723: } ! 724: ! 725: /** ! 726: * int ! 727: * mrepl(m) ! 728: * int m; ! 729: * Input: m - mode setting to be replicated. ! 730: * Action: Replicate the 3-bits of the mode from the owner ! 731: * position to all positions. ! 732: * Return: Replicated mode setup. ! 733: * Note: None. ! 734: */ ! 735: ! 736: int ! 737: mrepl(m) ! 738: register int m; ! 739: { ! 740: register int m1; ! 741: ! 742: m1 = m & AOWN; ! 743: m = m1 | (m1 >> 3) | (m1 >> 6); ! 744: if (m1 & S_ISUID) ! 745: m |= S_ISGID; ! 746: return(m); ! 747: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.