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

Defined functions

addresult defined in line 827; used 1 times
chkfn defined in line 330; used 8 times
fgen defined in line 699; used 1 times
iswild defined in line 847; used 1 times
match defined in line 867; used 1 times
splitpath defined in line 654; used 1 times
traverse defined in line 751; used 3 times
zchdir defined in line 475; used 1 times
zchin defined in line 272; used 1 times
zchki defined in line 362; used 5 times
zchko defined in line 394; used 1 times
zchout defined in line 310; used 3 times
zclose defined in line 256; used 14 times
zclosf defined in line 547; used 1 times
zdelet defined in line 426; used 1 times
zhome defined in line 485; used 2 times
zkself defined in line 186; never used
zltor defined in line 448; used 1 times
znewn defined in line 585; used 1 times
znext defined in line 575; used 3 times
zopeni defined in line 208; used 3 times
zopeno defined in line 233; used 7 times
zrtol defined in line 435; used 3 times
zsout defined in line 283; used 16 times
zsoutl defined in line 291; used 5 times
zsoutx defined in line 300; used 1 times
zxcmd defined in line 492; used 2 times
zxpand defined in line 560; used 6 times

Defined variables

DELCMD defined in line 83; never used
DIRCMD defined in line 82; used 1 times
PWDCMD defined in line 85; used 1 times
SPACM2 defined in line 93; never used
SPACMD defined in line 90; used 1 times
TYPCMD defined in line 84; never used
WHOCMD defined in line 98; never used
ckzsys defined in line 74; used 1 times
ckzv defined in line 1; used 1 times
fcount defined in line 176; used 7 times
freeptr defined in line 639; used 5 times
mtchptr defined in line 182; used 3 times
mtchs defined in line 181; used 3 times
nambuf defined in line 177; used 5 times
numfnd defined in line 641; used 5 times
pid defined in line 175; used 2 times
remlen defined in line 640; used 2 times
resptr defined in line 639; used 2 times
sspace defined in line 638; used 2 times

Defined struct's

path defined in line 628; used 14 times

Defined macros

BSD41 defined in line 36; never used
BSD42 defined in line 29; used 3 times
MAXNAMLEN defined in line 161; used 10 times
MAXWLD defined in line 167; used 2 times
O_RDONLY defined in line 157; used 2 times
PROVX1 defined in line 129; used 7 times
R_OK defined in line 140; used 2 times
SSPACE defined in line 636; used 2 times
W_OK defined in line 144; used 2 times
Last modified: 1985-08-14
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2801
Valid CSS Valid XHTML 1.0 Strict