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