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