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