home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc072.zip / ckufio.c < prev    next >
C/C++ Source or Header  |  1989-02-02  |  31KB  |  1,118 lines

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