|
|
1.1 root 1: char *ckzv = "File support, 5A(058) 21 Jan 92";
2:
3: /* C K U F I O -- Kermit file system support for UNIX, OS/2, and Aegis */
4:
5: /*
6: Author: Frank da Cruz ([email protected], [email protected]),
7: Columbia University Center for Computing Activities. Many other contributors.
8: First released January 1985.
9: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
10: York. Permission is granted to any individual or institution to use, copy, or
11: redistribute this software so long as it is not sold for profit, provided this
12: copyright notice is retained.
13: */
14:
15: /* Include Files */
16:
17: #include "ckcdeb.h"
18:
19: #include <signal.h>
20: #ifdef MINIX
21: #include <limits.h>
22: #endif /* MINIX */
23: #ifdef POSIX
24: #include <limits.h>
25: #endif /* POSIX */
26:
27: /* Directory structure header file */
28:
29: #ifdef OS2
30: /*
31: C-Kermit's OS/2 support originally by Chris Adie <[email protected]>
32: for C-Kermit 4F, Copyright (C) 1988 Edinburgh University Computing Service,
33: Scotland. Permission is granted to any individual or institution to use,
34: copy, or redistribute this software so long as it is not sold for profit,
35: provided this copyright notice is retained.
36:
37: Adapted to C-Kermit 5A and integrated into the UNIX support module
38: by Kai Uwe Rommel <[email protected]>, Muenchen, Germany,
39: December 1991.
40: */
41:
42: /*
43: Directory Separator macros, to allow this module to work with both UNIX and
44: OS/2: Because of ambiguity with the command line editor escape \ character,
45: the directory separator is currently left as / for OS/2 too, because the
46: OS/2 kernel accepts / as directory separatore too. But this is subject to
47: change in future versions to conform with the normal OS/2 style.
48: */
49: #define DIRSEP '/'
50: /* #define DIRSEP '\\' */
51: #define ISDIRSEP(c) ((c)=='/'||(c)=='\\')
52: #else /* not OS2 */
53: #define DIRSEP '/'
54: #define ISDIRSEP(c) ((c)=='/')
55: #endif /* OS2 */
56:
57: #ifdef SDIRENT
58: #define DIRENT
59: #endif /* SDIRENT */
60:
61: #ifdef XNDIR
62: #include <sys/ndir.h>
63: #else /* !XNDIR */
64: #ifdef NDIR
65: #include <ndir.h>
66: #else /* !NDIR, !XNDIR */
67: #ifdef RTU
68: #include "/usr/lib/ndir.h"
69: #else /* !RTU, !NDIR, !XNDIR */
70: #ifdef DIRENT
71: #ifdef SDIRENT
72: #include <sys/dirent.h>
73: #else
74: #include <dirent.h>
75: #endif /* SDIRENT */
76: #else
77: #ifdef OS2
78: #define OPENDIR
79: #define DIRENT
80: #include "ckodir.h"
81: #else/* !RTU, !NDIR, !XNDIR, !DIRENT, !OS2, i.e. all others */
82: #include <sys/dir.h>
83: #endif /* OS2 */
84: #endif /* DIRENT */
85: #endif /* RTU */
86: #endif /* NDIR */
87: #endif /* XNDIR */
88:
89: #ifdef OS2 /* OS/2 file system interface */
90: #define BSD4 /* is like Berkeley UNIX */
91: #define NOFILEH /* with no <file.h> */
92: #include <sys/utime.h>
93: #include <stdlib.h>
94: #include <process.h>
95: extern int binary; /* We need to know this for open() */
96: #define popen _popen
97: #define pclose _pclose
98: #else
99: #include <pwd.h> /* Password file for shell name */
100: #endif /* OS2 */
101:
102: #ifdef BSD4 /* BSD 4.x */
103: #define TIMESTAMP /* Can do file dates */
104: #include <time.h> /* Need this */
105: #include <sys/timeb.h> /* Need this if really BSD */
106: #endif /* BSD4 */
107:
108: #ifdef ATTSV
109: #define TIMESTAMP
110: #include <time.h>
111: /* void tzset(); (the "void" type upsets some compilers) */
112: #ifndef ultrix
113: extern long timezone;
114: #endif /* ultrix */
115: #endif /* ATTSV */
116:
117: /* Is `y' a leap year? */
118: #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
119:
120: /* Number of leap years from 1970 to `y' (not including `y' itself). */
121: #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
122:
123: #ifdef COMMENT /* not used */
124: /* Number of days in each month of the year. */
125: static char monlens[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
126: #endif /* COMMENT */
127:
128: #ifdef CIE
129: #include <stat.h> /* File status */
130: #else
131: #include <sys/stat.h>
132: #ifdef OS2
133: #include <sys/types.h>
134: /* because standard stat has trouble with trailing /'s we have to wrap it */
135: int os2stat(char *, struct stat *);
136: #define stat(path, buf) os2stat(path, buf)
137: #endif /* OS2 */
138: #endif /* CIE */
139:
140: /*
141: Functions (n is one of the predefined file numbers from ckcker.h):
142:
143: zopeni(n,name) -- Opens an existing file for input.
144: zopeno(n,name,attr,fcb) -- Opens a new file for output.
145: zclose(n) -- Closes a file.
146: zchin(n,&c) -- Gets the next character from an input file.
147: zsinl(n,&s,x) -- Read a line from file n, max len x, into address s.
148: zsout(n,s) -- Write a null-terminated string to output file, buffered.
149: zsoutl(n,s) -- Like zsout, but appends a line terminator.
150: zsoutx(n,s,x) -- Write x characters to output file, unbuffered.
151: zchout(n,c) -- Add a character to an output file, unbuffered.
152: zchki(name) -- Check if named file exists and is readable, return size.
153: zchko(name) -- Check if named file can be created.
154: zchkspa(name,n) -- Check if n bytes available to create new file, name.
155: znewn(name,s) -- Make a new unique file name based on the given name.
156: zdelet(name) -- Delete the named file.
157: zxpand(string) -- Expands the given wildcard string into a list of files.
158: znext(string) -- Returns the next file from the list in "string".
159: zxcmd(n,cmd) -- Execute the command in a lower fork on file number n.
160: zclosf() -- Close input file associated with zxcmd()'s lower fork.
161: zrtol(n1,n2) -- Convert remote filename into local form.
162: zltor(n1,n2) -- Convert local filename into remote form.
163: zchdir(dirnam) -- Change working directory.
164: zhome() -- Return pointer to home directory name string.
165: zkself() -- Kill self, log out own job.
166: zsattr(struct zattr *) -- Return attributes for file which is being sent.
167: zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
168: zrename(old, new) -- Rename a file.
169: */
170:
171: /* Kermit-specific includes */
172: /*
173: Definitions here supersede those from system include files.
174: ckcdeb.h is included above.
175: */
176: #include "ckcker.h" /* Kermit definitions */
177: #include "ckucmd.h" /* For sys-dependent keyword tables */
178: #include "ckuver.h" /* Version herald */
179:
180: char *ckzsys = HERALD;
181:
182: /* Support for tilde-expansion in file and directory names */
183:
184: #ifdef POSIX
185: #define NAMEENV "LOGNAME"
186: #endif /* POSIX */
187:
188: #ifdef BSD4
189: #define NAMEENV "USER"
190: #endif /* BSD4 */
191:
192: #ifdef ATTSV
193: #define NAMEENV "LOGNAME"
194: #endif /* ATTSV */
195:
196: /* Berkeley Unix Version 4.x */
197: /* 4.1bsd support from Charles E Brooks, EDN-VAX */
198:
199: #ifdef BSD4
200: #ifdef MAXNAMLEN
201: #define BSD42
202: #endif /* MAXNAMLEN */
203: #endif /* BSD4 */
204:
205: /* Definitions of some system commands */
206:
207: #ifdef OS2
208: char *DELCMD = "del "; /* For file deletion */
209: char *PWDCMD = "chdir "; /* For saying where I am */
210: char *TYPCMD = "type "; /* For typing a file */
211: char *DIRCMD = "dir "; /* For directory listing */
212: char *DIRCM2 = "dir "; /* For directory listing, no args */
213: char *WHOCMD = ""; /* Who's there? */
214: char *SPACMD = "chkdsk "; /* For space on disk */
215: char *SPACM2 = "chkdsk "; /* For space on disk */
216: #else
217: char *DELCMD = "rm -f "; /* For file deletion */
218: char *PWDCMD = "pwd "; /* For saying where I am */
219: #ifdef COMMENT
220: char *DIRCMD = "/bin/ls -ld "; /* For directory listing */
221: char *DIRCM2 = "/bin/ls -ld *"; /* For directory listing, no args */
222: #else
223: char *DIRCMD = "/bin/ls -l "; /* For directory listing */
224: char *DIRCM2 = "/bin/ls -l "; /* For directory listing, no args */
225: #endif
226: char *TYPCMD = "cat "; /* For typing a file */
227:
228: #ifdef FT18 /* Fortune For:Pro 1.8 */
229: #undef BSD4
230: #endif /* FT18 */
231:
232: #ifdef BSD4
233: char *SPACMD = "pwd ; df ."; /* Space in current directory */
234: #else
235: #ifdef FT18
236: char *SPACMD = "pwd ; du ; df .";
237: #else
238: char *SPACMD = "df ";
239: #endif /* FT18 */
240: #endif /* BSD4 */
241:
242: char *SPACM2 = "df "; /* For space in specified directory */
243:
244: #ifdef FT18
245: #define BSD4
246: #endif /* FT18 */
247:
248: #ifdef BSD4
249: char *WHOCMD = "finger "; /* For seeing who's logged in */
250: #else
251: char *WHOCMD = "who "; /* For seeing who's logged in */
252: #endif /* BSD4 */
253: #endif /* OS2 */
254:
255: #ifdef DTILDE /* For tilde expansion */
256: _PROTOTYP( char * tilde_expand, (char *) );
257: #endif /* DTILDE */
258:
259: /* More system-dependent includes, which depend on symbols defined */
260: /* in the Kermit-specific includes. Oh what a tangled web we weave... */
261:
262: #ifdef COHERENT
263: #define NOFILEH
264: #endif /* COHERENT */
265:
266: #ifdef MINIX
267: #define NOFILEH
268: #endif /* MINIX */
269:
270: #ifdef aegis /* <sys/file.h> */
271: #define NOFILEH
272: #endif /* aegis */
273:
274: #ifdef unos
275: #define NOFILEH
276: #endif /* unos */
277:
278: #ifndef NOFILEH
279: #include <sys/file.h>
280: #endif /* NOFILEH */
281:
282:
283: #ifndef is68k /* Whether to include <fcntl.h> */
284: #ifndef BSD41 /* All but a couple UNIXes have it. */
285: #ifndef FT18
286: #include <fcntl.h>
287: #endif /* FT18 */
288: #endif /* BSD41 */
289: #endif /* not is68k */
290:
291: #ifndef _POSIX_SOURCE
292: #ifndef NEXT
293: #ifndef SVR4
294: /* POSIX <pwd.h> already gave prototypes for these. */
295: #ifdef IRIX40
296: _PROTOTYP( struct passwd * getpwnam, (const char *) );
297: #else
298: _PROTOTYP( struct passwd * getpwnam, (char *) );
299: #endif /* IRIX40 */
300: _PROTOTYP( struct passwd * getpwuid, (PWID_T) );
301: _PROTOTYP( struct passwd * getpwent, (void) );
302: #endif /* SVR4 */
303: #endif /* NEXT */
304: #endif /* _POSIX_SOURCE */
305:
306: /* Define macros for getting file type */
307:
308: #ifdef OXOS
309: /*
310: Olivetti X/OS 2.3 has S_ISREG and S_ISDIR defined
311: incorrectly, so we force their redefinition.
312: */
313: #undef S_ISREG
314: #undef S_ISDIR
315: #endif /* OXOS */
316:
317: #ifdef UTSV /* Same deal for Amdah UTSV */
318: #undef S_ISREG
319: #undef S_ISDIR
320: #endif /* UTSV */
321:
322: #ifndef S_ISREG
323: #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
324: #endif /* S_ISREG */
325: #ifndef S_ISDIR
326: #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
327: #endif /* S_ISDIR */
328:
329: /* Define maximum length for a file name if not already defined */
330:
331: #ifndef MAXNAMLEN
332: #ifdef sun
333: #define MAXNAMLEN 255
334: #else
335: #ifdef FILENAME_MAX
336: #define MAXNAMLEN FILENAME_MAX
337: #else
338: #ifdef NAME_MAX
339: #define MAXNAMLEN NAME_MAX
340: #else
341: #ifdef _POSIX_NAME_MAX
342: #define MAXNAMLEN _POSIX_NAME_MAX
343: #else
344: #ifdef _D_NAME_MAX
345: #define MAXNAMLEN _D_NAME_MAX
346: #else
347: #ifdef DIRSIZ
348: #define MAXNAMLEN DIRSIZ
349: #else
350: #define MAXNAMLEN 14
351: #endif /* DIRSIZ */
352: #endif /* _D_NAME_MAX */
353: #endif /* _POSIX_NAME_MAX */
354: #endif /* NAME_MAX */
355: #endif /* FILENAME_MAX */
356: #endif /* sun */
357: #endif /* MAXNAMLEN */
358:
359: /* Longest pathname */
360:
361: #ifdef MAXPATHLEN
362: #ifdef MAXPATH
363: #undef MAXPATH
364: #endif /* MAXPATH */
365: #define MAXPATH MAXPATHLEN
366: #else
367: #ifdef PATH_MAX
368: #define MAXPATH PATH_MAX
369: #else
370: #ifdef _POSIX_PATH_MAX
371: #define MAXPATH _POSIX_PATH_MAX
372: #else
373: #ifdef BSD42
374: #define MAXPATH 1024
375: #else
376: #define MAXPATH 255
377: #endif /* BSD42 */
378: #endif /* _POSIX_PATH_MAX */
379: #endif /* PATH_MAX */
380: #endif /* MAXPATHLEN */
381:
382: /* Maximum number of filenames for wildcard expansion */
383:
384: #ifdef PROVX1
385: #define MAXWLD 50
386: #else
387: #ifdef BSD29
388: #define MAXWLD 50
389: #else
390: #ifdef pdp11
391: #define MAXWLD 50
392: #else
393: #define MAXWLD 1000
394: #endif /* pdp11 */
395: #endif /* BSD29 */
396: #endif /* PROVX1 */
397:
398: /* More internal function prototypes */
399: /*
400: * The path structure is used to represent the name to match.
401: * Each slash-separated segment of the name is kept in one
402: * such structure, and they are linked together, to make
403: * traversing the name easier.
404: */
405: struct path {
406: char npart[MAXNAMLEN+4]; /* name part of path segment */
407: struct path *fwd; /* forward ptr */
408: };
409: _PROTOTYP( int shxpand, (char *, char **, int ) );
410: _PROTOTYP( static int fgen, (char *, char **, int ) );
411: _PROTOTYP( static VOID traverse, (struct path *, char *, char *) );
412: _PROTOTYP( static VOID addresult, (char *) );
413: _PROTOTYP( static int match, (char *, char *) );
414: _PROTOTYP( static char * whoami, (void) );
415: _PROTOTYP( char * xindex, (char *, char) );
416: _PROTOTYP( UID_T real_uid, (void) );
417: _PROTOTYP( struct path *splitpath, (char *p) );
418:
419: /* Some systems define these symbols in include files, others don't... */
420:
421: #ifndef R_OK
422: #define R_OK 4 /* For access */
423: #endif
424:
425: #ifndef W_OK
426: #define W_OK 2
427: #endif
428:
429: #ifndef O_RDONLY
430: #define O_RDONLY 000
431: #endif
432:
433: /* Declarations */
434:
435: int maxnam = MAXNAMLEN; /* Available to the outside */
436: int maxpath = MAXPATH;
437:
438: FILE *fp[ZNFILS] = { /* File pointers */
439: NULL, NULL, NULL, NULL, NULL, NULL, NULL };
440: #ifdef OS2
441: int ispipe[ZNFILS]; /* Flag for file is a pipe */
442: #endif /* OS2 */
443:
444: /* Buffers and pointers used in buffered file input and output. */
445: #ifdef DYNAMIC
446: extern char *zinbuffer, *zoutbuffer;
447: #else
448: extern char zinbuffer[], zoutbuffer[];
449: #endif /* DYNAMIC */
450: extern char *zinptr, *zoutptr;
451: extern int zincnt, zoutcnt;
452: extern int wildxpand;
453:
454: extern UID_T real_uid();
455:
456: static long iflen = -1L; /* Input file length */
457:
458: static PID_T pid = 0; /* pid of child fork */
459: static int fcount; /* Number of files in wild group */
460: static char nambuf[MAXNAMLEN+4]; /* Buffer for a filename */
461: static char zmbuf[200]; /* For mail, remote print strings */
462:
463: /* static */ /* Not static, must be global now. */
464: char *mtchs[MAXWLD], /* Matches found for filename */
465: **mtchptr; /* Pointer to current match */
466:
467: /* Z K S E L F -- Kill Self: log out own job, if possible. */
468:
469: /* Note, should get current pid, but if your system doesn't have */
470: /* getppid(), then just kill(0,9)... */
471:
472: #ifndef SVR3
473: #ifndef POSIX
474: /* Already declared in unistd.h for SVR3 and POSIX */
475: #ifdef CK_ANSIC
476: extern PID_T getppid(void);
477: #else
478: #ifndef PS2AIX10
479: extern PID_T getppid();
480: #endif /* PS2AIX10 */
481: #endif /* CK_ANSIC */
482: #endif /* POSIX */
483: #endif /* SVR3 */
484: int
485: zkself() { /* For "bye", but no guarantee! */
486: #ifdef PROVX1
487: return(kill(0,9));
488: #else
489: #ifdef V7
490: return(kill(0,9));
491: #else
492: #ifdef TOWER1
493: return(kill(0,9));
494: #else
495: #ifdef FT18
496: return(kill(0,9));
497: #else
498: #ifdef aegis
499: return(kill(0,9));
500: #else
501: #ifdef COHERENT
502: return(kill(getpid(),1));
503: #else
504: #ifdef OS2
505: exit(3);
506: #else
507: exit(kill(getppid(),1));
508: #endif
509: #endif
510: #endif
511: #endif
512: #endif
513: #endif
514: #endif
515: }
516:
517: /* Z O P E N I -- Open an existing file for input. */
518:
519: int
520: zopeni(n,name) int n; char *name; {
521: debug(F111," zopeni",name,n);
522: debug(F101," fp","", fp[n]);
523: if (chkfn(n) != 0) return(0);
524: zincnt = 0; /* Reset input buffer */
525: if (n == ZSYSFN) { /* Input from a system function? */
526: /*** Note, this function should not be called with ZSYSFN ***/
527: /*** Always call zxcmd() directly, and give it the real file number ***/
528: /*** you want to use. ***/
529: debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
530: *nambuf = '\0'; /* No filename. */
531: return(0); /* fail. */
532: #ifdef COMMENT
533: return(zxcmd(n,name)); /* Try to fork the command */
534: #endif
535: }
536: if (n == ZSTDIO) { /* Standard input? */
537: if (isatty(0)) {
538: fprintf(stderr,"Terminal input not allowed");
539: debug(F110,"zopeni: attempts input from unredirected stdin","",0);
540: return(0);
541: }
542: fp[ZIFILE] = stdin;
543: #ifdef OS2
544: setmode(fileno(stdin),O_BINARY);
545: #endif /* OS2 */
546: return(1);
547: }
548: #ifdef OS2
549: if (n == ZIFILE)
550: fp[n] = fopen(name,"rb"); /* Binary mode */
551: else
552: #endif /* OS2 */
553: fp[n] = fopen(name,"r"); /* Real file, open it. */
554: debug(F111," zopeni", name, fp[n]);
555: if (fp[n] == NULL) perror("zopeni");
556: return((fp[n] != NULL) ? 1 : 0);
557: }
558:
559: /* Z O P E N O -- Open a new file for output. */
560:
561: int
562: zopeno(n,name,zz,fcb)
563: /* zopeno */ int n; char *name; struct zattr *zz; struct filinfo *fcb; {
564:
565: char p[8]; /* (===OS2 change===) */
566: /* char *p; */ /* Local-use pointer */
567:
568: /* As of Version 5A, the attribute structure and the file information */
569: /* structure are included in the arglist. */
570:
571: debug(F111,"zopeno",name,n);
572: if (fcb) {
573: debug(F101,"zopeno fcb disp","",fcb->dsp);
574: debug(F101,"zopeno fcb type","",fcb->typ);
575: debug(F101,"zopeno fcb char","",fcb->cs);
576: } else {
577: debug(F100,"zopeno fcb is NULL","",0);
578: }
579: if (n != ZDFILE)
580: debug(F111," zopeno",name,n);
581: if (chkfn(n) != 0) return(0);
582: if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */
583: fp[ZOFILE] = stdout;
584: if (n != ZDFILE)
585: debug(F101," fp[]=stdout", "", fp[n]);
586: zoutcnt = 0;
587: zoutptr = zoutbuffer;
588: return(1);
589: }
590:
591: /* A real file. Open it in desired mode (create or append). */
592:
593: strcpy(p,"w"); /* Assume write/create mode */
594: if (fcb) { /* If called with an FCB... */
595: if (fcb->dsp == XYFZ_A) /* Does it say Append? */
596: strcpy(p,"a"); /* Yes. */
597: }
598: #ifdef OS2
599: if (n == ZOFILE) strcat(p,"b"); /* Binary mode */
600: #endif /* OS2 */
601: fp[n] = fopen(name,p); /* Open the file */
602:
603: if (fp[n] == NULL) {
604: perror("zopeno can't open");
605: } else {
606: if (n == ZDFILE) setbuf(fp[n],NULL); /* Debugging file unbuffered */
607: }
608: zoutcnt = 0; /* (PWP) reset output buffer */
609: zoutptr = zoutbuffer;
610: if (n != ZDFILE)
611: debug(F101, " fp[n]", "", fp[n]);
612: return((fp[n] != NULL) ? 1 : 0);
613: }
614:
615: /* Z C L O S E -- Close the given file. */
616:
617: /* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */
618:
619: int
620: zclose(n) int n; {
621: int x, x2;
622: if (chkfn(n) < 1) return(0); /* Check range of n */
623:
624: if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */
625: x2 = zoutdump();
626: else
627: x2 = 0;
628:
629: x = 0; /* Initialize return code */
630: if (fp[ZSYSFN]) { /* If file is really pipe */
631: x = zclosf(n); /* do it specially */
632: } else {
633: if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]);
634: fp[n] = NULL;
635: }
636: iflen = -1L; /* Invalidate file length */
637: if (x == EOF) /* if we got a close error */
638: return (-1);
639: else if (x2 < 0) /* or an error flushing the last buffer */
640: return (-1); /* then return an error */
641: else
642: return (1);
643: }
644:
645: /* Z C H I N -- Get a character from the input file. */
646:
647: /* Returns -1 if EOF, 0 otherwise with character returned in argument */
648:
649: int
650: zchin(n,c) int n; int *c; {
651: int a, x;
652:
653: /* (PWP) Just in case this gets called when it shouldn't. */
654: if (n == ZIFILE) {
655: x = zminchar();
656: *c = x;
657: return(x);
658: }
659: /* if (chkfn(n) < 1) return(-1); */
660: a = getc(fp[n]);
661: if (a == EOF) return(-1);
662: #ifdef OS2
663: if (!binary && a == 0x1A) /* Ctrl-Z marks EOF for text mode*/
664: return(-1);
665: #endif
666: *c = (CHAR) a & 0377;
667: return(0);
668: }
669:
670: /* Z S I N L -- Read a line from a file */
671:
672: /*
673: Writes the line into the address provided by the caller.
674: n is the Kermit "channel number".
675: Writing terminates when newline is encountered, newline is not copied.
676: Writing also terminates upon EOF or if length x is exhausted.
677: Returns 0 on success, -1 on EOF or error.
678: */
679: int
680: zsinl(n,s,x) int n, x; char *s; {
681: int a, z = 0;
682:
683: if (chkfn(n) < 1) { /* Make sure file is open */
684: return(-1);
685: }
686: a = -1;
687: while (x--) {
688: #ifndef NLCHAR
689: int old;
690: old = a; /* Previous character */
691: #endif
692: if (zchin(n,&a) < 0) { /* Read a character from the file */
693: z = -1;
694: break;
695: }
696: #ifdef NLCHAR
697: if (a == (char) NLCHAR) break; /* Single-character line terminator */
698: #else
699: if (a == '\r') continue; /* CRLF line terminator */
700: if (old == '\r') {
701: if (a == '\n') break;
702: else *s++ = '\r';
703: }
704: #endif /* NLCHAR */
705: *s = a;
706: s++;
707: }
708: *s = '\0';
709: return(z);
710: }
711:
712: /*
713: * (PWP) (re)fill the buffered input buffer with data. All file input
714: * should go through this routine, usually by calling the zminchar()
715: * macro (in ckcker.h).
716: */
717:
718: /*
719: * Suggestion: if fread() returns 0, call ferror to find out what the
720: * problem was. If it was not EOF, then return -2 instead of -1.
721: * Upper layers (getpkt function in ckcfns.c) should set cxseen flag
722: * if it gets -2 return from zminchar macro.
723: */
724: int
725: zinfill() {
726: int x;
727:
728: errno = 0;
729: zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
730: #ifdef COMMENT
731: debug(F101,"zinfill fp","",fp[ZIFILE]);
732: debug(F101,"zinfill zincnt","",zincnt);
733: #endif
734: if (zincnt == 0) {
735: #ifndef UTEK
736: #ifdef ferror
737: x = ferror(fp[ZIFILE]);
738: debug(F101,"zinfill errno","",errno);
739: debug(F101,"zinfill ferror","",x);
740: if (x) return(-2);
741: #endif /* ferror */
742: #else
743: x = feof(fp[ZIFILE]);
744: debug(F101,"zinfill errno","",errno);
745: debug(F101,"zinfill feof","",x);
746: if (!x && ferror(fp[ZIFILE])) return(-2);
747: #endif /* UTEK */
748: return(-1);
749: }
750: zinptr = zinbuffer; /* set pointer to beginning, (== &zinbuffer[0]) */
751: zincnt--; /* one less char in buffer */
752: return((int)(*zinptr++) & 0377); /* because we return the first */
753: }
754:
755: /* Z S O U T -- Write a string out to the given file, buffered. */
756:
757: int
758: zsout(n,s) int n; char *s; {
759: if (chkfn(n) < 1) return(-1); /* Keep this here, prevents memory faults */
760: #ifdef COMMENT
761: while (*s) { /* (unbuffered for debugging) */
762: write(fileno(fp[n]),s,1); ++s;
763: }
764: #endif
765: #ifdef COMMENT
766: return(fputs(s,fp[n]) == EOF ? -1 : 0);
767: #else
768: if (n == ZSFILE)
769: return(write(fileno(fp[n]),s,(int)strlen(s)));
770: else
771: return(fputs(s,fp[n]) == EOF ? -1 : 0);
772: #endif
773: }
774:
775: /* Z S O U T L -- Write string to file, with line terminator, buffered */
776:
777: int
778: zsoutl(n,s) int n; char *s; {
779: /* if (chkfn(n) < 1) return(-1); */
780: if (fputs(s,fp[n]) == EOF) return(-1);
781: if (fputs("\n",fp[n]) == EOF) return(-1); /* (===OS2 ? \r\n) */
782: return(0);
783: }
784:
785: /* Z S O U T X -- Write x characters to file, unbuffered. */
786:
787: int
788: zsoutx(n,s,x) int n, x; char *s; {
789: #ifdef COMMENT
790: if (chkfn(n) < 1) return(-1);
791: return(write(fp[n]->_file,s,x));
792: #endif
793: return(write(fileno(fp[n]),s,x) == x ? x : -1);
794: }
795:
796:
797: /* Z C H O U T -- Add a character to the given file. */
798:
799: /* Should return 0 or greater on success, -1 on failure (e.g. disk full) */
800:
801: int
802: #ifdef CK_ANSIC
803: zchout(register int n, char c)
804: #else
805: zchout(n,c) register int n; char c;
806: #endif /* CK_ANSIC */
807: /* zchout() */ {
808: /* if (chkfn(n) < 1) return(-1); */
809: if (n == ZSFILE) { /* Use unbuffered for session log */
810: return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1);
811: } else { /* Buffered for everything else */
812: if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */
813: return(ferror(fp[n])?-1:0); /* Check to make sure */
814: else /* Otherwise... */
815: return(0); /* There was no error. */
816: }
817: }
818:
819: /* (PWP) buffered character output routine to speed up file IO */
820:
821: int
822: zoutdump() {
823: int x;
824: zoutptr = zoutbuffer; /* Reset buffer pointer in all cases */
825: debug(F101,"zoutdump chars","",zoutcnt);
826: if (zoutcnt == 0) { /* Nothing to output */
827: return(0);
828: } else if (zoutcnt < 0) { /* Unexpected negative argument */
829: zoutcnt = 0; /* Reset output buffer count */
830: return(-1); /* and fail. */
831: }
832:
833: /* Frank Prindle suggested that replacing this fwrite() by an fflush() */
834: /* followed by a write() would improve the efficiency, especially when */
835: /* writing to stdout. Subsequent tests showed a 5-fold improvement! */
836: /* if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) { */
837:
838: fflush(fp[ZOFILE]);
839: if ((x = write(fileno(fp[ZOFILE]),zoutbuffer,zoutcnt)) == zoutcnt) {
840: debug(F101,"zoutdump write ok","",zoutcnt);
841: zoutcnt = 0; /* Reset output buffer count */
842: return(0); /* write() worked OK */
843: } else {
844: debug(F101,"zoutdump write error","",errno);
845: debug(F101,"zoutdump write returns","",x);
846: zoutcnt = 0; /* Reset output buffer count */
847: return(-1); /* write() failed */
848: }
849: }
850:
851: /* C H K F N -- Internal function to verify file number is ok */
852:
853: /*
854: Returns:
855: -1: File number n is out of range
856: 0: n is in range, but file is not open
857: 1: n in range and file is open
858: */
859: int
860: chkfn(n) int n; {
861: switch (n) {
862: case ZCTERM:
863: case ZSTDIO:
864: case ZIFILE:
865: case ZOFILE:
866: case ZDFILE:
867: case ZTFILE:
868: case ZPFILE:
869: case ZSFILE:
870: case ZSYSFN:
871: case ZRFILE:
872: case ZWFILE: break;
873: default:
874: debug(F101,"chkfn: file number out of range","",n);
875: fprintf(stderr,"?File number out of range - %d\n",n);
876: return(-1);
877: }
878: return( (fp[n] == NULL) ? 0 : 1 );
879: }
880:
881: /* Z C H K I -- Check if input file exists and is readable */
882:
883: /*
884: Returns:
885: >= 0 if the file can be read (returns the size).
886: -1 if file doesn't exist or can't be accessed,
887: -2 if file exists but is not readable (e.g. a directory file).
888: -3 if file exists but protected against read access.
889: */
890: /*
891: For Berkeley Unix, a file must be of type "regular" to be readable.
892: Directory files, special files, and symbolic links are not readable.
893: */
894: long
895: zchki(name) char *name; {
896: struct stat buf;
897: int x;
898:
899: x = stat(name,&buf);
900: if (x < 0) {
901: debug(F111,"zchki stat fails",name,errno);
902: return(-1);
903: }
904: if (!S_ISREG (buf.st_mode)) { /* Must be regular file */
905: debug(F111,"zchki skipping:",name,x);
906: return(-2);
907: }
908: debug(F111,"zchki stat ok:",name,x);
909:
910: if ((x = access(name,R_OK)) < 0) { /* Is the file accessible? */
911: debug(F111," access failed:",name,x); /* No */
912: return(-3);
913: } else {
914: iflen = buf.st_size; /* Yes, remember size */
915: strncpy(nambuf,name,MAXNAMLEN); /* and name globally. */
916: debug(F111," access ok:",name,(int) iflen);
917: return( (iflen > -1L) ? iflen : 0L );
918: }
919: }
920:
921: /* Z C H K O -- Check if output file can be created */
922:
923: /*
924: Returns -1 if write permission for the file would be denied, 0 otherwise.
925: */
926: int
927: zchko(name) char *name; {
928: int i, x;
929: char *s;
930:
931: if (!name) return(-1); /* Watch out for null pointer. */
932: x = (int)strlen(name); /* Get length of filename */
933: debug(F101," length","",x);
934: s = malloc(x+3); /* Must copy because we can't */
935: if (!s) { /* write into our argument. */
936: fprintf(stderr,"Malloc error 46\n");
937: return(-1);
938: }
939: strcpy(s,name);
940:
941: for (i = x; i > 0; i--) /* Strip filename from right. */
942: if (ISDIRSEP(s[i-1])) break;
943: debug(F101," i","",i);
944:
945: #ifdef COMMENT
946: /* X/OPEN XPG3-compliant systems fail if argument ends with "/"... */
947: if (i == 0) /* If no path, use current directory */
948: strcpy(s,"./");
949: else /* Otherwise, use given one. */
950: s[i] = '\0';
951: #else
952: /* So now we use "path/." if path given, or "." if no path given. */
953: s[i++] = '.'; /* Append "." to path. */
954: s[i] = '\0';
955: #endif /* COMMENT */
956:
957: x = access(s,W_OK); /* Check access of path. */
958: if (x < 0)
959: debug(F111,"zchko access failed:",s,errno);
960: else
961: debug(F111,"zchko access ok:",s,x);
962: free(s); /* Free temporary storage */
963: return((x < 0) ? -1 : 0); /* and return. */
964: }
965:
966: /* Z D E L E T -- Delete the named file. */
967:
968: int
969: zdelet(name) char *name; {
970: return(unlink(name));
971: }
972:
973:
974: /* Z R T O L -- Convert remote filename into local form */
975:
976: /* For UNIX, this means changing uppercase letters to lowercase. */
977:
978: VOID
979: zrtol(name,name2) char *name, *name2; {
980: for ( ; *name != '\0'; name++) {
981: *name2++ = isupper(*name) ? tolower(*name) : *name;
982: }
983: *name2 = '\0';
984: debug(F110,"zrtol:",name2,0);
985: }
986:
987:
988: /* Z S T R I P -- Strip device & directory name from file specification */
989:
990: /* Strip pathname from filename "name", return pointer to result in name2 */
991:
992: static char work[257]; /* buffer for use by zstrip and zltor */
993:
994: VOID
995: zstrip(name,name2) char *name, **name2; {
996: char *cp, *pp;
997: debug(F110,"zstrip before",name,0);
998: pp = work;
999: #ifdef DTILDE
1000: if (*name == '~') name++;
1001: #endif /* DTILDE */
1002: for (cp = name; *cp != '\0'; cp++) {
1003: if (ISDIRSEP(*cp))
1004: pp = work;
1005: else
1006: *pp++ = *cp;
1007: }
1008: *pp = '\0'; /* Terminate the string */
1009: *name2 = work;
1010: debug(F110,"zstrip after",*name2,0);
1011: }
1012:
1013: /* Z L T O R -- Local TO Remote */
1014:
1015: VOID
1016: zltor(name,name2) char *name, *name2; {
1017: char *cp, *pp;
1018: int dc = 0;
1019: #ifdef aegis
1020: char *namechars;
1021: int tilde = 0, bslash = 0;
1022:
1023: if ((namechars = getenv("NAMECHARS")) != NULL) {
1024: if (xindex(namechars, '~' ) != NULL) tilde = '~';
1025: if (xindex(namechars, '\\') != NULL) bslash = '\\';
1026: } else {
1027: tilde = '~';
1028: bslash = '\\';
1029: }
1030: #endif /* aegis */
1031:
1032: debug(F110,"zltor",name,0);
1033: pp = work;
1034: #ifdef aegis
1035: cp = name;
1036: if (tilde && *cp == tilde)
1037: ++cp;
1038: for (; *cp != '\0'; cp++) {
1039: if (*cp == '/' || *cp == bslash) { /* strip path name */
1040: #else
1041: for (cp = name; *cp != '\0'; cp++) { /* strip path name */
1042: if (ISDIRSEP(*cp)) {
1043: #endif /* aegis */
1044: dc = 0;
1045: pp = work;
1046: }
1047: else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */
1048: else if (*cp == '~') *pp++ = 'X'; /* Change tilde to 'X' */
1049: else if (*cp == '#') *pp++ = 'X'; /* Change number sign to 'X' */
1050: else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */
1051: else *pp++ = *cp;
1052: }
1053: *pp = '\0'; /* Tie it off. */
1054: cp = name2; /* If nothing before dot, */
1055: if (*work == '.') *cp++ = 'X'; /* insert 'X' */
1056: strcpy(cp,work);
1057: debug(F110," name2",name2,0);
1058: }
1059:
1060:
1061: /* Z C H D I R -- Change directory */
1062: /*
1063: Call with:
1064: dirnam = pointer to name of directory to change to,
1065: which may be "" or NULL to indicate user's home directory.
1066: Returns:
1067: 0 on failure
1068: 1 on success
1069: */
1070: int
1071: zchdir(dirnam) char *dirnam; {
1072: char *hd, *sp, *p;
1073:
1074: debug(F110,"zchdir",dirnam,0);
1075: if (dirnam == NULL || dirnam == "" || *dirnam == '\0') /* If arg is null */
1076: dirnam = getenv("HOME"); /* use user's home directory. */
1077: sp = dirnam;
1078: debug(F110,"zchdir 2",dirnam,0);
1079:
1080: #ifdef DTILDE
1081: hd = tilde_expand(dirnam); /* Attempt to expand tilde */
1082: if (*hd == '\0') hd = dirnam; /* in directory name. */
1083: #else
1084: hd = dirnam;
1085: #endif /* DTILDE */
1086: debug(F110,"zchdir 3",hd,0);
1087: if (chdir(hd) == 0) return(1); /* Try to cd */ /* (===OS2===) */
1088: p = sp; /* Failed, lowercase it. */
1089: while (*p) {
1090: if (isupper(*p)) *p = tolower(*p);
1091: p++;
1092: }
1093: debug(F110,"zchdir 4",hd,0);
1094: #ifdef DTILDE
1095: hd = tilde_expand(sp); /* Try again to expand tilde */
1096: if (*hd == '\0') hd = sp;
1097: #else
1098: hd = sp; /* Point to result */
1099: #endif
1100: debug(F110,"zchdir 5",hd,0);
1101: /* return((chdir(hd) > -1) ? 1 : 0); (===OS2===) */
1102: return((chdir(hd) == 0) ? 1 : 0);
1103: }
1104:
1105:
1106: /* Z H O M E -- Return pointer to user's home directory */
1107:
1108: char *
1109: zhome() {
1110: char *home = NULL;
1111: home = getenv("HOME");
1112: return(home ? home : "."); /* (===OS2===) */
1113: }
1114:
1115: /* Z G T D I R -- Return pointer to user's current directory */
1116:
1117: #ifdef MAXPATHLEN
1118: #define CWDBL MAXPATHLEN
1119: #else
1120: #define CWDBL 100
1121: #endif
1122: static char cwdbuf[CWDBL+1];
1123:
1124: char *
1125: zgtdir() {
1126: char *buf;
1127:
1128: #ifdef SVORPOSIX
1129: extern char *getcwd();
1130: buf = cwdbuf;
1131: return(getcwd(buf,CWDBL));
1132: #else
1133: #ifdef OS2
1134: extern char *getcwd();
1135: buf = cwdbuf;
1136: return(getcwd(buf,CWDBL));
1137: #else
1138: #ifdef BSD4
1139: extern char *getwd();
1140: buf = cwdbuf;
1141: return(getwd(buf));
1142: #else
1143: return("directory unknown");
1144: #endif /* BSD4 */
1145: #endif /* OS2 */
1146: #endif /* SYSVORPOSIX */
1147: }
1148:
1149: /* Z X C M D -- Run a system command so its output can be read like a file */
1150:
1151: int
1152: zxcmd(filnum,comand) int filnum; char *comand; {
1153: #ifdef OS2
1154: if (chkfn(filnum) < 0) return(-1); /* Need a valid Kermit file number. */
1155: if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
1156: return(0);
1157: if (filnum == ZIFILE || filnum == ZRFILE) { /* Input from a command */
1158: if (priv_chk() || ((fp[filnum] = popen(comand,"r")) == NULL))
1159: return(0);
1160: } else { /* Output to a command */
1161: if (priv_chk() || ((fp[filnum] = popen(comand,"w")) == NULL))
1162: return(0);
1163: }
1164: ispipe[filnum] = 1;
1165: return(1);
1166: #else /* Not OS2 */
1167: int pipes[2];
1168: int out;
1169:
1170: if (chkfn(filnum) < 0) return(-1); /* Need a valid Kermit file number. */
1171: if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
1172: return(0);
1173:
1174: out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
1175:
1176: /* Output to a command */
1177:
1178: if (out) { /* Need popen() to do this. */
1179: #ifdef NOPOPEN
1180: return(0); /* no popen(), fail. */
1181: #else
1182: /* Use popen() to run the command. */
1183:
1184: #ifdef _POSIX_SOURCE
1185: /* Strictly speaking, popen() is not available in POSIX.1 */
1186: #define DCLPOPEN
1187: #endif /* _POSIX_SOURCE */
1188:
1189: #ifdef DCLPOPEN
1190: /* popen() needs declaring because it's not declared in <stdio.h> */
1191: FILE *popen();
1192: #endif /* DCLPOPEN */
1193:
1194: if (priv_chk() || ((fp[filnum] = popen(comand,"w")) == NULL))
1195: return(0);
1196: else return(1);
1197: #endif /* NOPOPEN */
1198: }
1199:
1200: /* Input from a command */
1201:
1202: if (pipe(pipes) != 0) {
1203: debug(F100,"zxcmd pipe failure","",0);
1204: return(0); /* can't make pipe, fail */
1205: }
1206:
1207: /* Create a fork in which to run the named process */
1208:
1209: #ifdef aegis
1210: if ((pid = vfork()) == 0) { /* child */
1211: #else
1212: if ((pid = fork()) == 0) { /* child */
1213: #endif
1214:
1215: /* We're in the fork. */
1216:
1217: char *shpath, *shname, *shptr; /* Find user's preferred shell */
1218: #ifndef aegis
1219: struct passwd *p;
1220: char *defshell = "/bin/sh"; /* default shell */
1221: #endif /* aegis */
1222: if (priv_can()) exit(1); /* Turn off any privileges! */
1223: debug(F101,"zxcmd pid","",pid);
1224: close(pipes[0]); /* close input side of pipe */
1225: close(0); /* close stdin */
1226: if (open("/dev/null",0) < 0) return(0); /* replace input by null */
1227: #ifndef SVORPOSIX
1228: dup2(pipes[1],1); /* BSD: replace stdout & stderr */
1229: dup2(pipes[1],2); /* by the pipe */
1230: #else
1231: close(1); /* AT&T: close stdout */
1232: if ( dup(pipes[1]) != 1 ) /* Send stdout to the pipe */
1233: return(0);
1234: close(2); /* Send stderr to the pipe */
1235: if ( dup(pipes[1]) != 2 )
1236: return(0);
1237: #endif /* SVORPOSIX */
1238: close(pipes[1]); /* Don't need this any more. */
1239:
1240: #ifdef aegis
1241: if ((shpath = getenv("SERVERSHELL")) == NULL) shpath = "/bin/sh";
1242: #else
1243: shpath = getenv("SHELL"); /* What shell? */
1244: if (shpath == NULL) {
1245: p = getpwuid( real_uid() ); /* Get login data */
1246: if (p == (struct passwd *)NULL || !*(p->pw_shell))
1247: shpath = defshell;
1248: else shpath = p->pw_shell;
1249: }
1250: #endif /* aegis */
1251: shptr = shname = shpath;
1252: while (*shptr != '\0')
1253: if (*shptr++ == '/')
1254: shname = shptr;
1255: debug(F100,"zxcmd...","",0);
1256: debug(F110,shpath,shname,0);
1257:
1258: execl(shpath,shname,"-c",comand,(char *)NULL); /* Execute the cmd */
1259: exit(0); /* just punt if it failed. */
1260: } else if (pid == -1) {
1261: debug(F100,"zxcmd fork failure","",0);
1262: return(0);
1263: }
1264: debug(F101,"zxcmd pid","",pid);
1265: if (out) {
1266: close(pipes[0]); /* Don't need the input side */
1267: fp[filnum] = fdopen(pipes[1],"w"); /* Open a stream for output. */
1268: fp[ZSYSFN] = fp[filnum]; /* Remember. */
1269: zoutcnt = 0; /* (PWP) reset input buffer */
1270: zoutptr = zoutbuffer;
1271: } else {
1272: close(pipes[1]); /* Don't need the output side */
1273: fp[filnum] = fdopen(pipes[0],"r"); /* Open a stream for input. */
1274: fp[ZSYSFN] = fp[filnum]; /* Remember. */
1275: zincnt = 0; /* (PWP) reset input buffer */
1276: zinptr = zinbuffer;
1277: }
1278: return(1);
1279: #endif /* OS2 */
1280: }
1281:
1282: /* Z C L O S F - wait for the child fork to terminate and close the pipe. */
1283:
1284: int
1285: zclosf(filnum) int filnum; {
1286: int wstat;
1287: debug(F101,"zclosf filnum","",filnum);
1288: #ifndef NOPOPEN
1289: #ifdef OS2
1290: if (ispipe[filnum]) {
1291: int x;
1292: x = pclose(fp[filnum]);
1293: fp[filnum] = NULL;
1294: ispipe[filnum] = 0;
1295: #else
1296: if (filnum == ZWFILE) {
1297: int x;
1298: x = pclose(fp[filnum]);
1299: fp[filnum] = fp[ZSYSFN] = NULL;
1300: #endif /* OS2 */
1301: return((x < 0) ? 0 : 1);
1302: }
1303: #endif /* NOPOPEN */
1304: debug(F101,"zclosf fp[filnum]","", fp[filnum]);
1305: debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]);
1306: #ifdef OS2
1307: fclose(fp[filnum]);
1308: fp[filnum] = NULL;
1309: #else
1310: if (pid != 0) {
1311: debug(F101,"zclosf killing pid","",pid);
1312: kill(pid,9);
1313: while ((wstat = wait((WAIT_T *)0)) != pid && wstat != -1) ;
1314: pid = 0;
1315: }
1316: fclose(fp[filnum]);
1317: fp[filnum] = fp[ZSYSFN] = NULL;
1318: #endif /* OS2 */
1319: return(1);
1320: }
1321:
1322: /* Z X P A N D -- Expand a wildcard string into an array of strings */
1323: /*
1324: Returns the number of files that match fn1, with data structures set up
1325: so that first file (if any) will be returned by the next znext() call.
1326: Depends on external variable wildxpand: 0 means we expand wildcards
1327: internally, nonzero means we call the shell to do it.
1328: */
1329:
1330: int
1331: zxpand(fn) char *fn; {
1332: char *p;
1333:
1334: #ifdef DTILDE /* Built with tilde-expansion? */
1335: char *tnam;
1336: #endif /* DTILDE */
1337: debug(F111,"zxpand entry",fn,wildxpand);
1338: #ifdef DTILDE /* Built with tilde-expansion? */
1339: if (*fn == '~') { /* Starts with tilde? */
1340: tnam = tilde_expand(fn); /* Try to expand it. */
1341: if (tnam) fn = tnam;
1342: }
1343: debug(F110,"zxpand after tilde_x",fn,0);
1344: #endif /* DTILDE */
1345: #ifndef OS2
1346: if (wildxpand) /* Who is expanding wildcards? */
1347: fcount = shxpand(fn,mtchs,MAXWLD); /* Shell */
1348: else
1349: #endif /* OS2 */
1350: fcount = fgen(fn,mtchs,MAXWLD); /* Kermit */
1351: if (fcount > 0) {
1352: mtchptr = mtchs; /* Save pointer for next. */
1353: }
1354: if (fcount > 0) {
1355: debug(F111,"zxpand ok",mtchs[0],fcount);
1356: return(fcount);
1357: }
1358: debug(F111,"zxpand fgen1",fn,fcount); /* Didn't get one, or got too many */
1359: p = malloc((int)strlen(fn) + 10); /* Make space */
1360: if (!p) return(0);
1361: zrtol(fn,p); /* Try again, maybe lowercase */
1362: #ifndef OS2
1363: if (wildxpand)
1364: fcount = shxpand(p,mtchs,MAXWLD); /* Shell */
1365: else
1366: #endif /* OS2 */
1367: fcount = fgen(p,mtchs,MAXWLD); /* Kermit */
1368: if (fcount > 0) { /* Got one? */
1369: mtchptr = mtchs; /* Save pointer for next. */
1370: debug(F111,"zxpand fgen2 ok",mtchs[0],fcount);
1371: } else debug(F111,"zxpand 2 not ok",p,fcount);
1372: free(p);
1373: return(fcount);
1374: }
1375:
1376:
1377: /* Z N E X T -- Get name of next file from list created by zxpand(). */
1378: /*
1379: Returns >0 if there's another file, with its name copied into the arg string,
1380: or 0 if no more files in list.
1381: */
1382: int
1383: znext(fn) char *fn; {
1384: if (fcount-- > 0) strcpy(fn,*mtchptr++);
1385: else *fn = '\0';
1386: debug(F111,"znext",fn,fcount+1);
1387: return(fcount+1);
1388: }
1389:
1390:
1391: /* Z C H K S P A -- Check if there is enough space to store the file */
1392:
1393: /*
1394: Call with file specification f, size n in bytes.
1395: Returns -1 on error, 0 if not enough space, 1 if enough space.
1396: */
1397: int
1398: zchkspa(f,n) char *f; long n; { /* Just dummy for now. */
1399: return(1); /* Always say OK. */
1400: }
1401:
1402:
1403: /* Z N E W N -- Make a new name for the given file */
1404:
1405: /*
1406: Given the name, fn, of a file that already exists, this function builds a
1407: new name of the form "<oldname>.~<n>~", where <oldname> is argument name
1408: (fn), and <n> is a version number, one higher than any existing version
1409: number for that file, up to 9999. This format is consistent with that used
1410: by GNU EMACS. If the constructed name is too long for the system's maximum,
1411: enough characters are truncated from the end of <fn> to allow the version
1412: number to fit. If no free version numbers exist between 1 and 9999, a
1413: version number of "xxxx" is used. Returns a pointer to the new name in
1414: argument s.
1415: */
1416:
1417: VOID
1418: znewn(fn,s) char *fn, **s; {
1419: #define ZNEWNBL 255 /* Name buffer length */
1420: #define ZNEWNMD 4 /* Max digits for version number */
1421: static char buf[ZNEWNBL+1];
1422: #ifdef OS2
1423: /*
1424: Well, OS/2 should be able to handle 8.3 FAT names still,
1425: although HPFS is so much easier to live with ...
1426: This code should be checked out with long names.
1427: */
1428: char *bp, *xp, *yp, *zp, ch, temp[14];
1429: int d, i, n;
1430: xp = bp = buf;
1431: while (*fn) { /* Copy name into buf */
1432: ch = *bp++ = *fn++;
1433: if (ISDIRSEP(ch) || (ch == ':')) xp=bp;
1434: }
1435: *bp = '\0';
1436: yp = xp;
1437: i = 1;
1438: while (*yp && (*yp != '.')) {
1439: yp++;
1440: if (++i<=6) zp=yp;
1441: }
1442: /* zp points to 6th character in name, or yp, whichever occurs first. */
1443: strcpy(temp,yp); /* Copy extension, if any */
1444: while (zp != xp+8) {
1445: if ( zp < xp+5 ) *zp++='0';
1446: else *zp++='?'; /* Pad out with wild cards */
1447: }
1448: strcpy(zp,temp); /* Get the extension back */
1449: n = zxpand(buf); /* Expand the resulting wild name */
1450: d = 0; /* Index number */
1451: while (znext(temp)) {
1452: i = atoi(temp+5);
1453: if (i > d) d = i;
1454: }
1455: sprintf(temp,"%03d",d+1); /* get the number into a string */
1456: memcpy(xp+5, temp, 3);
1457: #else /* Not OS2 */
1458: char *bp, *xp;
1459: int len = 0, d = 0, n, t, i, j, k, power = 1;
1460:
1461: int max = MAXNAMLEN; /* Maximum name length */
1462:
1463: if (max < 14) max = 14; /* Make it reasonable */
1464: if (max > ZNEWNBL) max = ZNEWNBL;
1465: bp = buf; /* Buffer for building new name */
1466: while (*fn) { /* Copy old name into buffer */
1467: *bp++ = *fn++;
1468: if (len++ > ZNEWNBL) break; /* ...up to buffer length */
1469: }
1470: for (i = 1; i < ZNEWNMD + 1; i++) { /* Version numbers up to 10**i - 1 */
1471: power *= 10; /* Next power of 10 */
1472: j = max - len; /* Space left for version number */
1473: k = 3 + i; /* Space needed for it */
1474: if (j < k) { /* Make room if necessary */
1475: len -= (k - j); /* Adjust length of filename */
1476: bp = buf + len; /* Point to new end */
1477: }
1478: *bp++ = '*'; /* Put a star on the end (UNIX) */
1479: *bp-- = '\0'; /* Terminate with null */
1480:
1481: n = zxpand(buf); /* Expand the resulting wild name */
1482: /* n is the number of matches */
1483: while (n-- > 0) { /* Find any existing name.~n~ files */
1484: xp = *mtchptr++; /* Point at matching name */
1485: xp += len; /* Look for .~<n>~ at the end of it */
1486: if (*xp == '.' && *(xp+1) == '~') { /* Has a version number */
1487: t = atoi(xp+2); /* Get it */
1488: if (t > d) d = t; /* Save d = highest version number */
1489: }
1490: }
1491: if (d < power-1) { /* Less than maximum possible? */
1492: sprintf(bp,".~%d~",d+1); /* Yes, make "name.~<d+1>~" */
1493: *s = buf; /* Point to new name */
1494: return; /* Done, return it */
1495: }
1496: }
1497: sprintf(bp,".~xxxx~"); /* Too many, use xxxx. */
1498: #endif /* OS2 */
1499: *s = buf;
1500: return;
1501: }
1502:
1503: /* Z R E N A M E -- Rename a file */
1504:
1505: /* Note, link() and unlink() are used because rename() is not available */
1506: /* in some versions of UNIX. */
1507: /* Call with old and new names */
1508: /* Returns 0 on success, -1 on failure. */
1509:
1510: int
1511: zrename(old,new) char *old, *new; {
1512: #ifdef OS2
1513: return rename(old, new);
1514: #else
1515: if (link(old,new) < 0) { /* Make a link with the new name. */
1516: debug(F110," link fails",old,0);
1517: return(-1);
1518: }
1519: if (unlink(old) < 0) { /* Unlink the old name. */
1520: debug(F110," link fails",old,0);
1521: return(-1);
1522: }
1523: return(0);
1524: #endif /* OS2 */
1525: }
1526:
1527: /* Z S A T T R */
1528: /*
1529: Fills in a Kermit file attribute structure for the file which is to be sent.
1530: Returns 0 on success with the structure filled in, or -1 on failure.
1531: If any string member is null, then it should be ignored.
1532: If any numeric member is -1, then it should be ignored.
1533: */
1534: int
1535: zsattr(xx) struct zattr *xx; {
1536: long k;
1537:
1538: k = iflen % 1024L; /* File length in K */
1539: if (k != 0L) k = 1L;
1540: xx->lengthk = (iflen / 1024L) + k;
1541: xx->type.len = 0; /* File type can't be filled in here */
1542: xx->type.val = "";
1543: if (*nambuf) {
1544: xx->date.val = zfcdat(nambuf); /* File creation date */
1545: xx->date.len = (int)strlen(xx->date.val);
1546: } else {
1547: xx->date.len = 0;
1548: xx->date.val = "";
1549: }
1550: xx->creator.len = 0; /* File creator */
1551: xx->creator.val = "";
1552: xx->account.len = 0; /* File account */
1553: xx->account.val = "";
1554: xx->area.len = 0; /* File area */
1555: xx->area.val = "";
1556: xx->passwd.len = 0; /* Area password */
1557: xx->passwd.val = "";
1558: xx->blksize = -1L; /* File blocksize */
1559: xx->access.len = 0; /* File access */
1560: xx->access.val = "";
1561: xx->encoding.len = 0; /* Transfer syntax */
1562: xx->encoding.val = 0;
1563: xx->disp.len = 0; /* Disposition upon arrival */
1564: xx->disp.val = "";
1565: xx->lprotect.len = 0; /* Local protection */
1566: xx->lprotect.val = "";
1567: xx->gprotect.len = 0; /* Generic protection */
1568: xx->gprotect.val = "";
1569: xx->systemid.len = 2; /* System ID */
1570: xx->systemid.val = "U1";
1571: xx->recfm.len = 0; /* Record format */
1572: xx->recfm.val = "";
1573: xx->sysparam.len = 0; /* System-dependent parameters */
1574: xx->sysparam.val = "";
1575: xx->length = iflen; /* Length */
1576: return(0);
1577: }
1578:
1579: #ifdef COMMENT
1580: int
1581: zfree(f) char *f; { /* Check free space */
1582: /* How??? */
1583: return(0);
1584: }
1585: #endif /* COMMENT */
1586:
1587: /* Z F C D A T -- Get file creation date */
1588: /*
1589: Call with pointer to filename.
1590: On success, returns pointer to creation date in yyyymmdd hh:mm:ss format.
1591: On failure, returns pointer to null string.
1592: */
1593: static char datbuf[40];
1594:
1595: /* static */ /* (===OS2 change===) */
1596: char *
1597: zfcdat(name) char *name; {
1598:
1599: #ifdef TIMESTAMP
1600: struct stat buffer;
1601: struct tm *time_stamp, *localtime();
1602: int yy, ss;
1603:
1604: datbuf[0] = '\0';
1605: if(stat(name,&buffer) != 0) {
1606: debug(F110,"zfcdat stat failed",name,0);
1607: return("");
1608: }
1609: time_stamp = localtime(&(buffer.st_mtime));
1610: yy = time_stamp->tm_year;
1611: if (yy < 100) /* In case it returns 2-digit year? */
1612: yy += 1900;
1613: if (yy < 0 || yy > 9999) { /* Make sure year is ok */
1614: debug(F110,"zfcdat date failed",name,0);
1615: return("");
1616: }
1617: if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11)
1618: return("");
1619: if (time_stamp->tm_mday < 0 || time_stamp->tm_mday > 31)
1620: return("");
1621: if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 23)
1622: return("");
1623: if (time_stamp->tm_min < 0 || time_stamp->tm_min > 59)
1624: return("");
1625: ss = time_stamp->tm_sec; /* Seconds */
1626: if (ss < 0 || ss > 59) /* Some systems give a BIG number */
1627: ss = 0;
1628: sprintf(datbuf,
1629: #ifdef pdp11
1630: /* For some reason, 2.1x BSD sprintf gets the last field wrong. */
1631: "%04d%02d%02d %02d:%02d:00",
1632: #else
1633: "%04d%02d%02d %02d:%02d:%02d",
1634: #endif /* pdp11 */
1635: yy,
1636: time_stamp->tm_mon + 1,
1637: time_stamp->tm_mday,
1638: time_stamp->tm_hour,
1639: time_stamp->tm_min
1640: #ifndef pdp11
1641: , ss
1642: #endif /* pdp11 */
1643: );
1644: yy = (int)strlen(datbuf);
1645: debug(F111,"zfcdat",datbuf,yy);
1646: if (yy > 17) datbuf[17] = '\0';
1647: return(datbuf);
1648: #else
1649: return("");
1650: #endif /* timestamp */
1651: }
1652:
1653: /* Z S T I M E -- Set creation date for incoming file */
1654: /*
1655: Call with:
1656: f = pointer to name of existing file.
1657: yy = pointer to a Kermit file attribute structure in which yy->date.val
1658: is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
1659: x = is a function code: 0 means to set the file's creation date as given.
1660: 1 means compare the given date with the file creation date.
1661: Returns:
1662: -1 on any kind of error.
1663: 0 if x is 0 and the file date was set successfully.
1664: 0 if x is 1 and date from attribute structure <= file creation date.
1665: 1 if x is 1 and date from attribute structure > file creation date.
1666: */
1667: int
1668: zstime(f,yy,x) char *f; struct zattr *yy; int x; {
1669: int r = -1; /* return code */
1670: /*
1671: It is ifdef'd TIMESTAMP because it might not work on V7. [email protected].
1672: */
1673: #ifdef TIMESTAMP
1674: /*
1675: To do: adapt code from OS-9 Kermit's ck9fio.c zstime function, which
1676: is more flexible, allowing [yy]yymmdd[ hh:mm[:ss]].
1677: */
1678: #ifndef OS2
1679: extern int ftime(), stat(), utime();
1680: /* at least, the declarations for int functions are not needed anyway */
1681: extern struct tm *localtime();
1682: /* and this should have been declared always through a header file */
1683: #endif /* OS2 */
1684: long tm, days;
1685: int i, n, isleapyear;
1686: /* J F M A M J J A S O N D */
1687: /* 31 28 31 30 31 30 31 31 30 31 30 31 */
1688: static
1689: int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 };
1690: char s[5];
1691: struct stat sb;
1692: #ifdef OS2
1693: struct utimbuf tp;
1694: #else
1695: #ifdef V7
1696: struct utimbuf {
1697: time_t timep[2]; /* New access and modificaton time */
1698: } tp;
1699: char *tz;
1700: long timezone; /* In case timezone not defined in .h file */
1701: #else
1702: struct utimbuf {
1703: time_t atime; /* New access time */
1704: time_t mtime; /* New modification time */
1705: } tp;
1706: #endif /* V7 */
1707: #endif /* OS2 */
1708:
1709: #ifdef ANYBSD
1710: long timezone;
1711: static struct timeb tbp;
1712: #endif
1713:
1714: debug(F110,"zstime",f,0);
1715:
1716: if ((yy->date.len == 0)
1717: || (yy->date.len != 17)
1718: || (yy->date.val[8] != ' ')
1719: || (yy->date.val[11] != ':')
1720: || (yy->date.val[14] != ':') ) {
1721: debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
1722: return(-1);
1723: }
1724: debug(F111,"zstime date check 1",yy->date.val,yy->date.len);
1725: for(i = 0; i < 8; i++) {
1726: if (!isdigit(yy->date.val[i])) {
1727: debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
1728: return(-1);
1729: }
1730: }
1731: debug(F111,"zstime date check 2",yy->date.val,yy->date.len);
1732: i++;
1733:
1734: for (; i < 16; i += 3) {
1735: if ((!isdigit(yy->date.val[i])) || (!isdigit(yy->date.val[i + 1]))) {
1736: debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
1737: return(-1);
1738: }
1739: }
1740: debug(F111,"zstime date check 3",yy->date.val,yy->date.len);
1741:
1742: #ifdef ANYBSD
1743: debug(F100,"ztime BSD calling ftime","",0);
1744: ftime(&tbp);
1745: debug(F100,"ztime BSD back from ftime","",0);
1746: timezone = tbp.timezone * 60L;
1747: debug(F101,"ztime BSD timezone","",timezone);
1748: #endif
1749:
1750: #ifdef ATTSV
1751: tzset(); /* Set `timezone'. */
1752: #endif /* ATTSV */
1753:
1754: #ifdef V7
1755: if ((tz = getenv("TZ")) == NULL)
1756: timezone = 0; /* UTC/GMT */
1757: else
1758: timezone = atoi(&tz[3]); /* Set 'timezone'. */
1759: timezone *= 60L;
1760: #endif
1761:
1762: debug(F100,"zstime so far so good","",0);
1763:
1764: s[4] = '\0';
1765: for (i = 0; i < 4; i++) /* Fix the year */
1766: s[i] = yy->date.val[i];
1767:
1768: debug(F110,"zstime year",s,0);
1769:
1770: n = atoi(s);
1771:
1772: debug(F111,"zstime year",s,n);
1773:
1774: /* Previous year's leap days. This won't work after year 2100, */
1775: /* I don't care about that! */
1776: isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
1777: days = (long) (n - 1970) * 365;
1778: days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
1779:
1780: s[2] = '\0';
1781:
1782: for (i = 4 ; i < 16; i += 2) {
1783: s[0] = yy->date.val[i];
1784: s[1] = yy->date.val[i + 1];
1785: n = atoi(s);
1786: debug(F110,"zstime entering switch",s,0);
1787: switch (i) {
1788: case 4: /* MM: month */
1789: if ((n < 1 ) || ( n > 12)) {
1790: debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
1791: return(-1);
1792: }
1793: days += monthdays [n];
1794: if (isleapyear && n > 2)
1795: ++days;
1796: continue;
1797:
1798: case 6: /* DD: day */
1799: if ((n < 1 ) || ( n > 31)) {
1800: debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
1801: return(-1);
1802: }
1803: tm = (days + n - 1) * 24L * 60L * 60L;
1804: i++; /* Skip the space */
1805: continue;
1806:
1807: case 9: /* hh: hour */
1808: if ((n < 0 ) || ( n > 23)) {
1809: debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
1810: return(-1);
1811: }
1812: tm += n * 60L * 60L;
1813: i++; /* Skip the colon */
1814: continue;
1815:
1816: case 12: /* mm: minute */
1817: if ((n < 0 ) || ( n > 59)) {
1818: debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
1819: return(-1);
1820: }
1821: #ifdef ANYBSD /* Correct for time zone */
1822: tm += timezone;
1823: #else
1824: #ifdef ultrix
1825: tm += (long) timezone;
1826: #else
1827: tm += timezone;
1828: #endif /* ultrix */
1829: #endif /* ANYBSD */
1830: tm += n * 60L;
1831: i++; /* Skip the colon */
1832: continue;
1833:
1834: case 15: /* ss: second */
1835: if ((n < 0 ) || ( n > 59)) {
1836: debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
1837: return(-1);
1838: }
1839: tm += n;
1840: }
1841:
1842: if (localtime(&tm)->tm_isdst)
1843: tm -= 60L * 60L; /* Adjust for daylight savings time */
1844: }
1845:
1846: debug(F111,"Attribute creation date ok ",yy->date.val,yy->date.len);
1847:
1848: if (stat(f,&sb)) { /* Get the time for the file */
1849: debug(F110,"Can't stat file:",f,0);
1850: return(-1);
1851: }
1852: #ifdef OS2
1853: tp.modtime = tm; /* Set modif. time to creation date */
1854: tp.actime = sb.st_atime; /* Don't change the access time */
1855: #else
1856: #ifdef V7
1857: tp.timep[0] = tm; /* Set modif. time to creation date */
1858: tp.timep[1] = sb.st_atime; /* Don't change the access time */
1859: #else
1860: tp.mtime = tm; /* Set modif. time to creation date */
1861: tp.atime = sb.st_atime; /* Don't change the access time */
1862: #endif /* V7 */
1863: #endif /* OS2 */
1864:
1865: switch (x) { /* Execute desired function */
1866: case 0: /* Set the creation date of the file */
1867: if (utime(f,&tp)) { /* Fix modification time */
1868: debug(F110,"Can't set modification time for file: ",f,0);
1869: r = -1;
1870: } else {
1871: debug(F110,"Modification time is set for file: ",f,0);
1872: r = 0;
1873: }
1874: break;
1875: case 1: /* Compare the dates */
1876: debug(F111,"zstime compare",f,sb.st_atime);
1877: debug(F111,"zstime compare","packet",tm);
1878: if (sb.st_atime < tm) r = 0; else r = 1;
1879: break;
1880: default: /* Error */
1881: r = -1;
1882: }
1883: #endif /* TIMESTAMP */
1884: return(r);
1885: }
1886:
1887: /* Find initialization file. */
1888:
1889: #ifdef NOTUSED
1890: int
1891: zkermini() {
1892: /* nothing here for Unix. This function added for benefit of VMS Kermit. */
1893: return(0);
1894: }
1895: #endif /* NOTUSED */
1896:
1897: #ifndef NOFRILLS
1898: int
1899: zmail(p,f) char *p; char *f; { /* Send file f as mail to address p */
1900: /*
1901: Returns 0 on success
1902: 2 if mail delivered but temp file can't be deleted
1903: -2 if mail can't be delivered
1904: The UNIX version always returns 0 because it can't get a good return
1905: code from zsyscmd.
1906: */
1907: #ifdef BSD4
1908: /* The idea is to use /usr/ucb/mail, rather than regular mail, so that */
1909: /* a subject line can be included with -s. Since we can't depend on the */
1910: /* user's path, we use the convention that /usr/ucb/Mail = /usr/ucb/mail */
1911: /* and even if Mail has been moved to somewhere else, this should still */
1912: /* find it... The search could be made more reliable by actually using */
1913: /* access() to see if /usr/ucb/Mail exists. */
1914:
1915: /* Should also make some check on zmbuf overflow... */
1916:
1917: #ifdef OXOS
1918: sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
1919: #else
1920: sprintf(zmbuf,"Mail -s %c%s%c %s < %s", '"', f, '"', p, f);
1921: #endif /* OXOS */
1922: zsyscmd(zmbuf);
1923: #else
1924: #ifdef SVORPOSIX
1925: sprintf(zmbuf,"mail %s < %s", p, f);
1926: zsyscmd(zmbuf);
1927: #else
1928: *zmbuf = '\0';
1929: #endif
1930: #endif
1931: return(0);
1932: }
1933: #endif /* NOFRILLS */
1934:
1935: #ifndef NOFRILLS
1936: int
1937: zprint(p,f) char *p; char *f; { /* Print file f with options p */
1938:
1939: #ifdef OS2
1940: sprintf(zmbuf,"print %s %s", p, f); /* Construct print command */
1941: zsyscmd(zmbuf);
1942: #else
1943: #ifdef UNIX
1944: #ifdef ANYBSD /* BSD uses lpr to spool */
1945: #ifndef OXOS /* Except Olivetti... */
1946: #define SPOOLER "lpr"
1947: #else
1948: #define SPOOLER "lp"
1949: #endif /* OXOS */
1950: #else /* Sys V uses lp */
1951: #ifdef TRS16 /* except for Tandy-16/6000... */
1952: #define SPOOLER "lpr"
1953: #else
1954: #define SPOOLER "lp"
1955: #endif
1956: #endif
1957: /*
1958: Note use of standard input redirection. In some systems, lp[r] runs
1959: setuid to lp (or ...?), so if user has sent a file into a directory
1960: that lp does not have read access to, it can't be printed unless it is
1961: feed to lp[r] as standard input.
1962: */
1963: sprintf(zmbuf,"%s %s < %s", SPOOLER, p, f); /* Construct print command */
1964: zsyscmd(zmbuf);
1965: #else /* Not UNIX */
1966: *zmbuf = '\0';
1967: #endif /* UNIX */
1968: #endif /* OS2 */
1969: return(0);
1970: }
1971: #endif /* NOFRILLS */
1972:
1973: /*
1974: Wildcard expansion functions. C-Kermit used to do this itself (see #else
1975: part...). New code (version 5A, 1990-91) just asks UNIX to do it.
1976: This lets users use the wildcard expansion features of their favorite shell.
1977: Operation is slower because of the forking & piping, but flexibility is
1978: greater and program is smaller. For OS/2, C-Kermit still does this itself.
1979: */
1980:
1981: static char scratch[MAXPATH+4]; /* Used by both methods */
1982:
1983: #ifndef OS2
1984: static int oldmtchs = 0; /* Let shell (ls) expand them. */
1985: #ifdef COMMENT
1986: static char *lscmd = "/bin/ls -d"; /* Command to use. */
1987: #else
1988: static char *lscmd = "echo"; /* Command to use. */
1989: #endif /* COMMENT */
1990:
1991: int
1992: shxpand(pat,namlst,len) char *pat, *namlst[]; int len; {
1993: char *fgbuf = NULL; /* Buffer for forming ls command */
1994: char *p, *q; /* Workers */
1995: int i, x, retcode; char c; /* ... */
1996:
1997: x = (int)strlen(pat) + (int)strlen(lscmd) + 3; /* Length of ls command */
1998: for (i = 0; i < oldmtchs; i++) /* Free previous file list */
1999: free(namlst[i]);
2000: fgbuf = malloc(x); /* Get buffer for command */
2001: if (!fgbuf) return(-1); /* Fail if cannot */
2002: sprintf(fgbuf,"%s %s",lscmd,pat); /* Form the command */
2003: zxcmd(ZIFILE,fgbuf); /* Start the command */
2004: i = 0; /* File counter */
2005: p = scratch; /* Point to scratch area */
2006: retcode = -1; /* Assume failure */
2007: while ((x = zminchar()) != -1) { /* Read characters from command */
2008: c = (char) x;
2009: if (c == ' ' || c == '\n') { /* Got newline or space? */
2010: *p = '\0'; /* Yes, terminate string */
2011: p = scratch; /* Point back to beginning */
2012: if (zchki(p) == -1) /* Does file exist? */
2013: continue; /* No, continue */
2014: x = (int)strlen(p); /* Yes, get length of name */
2015: q = malloc(x+1); /* Allocate space for it */
2016: if (!q) goto shxfin; /* Fail if space can't be obtained */
2017: strcpy(q,scratch); /* Copy name to space */
2018: namlst[i++] = q; /* Copy pointer to name into array */
2019: if (i > len) goto shxfin; /* Fail if too many */
2020: } else { /* Regular character */
2021: *p++ = c; /* Copy it into scratch area */
2022: }
2023: }
2024: retcode = i; /* Return number of matching files */
2025: shxfin: /* Common exit point */
2026: free(fgbuf); /* Free command buffer */
2027: zclosf(ZIFILE); /* Delete the command fork. */
2028: oldmtchs = i; /* Remember how many files */
2029: return(retcode);
2030: }
2031: #endif /* OS2 */
2032:
2033: /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
2034:
2035: /* Define the size of the string space for filename expansion. */
2036:
2037: #ifndef DYNAMIC
2038: #ifdef PROVX1
2039: #define SSPACE 500
2040: #else
2041: #ifdef BSD29
2042: #define SSPACE 500
2043: #else
2044: #ifdef pdp11
2045: #define SSPACE 500
2046: #else
2047: #ifdef aegis
2048: #define SSPACE 10000 /* size of string-generating buffer */
2049: static char bslash; /* backslash character if active */
2050: #else /* Default static buffer size */
2051: #define SSPACE 2000 /* size of string-generating buffer */
2052: #endif /* aegis */
2053: #endif /* pdp11 */
2054: #endif /* BSD29 */
2055: #endif /* PROVX1 */
2056: static char sspace[SSPACE]; /* buffer for generating filenames */
2057: #else /* DYNAMIC */
2058: #define SSPACE 10000
2059: static char *sspace = (char *)0;
2060: #endif /* DYNAMIC */
2061: static int ssplen = SSPACE; /* length of string space buffer */
2062:
2063: static char *freeptr,**resptr; /* copies of caller's arguments */
2064: static int remlen; /* remaining length in caller's array*/
2065: static int numfnd; /* number of matches found */
2066:
2067: /*
2068: * splitpath:
2069: * takes a string and splits the slash-separated portions into
2070: * a list of path structures. Returns the head of the list. The
2071: * structures are allocated by malloc, so they must be freed.
2072: * Splitpath is used internally by the filename generator.
2073: *
2074: * Input: A string.
2075: * Returns: A linked list of the slash-separated segments of the input.
2076: */
2077:
2078: struct path *
2079: splitpath(p) char *p; {
2080: struct path *head,*cur,*prv;
2081: int i;
2082:
2083: debug(F110,"splitpath",p,0);
2084:
2085: head = prv = NULL;
2086: if (ISDIRSEP(*p)) p++; /* skip leading slash */
2087: while (*p != '\0') {
2088: cur = (struct path *) malloc(sizeof (struct path));
2089: debug(F101,"splitpath malloc","",cur);
2090: if (cur == NULL)
2091: fatal("malloc fails in splitpath()");
2092: cur -> fwd = NULL;
2093: if (head == NULL)
2094: head = cur;
2095: else
2096: prv -> fwd = cur; /* link into chain */
2097: prv = cur;
2098: #ifdef aegis
2099: /* treat backslash as "../" */
2100: if (bslash && *p == bslash) {
2101: strcpy(cur->npart, "..");
2102: ++p;
2103: } else {
2104: for (i=0; i < MAXNAMLEN && *p && *p != '/' && *p != bslash; i++)
2105: cur -> npart[i] = *p++;
2106: cur -> npart[i] = '\0'; /* end this segment */
2107: if (i >= MAXNAMLEN)
2108: while (*p && *p != '/' && *p != bslash)
2109: p++;
2110: }
2111: if (*p == '/') p++;
2112: #else
2113: #ifdef OS2
2114: for (i = 0;
2115: i < MAXNAMLEN && !ISDIRSEP(*p) && *p != ':' && *p != '\0';
2116: i++ )
2117: cur -> npart[i] = *p++;
2118: if ( *p == ':' ) {
2119: cur -> npart[i++] = *p++;
2120: if ( !ISDIRSEP(*p) )
2121: cur -> npart[i++] = '.';
2122: }
2123: #else
2124: for (i=0; i < MAXNAMLEN && !ISDIRSEP(*p) && *p != '\0'; i++) {
2125: cur -> npart[i] = *p++;
2126: }
2127: #endif /* OS2 */
2128: cur -> npart[i] = '\0'; /* end this segment */
2129: if (i >= MAXNAMLEN)
2130: while (!ISDIRSEP(*p) && *p != '\0') p++;
2131: if (ISDIRSEP(*p))
2132: p++;
2133:
2134: #endif /* aegis */
2135: }
2136: return(head);
2137: }
2138:
2139: /*
2140: * fgen:
2141: * This is the actual name generator. It is passed a string,
2142: * possibly containing wildcards, and an array of character pointers.
2143: * It finds all the matching filenames and stores them into the array.
2144: * The returned strings are allocated from a static buffer local to
2145: * this module (so the caller doesn't have to worry about deallocating
2146: * them); this means that successive calls to fgen will wipe out
2147: * the results of previous calls. This isn't a problem here
2148: * because we process one wildcard string at a time.
2149: *
2150: * Input: a wildcard string, an array to write names to, the
2151: * length of the array.
2152: * Returns: the number of matches. The array is filled with filenames
2153: * that matched the pattern. If there wasn't enough room in the
2154: * array, -1 is returned.
2155: * By: Jeff Damens, CUCCA, 1984.
2156: */
2157: static int
2158: fgen(pat,resarry,len) char *pat,*resarry[]; int len; {
2159: struct path *head;
2160: char *sptr;
2161: #ifdef aegis
2162: char *namechars;
2163: int tilde = 0, bquote = 0;
2164:
2165: if ((namechars = getenv("NAMECHARS")) != NULL) {
2166: if (xindex(namechars, '~' ) != NULL) tilde = '~';
2167: if (xindex(namechars, '\\') != NULL) bslash = '\\';
2168: if (xindex(namechars, '`' ) != NULL) bquote = '`';
2169: } else {
2170: tilde = '~'; bslash = '\\'; bquote = '`';
2171: }
2172:
2173: sptr = scratch;
2174:
2175: /* copy "`node_data", etc. anchors */
2176: if (bquote && *pat == bquote)
2177: while (*pat && *pat != '/' && *pat != bslash)
2178: *sptr++ = *pat++;
2179: else if (tilde && *pat == tilde)
2180: *sptr++ = *pat++;
2181: while (*pat == '/')
2182: *sptr++ = *pat++;
2183: if (sptr == scratch) {
2184: strcpy(scratch,"./");
2185: sptr = scratch+2;
2186: } /* init buffer correctly */
2187: head = splitpath(pat);
2188: #else /* not aegis */
2189: debug(F110,"fgen pat",pat,0);
2190: head = splitpath(pat);
2191: sptr = scratch;
2192: if (!ISDIRSEP(*pat))
2193: *sptr++ = '.'; /* init buffer correctly */
2194: *sptr++ = DIRSEP;
2195: #ifdef OS2
2196: if (isalpha(pat[0]) && pat[1] == ':')
2197: sptr = scratch; /* reset in case of leading drive: */
2198: #endif
2199: #endif /* aegis */
2200: numfnd = 0; /* none found yet */
2201: #ifdef DYNAMIC
2202: if (!sspace) { /* Need to allocate string space? */
2203: while (ssplen > 50) {
2204: if ((sspace = malloc(ssplen+2))) { /* Got it. */
2205: debug(F101,"fgen string space","",ssplen);
2206: break;
2207: }
2208: ssplen = (ssplen / 2) + (ssplen / 4); /* Didn't, reduce by 3/4 */
2209: }
2210: if (ssplen < 50) { /* Did we get it? */
2211: fprintf(stderr,"fgen can't malloc string space\n");
2212: return(-1);
2213: }
2214: }
2215: #endif /* DYNAMIC */
2216: freeptr = sspace; /* this is where matches are copied */
2217: resptr = resarry; /* static copies of these so */
2218: remlen = len; /* recursive calls can alter them */
2219: traverse(head,scratch,sptr); /* go walk the directory tree */
2220: #ifdef COMMENT
2221: /*
2222: This code, circa 1984, has never worked right - it references the head
2223: pointer after it has already been freed. Lord knows what might have been
2224: happening because of this. Thanks to Steve Walton for finding & fixing this
2225: bug.
2226: */
2227: for (; head != NULL; head = head -> fwd)
2228: free(head); /* return the path segments */
2229: #else
2230: while (head != NULL) {
2231: struct path *next = head -> fwd;
2232: free(head);
2233: head = next;
2234: }
2235: #endif /* COMMENT */
2236: return(numfnd); /* and return the number of matches */
2237: }
2238:
2239: /* traverse:
2240: * Walks the directory tree looking for matches to its arguments.
2241: * The algorithm is, briefly:
2242: * If the current pattern segment contains no wildcards, that
2243: * segment is added to what we already have. If the name so far
2244: * exists, we call ourselves recursively with the next segment
2245: * in the pattern string; otherwise, we just return.
2246: *
2247: * If the current pattern segment contains wildcards, we open the name
2248: * we've accumulated so far (assuming it is really a directory), then read
2249: * each filename in it, and, if it matches the wildcard pattern segment, add
2250: * that filename to what we have so far and call ourselves recursively on the
2251: * next segment.
2252: *
2253: * Finally, when no more pattern segments remain, we add what's accumulated
2254: * so far to the result array and increment the number of matches.
2255: *
2256: * Input: a pattern path list (as generated by splitpath), a string
2257: * pointer that points to what we've traversed so far (this
2258: * can be initialized to "/" to start the search at the root
2259: * directory, or to "./" to start the search at the current
2260: * directory), and a string pointer to the end of the string
2261: * in the previous argument.
2262: * Returns: nothing.
2263: */
2264: static VOID
2265: traverse(pl,sofar,endcur) struct path *pl; char *sofar, *endcur; {
2266:
2267: /* Define LONGFN (long file names) automatically for BSD 2.9 and 4.2 */
2268: /* LONGFN can also be defined on the cc command line. */
2269:
2270: #ifdef BSD29
2271: #ifndef LONGFN
2272: #define LONGFN
2273: #endif
2274: #endif
2275:
2276: #ifdef BSD42
2277: #ifndef LONGFN
2278: #define LONGFN
2279: #endif
2280: #endif
2281:
2282: /* Appropriate declarations for directory routines and structures */
2283: /* #define OPENDIR means to use opendir(), readdir(), closedir() */
2284: /* If OPENDIR not defined, we use open(), read(), close() */
2285:
2286: #ifdef DIRENT /* New way, <dirent.h> */
2287: #define OPENDIR
2288: DIR *fd, *opendir();
2289: struct dirent *dirbuf;
2290: struct dirent *readdir();
2291: #else /* !DIRENT */
2292: #ifdef LONGFN /* Old way, <dir.h> with opendir() */
2293: #define OPENDIR
2294: DIR *fd, *opendir();
2295: struct direct *dirbuf;
2296: #else /* !LONGFN */
2297: int fd; /* Old way, <dir.h> with open() */
2298: struct direct dir_entry;
2299: struct direct *dirbuf = &dir_entry;
2300: #endif /* LONGFN */
2301: #endif /* DIRENT */
2302:
2303: struct stat statbuf; /* for file info */
2304:
2305: if (pl == NULL) {
2306: *--endcur = '\0'; /* end string, overwrite trailing / */
2307: addresult(sofar);
2308: return;
2309: }
2310: if (!iswild(pl -> npart)) {
2311: strcpy(endcur,pl -> npart);
2312: endcur += (int)strlen(pl -> npart);
2313: *endcur = '\0'; /* end current string */
2314: if (stat(sofar,&statbuf) == 0) { /* if current piece exists */
2315: #ifdef OS2
2316: if (endcur - sofar == 3 && endcur[-1] == '.' && endcur[-2] == ':')
2317: endcur--;
2318: else
2319: #endif /* OS2 */
2320: *endcur++ = DIRSEP; /* add slash to end */
2321: *endcur = '\0'; /* and end the string */
2322: traverse(pl -> fwd,sofar,endcur);
2323: }
2324: return;
2325: }
2326:
2327: /* Segment contains wildcards, have to search directory */
2328:
2329: *endcur = '\0'; /* end current string */
2330: if (stat(sofar,&statbuf) == -1) return; /* doesn't exist, forget it */
2331: if (!S_ISDIR (statbuf.st_mode)) return; /* not a directory, skip */
2332:
2333: #ifdef OPENDIR
2334: if ((fd = opendir(sofar)) == NULL) return; /* Can't open, fail. */
2335: while (dirbuf = readdir(fd))
2336: #else /* !OPENDIR */
2337: if ((fd = open(sofar,O_RDONLY)) < 0) return; /* Can't open, fail. */
2338: while (read(fd, (char *)dirbuf, sizeof dir_entry))
2339: #endif /* OPENDIR */
2340: {
2341: /* Get null-terminated copy!!! */
2342: strncpy(nambuf,dirbuf->d_name,MAXNAMLEN);
2343: nambuf[MAXNAMLEN] = '\0';
2344: #ifdef unos
2345: if (dirbuf->d_ino != -1 && match(pl -> npart,nambuf))
2346: #else
2347: /* #ifdef _POSIX_SOURCE */
2348: /*
2349: This is not specified in POSIX.1. In POSIX.2, there will be
2350: some kind of filename matching facility, but it will not be done this way.
2351: Therefore, we should not even be looking in the directory at all.
2352: Maybe POSIX implementations should force "set wildcard shell"?
2353: */
2354:
2355: #ifdef sun
2356: if (dirbuf->d_fileno != 0 && match(pl -> npart,nambuf))
2357: #else
2358: #ifdef ultrix
2359: if (dirbuf->gd_ino != 0 && match(pl -> npart,nambuf))
2360: #else
2361: if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf))
2362: #endif /* ultrix */
2363: #endif /* sun */
2364:
2365: /* #else */ /* not _POSIX_SOURCE */
2366: /* if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf)) */
2367: /* #endif */ /* _POSIX_SOURCE */
2368:
2369: #endif /* unos */
2370: {
2371: char *eos;
2372: strcpy(endcur,nambuf);
2373: eos = endcur + (int)strlen(nambuf);
2374: *eos++ = DIRSEP; /* end this segment */
2375: traverse(pl -> fwd,sofar,eos);
2376: }
2377: }
2378: #ifdef OPENDIR
2379: closedir(fd);
2380: #else /* !OPENDIR */
2381: close(fd);
2382: #endif /* OPENDIR */
2383: }
2384:
2385: /*
2386: * addresult:
2387: * Adds a result string to the result array. Increments the number
2388: * of matches found, copies the found string into our string
2389: * buffer, and puts a pointer to the buffer into the caller's result
2390: * array. Our free buffer pointer is updated. If there is no
2391: * more room in the caller's array, the number of matches is set to -1.
2392: * Input: a result string.
2393: * Returns: nothing.
2394: */
2395: static VOID
2396: addresult(str) char *str; {
2397: int l;
2398: debug(F111,"addresult",str,remlen);
2399: if (str[0] == '.' && ISDIRSEP(str[1])) str += 2; /* (===OS2 change===) */
2400: if (--remlen < 0) {
2401: numfnd = -1;
2402: return;
2403: }
2404: l = (int)strlen(str) + 1; /* size this will take up */
2405: if ((freeptr + l) > (sspace + ssplen)) {
2406: numfnd = -1; /* do not record if not enough space */
2407: return;
2408: }
2409: strcpy(freeptr,str);
2410: *resptr++ = freeptr;
2411: freeptr += l;
2412: numfnd++;
2413: }
2414:
2415: /*
2416: * match:
2417: * pattern matcher. Takes a string and a pattern possibly containing
2418: * the wildcard characters '*' and '?'. Returns true if the pattern
2419: * matches the string, false otherwise.
2420: * by: Jeff Damens, CUCCA, 1984
2421: * skipping over dot files and backslash quoting added by fdc, 1990.
2422: *
2423: * Input: a string and a wildcard pattern.
2424: * Returns: 1 if match, 0 if no match.
2425: */
2426: static int
2427: match(pattern,string) char *pattern,*string; {
2428: char *psave,*ssave; /* back up pointers for failure */
2429: int q = 0; /* quote flag */
2430:
2431: debug(F110,"match str",string,0);
2432: psave = ssave = NULL;
2433: #ifndef MATCHDOT
2434: if (*string == '.' && *pattern != '.') {
2435: debug(F110,"match skip",string,0);
2436: return(0);
2437: }
2438: #endif
2439: while (1) {
2440: for (; *pattern == *string; pattern++,string++) /* skip first */
2441: if (*string == '\0') return(1); /* end of strings, succeed */
2442:
2443: if (*pattern == '\\' && q == 0) { /* Watch out for quoted */
2444: q = 1; /* metacharacters */
2445: pattern++; /* advance past quote */
2446: if (*pattern != *string) return(0);
2447: continue;
2448: } else q = 0;
2449:
2450: if (q) {
2451: return(0);
2452: } else {
2453: if (*string != '\0' && *pattern == '?') {
2454: pattern++; /* '?', let it match */
2455: string++;
2456: } else if (*pattern == '*') { /* '*' ... */
2457: psave = ++pattern; /* remember where we saw it */
2458: ssave = string; /* let it match 0 chars */
2459: } else if (ssave != NULL && *ssave != '\0') { /* if not at end */
2460: /* ...have seen a star */
2461: string = ++ssave; /* skip 1 char from string */
2462: pattern = psave; /* and back up pattern */
2463: } else return(0); /* otherwise just fail */
2464: }
2465: }
2466: }
2467:
2468: /*
2469: The following two functions are for expanding tilde in filenames
2470: Contributed by Howie Kaye, CUCCA, developed for CCMD package.
2471: */
2472:
2473: /* W H O A M I -- Get user's username. */
2474:
2475: /*
2476: 1) Get real uid
2477: 2) See if the $USER environment variable is set ($LOGNAME on AT&T)
2478: 3) If $USER's uid is the same as ruid, realname is $USER
2479: 4) Otherwise get logged in user's name
2480: 5) If that name has the same uid as the real uid realname is loginname
2481: 6) Otherwise, get a name for ruid from /etc/passwd
2482: */
2483: static char *
2484: whoami () {
2485: #ifdef DTILDE
2486: static char realname[256]; /* user's name */
2487: static int ruid = -1; /* user's real uid */
2488: char loginname[256], envname[256]; /* temp storage */
2489: char *c;
2490: struct passwd *p;
2491: _PROTOTYP(extern char * getlogin, (void) );
2492:
2493: if (ruid != -1)
2494: return(realname);
2495:
2496: ruid = real_uid(); /* get our uid */
2497:
2498: /* how about $USER or $LOGNAME? */
2499: if ((c = getenv(NAMEENV)) != NULL) { /* check the env variable */
2500: strcpy (envname, c);
2501: p = getpwnam(envname);
2502: if (p->pw_uid == ruid) { /* get passwd entry for envname */
2503: strcpy (realname, envname); /* if the uid's are the same */
2504: return(realname);
2505: }
2506: }
2507:
2508: /* can we use loginname() ? */
2509:
2510: if ((c = getlogin()) != NULL) { /* name from utmp file */
2511: strcpy (loginname, c);
2512: if ((p = getpwnam(loginname)) != NULL) /* get passwd entry */
2513: if (p->pw_uid == ruid) { /* for loginname */
2514: strcpy (realname, loginname); /* if the uid's are the same */
2515: return(realname);
2516: }
2517: }
2518:
2519: /* Use first name we get for ruid */
2520:
2521: if ((p = getpwuid(ruid)) == NULL) { /* name for uid */
2522: realname[0] = '\0'; /* no user name */
2523: ruid = -1;
2524: return(NULL);
2525: }
2526: strcpy (realname, p->pw_name);
2527: return(realname);
2528: #else
2529: return(NULL);
2530: #endif /* DTILDE */
2531: }
2532:
2533: /* T I L D E _ E X P A N D -- expand ~user to the user's home directory. */
2534:
2535: char *
2536: tilde_expand(dirname) char *dirname; {
2537: #define BUFLEN 256
2538: #ifdef DTILDE
2539: struct passwd *user;
2540: static char olddir[BUFLEN];
2541: static char oldrealdir[BUFLEN];
2542: static char temp[BUFLEN];
2543: int i, j;
2544:
2545: debug(F111,"tilde_expand",dirname,dirname[0]);
2546:
2547: if (dirname[0] != '~') /* Not a tilde...return param */
2548: return(dirname);
2549: if (!strcmp(olddir,dirname)) { /* Same as last time */
2550: return(oldrealdir); /* so return old answer. */
2551: } else {
2552: j = (int)strlen(dirname);
2553: for (i = 0; i < j; i++) /* find username part of string */
2554: if (!ISDIRSEP(dirname[i]))
2555: temp[i] = dirname[i];
2556: else break;
2557: temp[i] = '\0'; /* tie off with a NULL */
2558: if (i == 1) { /* if just a "~" */
2559: user = getpwnam(whoami()); /* get info on current user */
2560: } else {
2561: user = getpwnam(&temp[1]); /* otherwise on the specified user */
2562: }
2563: }
2564: if (user != NULL) { /* valid user? */
2565: strcpy(olddir, dirname); /* remember the directory */
2566: strcpy(oldrealdir,user->pw_dir); /* and their home directory */
2567: strcat(oldrealdir,&dirname[i]);
2568: return(oldrealdir);
2569: } else { /* invalid? */
2570: strcpy(olddir, dirname); /* remember for next time */
2571: strcpy(oldrealdir, dirname);
2572: return(oldrealdir);
2573: }
2574: #else
2575: return(NULL);
2576: #endif /* DTILDE */
2577: }
2578:
2579: /*
2580: Functions for executing system commands.
2581: zsyscmd() executes the system command in the normal, default way for
2582: the system. In UNIX, it does what system() does. Thus, its results
2583: are always predictable.
2584: zshcmd() executes the command using the user's preferred shell.
2585: */
2586: int
2587: zsyscmd(s) char *s; {
2588: #ifdef OS2
2589: if (!priv_chk()) system(s);
2590: #else
2591: PID_T shpid;
2592: #ifdef COMMENT
2593: /* This doesn't work... */
2594: WAIT_T status;
2595: #else
2596: int status;
2597: #endif /* COMMENT */
2598:
2599: if (shpid = fork()) {
2600: if (shpid < (PID_T)0) return(-1); /* Parent */
2601: while (shpid != (PID_T) wait(&status))
2602: ;
2603: return(status);
2604: }
2605: if (priv_can()) { /* Child: cancel any priv's */
2606: printf("?Privilege cancellation failure\n");
2607: _exit(255);
2608: }
2609: execl("/bin/sh","sh","-c",s,NULL);
2610: perror("/bin/sh");
2611: _exit(255);
2612: return(0); /* Shut up ANSI compilers. */
2613: #endif /* OS2 */
2614: }
2615:
2616: /*
2617: UNIX code by H. Fischer; copyright rights assigned to Columbia Univ.
2618: Adapted to use getpwuid to find login shell because many systems do not
2619: have SHELL in environment, and to use direct calling of shell rather
2620: than intermediate system() call. -- H. Fischer
2621: Call with s pointing to command to execute.
2622: */
2623:
2624: int
2625: zshcmd(s) char *s; {
2626: PID_T pid;
2627:
2628: #ifdef OS2
2629: char *shell = getenv("COMSPEC");
2630: if (!priv_chk())
2631: if (*s == '\0')
2632: spawnl(P_WAIT, shell, shell, NULL);
2633: else
2634: system(s);
2635: #else
2636: #ifdef AMIGA
2637: if (!priv_chk()) system(s);
2638: #else
2639: #ifdef datageneral
2640: if (priv_chk) return(1);
2641: if (*s == '\0') /* Interactive shell requested? */
2642: #ifdef mvux
2643: system("/bin/sh ");
2644: #else
2645: system("x :cli prefix Kermit_Baby:");
2646: #endif /* mvux */
2647: else /* Otherwise, */
2648: system(s); /* Best for aos/vs?? */
2649:
2650: #else
2651: #ifdef aegis
2652: if ((pid = vfork()) == 0) { /* Make child quickly */
2653: char *shpath, *shname, *shptr; /* For finding desired shell */
2654:
2655: if (priv_can()) exit(1); /* Turn off privs. */
2656: if ((shpath = getenv("SHELL")) == NULL) shpath = "/com/sh";
2657:
2658: #else /* All Unix systems */
2659: if ((pid = fork()) == 0) { /* Make child */
2660: char *shpath, *shname, *shptr; /* For finding desired shell */
2661: struct passwd *p;
2662: char *defshell = "/bin/sh"; /* Default */
2663:
2664: if (priv_can()) exit(1); /* Turn off privs. */
2665: p = getpwuid(real_uid()); /* Get login data */
2666: if (p == (struct passwd *) NULL || !*(p->pw_shell))
2667: shpath = defshell;
2668: else
2669: shpath = p->pw_shell;
2670: #endif /* aegis */
2671: shptr = shname = shpath;
2672: while (*shptr != '\0')
2673: if (*shptr++ == DIRSEP)
2674: shname = shptr;
2675: if (s == NULL || *s == '\0') { /* Interactive shell requested? */
2676: execl(shpath,shname,"-i",NULL); /* Yes, do that */
2677: } else { /* Otherwise, */
2678: execl(shpath,shname,"-c",s,NULL); /* exec the given command */
2679: } /* If execl() failed, */
2680: exit(BAD_EXIT); /* return bad return code. */
2681:
2682: } else { /* Parent */
2683:
2684: int wstat; /* ... must wait for child */
2685: SIGTYP (*istat)(), (*qstat)();
2686:
2687: if (pid == -1) return(0); /* fork() failed? */
2688:
2689: istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
2690: qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
2691:
2692: while (((wstat = wait((WAIT_T *)0)) != pid) && (wstat != -1))
2693: ; /* Wait for fork */
2694: signal(SIGINT,istat); /* Restore interrupts */
2695: signal(SIGQUIT,qstat);
2696: }
2697: #endif
2698: #endif
2699: #endif
2700: return(1);
2701: }
2702:
2703: #ifdef aegis
2704: /*
2705: Replacement for strchr() and index(), neither of which seem to be universal.
2706: */
2707:
2708: static char *
2709: #ifdef CK_ANSIC
2710: xindex(char * s, char c)
2711: #else
2712: xindex(s,c) char *s, c;
2713: #endif /* CK_ANSIC */
2714: /* xindex */ {
2715: while (*s != '\0' && *s != c) s++;
2716: if (*s == c) return(s); else return(NULL);
2717: }
2718: #endif /* aegis */
2719:
2720: /* I S W I L D -- Check if filespec is "wild" */
2721:
2722: /*
2723: Returns 0 if it is a single file, 1 if it contains wildcard characters.
2724: Note: must match the algorithm used by match(), hence no [a-z], etc.
2725: */
2726: int
2727: iswild(filespec) char *filespec; {
2728: char c; int x; char *p;
2729: if (wildxpand) {
2730: if ((x = zxpand(filespec)) > 1) return(1);
2731: p = malloc(MAXNAMLEN + 20);
2732: znext(p);
2733: x = (strcmp(filespec,p) != 0);
2734: free(p);
2735: return(x);
2736: } else {
2737: while ((c = *filespec++) != '\0')
2738: if (c == '*' || c == '?') return(1);
2739: return(0);
2740: }
2741: }
2742:
2743: #ifdef OS2
2744:
2745: /* Z C H D S K -- Change currently selected disk device */
2746:
2747: /* Returns -1 if error, otherwise 0 */
2748:
2749: zchdsk(c) char c; {
2750: int i = toupper(c) - 64;
2751: return( _chdrive(i) ? 0 : -1 );
2752: }
2753:
2754: #undef stat
2755:
2756: os2stat(char *path, struct stat *st) {
2757: char local[MAXPATHLEN];
2758: int len;
2759:
2760: strcpy(local, path);
2761: len = strlen(local);
2762:
2763: if ( len == 2 && local[1] == ':' )
2764: local[2] = DIRSEP, local[3] = 0; /* if drive only, append / */
2765: else if ( len == 0 )
2766: local[0] = DIRSEP, local[1] = 0; /* if empty path, take / instead */
2767: else if ( len > 1 && ISDIRSEP(local[len - 1]) && local[len - 2] != ':' )
2768: local[len - 1] = 0; /* strip trailing / except after d: */
2769:
2770: return stat(local, st);
2771: }
2772:
2773: #endif /* OS2 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.