|
|
1.1 ! root 1: char *ckzv = "Unix file support, 4E(037) 27 Jan 88"; ! 2: ! 3: /* C K U F I O -- Kermit file system support for Unix systems */ ! 4: ! 5: /* 4E, conditionals added for Apollo Aegis. */ ! 6: ! 7: /* ! 8: Author: Frank da Cruz (SY.FDC@CU20B), ! 9: Columbia University Center for Computing Activities, January 1985. ! 10: Copyright (C) 1985, Trustees of Columbia University in the City of New York. ! 11: Permission is granted to any individual or institution to use, copy, or ! 12: redistribute this software so long as it is not sold for profit, provided this ! 13: copyright notice is retained. ! 14: */ ! 15: /* Includes */ ! 16: ! 17: #include <sys/types.h> /* Data types */ ! 18: #include "ckcker.h" /* Kermit definitions */ ! 19: #include "ckcdeb.h" /* Typedefs, debug formats, etc */ ! 20: #include <ctype.h> /* Character types */ ! 21: #include <stdio.h> /* Standard i/o */ ! 22: #include <sys/dir.h> /* Directory structure */ ! 23: #include <pwd.h> /* Password file for shell name */ ! 24: ! 25: #ifdef CIE ! 26: #include <stat.h> /* File status */ ! 27: #else ! 28: #include <sys/stat.h> ! 29: #endif ! 30: ! 31: ! 32: /* Berkeley Unix Version 4.x */ ! 33: /* 4.1bsd support added by Charles E Brooks, EDN-VAX */ ! 34: ! 35: #ifdef BSD4 ! 36: #ifdef MAXNAMLEN ! 37: #define BSD42 ! 38: char *ckzsys = " 4.2 BSD"; ! 39: #else ! 40: #ifdef FT18 ! 41: #define BSD41 ! 42: char *ckzsys = " Fortune For:Pro 1.8"; ! 43: #else ! 44: #define BSD41 ! 45: char *ckzsys = " 4.1 BSD"; ! 46: #endif ! 47: #endif ! 48: #endif ! 49: ! 50: /* 2.9bsd support contributed by Bradley Smith, UCLA */ ! 51: #ifdef BSD29 ! 52: char *ckzsys = " 2.9 BSD"; ! 53: #endif ! 54: ! 55: /* Version 7 Unix */ ! 56: #ifdef V7 ! 57: char *ckzsys = " Version 7 Unix"; ! 58: #endif ! 59: ! 60: /* Version 9 Unix */ ! 61: #ifdef V9 ! 62: char *ckzsys = " Version 9 Unix"; ! 63: #endif ! 64: ! 65: /* DEC Professional-300 series with Venturcom Venix v1 */ ! 66: #ifdef PROVX1 ! 67: char *ckzsys = " DEC Pro-3xx/Venix v1"; ! 68: #endif ! 69: ! 70: /* NCR Tower support contributed by John Bray, Auburn, AL. */ ! 71: /* Tower OS is like Sys III but with BSD features -- mostly follows BSD. */ ! 72: #ifdef TOWER1 ! 73: char *ckzsys = " NCR Tower 1632, OS 1.02"; ! 74: #endif ! 75: ! 76: /* Sys III/V, Xenix, PC/IX,... support by Herm Fischer, Litton Data Systems */ ! 77: #ifdef UXIII ! 78: #ifdef XENIX ! 79: char *ckzsys = " Xenix/286"; ! 80: #else ! 81: #ifdef PCIX ! 82: char *ckzsys = " PC/IX"; ! 83: #else ! 84: #ifdef ISIII ! 85: char *ckzsys = " Interactive Systems Corp, System III"; ! 86: #else ! 87: #ifdef ZILOG ! 88: char *ckzsys = " Zilog S8000 Zeus 3.21+"; ! 89: #else ! 90: char *ckzsys = " AT&T System III/System V"; ! 91: #endif ! 92: #endif ! 93: #endif ! 94: #endif ! 95: #endif ! 96: ! 97: /* Definitions of some Unix system commands */ ! 98: ! 99: char *DELCMD = "rm -f "; /* For file deletion */ ! 100: char *PWDCMD = "pwd "; /* For saying where I am */ ! 101: ! 102: #ifdef FT18 ! 103: char *DIRCMD = "ls -l | more "; /* For directory listing */ ! 104: char *TYPCMD = "more "; /* For typing a file */ ! 105: #else ! 106: char *TYPCMD = "cat "; /* For typing a file */ ! 107: char *DIRCMD = "ls -l "; /* For directory listing */ ! 108: #endif ! 109: ! 110: #ifdef FT18 ! 111: #undef BSD4 ! 112: #endif ! 113: ! 114: #ifdef BSD4 ! 115: char *SPACMD = "pwd ; quota ; df ."; /* Space/quota of current directory */ ! 116: #else ! 117: #ifdef FT18 ! 118: char #SPACMD = "pwd ; du ; df ."; ! 119: #else ! 120: char *SPACMD = "df "; ! 121: #endif ! 122: #endif ! 123: ! 124: char *SPACM2 = "df "; /* For space in specified directory */ ! 125: ! 126: #ifdef FT18 ! 127: #define BSD4 ! 128: #endif ! 129: ! 130: #ifdef BSD4 ! 131: char *WHOCMD = "finger "; /* For seeing who's logged in */ ! 132: #else ! 133: char *WHOCMD = "who "; /* For seeing who's logged in */ ! 134: #endif ! 135: ! 136: /* ! 137: Functions (n is one of the predefined file numbers from ckermi.h): ! 138: ! 139: zopeni(n,name) -- Opens an existing file for input. ! 140: zopeno(n,name) -- Opens a new file for output. ! 141: zclose(n) -- Closes a file. ! 142: zchin(n,&c) -- Gets the next character from an input file. ! 143: zsout(n,s) -- Write a null-terminated string to output file, buffered. ! 144: zsoutl(n,s) -- Like zsout, but appends a line terminator. ! 145: zsoutx(n,s,x) -- Write x characters to output file, unbuffered. ! 146: zchout(n,c) -- Add a character to an output file, unbuffered. ! 147: zchki(name) -- Check if named file exists and is readable, return size. ! 148: zchko(name) -- Check if named file can be created. ! 149: znewn(name,s) -- Make a new unique file name based on the given name. ! 150: zdelet(name) -- Delete the named file. ! 151: zxpand(string) -- Expands the given wildcard string into a list of files. ! 152: znext(string) -- Returns the next file from the list in "string". ! 153: zxcmd(cmd) -- Execute the command in a lower fork. ! 154: zclosf() -- Close input file associated with zxcmd()'s lower fork. ! 155: zrtol(n1,n2) -- Convert remote filename into local form. ! 156: zltor(n1,n2) -- Convert local filename into remote form. ! 157: zchdir(dirnam) -- Change working directory. ! 158: zhome() -- Return pointer to home directory name string. ! 159: zkself() -- Kill self, log out own job. ! 160: */ ! 161: ! 162: #ifdef FT18 ! 163: #define PROVX1 ! 164: #endif ! 165: ! 166: /* Which systems include <sys/file.h>... */ ! 167: #ifndef PROVX1 ! 168: #ifndef aegis ! 169: #ifndef CIE ! 170: #ifndef XENIX ! 171: /* Watch out, some versions of Xenix might need to do this include, */ ! 172: /* but reportedly SCO Xenix 2.2 on an 80x86 system does not. */ ! 173: #include <sys/file.h> /* File access */ ! 174: #endif ! 175: #endif ! 176: #endif ! 177: #endif ! 178: ! 179: #ifdef FT18 ! 180: #undef PROVX1 ! 181: #endif ! 182: ! 183: /* Some systems define these symbols in include files, others don't... */ ! 184: #ifndef R_OK ! 185: #define R_OK 4 /* For access */ ! 186: #endif ! 187: ! 188: #ifndef W_OK ! 189: #define W_OK 2 ! 190: #endif ! 191: ! 192: #ifdef PROVX1 ! 193: #define MAXNAMLEN DIRSIZ /* Max file name length */ ! 194: #endif ! 195: ! 196: #ifdef UXIII ! 197: #include <fcntl.h> ! 198: #define MAXNAMLEN DIRSIZ ! 199: #endif ! 200: ! 201: #ifndef O_RDONLY ! 202: #define O_RDONLY 000 ! 203: #endif ! 204: ! 205: #ifndef MAXNAMLEN ! 206: #define MAXNAMLEN 14 /* If still not defined... */ ! 207: #endif ! 208: ! 209: #ifdef PROVX1 ! 210: #define MAXWLD 50 /* Maximum wildcard filenames */ ! 211: #else ! 212: #ifdef BSD29 ! 213: #define MAXWLD 50 /* Maximum wildcard filenames */ ! 214: #else ! 215: #define MAXWLD 500 ! 216: #endif ! 217: #endif ! 218: ! 219: /* Declarations */ ! 220: ! 221: FILE *fp[ZNFILS] = { /* File pointers */ ! 222: NULL, NULL, NULL, NULL, NULL, NULL, NULL }; ! 223: ! 224: static int pid; /* pid of child fork */ ! 225: static int fcount; /* Number of files in wild group */ ! 226: static char nambuf[MAXNAMLEN+2]; /* Buffer for a filename */ ! 227: char *malloc(), *getenv(), *strcpy(); /* System functions */ ! 228: extern errno; /* System error code */ ! 229: ! 230: static char *mtchs[MAXWLD], /* Matches found for filename */ ! 231: **mtchptr; /* Pointer to current match */ ! 232: ! 233: /* Z K S E L F -- Kill Self: log out own job, if possible. */ ! 234: ! 235: /* Note, should get current pid, but if your system doesn't have */ ! 236: /* getppid(), then just kill(0,9)... */ ! 237: ! 238: zkself() { /* For "bye", but no guarantee! */ ! 239: #ifdef PROVX1 ! 240: return(kill(0,9)); ! 241: #else ! 242: #ifdef V7 ! 243: return(kill(0,9)); ! 244: #else ! 245: #ifdef V9 ! 246: return(kill(0,9)); ! 247: #else ! 248: #ifdef TOWER1 ! 249: return(kill(0,9)); ! 250: #else ! 251: #ifdef FT18 ! 252: return(kill(0,9)); ! 253: #else ! 254: #ifdef aegis ! 255: return(kill(0,9)); ! 256: #else ! 257: return(kill(getppid(),1)); ! 258: #endif ! 259: #endif ! 260: #endif ! 261: #endif ! 262: #endif ! 263: #endif ! 264: } ! 265: ! 266: /* Z O P E N I -- Open an existing file for input. */ ! 267: ! 268: zopeni(n,name) int n; char *name; { ! 269: debug(F111," zopeni",name,n); ! 270: debug(F101," fp","",(int) fp[n]); ! 271: if (chkfn(n) != 0) return(0); ! 272: if (n == ZSYSFN) { /* Input from a system function? */ ! 273: debug(F110," invoking zxcmd",name,0); ! 274: return(zxcmd(name)); /* Try to fork the command */ ! 275: } ! 276: if (n == ZSTDIO) { /* Standard input? */ ! 277: if (isatty(0)) { ! 278: ermsg("Terminal input not allowed"); ! 279: debug(F110,"zopeni: attempts input from unredirected stdin","",0); ! 280: return(0); ! 281: } ! 282: fp[ZIFILE] = stdin; ! 283: return(1); ! 284: } ! 285: fp[n] = fopen(name,"r"); /* Real file. */ ! 286: debug(F111," zopeni", name, (int) fp[n]); ! 287: if (fp[n] == NULL) perror("zopeni"); ! 288: return((fp[n] != NULL) ? 1 : 0); ! 289: } ! 290: ! 291: /* Z O P E N O -- Open a new file for output. */ ! 292: ! 293: zopeno(n,name) int n; char *name; { ! 294: debug(F111," zopeno",name,n); ! 295: if (chkfn(n) != 0) return(0); ! 296: if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */ ! 297: fp[ZOFILE] = stdout; ! 298: debug(F101," fp[]=stdout", "", (int) fp[n]); ! 299: return(1); ! 300: } ! 301: fp[n] = fopen(name,"w"); /* A real file, try to open */ ! 302: if (fp[n] == NULL) { ! 303: perror("zopeno can't open"); ! 304: } else { ! 305: chown(name, getuid(), getgid()); /* In case set[gu]id */ ! 306: if (n == ZDFILE) setbuf(fp[n],NULL); /* Debugging file unbuffered */ ! 307: } ! 308: debug(F101, " fp[n]", "", (int) fp[n]); ! 309: return((fp[n] != NULL) ? 1 : 0); ! 310: } ! 311: ! 312: /* Z C L O S E -- Close the given file. */ ! 313: ! 314: /* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */ ! 315: ! 316: zclose(n) int n; { ! 317: int x; ! 318: if (chkfn(n) < 1) return(0); /* Check range of n */ ! 319: if ((n == ZIFILE) && fp[ZSYSFN]) { /* If system function */ ! 320: x = zclosf(); /* do it specially */ ! 321: } else { ! 322: if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]); ! 323: fp[n] = NULL; ! 324: } ! 325: return((x == EOF) ? -1 : 1); ! 326: } ! 327: ! 328: /* Z C H I N -- Get a character from the input file. */ ! 329: ! 330: /* Returns -1 if EOF, 0 otherwise with character returned in argument */ ! 331: ! 332: zchin(n,c) int n; char *c; { ! 333: int a; ! 334: if (chkfn(n) < 1) return(-1); ! 335: a = getc(fp[n]); ! 336: if (a == EOF) return(-1); ! 337: *c = a & 0377; ! 338: return(0); ! 339: } ! 340: ! 341: /* Z S O U T -- Write a string to the given file, buffered. */ ! 342: ! 343: zsout(n,s) int n; char *s; { ! 344: if (chkfn(n) < 1) return(-1); ! 345: fputs(s,fp[n]); ! 346: return(0); ! 347: } ! 348: ! 349: /* Z S O U T L -- Write string to file, with line terminator, buffered */ ! 350: ! 351: zsoutl(n,s) int n; char *s; { ! 352: if (chkfn(n) < 1) return(-1); ! 353: fputs(s,fp[n]); ! 354: fputs("\n",fp[n]); ! 355: return(0); ! 356: } ! 357: ! 358: /* Z S O U T X -- Write x characters to file, unbuffered. */ ! 359: ! 360: zsoutx(n,s,x) int n, x; char *s; { ! 361: if (chkfn(n) < 1) return(-1); ! 362: /* return(write(fp[n]->_file,s,x)); */ ! 363: return(write(fileno(fp[n]),s,x)); ! 364: } ! 365: ! 366: ! 367: /* Z C H O U T -- Add a character to the given file. */ ! 368: ! 369: /* Should return 0 or greater on success, -1 on failure (e.g. disk full) */ ! 370: ! 371: zchout(n,c) int n; char c; { ! 372: if (chkfn(n) < 1) return(-1); ! 373: if (n == ZSFILE) ! 374: return(write(fileno(fp[n]),&c,1)); /* Use unbuffered for session log */ ! 375: else { /* Buffered for everything else */ ! 376: if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */ ! 377: return(ferror(fp[n])?-1:0); /* Check to make sure */ ! 378: else /* Otherwise... */ ! 379: return(0); /* There was no error. */ ! 380: } ! 381: } ! 382: ! 383: /* C H K F N -- Internal function to verify file number is ok */ ! 384: ! 385: /* ! 386: Returns: ! 387: -1: File number n is out of range ! 388: 0: n is in range, but file is not open ! 389: 1: n in range and file is open ! 390: */ ! 391: chkfn(n) int n; { ! 392: switch (n) { ! 393: case ZCTERM: ! 394: case ZSTDIO: ! 395: case ZIFILE: ! 396: case ZOFILE: ! 397: case ZDFILE: ! 398: case ZTFILE: ! 399: case ZPFILE: ! 400: case ZSFILE: ! 401: case ZSYSFN: break; ! 402: default: ! 403: debug(F101,"chkfn: file number out of range","",n); ! 404: fprintf(stderr,"?File number out of range - %d\n",n); ! 405: return(-1); ! 406: } ! 407: return( (fp[n] == NULL) ? 0 : 1 ); ! 408: } ! 409: ! 410: /* Z C H K I -- Check if input file exists and is readable */ ! 411: ! 412: /* ! 413: Returns: ! 414: >= 0 if the file can be read (returns the size). ! 415: -1 if file doesn't exist or can't be accessed, ! 416: -2 if file exists but is not readable (e.g. a directory file). ! 417: -3 if file exists but protected against read access. ! 418: */ ! 419: /* ! 420: For Berkeley Unix, a file must be of type "regular" to be readable. ! 421: Directory files, special files, and symbolic links are not readable. ! 422: */ ! 423: long ! 424: zchki(name) char *name; { ! 425: struct stat buf; ! 426: int x; long y; ! 427: ! 428: x = stat(name,&buf); ! 429: if (x < 0) { ! 430: debug(F111,"zchki stat fails",name,errno); ! 431: return(-1); ! 432: } ! 433: x = buf.st_mode & S_IFMT; /* Isolate file format field */ ! 434: if ((x != 0) && (x != S_IFREG)) { ! 435: debug(F111,"zchki skipping:",name,x); ! 436: return(-2); ! 437: } ! 438: debug(F111,"zchki stat ok:",name,x); ! 439: ! 440: if ((x = access(name,R_OK)) < 0) { /* Is the file accessible? */ ! 441: debug(F111," access failed:",name,x); /* No */ ! 442: return(-3); ! 443: } else { ! 444: y = buf.st_size; ! 445: debug(F111," access ok:",name,(int) y); /* Yes */ ! 446: return( (y > -1) ? y : 0 ); ! 447: } ! 448: } ! 449: ! 450: /* Z C H K O -- Check if output file can be created */ ! 451: ! 452: /* ! 453: Returns -1 if write permission for the file would be denied, 0 otherwise. ! 454: */ ! 455: zchko(name) char *name; { ! 456: int i, x; ! 457: char s[50], *sp; ! 458: ! 459: sp = s; /* Make a copy, get length */ ! 460: x = 0; ! 461: while ((*sp++ = *name++) != '\0') ! 462: x++; ! 463: if (x == 0) return(-1); /* If no filename, fail. */ ! 464: ! 465: debug(F101," length","",x); ! 466: for (i = x; i > 0; i--) /* Strip filename. */ ! 467: if (s[i-1] == '/') break; ! 468: ! 469: debug(F101," i","",i); ! 470: if (i == 0) /* If no path, use current directory */ ! 471: strcpy(s,"./"); ! 472: else /* Otherwise, use given one. */ ! 473: s[i] = '\0'; ! 474: ! 475: x = access(s,W_OK); /* Check access of path. */ ! 476: if (x < 0) { ! 477: debug(F111,"zchko access failed:",s,errno); ! 478: return(-1); ! 479: } else { ! 480: debug(F111,"zchko access ok:",s,x); ! 481: return(0); ! 482: } ! 483: } ! 484: ! 485: /* Z D E L E T -- Delete the named file. */ ! 486: ! 487: zdelet(name) char *name; { ! 488: unlink(name); ! 489: } ! 490: ! 491: ! 492: /* Z R T O L -- Convert remote filename into local form */ ! 493: ! 494: /* For UNIX, this means changing uppercase letters to lowercase. */ ! 495: ! 496: zrtol(name,name2) char *name, *name2; { ! 497: for ( ; *name != '\0'; name++) { ! 498: *name2++ = isupper(*name) ? tolower(*name) : *name; ! 499: } ! 500: *name2 = '\0'; ! 501: debug(F110,"zrtol:",name2,0); ! 502: } ! 503: ! 504: ! 505: /* Z L T O R -- Local TO Remote */ ! 506: ! 507: /* Convert filename from local format to common (remote) form. */ ! 508: ! 509: zltor(name,name2) char *name, *name2; { ! 510: char work[100], *cp, *pp; ! 511: int dc = 0; ! 512: #ifdef aegis ! 513: char *getenv(), *index(), *namechars; ! 514: int tilde = 0, bslash = 0; ! 515: ! 516: if ((namechars = getenv("NAMECHARS")) != NULL) { ! 517: if (index(namechars, '~' ) != NULL) tilde = '~'; ! 518: if (index(namechars, '\\') != NULL) bslash = '\\'; ! 519: } else { ! 520: tilde = '~'; ! 521: bslash = '\\'; ! 522: } ! 523: #endif ! 524: ! 525: debug(F110,"zltor",name,0); ! 526: pp = work; ! 527: #ifdef aegis ! 528: cp = name; ! 529: if (tilde && *cp == tilde) ! 530: ++cp; ! 531: for (; *cp != '\0'; cp++) { /* strip path name */ ! 532: if (*cp == '/' || *cp == bslash) { ! 533: #else ! 534: for (cp = name; *cp != '\0'; cp++) { /* strip path name */ ! 535: if (*cp == '/') { ! 536: #endif ! 537: dc = 0; ! 538: pp = work; ! 539: } ! 540: else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */ ! 541: else if (*cp == '~') *pp++ = 'X'; /* Change tilde to 'X' */ ! 542: else if (*cp == '#') *pp++ = 'X'; /* Change number sign to 'X' */ ! 543: else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */ ! 544: else *pp++ = *cp; ! 545: } ! 546: *pp = '\0'; /* Tie it off. */ ! 547: cp = name2; /* If nothing before dot, */ ! 548: if (*work == '.') *cp++ = 'X'; /* insert 'X' */ ! 549: strcpy(cp,work); ! 550: debug(F110," name2",name2,0); ! 551: } ! 552: ! 553: ! 554: /* Z C H D I R -- Change directory */ ! 555: ! 556: zchdir(dirnam) char *dirnam; { ! 557: char *hd; ! 558: if (*dirnam == '\0') hd = getenv("HOME"); ! 559: else hd = dirnam; ! 560: return((chdir(hd) == 0) ? 1 : 0); ! 561: } ! 562: ! 563: ! 564: /* Z H O M E -- Return pointer to user's home directory */ ! 565: ! 566: char * ! 567: zhome() { ! 568: return(getenv("HOME")); ! 569: } ! 570: ! 571: /* Z G T D I R -- Return pointer to user's current directory */ ! 572: ! 573: char * ! 574: zgtdir() { ! 575: ! 576: #ifdef MAXPATHLEN ! 577: #define CWDBL MAXPATHLEN ! 578: #else ! 579: #define CWDBL 100 ! 580: #endif ! 581: ! 582: #ifdef UXIII ! 583: char cwdbuf[CWDBL+1]; ! 584: char *buf; ! 585: char *getcwd(); ! 586: buf = cwdbuf; ! 587: return(getcwd(buf,CWDBL)); ! 588: #else ! 589: #ifdef BSD4 ! 590: char cwdbuf[CWDBL+1]; ! 591: char *buf; ! 592: char *getwd(); ! 593: buf = cwdbuf; ! 594: return(getwd(buf)); ! 595: #else ! 596: return("(directory unknown)"); ! 597: #endif ! 598: #endif ! 599: } ! 600: ! 601: /* Z X C M D -- Run a system command so its output can be read like a file */ ! 602: ! 603: zxcmd(comand) char *comand; { ! 604: int pipes[2]; ! 605: if (pipe(pipes) != 0) { ! 606: debug(F100,"zxcmd pipe failure","",0); ! 607: return(0); /* can't make pipe, fail */ ! 608: } ! 609: #ifdef aegis ! 610: if ((pid = vfork()) == 0) { /* child */ ! 611: #else ! 612: if ((pid = fork()) == 0) { /* child */ ! 613: #endif ! 614: ! 615: ! 616: /*#if BSD4*/ /* Code from Dave Tweten@AMES-NAS */ ! 617: /* readapted to use getpwuid to find login shell */ ! 618: /* -- H. Fischer */ ! 619: char *shpath, *shname, *shptr; /* to find desired shell */ ! 620: #ifndef aegis ! 621: struct passwd *p; ! 622: extern struct passwd * getpwuid(); ! 623: extern int getuid(); ! 624: char *defShel = "/bin/sh"; /* default shell */ ! 625: #endif ! 626: ! 627: close(pipes[0]); /* close input side of pipe */ ! 628: close(0); /* close stdin */ ! 629: if (open("/dev/null",0) < 0) return(0); /* replace input by null */ ! 630: ! 631: #ifndef UXIII ! 632: dup2(pipes[1],1); /* replace stdout & stderr */ ! 633: dup2(pipes[1],2); /* by the pipe */ ! 634: #else ! 635: close(1); /* simulate dup2 */ ! 636: if (dup(pipes[1]) != 1 ) ! 637: conol("trouble duping stdout in routine zxcmd\n"); ! 638: close(2); /* simulate dup2 */ ! 639: if (dup(pipes[1]) != 2 ) ! 640: conol("trouble duping stderr in routine zxcmd\n"); ! 641: #endif ! 642: ! 643: close(pipes[1]); /* get rid of this copy of the pipe */ ! 644: ! 645: #ifdef aegis ! 646: if ((shpath = getenv("SERVERSHELL")) == NULL) shpath = "/bin/sh"; ! 647: #else ! 648: ! 649: /**** shptr = shname = shpath = getenv("SHELL"); /* What shell? */ ! 650: p = getpwuid( getuid() ); /* get login data */ ! 651: if ( p == (struct passwd *) NULL || !*(p->pw_shell) ) shpath = defShel; ! 652: else shpath = p->pw_shell; ! 653: #endif ! 654: shptr = shname = shpath; ! 655: while (*shptr != '\0') if (*shptr++ == '/') shname = shptr; ! 656: debug(F100,"zxcmd...","",0); ! 657: debug(F110,shpath,shname,0); ! 658: ! 659: /* Remove the following uid calls if they cause trouble... */ ! 660: #ifdef BSD4 ! 661: setegid(getgid()); /* Override 4.3BSD csh */ ! 662: seteuid(getuid()); /* security checks */ ! 663: #endif /* bsd4 */ ! 664: ! 665: execl(shpath,shname,"-c",comand,(char *)NULL); /* Execute the cmd */ ! 666: exit(0); /* just punt if it failed. */ ! 667: } else if (pid == -1) { ! 668: debug(F100,"zxcmd fork failure","",0); ! 669: return(0); ! 670: } ! 671: close(pipes[1]); /* don't need the output side */ ! 672: fp[ZIFILE] = fdopen(pipes[0],"r"); /* open a stream for it */ ! 673: fp[ZSYSFN] = fp[ZIFILE]; /* Remember. */ ! 674: return(1); ! 675: } ! 676: ! 677: /* Z C L O S F - wait for the child fork to terminate and close the pipe. */ ! 678: ! 679: zclosf() { ! 680: int wstat; ! 681: if (kill(pid,9) == 0) { ! 682: debug(F101,"zclosf pid =","",pid); ! 683: while ((wstat = wait((int *)0)) != pid && wstat != -1) ; ! 684: pid = 0; ! 685: } ! 686: fclose(fp[ZIFILE]); ! 687: fp[ZIFILE] = fp[ZSYSFN] = NULL; ! 688: return(1); ! 689: } ! 690: ! 691: /* Z X P A N D -- Expand a wildcard string into an array of strings */ ! 692: /* ! 693: Returns the number of files that match fn1, with data structures set up ! 694: so that first file (if any) will be returned by the next znext() call. ! 695: */ ! 696: zxpand(fn) char *fn; { ! 697: fcount = fgen(fn,mtchs,MAXWLD); /* Look up the file. */ ! 698: if (fcount > 0) { ! 699: mtchptr = mtchs; /* Save pointer for next. */ ! 700: } ! 701: debug(F111,"zxpand",mtchs[0],fcount); ! 702: return(fcount); ! 703: } ! 704: ! 705: ! 706: /* Z N E X T -- Get name of next file from list created by zxpand(). */ ! 707: /* ! 708: Returns >0 if there's another file, with its name copied into the arg string, ! 709: or 0 if no more files in list. ! 710: */ ! 711: znext(fn) char *fn; { ! 712: if (fcount-- > 0) strcpy(fn,*mtchptr++); ! 713: else *fn = '\0'; ! 714: debug(F111,"znext",fn,fcount+1); ! 715: return(fcount+1); ! 716: } ! 717: ! 718: ! 719: /* Z N E W N -- Make a new name for the given file */ ! 720: ! 721: znewn(fn,s) char *fn, **s; { ! 722: #ifdef BSD4 ! 723: static char buf[256]; ! 724: #else ! 725: static char buf[100]; ! 726: #endif ! 727: char *bp, *xp; ! 728: int len = 0, n = 0, d = 0, t, i, power = 1; ! 729: #ifdef MAXNAMLEN ! 730: int max = MAXNAMLEN; ! 731: #else ! 732: int max = 14; ! 733: #endif ! 734: bp = buf; ! 735: while (*fn) { /* Copy name into buf */ ! 736: *bp++ = *fn++; ! 737: len++; ! 738: } ! 739: if (len > max-2) { /* Don't let it get too long */ ! 740: bp = buf + max-2; ! 741: len = max - 2; ! 742: } ! 743: ! 744: for (i = 1; i < 4; i++) { /* Try up to 999 times */ ! 745: power *= 10; ! 746: *bp++ = '*'; /* Put a star on the end */ ! 747: *bp-- = '\0'; ! 748: ! 749: n = zxpand(buf); /* Expand the resulting wild name */ ! 750: ! 751: while (n-- > 0) { /* Find any existing name~d files */ ! 752: xp = *mtchptr++; ! 753: xp += len; ! 754: if (*xp == '~') { ! 755: t = atoi(xp+1); ! 756: if (t > d) d = t; /* Get maximum d */ ! 757: } ! 758: } ! 759: if (d < power-1) { ! 760: sprintf(bp,"~%d",d+1); /* Make name~(d+1) */ ! 761: *s = buf; ! 762: return; ! 763: } ! 764: bp--; len--; ! 765: } ! 766: /* If we ever get here, we'll overwrite the xxx~100 file... */ ! 767: } ! 768: ! 769: /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */ ! 770: ! 771: /* ! 772: * The path structure is used to represent the name to match. ! 773: * Each slash-separated segment of the name is kept in one ! 774: * such structure, and they are linked together, to make ! 775: * traversing the name easier. ! 776: */ ! 777: ! 778: struct path { ! 779: char npart[MAXNAMLEN]; /* name part of path segment */ ! 780: struct path *fwd; /* forward ptr */ ! 781: }; ! 782: ! 783: #ifdef PROVX1 ! 784: #define SSPACE 500 ! 785: #else ! 786: #ifdef BSD29 ! 787: #define SSPACE 500 ! 788: #else ! 789: #ifdef aegis ! 790: #define SSPACE 10000 /* size of string-generating buffer */ ! 791: static char bslash; /* backslash character if active */ ! 792: #else ! 793: #define SSPACE 2000 /* size of string-generating buffer */ ! 794: #endif ! 795: #endif ! 796: #endif ! 797: static char sspace[SSPACE]; /* buffer to generate names in */ ! 798: static char *freeptr,**resptr; /* copies of caller's arguments */ ! 799: static int remlen; /* remaining length in caller's array*/ ! 800: static int numfnd; /* number of matches found */ ! 801: ! 802: /* ! 803: * splitpath: ! 804: * takes a string and splits the slash-separated portions into ! 805: * a list of path structures. Returns the head of the list. The ! 806: * structures are allocated by malloc, so they must be freed. ! 807: * Splitpath is used internally by the filename generator. ! 808: * ! 809: * Input: A string. ! 810: * Returns: A linked list of the slash-separated segments of the input. ! 811: */ ! 812: ! 813: struct path * ! 814: splitpath(p) ! 815: char *p; ! 816: { ! 817: struct path *head,*cur,*prv; ! 818: int i; ! 819: head = prv = NULL; ! 820: if (*p == '/') p++; /* skip leading slash */ ! 821: while (*p != '\0') ! 822: { ! 823: cur = (struct path *) malloc(sizeof (struct path)); ! 824: debug(F101,"splitpath malloc","",cur); ! 825: if (cur == NULL) fatal("malloc fails in splitpath()"); ! 826: cur -> fwd = NULL; ! 827: if (head == NULL) head = cur; ! 828: else prv -> fwd = cur; /* link into chain */ ! 829: prv = cur; ! 830: #ifdef aegis ! 831: /* treat backslash as "../" */ ! 832: if (bslash && *p == bslash) { ! 833: strcpy(cur->npart, ".."); ! 834: ++p; ! 835: } else { ! 836: for (i=0; i < MAXNAMLEN && *p && *p != '/' && *p != bslash; i++) ! 837: cur -> npart[i] = *p++; ! 838: cur -> npart[i] = '\0'; /* end this segment */ ! 839: if (i >= MAXNAMLEN) while (*p && *p != '/' && *p != bslash) p++; ! 840: } ! 841: if (*p == '/') p++; ! 842: #else ! 843: for (i=0; i < MAXNAMLEN && *p != '/' && *p != '\0'; i++) ! 844: cur -> npart[i] = *p++; ! 845: cur -> npart[i] = '\0'; /* end this segment */ ! 846: if (i >= MAXNAMLEN) while (*p != '/' && *p != '\0') p++; ! 847: if (*p == '/') p++; ! 848: #endif ! 849: } ! 850: return(head); ! 851: } ! 852: ! 853: /* ! 854: * fgen: ! 855: * This is the actual name generator. It is passed a string, ! 856: * possibly containing wildcards, and an array of character pointers. ! 857: * It finds all the matching filenames and stores them into the array. ! 858: * The returned strings are allocated from a static buffer local to ! 859: * this module (so the caller doesn't have to worry about deallocating ! 860: * them); this means that successive calls to fgen will wipe out ! 861: * the results of previous calls. This isn't a problem here ! 862: * because we process one wildcard string at a time. ! 863: * ! 864: * Input: a wildcard string, an array to write names to, the ! 865: * length of the array. ! 866: * Returns: the number of matches. The array is filled with filenames ! 867: * that matched the pattern. If there wasn't enough room in the ! 868: * array, -1 is returned. ! 869: * By: Jeff Damens, CUCCA, 1984. ! 870: */ ! 871: ! 872: fgen(pat,resarry,len) ! 873: char *pat,*resarry[]; ! 874: int len; ! 875: { ! 876: struct path *head; ! 877: char scratch[100],*sptr; ! 878: #ifdef aegis ! 879: char *getenv(), *index(), *namechars; ! 880: int tilde = 0, bquote = 0; ! 881: ! 882: if ((namechars = getenv("NAMECHARS")) != NULL) { ! 883: if (index(namechars, '~' ) != NULL) tilde = '~'; ! 884: if (index(namechars, '\\') != NULL) bslash = '\\'; ! 885: if (index(namechars, '`' ) != NULL) bquote = '`'; ! 886: } ! 887: else { tilde = '~'; bslash = '\\'; bquote = '`'; } ! 888: ! 889: sptr = scratch; ! 890: /* copy "`node_data", etc. anchors */ ! 891: if (bquote && *pat == bquote) ! 892: while (*pat && *pat != '/' && *pat != bslash) ! 893: *sptr++ = *pat++; ! 894: else if (tilde && *pat == tilde) ! 895: *sptr++ = *pat++; ! 896: while (*pat == '/') ! 897: *sptr++ = *pat++; ! 898: if (sptr == scratch) ! 899: { ! 900: strcpy(scratch,"./"); ! 901: sptr = scratch+2; ! 902: } /* init buffer correctly */ ! 903: head = splitpath(pat); ! 904: #else ! 905: head = splitpath(pat); ! 906: if (*pat == '/') ! 907: { ! 908: scratch[0] = '/'; ! 909: sptr = scratch+1; ! 910: } ! 911: else ! 912: { ! 913: strcpy(scratch,"./"); ! 914: sptr = scratch+2; ! 915: } /* init buffer correctly */ ! 916: #endif ! 917: numfnd = 0; /* none found yet */ ! 918: freeptr = sspace; /* this is where matches are copied */ ! 919: resptr = resarry; /* static copies of these so*/ ! 920: remlen = len; /* recursive calls can alter them */ ! 921: traverse(head,scratch,sptr); /* go walk the directory tree */ ! 922: for (; head != NULL; head = head -> fwd) ! 923: free(head); /* return the path segments */ ! 924: return(numfnd); /* and return the number of matches */ ! 925: } ! 926: ! 927: /* traverse: ! 928: * Walks the directory tree looking for matches to its arguments. ! 929: * The algorithm is, briefly: ! 930: * If the current pattern segment contains no wildcards, that ! 931: * segment is added to what we already have. If the name so far ! 932: * exists, we call ourselves recursively with the next segment ! 933: * in the pattern string; otherwise, we just return. ! 934: * ! 935: * If the current pattern segment contains wildcards, we open the name ! 936: * we've accumulated so far (assuming it is really a directory), then read ! 937: * each filename in it, and, if it matches the wildcard pattern segment, add ! 938: * that filename to what we have so far and call ourselves recursively on the ! 939: * next segment. ! 940: * ! 941: * Finally, when no more pattern segments remain, we add what's accumulated ! 942: * so far to the result array and increment the number of matches. ! 943: * ! 944: * Input: a pattern path list (as generated by splitpath), a string ! 945: * pointer that points to what we've traversed so far (this ! 946: * can be initialized to "/" to start the search at the root ! 947: * directory, or to "./" to start the search at the current ! 948: * directory), and a string pointer to the end of the string ! 949: * in the previous argument. ! 950: * Returns: nothing. ! 951: */ ! 952: traverse(pl,sofar,endcur) ! 953: struct path *pl; ! 954: char *sofar,*endcur; ! 955: { ! 956: #ifdef BSD42 ! 957: DIR *fd, *opendir(); ! 958: struct direct *dirbuf; ! 959: #else ! 960: #ifdef BSD29 ! 961: DIR *fd, *opendir(); ! 962: struct direct *dirbuf; ! 963: #else ! 964: int fd; ! 965: struct direct dir_entry; ! 966: struct direct *dirbuf = &dir_entry; ! 967: #endif ! 968: #endif ! 969: struct stat statbuf; ! 970: if (pl == NULL) ! 971: { ! 972: *--endcur = '\0'; /* end string, overwrite trailing / */ ! 973: addresult(sofar); ! 974: return; ! 975: } ! 976: if (!iswild(pl -> npart)) ! 977: { ! 978: strcpy(endcur,pl -> npart); ! 979: endcur += strlen(pl -> npart); ! 980: *endcur = '\0'; /* end current string */ ! 981: if (stat(sofar,&statbuf) == 0) /* if current piece exists */ ! 982: { ! 983: *endcur++ = '/'; /* add slash to end */ ! 984: *endcur = '\0'; /* and end the string */ ! 985: traverse(pl -> fwd,sofar,endcur); ! 986: } ! 987: return; ! 988: } ! 989: /* cont'd... */ ! 990: ! 991: /*...traverse, cont'd */ ! 992: ! 993: /* segment contains wildcards, have to search directory */ ! 994: *endcur = '\0'; /* end current string */ ! 995: if (stat(sofar,&statbuf) == -1) return; /* doesn't exist, forget it */ ! 996: if ((statbuf.st_mode & S_IFDIR) == 0) return; /* not a directory, skip */ ! 997: #ifdef BSD42 /* ==BSD4 */ ! 998: if ((fd = opendir(sofar)) == NULL) return; /* can't open, forget it */ ! 999: while (dirbuf = readdir(fd)) ! 1000: #else ! 1001: #ifdef BSD29 /* ==BSD29 */ ! 1002: if ((fd = opendir(sofar)) == NULL) return; /* can't open, forget it */ ! 1003: while (dirbuf = readdir(fd)) ! 1004: #else ! 1005: ! 1006: if ((fd = open(sofar,O_RDONLY)) < 0) return; /* can't open, forget it */ ! 1007: while ( read(fd,dirbuf,sizeof dir_entry) ) ! 1008: #endif ! 1009: #endif ! 1010: { ! 1011: strncpy(nambuf,dirbuf->d_name,MAXNAMLEN); /* Get a null terminated copy!!! */ ! 1012: nambuf[MAXNAMLEN] = '\0'; ! 1013: if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf)) { ! 1014: char *eos; ! 1015: strcpy(endcur,nambuf); ! 1016: eos = endcur + strlen(nambuf); ! 1017: *eos = '/'; /* end this segment */ ! 1018: traverse(pl -> fwd,sofar,eos+1); ! 1019: } ! 1020: } ! 1021: #ifdef BSD42 /* ==BSD4 */ ! 1022: closedir(fd); ! 1023: #else ! 1024: #ifdef BSD29 ! 1025: closedir(fd); ! 1026: #else ! 1027: close(fd); ! 1028: #endif ! 1029: #endif ! 1030: } ! 1031: ! 1032: /* ! 1033: * addresult: ! 1034: * Adds a result string to the result array. Increments the number ! 1035: * of matches found, copies the found string into our string ! 1036: * buffer, and puts a pointer to the buffer into the caller's result ! 1037: * array. Our free buffer pointer is updated. If there is no ! 1038: * more room in the caller's array, the number of matches is set to -1. ! 1039: * Input: a result string. ! 1040: * Returns: nothing. ! 1041: */ ! 1042: ! 1043: addresult(str) ! 1044: char *str; ! 1045: { ! 1046: int l; ! 1047: if (strncmp(str,"./",2) == 0) str += 2; ! 1048: if (--remlen < 0) { ! 1049: numfnd = -1; ! 1050: return; ! 1051: } ! 1052: l = strlen(str) + 1; /* size this will take up */ ! 1053: if ((freeptr + l) > &sspace[SSPACE-1]) { ! 1054: numfnd = -1; /* do not record if not enough space */ ! 1055: return; ! 1056: } ! 1057: strcpy(freeptr,str); ! 1058: *resptr++ = freeptr; ! 1059: freeptr += l; ! 1060: numfnd++; ! 1061: } ! 1062: ! 1063: iswild(str) ! 1064: char *str; ! 1065: { ! 1066: char c; ! 1067: while ((c = *str++) != '\0') ! 1068: if (c == '*' || c == '?') return(1); ! 1069: return(0); ! 1070: } ! 1071: ! 1072: /* ! 1073: * match: ! 1074: * pattern matcher. Takes a string and a pattern possibly containing ! 1075: * the wildcard characters '*' and '?'. Returns true if the pattern ! 1076: * matches the string, false otherwise. ! 1077: * by: Jeff Damens, CUCCA ! 1078: * ! 1079: * Input: a string and a wildcard pattern. ! 1080: * Returns: 1 if match, 0 if no match. ! 1081: */ ! 1082: ! 1083: match(pattern,string) char *pattern,*string; { ! 1084: char *psave,*ssave; /* back up pointers for failure */ ! 1085: psave = ssave = NULL; ! 1086: while (1) { ! 1087: for (; *pattern == *string; pattern++,string++) /* skip first */ ! 1088: if (*string == '\0') return(1); /* end of strings, succeed */ ! 1089: if (*string != '\0' && *pattern == '?') { ! 1090: pattern++; /* '?', let it match */ ! 1091: string++; ! 1092: } else if (*pattern == '*') { /* '*' ... */ ! 1093: psave = ++pattern; /* remember where we saw it */ ! 1094: ssave = string; /* let it match 0 chars */ ! 1095: } else if (ssave != NULL && *ssave != '\0') { /* if not at end */ ! 1096: /* ...have seen a star */ ! 1097: string = ++ssave; /* skip 1 char from string */ ! 1098: pattern = psave; /* and back up pattern */ ! 1099: } else return(0); /* otherwise just fail */ ! 1100: } ! 1101: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.