Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watnot!watmath!clyde!rutgers!pyrnj!mirror!rs From: rs@mirror.UUCP Newsgroups: net.sources Subject: "Everyone's" shell (un)archiving tools, Part1/2 Message-ID: <2528@mirror.TMC.COM> Date: Tue, 24-Mar-87 18:19:06 EST Article-I.D.: mirror.2528 Posted: Tue Mar 24 18:19:06 1987 Date-Received: Fri, 27-Mar-87 00:38:25 EST Organization: Mirror Systems, Cambridge, MA Lines: 2190 This is the set of tools I've been using recently in mod.sources. It's designed to be portable to non-Unix systems, and includes a program that should let yuckky MS-DOS, iccky AMIGA-DOS, and similar beasties unpack shell archives. It does pretty well at doing many of the items in the mod.sources archive. Please beat on this and send me feedback, porting notes, and other brickbats; I'll publish this in mod.sources in a couple of weeks. /r$ #! /bin/sh # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # If this archive is complete, you will see the message: # "End of archive 1 (of 2)." # Contents: MANIFEST Makefile README cwd.c findsrc.c findsrc.man # getopt.c glue.c host.c makekit.man mem.c shar.c shar.h shar.man # shell.c shell.man sysfuncs.c unshar.man # Wrapped by rs@mirror on Tue Mar 24 18:12:02 1987 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo shar: Extracting \"MANIFEST\" \(1276 characters\) if test -f MANIFEST ; then echo shar: Will not over-write existing file \"MANIFEST\" else sed "s/^X//" >MANIFEST <<'END_OF_MANIFEST' X File Name Archive # Description X----------------------------------------------------------- X MANIFEST 1 This shipping list X Makefile 1 Guess X README 1 Acknowledgements, installation notes X cwd.c 1 Routines to find current directory X findsrc.c 1 Find source files, based on filename X findsrc.man 1 Manpage for findsrc X getopt.c 1 For those that need it X glue.c 1 Glue for "safe" unshar X host.c 1 Find our machine name X makekit.c 2 Partition files into reasonable-sized kits X makekit.man 1 Manpage for makekit X mem.c 1 Memory allocator, uses calloc X parser.c 2 Interpreter for shell archives X shar.c 1 Create script to create files X shar.h 1 Header file, used by everyone X shar.man 1 Manpage for makekit X shell.c 1 Main routine for my shell interpreter X shell.man 1 Manpage for shell X sysfuncs.c 1 System-dependent routines X unshar.c 2 Strip news, notes, mail headers from shar's X unshar.man 1 Manpage for unshar END_OF_MANIFEST if test 1276 -ne `wc -c Makefile <<'END_OF_Makefile' X## X## SOURCE-SHIPPING TOOLS MAKEFILE X## $Header: Makefile,v 1.16 87/03/18 13:12:39 rs Exp $ X## X X## Edit appropriately. XCFLAGS = -O X X## Use these two lines if you use ranlib... XRANLIB = ranlib lib.a XAR_OBJ = $(LOBJ) X## ...or use these two if you don't. X#AR_OBJ = `lorder $(LOBJ) | tsort` X#RANLIB = @echo X X## Use this line if you have ctags (free from mod.sources)... XCTAGS = ctags -tw $(SRCS) $H X# ...or this line if you don't. X#CTAGS = @echo X X## Where executables should be put. XDESTDIR = /usr/local/bin X X## The manpage for "foo" goes in $(MANDIR)/foo.$1 XMANDIR = /usr/man/man1 X1 = 1 X#MANDIR = /usr/man/u_man/manl X#1 = 1L X X## X## END OF CONFIGURATION SECTION X## X X## Shorthands for sources, objects, etc. XH = shar.h XL = lib.a XPROGS = findsrc makekit shar unshar shell XSRCS = findsrc.c getopt.c makekit.c mem.c shar.c unshar.c XLSRC = cwd.c getopt.c host.c sysfuncs.c glue.c parser.c mem.c XLOBJ = cwd.o getopt.o host.o sysfuncs.o glue.o parser.o mem.o XMAN = findsrc.$1 makekit.$1 shar.$1 unshar.$1 shell.$1 X X Xall: programs tags X Xinstall: newprog newman X X X## You might want to change these actions... Xnewprog: $(PROGS) X cd $(DESTDIR) ; rm -f $(PROGS) X cp $(PROGS) $(DESTDIR) X cd $(DESTDIR) ; strip $(PROGS) ; chmod 755 $(PROGS) X# cd $(DESTDIR) ; /etc/chown root $(PROGS) X Xnewman: $(MAN) X cd $(MANDIR) ; rm -f $(MAN) X cp $(MAN) $(MANDIR) X X X## CREATING MANPAGES X.SUFFIXES: .$1 .man X.man.$1: X cp $< $@ X chmod 444 $@ X X## PROGRAM TARGETS Xprograms: $(PROGS) X Xfindsrc: findsrc.o $H $L X $(CC) $(CFLAGS) -o findsrc findsrc.o $L X Xmakekit: makekit.o $H $L X $(CC) $(CFLAGS) -o makekit makekit.o $L X Xshar: shar.o $H $L X $(CC) $(CFLAGS) -o shar shar.o $L X Xshell: shell.o $H $L X $(CC) $(CFLAGS) -o shell shell.o $L X X## Special -- gotta build these from the .c files... Xunshar: unshar.c $H $L X $(CC) $(CFLAGS) -o unshar unshar.c $L Xunshar.safe: unshar.c $H $L X $(CC) $(CFLAGS) -DUSE_MY_SHELL -o unshar unshar.c $L X X X## UTILITY TARGETS Xlib.a: $(LOBJ) X @rm -f lib.a X ar r lib.a $(AR_OBJ) X $(RANLIB) X$(LOBJ): $H X Xtags: $(SRCS) $H X $(CTAGS) X Xclean: X rm -f *.[oa] *.$1 *.BAK $(PROGS) unshar.safe X rm -f lint lib.ln tags core foo a.out X X X## LINT (probably only good for 4.[23]BSD Unices) X#LINTF = -p -ahb XLINTF = -ahb Xlint: programs lib.ln X exec lint $(LINTF)u >lint $(LSRC) X exec lint $(LINTF) >>lint findsrc.c lib.ln X exec lint $(LINTF) >>lint makekit.c lib.ln X exec lint $(LINTF) >>lint shar.c lib.ln X exec lint $(LINTF) >>lint shell.c lib.ln X exec lint $(LINTF) >>lint unshar.c lib.ln X# exec lint $(LINTF) -DUSE_MY_SHELL >>lint unshar.c lib.ln X X Xlib.ln: $(LSRC) X lint -CX $(LSRC) X mv llib-lX.ln lib.ln END_OF_Makefile if test 2618 -ne `wc -c README <<'END_OF_README' XThis set of tools is designed to make it easier to ship sources around. XI wrote them because I do a lot of that as moderator of mod.sources, and Xnothing else did the job for me. This set isn't perfect, but's very Xclose. Included are a program to find source files, a program to partition Xthem into reasonable sizes, a program to make shell archives out of Xthem, a program to strip mail, news, and notes headers from archives Xbefore feeding them to a shell, and a program to simulate /bin/sh for Xnon-Unix system. X XThe sources in this distribution are being released into the public Xdomain; do what you want, but let your conscience be your guide. XIf you somehow enhance this package, please send it on to me so that Xothers can benefit. X XI'll try to answer any questions or problems that come up -- send me Xelectronic mail. X XTo install, edit the Makefile and shar.h as necessary (see detailed list Xof parameters, below), then run make; doing make install will put the Xmanpages and executables where you told it to. I don't think "make lint" Xwill work anywhere other than a 4.[23]BSD system. X XIf you aren't running on Unix, then you will have to write replacements Xfor the functions in sysfuncs.c; everything else should be OK. If you Xdon't have a Unix-like make available, you will have to write a command Xscript or otherwise work out something with your compiler. X XI freely stole ideas from a number of people who have been good enough to Xput their stuff out on Usenet. Particular thanks to Gary Perlman and Larry XWall for giving me something nice to reverse-engineer, and Michael Mauldin Xfor unshar. It may have been a mistake to take people's names out of the Xcode; if I upset anyone by doing this, please let me know. X XThere are a couple of things that could still be done, but I'm tired of Xworking on this, and I don't need them often enough to want to come up Xwith general solutions. Specifically: X Automatically splitting up large text files; X Automatically invoking uuencode when sending binaries; and X Perhaps arranging for the archive to invoke uudecode. X XEnjoy! X Richard $alz X Mirror Systems X 2067 Massachusetts Avenue X Cambridge, MA 02140 X {ihnp4, harvard!wjh12, cca, cbosgd, seismo}!mirror!rs X rs%mirror.UUCP@cca X rs@mirror.TMC.COM X XMy, my, my, aren't we anal: X $Header: README,v 1.7 87/03/24 18:09:04 rs Exp $ X XCOMPILATION PARAMETERS X---------------------- X[The Makefile is ... er ... self-documented.] X XCAN_POPEN X If #define'd, then findsrc will do a popen() to file(1) to see if X the file is executable, etc. X XDEF_SAVEIT X This is used by unshar, and sets whether or not to save the headers X by default. X XGETWD GETCWD PWDPOPEN PWDGETENV X These are used in cwd.c to determine how to find out the current X directory, which unshar sometimes needs to know. X XGETHOSTNAME HOST UNAME UUNAME WHOAMI X There are used in host.c to determine how to find out the host name, X which shar needs to know. X XIDX, RDX X Some Unices call index/rindex strchr/strrchr. X XIN_SYS_DIR IN_SYS_NDIR IN_NDIR X The findsrc program uses the BSD-style directory-reading routines. X These routines, and the structures they use, are typically defined in X one of or "ndir.h", respectively. X XNEED_MKDIR X In sysfuncs, this includes a subroutine that calls system() to do a X mkdir command; otherwise mkdir() must be in your C library. X XNEED_GETOPT X Define this if getopt is not in your C library. X XSYS_WAIT X Define this if you have and the vfork system call. X XTHE_TTY X This should be a "device" to open so we can read input from the X user's terminal if standard input is, e.g., coming from a file. X Unix systems should use the default "/dev/tty"; MS-DOS and would X be "CON:" I guess? X XUSE_MY_SHELL X Used in unshar. If #define'd, then the archive is passed to my shell X interpreter sub-routine. The default is to do a popen() to /bin/sh. X XUSER_ENV X The name of the environment variable that holds the user's name, X which shar needs to know. X Xtypedef int *align_t X This is a worst-case alignment, to get lint to shut up about malloc'd X space. For ANSI C, e.g., this should be "typedef void *align_t". X Xtypedef long time_t X What datatype is needed to hold a time value. X Xtypedef long off_t X What datatype is needed to hold a file size. END_OF_README if test 4350 -ne `wc -c cwd.c <<'END_OF_cwd.c' X/* X** Return current working directory. Something for everyone. X*/ X/* LINTLIBRARY */ X#include "shar.h" XRCS("$Header: cwd.c,v 1.3 87/03/02 11:03:21 rs Exp $") X X X#ifdef PWDGETENV X/* ARGSUSED */ Xchar * XCwd(p, i) X char *p; X int i; X{ X char *q; X X return((q = getenv(PWDGETENV)) ? strcpy(p, q) : NULL); X} X#endif /* PWDGETENV */ X X X#ifdef GETWD X/* ARGSUSED1 */ Xchar * XCwd(p, size) X char *p; X int size; X{ X return(getwd(p) ? p : NULL); X} X#endif /* GETWD */ X X X#ifdef GETCWD Xchar * XCwd(p, size) X char *p; X int size; X{ X return(getcwd(p, size) ? p : NULL); X} X#endif /* GETCWD */ X X X#ifdef PWDPOPEN Xextern FILE *popen(); Xchar * XCwd(p, size) X char *p; X int size; X{ X FILE *F; X int i; X X if (F = popen("exec pwd", "r")) { X if (fgets(p, size, F) && p[i = strlen(p) - 1] == '\n') { X p[i] = '\0'; X (void)fclose(F); X return(p); X } X (void)fclose(F); X } X return(NULL); X} X#endif /* PWDPOPEN */ END_OF_cwd.c if test 941 -ne `wc -c findsrc.c <<'END_OF_findsrc.c' X/* X** FINDSRC X** Walk directories, trying to find source files. X** X** Options: X** -d [yn] Set default answer to yes or no X** -. Do .cshrc, .profile, etc. X** -o file Redirect stdout X** -R Do RCS and SCCS files and directories X** -S Do SCCS and RCS files and directories X** -v Verbose, include those that were rejected X*/ X#include "shar.h" XRCS("$Header: findsrc.c,v 1.18 87/03/18 14:03:03 rs Exp $") X X X/* X** How many levels to walk down? X*/ X#define MAX_LEVELS 6 X X X/* X** Global variables. X*/ Xint DoDOTFILES; /* Do .newsrc and friends? */ Xint DoRCS; /* Do RCS and SCCS files? */ Xint Default; /* Default answer from user */ Xint Verbose; /* List rejected files, too? */ Xchar Dname[] = "/tmp/findDXXXXXX"; /* Filename of directory list */ Xchar Fname[] = "/tmp/findFXXXXXX"; /* Filename of file list */ XFILE *Dfile; /* List of directories found */ XFILE *Ffile; /* List of files found */ XFILE *DEVTTY; /* The tty, if in filter mode */ X X X/* X** Signal handler. Clean up and die. X*/ Xstatic XCatch(s) X int s; X{ X int e; X X e = errno; X (void)unlink(Dname); X (void)unlink(Fname); X fprintf(stderr, "Got signal %d, %s.\n", s, Ermsg(e)); X exit(1); X} X X X/* X** Given a filename, apply heuristics to see if we want it. X*/ Xstatic int XWanted(Name) X register char *Name; X{ X register FILE *F; X register char *s; X register char *p; X register char *d; X char buff[BUFSIZ]; X X /* Get down to brass tacks. */ X s = (p = RDX(Name, '/')) ? p + 1 : Name; X X /* Only do directories other than . and .. and regular files. */ X if ((Ftype(Name) != F_DIR && Ftype(Name) != F_FILE) X || EQ(s, ".") || EQ(s, "..")) X return(FALSE); X X /* Common cruft we never want. */ X if (EQ(s, "foo") || EQ(s, "core") || EQ(s, "tags") || EQ(s, "lint")) X return(FALSE); X X /* Disregard stuff with bogus suffixes. */ X d = RDX(s, '.'); X if ((p = d) X && (EQ(++p, "out") || EQ(p, "orig") || EQ(p, "rej") || EQ(p, "BAK") X || EQ(p, "CKP") || EQ(p, "old") || EQ(p, "o"))) X return(FALSE); X X /* Want .cshrc, .newsrc, etc.? */ X if (*s == '.' && isalpha(s[1])) X return(DoDOTFILES); X X /* RCS or SCCS file or directory? */ X if (EQ(s, "RCS") X || ((p = RDX(s, ',')) && *++p == 'v' && *++p == '\0') X || EQ(s, "SCCS") || (s[0] == 's' && s[1] == '.')) X return(DoRCS); X X /* Mlisp (yes to .ml, no to .mo)? */ X if ((p = d) && *++p == 'm' && p[2] == '\0') X return(*++p = 'l'); X X /* C source or manpage? */ X if ((p = d) && (*++p == 'c' || *p == 'h' || isdigit(*p)) X && *++p == '\0') X return(TRUE); X X /* Make control file? */ X if ((*s == 'M' || *s == 'm') && EQ(s + 1, "akefile")) X return(TRUE); X X /* Convert to lowercase, and see if it's a README or MANIFEST. */ X for (p = strcpy(buff, s); *p; p++) X if (isupper(*p)) X *p = tolower(*p); X if (EQ(buff, "readme") || EQ(buff, "read_me") || EQ(buff, "read-me") X || EQ(buff, "manifest")) X return(TRUE); X X /* If we have a default, give it back. */ X if (Default) X return(Default == 'y'); X X#ifdef CAN_POPEN X /* See what file(1) has to say; if it says executable, punt. */ X (void)sprintf(buff, "exec file '%s'", Name); X if (F = popen(buff, "r")) { X (void)fgets(buff, sizeof buff, F); X (void)pclose(F); X for (p = buff; p = IDX(p, 'e'); p++) X if (PREFIX(p, "executable")) X return(FALSE); X (void)fputs(buff, stderr); X } X#endif /* CAN_POPEN */ X X /* Add it? */ X while (TRUE) { X if (DEVTTY == NULL) X DEVTTY = fopen(THE_TTY, "r"); X fprintf(stderr, "Add this one (y or n)[y]? "); X (void)fflush(stderr); X if (fgets(buff, sizeof buff, DEVTTY) == NULL X || buff[0] == '\n' || buff[0] == 'y' || buff[0] == 'Y') X break; X if (buff[0] == 'n' || buff[0] == 'N') X return(FALSE); X if (buff[0] == '!' ) X (void)system(&buff[1]); X fprintf(stderr, "--------------------\n%s: ", Name); X clearerr(DEVTTY); X } X return(TRUE); X} X X X/* X** Quick and dirty recursive routine to walk down directory tree. X** Could be made more general, but why bother? X*/ Xstatic void XProcess(p, level) X register char *p; X register int level; X{ X register char *q; X DIR *Dp; X struct direct *E; X char buff[BUFSIZ]; X X if (!GetStat(p)) X fprintf(stderr, "Can't walk down %s, %s.\n", Ermsg(errno)); X else { X /* Skip leading ./ which find(1), e.g., likes to put out. */ X if (p[0] == '.' && p[1] == '/') X p += 2; X X if (Wanted(p)) X fprintf(Ftype(p) == F_FILE ? Ffile : Dfile, "%s\n", p); X else if (Verbose) X fprintf(Ftype(p) == F_FILE ? Ffile : Dfile, "PUNTED %s\n", p); X X if (Ftype(p) == F_DIR) X if (++level == MAX_LEVELS) X fprintf(stderr, "Won't walk down %s -- more than %d levels.\n", X p, level); X else if (Dp = opendir(p)) { X q = buff + strlen(strcpy(buff, p)); X for (*q++ = '/'; E = readdir(Dp); ) X if (!EQ(E->d_name, ".") && !EQ(E->d_name, "..")) { X (void)strcpy(q, E->d_name); X Process(buff, level); X } X (void)closedir(Dp); X } X else X fprintf(stderr, "Can't open directory %s, %s.\n", X p, Ermsg(errno)); X } X} X X Xmain(ac, av) X register int ac; X register char *av[]; X{ X register char *p; X register int i; X register int Oops; X char buff[BUFSIZ]; X X /* Parse JCL. */ X for (Oops = 0; (i = getopt(ac, av, ".d:o:RSv")) != EOF; ) X switch (i) { X default: X Oops++; X break; X case '.': X DoDOTFILES++; X break; X case 'd': X switch (optarg[0]) { X default: X Oops++; X case 'y': X case 'n': X break; X case 'Y': X Default = 'y'; X break; X case 'N': X Default = 'n'; X break; X } X break; X case 'o': X if (freopen(optarg, "w", stdout) == NULL) { X fprintf(stderr, "Can't open %s for output, %s.\n", X optarg, Ermsg(errno)); X exit(1); X } X case 'R': X case 'S': X DoRCS++; X break; X case 'v': X Verbose++; X break; X } X if (Oops) { X fprintf(stderr, "Usage: findsrc [-d{yn}] [-.] [-{RS}] [-v] files...\n"); X exit(1); X } X av += optind; X X /* Set signal catcher, open temp files. */ X SetSigs(TRUE, Catch); X Dfile = fopen(mktemp(Dname), "w"); X Ffile = fopen(mktemp(Fname), "w"); X X /* Read list of files, determine their status. */ X if (*av) X for (DEVTTY = stdin; *av; av++) X Process(*av, 0); X else X while (fgets(buff, sizeof buff, stdin)) { X if (p = IDX(buff, '\n')) X *p = '\0'; X else X fprintf(stderr, "Warning, line too long:\n\t%s\n", buff); X Process(buff, 0); X } X X /* First print directories. */ X if (freopen(Dname, "r", Dfile)) { X while (fgets(buff, sizeof buff, Dfile)) X (void)fputs(buff, stdout); X (void)fclose(Dfile); X } X X /* Now print regular files. */ X if (freopen(Fname, "r", Ffile)) { X while (fgets(buff, sizeof buff, Ffile)) X (void)fputs(buff, stdout); X (void)fclose(Ffile); X } X X /* That's all she wrote. */ X (void)unlink(Dname); X (void)unlink(Fname); X exit(0); X} END_OF_findsrc.c if test 6863 -ne `wc -c findsrc.man <<'END_OF_findsrc.man' X.TH FINDSRC 1 LOCAL X.\" $Header: findsrc.man,v 1.2 87/03/06 14:02:49 rs Exp $ X.SH NAME Xfindsrc \- walk directories, trying to find source files X.SH SYNOPSIS X.B findsrc X[ X.B \-. X] [ X.BI \-d y_or_n X] [ X.BI \-o output_file X] [ X.B \-R X] [ X.B \-S X] [ X.B \-v X] [ file... ] X.SH DESCRIPTION X.I Findsrc Xrecursively examines all directories and files specified on the command Xline, and determines, based on the file name, whether the file contains Xsource code or not. XAll directories are listed first, followed by all regular files, Xwith one item per line. X.PP XIf X.I findsrc Xis unable to make a decision, it invokes the X.IR file (1) Xcommand, and prompts the user for a decision. XIn reply to the prompt, type the letter ``y'' or ``n'' (either case); XRETURN means yes. XIf the reply starts with an exclamation point, the rest of the line Xis passed off to a sub-shell and the question is repeated. XThe ``\-d'' option may be used with an argument of ``y'' or ``n'' Xto by-pass the interaction, and provide a default answer. X.PP XThe ``\-o'' option may be used to specify an output filename. XThis is designed to prevent confusion if a command like the following Xis executed: X.RS Xfindsrc . * >LIST X.RE X.PP XBy default, X.I findsrc Xignores files whose names begin with a period, like ``.newsrc'' or X``.tags''; such files may be included by using the ``\-.'' option. X.I Findsrc Xalso normally ignores X.SM RCS Xand X.SM SCCS Xfiles and directories; using either the ``\-R'' or ``\-S'' option causes Xboth to be included. X.PP X.I Findsrc Xnormally lists only the names of those files that have been selected. XIf the ``\-v'' option is used, rejected files are also listed preceeded Xby the word ``PUNTED.'' X.PP XIf no files are specified on the command line, the program operates as Xa filter, reading a list of files and directories from the standard Xinput, one per line. X.SH "SEE ALSO" Xmakekit(1L). END_OF_findsrc.man if test 1865 -ne `wc -c getopt.c <<'END_OF_getopt.c' X/* X** Return options and their values from the command line. X** X** This comes from the AT&T public-domain getopt published in mod.sources. X*/ X/* LINTLIBRARY */ X#include "shar.h" XRCS("$Header: getopt.c,v 1.4 87/03/02 11:03:24 rs Exp $") X X#ifdef NEED_GETOPT X X X#define TYPE int X X#define ERR(s, c) if(opterr){\ X char errbuf[2];\ X errbuf[0] = c; errbuf[1] = '\n';\ X (void) write(2, argv[0], (TYPE)strlen(argv[0]));\ X (void) write(2, s, (TYPE)strlen(s));\ X (void) write(2, errbuf, 2);} X Xextern int strcmp(); X Xint opterr = 1; Xint optind = 1; Xint optopt; Xchar *optarg; X Xint Xgetopt(argc, argv, opts) Xint argc; Xchar **argv, *opts; X{ X static int sp = 1; X register int c; X register char *cp; X X if(sp == 1) X if(optind >= argc || X argv[optind][0] != '-' || argv[optind][1] == '\0') X return(EOF); X else if(strcmp(argv[optind], "--") == NULL) { X optind++; X X } X optopt = c = argv[optind][sp]; X if(c == ':' || (cp=IDX(opts, c)) == NULL) { X ERR(": illegal option -- ", c); X if(argv[optind][++sp] == '\0') { X optind++; X sp = 1; X } X return('?'); X } X if(*++cp == ':') { X if(argv[optind][sp+1] != '\0') X optarg = &argv[optind++][sp+1]; X else if(++optind >= argc) { X ERR(": option requires an argument -- ", c); X sp = 1; X return('?'); X } else X optarg = argv[optind++]; X sp = 1; X } else { X if(argv[optind][++sp] == '\0') { X sp = 1; X optind++; X } X optarg = NULL; X } X return(c); X} X X#endif /* NEED_GETOPT */ END_OF_getopt.c if test 1422 -ne `wc -c glue.c <<'END_OF_glue.c' X/* X** Subroutine to call the shell archive parser. This is "glue" X** between unshar and the parser proper. X*/ X#include "shar.h" XRCS("$Header: glue.c,v 1.1 87/03/09 16:24:17 rs Exp $") X X X/* X** Copy the input to a temporary file, then call the shell parser. X*/ XBinSh(Name, Stream, Pushback) X char *Name; X register FILE *Stream; X char *Pushback; X{ X static char TEMP[] = "/tmp/shellXXXXXX"; X register FILE *F; X char buff[BUFSIZ]; X char *vec[MAX_WORDS]; X X Interactive = Name == NULL; X File = mktemp(TEMP); X F = fopen(File, "w"); X (void)fputs(Pushback, F); X while (fgets(buff, sizeof buff, Stream)) X (void)fputs(buff, F); X (void)fclose(Stream); X X if ((Input = fopen(TEMP, "r")) == NULL) X fprintf(stderr, "Can't open %s, %s!?\n", TEMP, Ermsg(errno)); X else X while (GetLine(TRUE)) X if (Argify(vec)) X (void)Exec(vec); X X (void)unlink(TEMP); X} END_OF_glue.c if test 897 -ne `wc -c host.c <<'END_OF_host.c' X/* X** Return name of this host. Something for everyone. X*/ X/* LINTLIBRARY */ X#include "shar.h" XRCS("$Header: host.c,v 1.5 87/03/02 11:03:26 rs Exp $") X X X#ifdef HOST Xchar * XHost() X{ X return(HOST); X} X#endif /* HOST */ X X X#ifdef GETHOSTNAME Xchar * XHost() X{ X static char buff[64]; X X return(gethostname(buff, sizeof buff) < 0 ? "SITE" : buff); X} X#endif /* GETHOSTNAME */ X X X#ifdef UNAME X#include Xchar * XHost() X{ X static struct utsname U; X X return(uname(&U) < 0 ? "SITE" : U.nodename); X} X#endif /* UNAME */ X X X#ifdef UUNAME Xextern FILE *popen(); Xchar * XHost() X{ X static char buff[50]; X char *p; X X if (F = popen("exec uuname -l", "r")) { X if (fgets(buff, sizeof buff, F) == buff && (p = IDX(name, '\n'))) { X (void)pclose(F); X *p = '\0'; X return(buff); X } X (void)pclose(F); X } X return("SITE"); X} X#endif /* UUNAME */ X X X#ifdef WHOAMI Xchar * XHost() X{ X static char name[64]; X register FILE *F; X register char *p; X char buff[100]; X X /* Try /etc/whoami; look for a single well-formed line. */ X if (F = fopen("/etc/whoami", "r")) { X if (fgets(name, sizeof name, F) && (p = IDX(name, '\n'))) X (void)fclose(F); X *p = '\0'; X return(name); X } X (void)fclose(F); X } X X /* Try /usr/include/whoami.h; look for #define sysname "foo" somewhere. */ X if (F = fopen("/usr/include/whoami.h", "r")) { X while (fgets(buff, sizeof buff, F)) X /* I don't like sscanf, nor do I trust it. Sigh. */ X if (sscanf(buff, "#define sysname \"%[^\"]\"", name) == 1) { X (void)fclose(F); X return(name); X } X (void)fclose(F); X } X return("SITE"); X} X#endif /* WHOAMI */ END_OF_host.c if test 1645 -ne `wc -c makekit.man <<'END_OF_makekit.man' X.TH MAKEKIT 1 LOCAL X.\" $Header: makekit.man,v 1.7 87/03/13 12:56:33 rs Exp $ X.SH NAME Xmakekit \- split files up into shell archive packages X.SH SYNOPSIS X.B makekit X[ X.B -e X] [ X.BI -h # X] [ X.BI -i name X] [ X.BI -k # X] [ X.B -m X] [ X.BI -n name X] [ X.BI -o name X] [ X.B -p X] [ X.BI -s #[k] X] [ X.BI -t text X] [ Xfile... X] X.SH DESCRIPTION X.I Makekit Xreads a list of files and directories, determines their sizes, Xand parcels them up into a series of shell archives such that all the Xarchives are of reasonable size. XIt then invokes X.IR shar (1L) Xto actually create the archives. X.PP XBy default, no archive will be larger than about 50,000 bytes; this may be Xchanged by using the ``\-s'' option. XIf the number given with the ``\-s'' option ends with the letter ``k'' Xthen the size is multiplied by 1024, otherwise it is taken to be the Xdesired maximum size, in bytes. XEach archive will have a name that looks like X.IR Part nn, Xwhere ``nn'' represents the two-digit sequence number (with leading zero Xif needed). XThe leader part of the archive name may be changed with the ``\-n'' option. XThe ``\-n'' is also useful when write permission to the directory being Xarchive is defined; e.g., ``\-n/tmp/KERNEL.'' X.PP X.I Makekit Xreads its list of files on the command line, or standard input Xif none are given. XIt is also possible to specify an input filename with the ``\-i'' option. XThe input should contain a list of files, one to a line, to separate. XIn addition, if each input line looks like this: X.RS Xfilename\ \ \ whitespaces\ \ \ optional-digits\ \ \ whitespaces\ \ \ text X.RE Xthen X.I makekit Xwill ignore the spaces and digits, but remember the text associated with Xeach file, and output it with the filename when generating the ``shipping Xmanifest.'' XFurther, the ``\-h'' option may be given to have the program skip the Xindicated number of lines in the input; this option is provided so that X.I makekit Xcan more easily re-parse the manifests it has generated. X.PP XThe generated manifest will be sent to the standard output. XAn alternate output file may be given by using the ``\-o'' option; if Xthe output file exists, X.I makekit Xwill try to rename it with an extension of X.IR \&.BAK \&. XIf the ``\-o'' option is used, X.I makekit Xwill add that name to the list of files to be archived; the ``\-e'' Xoption may be given to exclude the manifest from the list. X.PP XThe ``\-m'' option is the same as given the options, X\&``-iMANIFEST -oMANIFEST -h2.'' X.PP XAfter partitioning the files and directories, X.I makekit Xcalls X.I shar Xwith the proper options to generate archives in a series. XEach resultant archive will, when executed, check to see if all the parts Xare present. XBy using the ``\-t'' option, you can specify a line of starting instructions Xto display to the recipient when all pieces have been unpacked. XSee X.I shar Xfor more information on multi-part archives. XIf the ``\-x'' option is used, X.I shar Xis not called, but the manifest is still created. X.PP X.I Makekit Xnormally reorders its input so that the archives are as ``dense'' as Xpossible, with the exception that directories are given priority over Xfiles, and a file named X.I README Xis the first of all. XThe manifest is also sorted in alphabetical order; this makes it easy Xto locate ``missing'' files when the distribution is a large one. XThe ``\-p'' option may be used to override both sortings, however, Xand preserve the original order of the input list in generating Xboth the manifest, and the shell archives. X.SH NOTES X.I Makekit Xtries to partition the files so that all directories are in the first archive. XThis usually means the first archive must be the first one to be unpacked. X.SH "SEE ALSO" Xfindsrc(1L), shar(1L) END_OF_makekit.man if test 3676 -ne `wc -c mem.c <<'END_OF_mem.c' X/* X** Get some memory or die trying. X*/ X/* LINTLIBRARY */ X#include "shar.h" XRCS("$Header: mem.c,v 1.6 87/03/04 14:51:20 rs Exp $") X X Xalign_t Xgetmem(i, j) X unsigned int i; X unsigned int j; X{ X extern char *calloc(); X align_t p; X X if ((p = (align_t)calloc(i, j)) == NULL) { X /* Print the unsigned's as int's so ridiculous values show up. */ X fprintf(stderr, "Can't Calloc(%d,%d), %s.\n", i, j, Ermsg(errno)); X exit(1); X } X return(p); X} END_OF_mem.c if test 460 -ne `wc -c shar.c <<'END_OF_shar.c' X/* X** SHAR X** Make a shell archive of a list of files. X** X** Options: X** -b Strip leading directories off names before packing X** -n # Set number of this archive in a series X** -o foo Output goes to file foo, not stdout X** -e # Set ending archive number of series X** -t "See README" Set instructions for when all archives are done X*/ X#include "shar.h" XRCS("$Header: shar.c,v 1.18 87/03/18 14:10:21 rs Exp $") X X X/* X** This prolog is output before the archive. X*/ Xstatic char *Prolog[] = { X "! /bin/sh", X " This is a shell archive. Remove anything before this line, then unpack", X " it by saving it into a file and typing \"sh file\". To overwrite existing", X " files, type \"sh file -c\". You can also feed this as standard input via", X " unshar, or by typing \"sh 1 ? "s" : ""); X printf("sed \"s/^X//\" >%s <<'END_OF_%s'\n", Name, Name); X X /* Output the file contents. */ X for (Bads = 0, Lastchar = '\n'; fgets(buf, BUFSIZ, stdin); ) { X printf("X"); X if (buf[0]) { X for (s = buf; *s; s++) { X if (BADCHAR(*s)) X Bads++; X (void)putchar(*s); X } X Lastchar = s[-1]; X } X else X Lastchar = 'X'; X } X X /* Tell about missing \n and control characters. */ X if (Lastchar != '\n') X (void)putchar('\n'); X printf("END_OF_%s\n", Name); X if (Lastchar != '\n') { X printf("echo shar: Missing newline added to \\\"%s\\\"\n", Name); X fprintf(stderr, "Missing newline added to \"%s\"\n", Name); X } X if (Bads) { X printf( X "echo shar: %d control character%s may be missing from \\\"%s\\\"\n", X Bads, Bads > 1 ? "s" : "", Name); X fprintf(stderr, "Found %d control char%s in \"%s\"\n", X Bads, Bads > 1 ? "s" : "", Name); X } X X /* Output size check. */ X printf("if test %ld -ne `wc -c <%s`; then\n", (long)Size, Name); X printf(" echo shar: \\\"%s\\\" unpacked with wrong size!\n", Name); X printf("fi\n"); X X /* Executable? */ X if (Fexecute(file)) X printf("chmod +x %s\n", Name); X X printf("# end of overwriting check\nfi\n"); X } X} X X Xmain(ac, av) X int ac; X register char *av[]; X{ X register char *Trailer; X register char *p; X register int i; X register int length; X register int Oops; X register int Knum; X register int Kmax; X time_t clock; X int Basename; X X /* Parse JCL. */ X Basename = 0; X Knum = 0; X Kmax = 0; X Trailer = NULL; X for (Oops = 0; (i = getopt(ac, av, "be:n:o:t:")) != EOF; ) X switch (i) { X default: X Oops++; X break; X case 'b': X Basename++; X break; X case 'e': X Kmax = atoi(optarg); X break; X case 'n': X Knum = atoi(optarg); X break; X case 'o': X if (freopen(optarg, "w", stdout) == NULL) { X fprintf(stderr, "Can't open %s for output, %s.\n", X optarg, Ermsg(errno)); X Oops++; X } X break; X case 't': X Trailer = optarg; X break; X } X av += optind; X if (*av == NULL) { X fprintf(stderr, "No input files\n"); X Oops++; X } X if (Oops) { X fprintf(stderr, "USAGE: shar [-b] [-o:] [-n:e:t:] file... >SHAR\n"); X exit(1); X } X X /* Everything readable and reasonably-named? */ X for (Oops = 0, i = 0; p = av[i]; i++) X if (freopen(p, "r", stdin) == NULL) { X fprintf(stderr, "Can't read %s, %s.\n", p, Ermsg(errno)); X Oops++; X } X else X for (; *p; p++) X if (!isascii(*p) X || (!isalnum(*p) && IDX(OK_CHARS, *p) == NULL)) { X fprintf(stderr, "Bad character '%c' in '%s'.\n", *p, av[i]); X Oops++; X } X if (Oops) X exit(2); X X /* Prolog. */ X for (i = 0; p = Prolog[i]; i++) X printf("#%s\n", p); X if (Knum && Kmax) X printf("#\t\t\"End of archive %d (of %d).\"\n", Knum, Kmax); X else X printf("#\t\t\"End of shell archive.\"\n"); X printf("# Contents: "); X for (length = 12, i = 0; p = av[i++]; length += strlen(p) + 1) X if (length + strlen(p) + 1 < WIDTH) X printf(" %s", p); X else { X printf("\n# %s", p); X length = 4; X } X printf("\n"); X clock = time((time_t *)NULL); X printf("# Wrapped by %s@%s on %s", User(), Host(), ctime(&clock)); X printf("PATH=/bin:/usr/bin:/usr/ucb ; export PATH\n"); X X /* Do it. */ X while (*av) X shar(*av++, Basename); X X /* Epilog. */ X if (Knum && Kmax) { X printf("echo shar: End of archive %d \\(of %d\\).\n", Knum, Kmax); X printf("cp /dev/null ark%disdone\n", Knum); X printf("MISSING=\"\"\n"); X printf("for I in"); X for (i = 0; i < Kmax; i++) X printf(" %d", i + 1); X printf(" ; do\n"); X printf(" if test ! -f ark${I}isdone ; then\n"); X printf("\tMISSING=\"${MISSING} ${I}\"\n"); X printf(" fi\n"); X printf("done\n"); X printf("if test \"${MISSING}\" = \"\" ; then\n"); X if (Kmax == 2) X printf(" echo You have unpacked both archives.\n"); X else X printf(" echo You have unpacked all %d archives.\n", Kmax); X if (Trailer && *Trailer) X printf(" echo \"%s\"\n", Trailer); X printf(" rm -f ark[1-9]isdone%s\n", X Kmax >= 9 ? " ark[1-9][0-9]isdone" : ""); X printf("else\n"); X printf(" echo You still need to unpack the following archives:\n"); X printf(" echo \" \" ${MISSING}\n"); X printf("fi\n"); X printf("## End of shell archive.\n"); X } X else X printf("echo shar: End of shell archive.\n"); X X printf("exit 0\n"); X X exit(0); X} END_OF_shar.c if test 6386 -ne `wc -c shar.h <<'END_OF_shar.h' X/* X** Header file for shar and friends. X** X** $Header: shar.h,v 1.25 87/03/18 14:03:27 rs Exp $ X*/ X X X/* X** Edit as necessary. X*/ X X/* Variances in local dialects. */ X#define IDX index /* Maybe strchr? */ X#define RDX rindex /* Maybe strrchr? */ X/*efine NEED_MKDIR /* Don't have mkdir(2)? */ X/*efine NEED_QSORT /* Don't have qsort(3)? */ X#define NEED_GETOPT /* Need local getopt object? */ X#define CAN_POPEN /* Can invoke file(1) command? */ X/*efine USE_MY_SHELL /* Don't popen("/bin/sh")? */ X Xtypedef int *align_t; /* Worst-case alignment, for lint */ X/* typedef long time_t /* Needed for non-BSD sites? */ X/* typedef long off_t /* Needed for non-BSD sites? */ X X#define DEF_SAVEIT 1 /* Save headers by default? */ X X/* Where is BSD-compatible directory header file? Pick one. */ X#define IN_SYS_DIR /* */ X/*efine IN_SYS_NDIR /* */ X/*efine IN_DIR /* "dir.h" */ X X/* Do you have ? If so, then you have vfork, too. */ X#define SYS_WAIT X X/* Login name from environment; pick one. */ X#define USER_ENV "USER" /* .. */ X/*efine USER_ENV "LOGNAME" /* .. */ X/*efine USER_ENV "NAME" /* .. */ X X/* What we should fopen() if stdin is not the tty. */ X#define THE_TTY "/dev/tty" /* Maybe "con:" for MS-DOS? */ X X/* Name of the machine we're running on; pick one. */ X#define GETHOSTNAME /* Use gethostname(2) call */ X/*efine UNAME /* Use uname(2) call */ X/*efine UUNAME /* Invoke "uuname -l" */ X/*efine WHOAMI /* Try /etc/whoami & */ X/*efine HOST "SITE" /* If all else fails */ X X/* How do we find the current working directory? */ X#define GETWD /* Use getwd(3) routine */ X/* fine GETCWD /* Use getcwd(3) routine */ X/* fine PWDPOPEN /* Invoke "pwd" */ X/* fine PWDGETENV "PWD" /* Get $PWD from environment */ X X/* Prefixes for first two lines of saved NOTESFILES articles. */ X#define NOTES1 "/* Written " X#define NOTES2 "/* ---" X X/* Legal characters for filenames. Note that shar doesn't do quoting... */ X#define OK_CHARS "@%_-+=.,/" X X/* X** END OF CONFIGURATION SECTION X*/ X X#include X#include X#include X X#ifdef IN_SYS_DIR X#include X#endif /* IN_SYS_DIR */ X#ifdef IN_SYS_NDIR X#include X#endif /* IN_SYS_NDIR */ X#ifdef IN_NDIR X#include "ndir.h" X#endif /* IN_DIR */ X X X/* X** Handy shorthands. X*/ X#define TRUE 1 X#define FALSE 0 X#define WIDTH 72 X#define F_DIR '$' /* Something is a directory */ X#define F_FILE 'A' /* Something is a regular file */ X#define S_IGNORE 'L' /* Ignore this signal */ X#define S_RESET 'Z' /* Reset signal to default */ X X/* These are used by the archive parser. */ X#define MAX_LINE_SIZE 200 /* Length of physical input line*/ X#define MAX_VAR_NAME 30 /* Length of a variable's name */ X#define MAX_VAR_VALUE 128 /* Length of a variable's value */ X#define MAX_VARS 20 /* Number of shell vars allowed */ X#define MAX_WORDS 30 /* Make words in command lnes */ X X X/* X** Keep RCS stuff away from lint. X*/ X#ifdef lint X#define RCS(text) /* NULL */ X#else X#define RCS(text) static char ID[] = text; X#endif /* lint */ X X X/* X** Memory hacking. X*/ X#define NEW(T, count) ((T *)getmem(sizeof(T), (unsigned int)(count))) X#define ALLOC(n) getmem(1, (unsigned int)(n)) X#define COPY(s) strcpy(NEW(char, strlen((s)) + 1), (s)) X X X/* X** Macros. X*/ X#define BADCHAR(c) (iscntrl((c)) && !isspace((c))) X#define EQ(a, b) (strcmp((a), (b)) == 0) X#define EQn(a, b, n) (strncmp((a), (b), (n)) == 0) X#define PREFIX(a, b) (EQn((a), (b), sizeof b - 1)) X#define WHITE(c) ((c) == ' ' || (c) == '\t') X X X/* X** Linked in later. X*/ Xextern int errno; Xextern int optind; Xextern char *optarg; X X/* From your C run-time library. */ Xextern FILE *popen(); Xextern time_t time(); Xextern long atol(); Xextern char *IDX(); Xextern char *RDX(); Xextern char *ctime(); Xextern char *gets(); Xextern char *mktemp(); Xextern char *strcat(); Xextern char *strcpy(); Xextern char *strncpy(); Xextern char *getenv(); X X/* From our local library. */ Xextern align_t getmem(); Xextern off_t Fsize(); Xextern char *Copy(); Xextern char *Cwd(); Xextern char *Ermsg(); Xextern char *Host(); Xextern char *User(); X X/* Exported by the archive parser. */ Xextern FILE *Input; /* Current input stream */ Xextern char *File; /* Input filename */ Xextern int Interactive; /* isatty(fileno(stdin))? */ Xextern void SynErr(); /* Fatal syntax error */ END_OF_shar.h if test 4373 -ne `wc -c shar.man <<'END_OF_shar.man' X.TH SHAR 1 LOCAL X.\" $Header: shar.man,v 1.1 87/02/27 13:45:27 rs Exp $ X.SH NAME Xshar \- create shell archive file for extraction by /bin/sh X.SH SYNOPSIS X.B shar X[ X.B \-b X] [ X.BI \-n seq_number X] [ X.BI \-e seq_end X] [ X.BI \-o output_file X] [ X.BI \-t final_text X] files X.SH DESCRIPTION X.I Shar Xtakes a list of files, and generates a X.IR /bin/sh Xscript that, when executed, will re-create those files in a different Xdirectory or on a different machine. XThe resultant script will use X.IR wc (1) Xto do a mild error-check, and will warn about possibly-omitted Xcontrol characters. X.PP X.I Shar Xgenerates scripts that will make directories and plain files. XIt will not try to generate intermediate filenames, however, so X.RS Xshar foo/bar/file X.RE Xwill not work. Do X.RS Xshar foo foo/bar foo/bar/file X.RE Xinstead. X.PP XThe script is normally sent to standard output; the ``\-o'' option may be Xused to specify an output filename. XThis is designed to prevent filling up the disk if X.RS Xshar * >SHAR X.RE Xcommand is done; do X.RS Xshar -o SHAR * X.RE Xinstead. X.PP XThe ``\-b'' option says that all leading directory names should be stripped Xfrom the file when they are packed into the archive. XFor example, X.RS Xshar -b /etc/termcap X.RE Xcreates an archive that, when executed, creates a file named X``termcap'' in the current directory, rather than overwrite the Xhost system file. XNote, however, that the scripts generated by X.I shar Xrefuse to overwrite pre-existing files; the ``\-b'' option is Xfor convenience, and may not strictly be necessary. X.SS "Multi\-part Archives" XMost larger software packages are usually sent out in two or more shell Xarchives. XThe ``\-n,'' ``\-e,'' and ``\-t'' options are used to make an archive Xthat is part of a series. XThe individual archives are often called ``kits'' when this is done. XThe ``\-n'' option specifies the archive number; the ``\-e'' option species Xthe highest number in the series. XWhen executed, the generated archives will then echo messages like X.RS Xshar: End of archive 3 of 9. X.RE Xat their end. X.PP XIn addition, each shar will generate a file named X.IR ark X isdone . XEach script will contain a loop to check for the presence of these Xfiles, and indicate to the recipient which archives still need to be Xexecuted. XThe ``\-t'' option may be used to give starting instructions to the recipient. XWhen the scripts determine that all the archives have been unpacked, Xthe text specified with this flag is displayed. XFor example, X.RS Xshar -n1 -k9 -t "Now do 'sh ./Configure'" *.c >SHAR X.RE XAdds commands to output the following when all the archives have been unpacked: X.RS X.nf XYou have run archive 1. X\& . X\& . X\& . XYou have run archive 9. XYou have run all 9 archives. XNow do 'sh ./Configure' X.fi X.RE X.SH "SEE ALSO" Xecho(1), findsrc(1L), makekit(1L), mkdir(1), sh(1), test(1), unshar(1L), Xwc(1). END_OF_shar.man if test 2834 -ne `wc -c shell.c <<'END_OF_shell.c' X/* X** Stand-alone driver for shell. X*/ X#include "shar.h" XRCS("$Header: shell.c,v 1.4 87/03/24 16:19:56 rs Exp $") X X Xextern void SetVar(); X X Xmain(ac, av) X register int ac; X register char *av[]; X{ X char *vec[MAX_WORDS]; X char buff[MAX_VAR_VALUE]; X X if (Interactive = ac == 1) { X fprintf(stderr, "Testing shell interpreter...\n"); X Input = stdin; X File = "stdin"; X } X else { X if ((Input = fopen(File = av[1], "r")) == NULL) X SynErr("UNREADABLE INPUT"); X /* Build the positional parameters. */ X for (ac = 1; av[ac]; ac++) { X (void)sprintf(buff, "%d", ac - 1); X SetVar(buff, av[ac]); X } X } X X /* Read, parse, and execute. */ X while (GetLine(TRUE)) X if (Argify(vec)) X (void)Exec(vec); X X /* That's it. */ X exit(0); X} END_OF_shell.c if test 767 -ne `wc -c shell.man <<'END_OF_shell.man' X.TH SHELL 1 LOCAL X.\" $Header: shell.man,v 1.2 87/03/09 16:55:28 rs Exp $ X.SH NAME Xshell \- Interpreter for shell archives X.SH SYNOPSIS X.B shell X[ X.B file X] X.SH DESCRIPTION XThis program interprets enough UNIX shell syntax, and command usage, Xto enable it to unpack many different types of UNIX shell archives, Xor ``shar's.'' XIt is primarily intended to be used on non-UNIX systems that need to Xunpack such archives. X.PP X.I Shell Xdoes X.B not Xcheck for security holes, and will blithely execute commands like X.RS Xcp /dev/null /etc/passwd X.RE Xwhich, if executed by the super-user, can be disastrous. X.PP XThe X.I shell Xparser is line-based, where lines are then split into tokens; it is not a Xtrue token-based parser. XIn general, it is best if all X.I sh Xkeywords that can appear alone on a line do so, and that compound Xcommands (i.e., using a semi-colon) be avoided. XFor more details on the syntax, see the source (sorry...). X.SH BUGS XIt is probably easier to write a true portable replacement for /bin/sh Xthan it is to write something which understands all shar formats. X.SH SEE ALSO Xshar(1L). END_OF_shell.man if test 1091 -ne `wc -c sysfuncs.c <<'END_OF_sysfuncs.c' X/* X** System-specific stuff. This module will need to be ported to X** other systems. X*/ X/* LINTLIBRARY */ X#include "shar.h" X#include X#include X#include X#include X#ifdef SYS_WAIT X#include X#else X#endif /* SYS_WAIT */ XRCS("$Header: sysfuncs.c,v 1.7 87/03/13 13:08:34 rs Exp $") X X X/* How to fork(), what to wait with. */ X#ifdef SYS_WAIT X#define FORK() vfork() X#define W_VAL(w) ((w).w_retcode) Xtypedef union wait WAITER; X#else X#define FORK() fork() X#define W_VAL(w) ((w) >> 8) Xtypedef int WAITER; X#endif /* SYS_WAIT */ X X X/* Mask of executable bits. */ X#define EXE_MASK (S_IEXEC | (S_IEXEC >> 3) | (S_IEXEC >> 6)) X X/* Stat buffer for last file. */ Xstatic struct stat Sb; X X X/* X** Get user name. Not secure, but who sends nastygrams as shell archives? X*/ Xchar * XUser() X{ X extern struct passwd *getpwuid(); X struct passwd *p; X char *g; X X if (g = getenv(USER_ENV)) X return(g); X return((p = getpwuid(getuid())) ? p->pw_name : "USER"); X} X X X/* X** Set up a signal handler. X*/ XSetSigs(What, Func) X int What; X int (*Func)(); X{ X if (What == S_IGNORE) X Func = SIG_IGN; X else if (What == S_RESET) X Func = SIG_DFL; X if (signal(SIGINT, SIG_IGN) != SIG_IGN) X (void)signal(SIGINT, Func); X if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) X (void)signal(SIGQUIT, Func); X} X X X/* X** Stat the file if it's not the one we did last time. X*/ Xint XGetStat(p) X char *p; X{ X static char Name[BUFSIZ]; X X if (*p == Name[0] && EQ(p, Name)) X return(TRUE); X return(stat(strcpy(Name, p), &Sb) < 0 ? FALSE : TRUE); X} X X X/* X** Return the file type -- directory or regular file. X*/ Xint XFtype(p) X char *p; X{ X return(GetStat(p) && ((Sb.st_mode & S_IFMT) == S_IFDIR) ? F_DIR : F_FILE); X} X X X/* X** Return the file size. X*/ Xoff_t XFsize(p) X char *p; X{ X return(GetStat(p) ? Sb.st_size : 0); X} X X X/* X** Is a file executable? X*/ Xint XFexecute(p) X char *p; X{ X return(GetStat(p) && (Sb.st_mode & EXE_MASK) ? TRUE : FALSE); X} X X X/* X** Return the process ID. X*/ Xint XPid() X{ X static int X; X X if (X == 0) X X = getpid(); X return(X); X} X X X/* X** Return the text string that corresponds to errno. X*/ Xchar * XErmsg(e) X int e; X{ X extern int sys_nerr; X extern char *sys_errlist[]; X static char buff[30]; X X if (e > 0 && e < sys_nerr) X return(sys_errlist[e]); X (void)sprintf(buff, "Error code %d", e); X return(buff); X} X X X/* X** Fork off a command. X*/ Xint XExecute(av) X char *av[]; X{ X register int i; X register int j; X WAITER W; X X if ((i = FORK()) == 0) { X SetSigs(S_RESET, (int (*)())NULL); X (void)execvp(av[0], av); X perror(av[0]); X _exit(1); X } X X SetSigs(S_IGNORE, (int (*)())NULL); X while ((j = wait(&W)) < 0 && j != i) X ; X SetSigs(S_RESET, (int (*)())NULL); X return(W_VAL(W)); X} X X X#ifdef NEED_MKDIR X/* X** Quick and dirty mkdir routine for them that's need it. X*/ Xint Xmkdir(name, mode) X char *name; X int mode; X{ X char *av[3]; X int i; X X av[0] = "mkdir"; X av[1] = name; X av[2] = NULL; X U = umask(~mode); X i = Execute(av); X (void)umask(U); X return(i ? -1 : 0); X} X#endif /* NEED_MKDIR */ X X X#ifdef NEED_QSORT X/* X** Bubble sort an array of arbitrarily-sized elements. This routine X** can be used as an (inefficient) replacement for the Unix qsort X** routine, hence the name. If I were to put this into my C library, X** I'd do two things: X** -Make it be a quicksort; X** -Have a front routine which called specialized routines for X** cases where Width equals sizeof(int), sizeof(char *), etc. X*/ Xqsort(Table, Number, Width, Compare) X register char *Table; X register int Number; X register int Width; X register int (*Compare)(); X{ X register char *i; X register char *j; X X for (i = &Table[Number * Width]; (i -= Width) >= &Table[Width]; ) X for (j = i; (j -= Width) >= &Table[0]; ) X if ((*Compare)(i, j) < 0) { X register char *p; X register char *q; X register int t; X register int w; X X /* Swap elements pointed to by i and j. */ X for (w = Width, p = i, q = j; --w >= 0; *p++ = *q, *q++ = t) X t = *p; X } X} X#endif /* NEED_QSORT */ X X X#undef NOTDEF X#ifdef NOTDEF X/* X** Cons all the arguments together into a single command line and hand X** it off to the shell to execute. This is only here for someone to use X** as the basis of, say, an MSDOS port. X*/ Xint XExecute(av) X register char *av[]; X{ X register char **v; X register char *p; X register char *q; X register int i; X X /* Get length of command line. */ X for (i = 5, v = av; *v; v++) X i += strlen(*v) + 1; X X /* Create command line and execute it. */ X p = NEW(char, i); X for (q = p + strlen(strcpy(p, "exec")), v = av; *v; v++) { X *q++ = ' '; X q += strlen(strcpy(q, *v)); X } X X return(system(p)); X} X#endif /* NOTDEF */ END_OF_sysfuncs.c if test 4828 -ne `wc -c unshar.man <<'END_OF_unshar.man' X.TH UNSHAR 1 LOCAL X.\" $Header: unshar.man,v 1.1 87/02/27 13:45:34 rs Exp $ X.SH NAME Xunshar \- unpack shell archives from news, mail, notes, etc. X.SH SYNOPSIS X.B unshar X[ X.BI \-c\| directory X] [ X.BI \-d\| directory X] [ X.B \-f X] [ X.B \-n X] [ X.B \-s X] [files] X.SH DESCRIPTION X.I Unshar Xremoves mail and news header lines from its input, and feeds the remainder Xto X.IR /bin/sh (1) Xso that a shell archive can be properly unpacked. XIf no files are specified, X.I unshar Xreads from standard input. XThe program is designed to be useful when unpacking archives directly Xfrom the news or mail systems (e.g., s | unshar). X.PP X.I Unshar Xnormally unpacks its files in the current directory. XUse the ``\-c'' option to have the program change to a new directory Xbefore invoking the shell. XIf the directory does not exist, it will try to create it. XIf the directory name starts with a question mark, then X.I unshar Xwill ask for the directory name before doing anything; this is most useful Xwith the environment variable UNSHAREDIR. XIf the directory name starts with a tilde, then the value of the HOME Xenvironment variable is inserted in place of that character. XFor convenience, the ``\-d'' option is a synonym for the ``\-c'' option. X.PP X.I Unshar Xnormally complains if the input looks like something other than a shar file. X(Among other things, it checks for files that resemble C, and Pascal code). XIt can be fooled, however, by nonstandard versions of news, notes, etc. XThe ``\-f'' option forces X.I unshar Xto try unpacking files, even if they look like something else. X.PP XDepending on how the program is installed, X.I unshar Xmay or may not try to preserve the header part of file ``foo'' Xinto the name ``foo.hdr'' (if the file is standard input, the name Xwill be ``UNSHAR.HDR''). XUsing the XUsing the ``\-s'' option forces the program to save the headers, while Xusing the ``\-n'' option forces it to discard the headers. XThe file is appended to, if it already exists, so all headers can be easily Xsaved in one file. X.SH ENVIRONMENT X.ta \w'UNSHAREDIR 'u XHOME Value used if a leading tilde is given in directory name. X.br XUNSHAREDIR Default value for ``\-c'' option. X.SH SEE ALSO Xshar(1). END_OF_unshar.man if test 2178 -ne `wc -c