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