Annotation of 43BSDReno/contrib/kermit/ckufio.c, revision 1.1.1.1

1.1       root        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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.