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