Chuck_M_Grandgent@cup.portal.com (05/16/88)
Here's a "more intelligent" shar (shell archiver) I got bit by the Minix 1.2 shar when stupid me let an executable sneak into a shell archive, effectively wrecking it (I should have been more careful). This shar is a combination of Michiel Husijes's shar.c and Andy Tanenbaum's recent file.c. It (hopefully) only allows "safe" files into a shell archive. I hope this increase in functionality is enough to warrant its being posted. If it isn't, my apologies. chuck_m_grandgent@cup.portal.com 5/15/88 This is a shell archive. Unarchive with /bin/sh, not csh. --------------------------- Cut here ------------------------ echo x - shar.c gres '^X' '' > shar.c << '/' X/* shar - make a shell archive Author: Michiel Husijes */ X/* X * This is a combination of Michiel Husijes's shar.c X * and Andy Tanenbaum's file.c. X * When CREATING a shell archive, it will only include files X * it identifies as "C" programs or good ascii text. X * Otherwise, if binary files are included in a shell archive, X * the shell archive is apparently unuseable. X * X * ===>> Also, the check to see if a file is a shell script should be X * made AFTER the check to see if it's ascii text or "C" program, X * otherwise, if a .C file has "x" permissions it will be identified X * as a shell script instead of a "C" program. X * X * - chuck_m_grandgent@cup.portal.com 5/15/88 X */ X X#include <blocksize.h> X#include <ar.h> X#include <minix/stat.h> X X#define IO_SIZE (10 * BLOCK_SIZE) X Xchar input[IO_SIZE]; Xchar output[IO_SIZE]; Xint index = 0; X X X#define A_OUT 001401 /* magic number for executables */ X#define SPLIT 002040 /* second word on split I/D binaries */ X#define XBITS 00111 /* rwXrwXrwX (x bits in the mode) */ X#define ENGLISH 25 /* cutoff for determining if text is Eng.*/ Xchar buf[BLOCK_SIZE]; X Xmain(argc, argv) Xint argc; Xregister char *argv[]; X{ X register int i; X int fd; X X print("\nThis is a shell archive."); X print("\nUnarchive with /bin/sh, not csh."); X print("\n--------------------------- Cut here ------------------------"); X for (i = 1; i < argc; i++) { X if ((fd = open(argv[i], 0)) < 0) { X write(2, "Cannot open ", 12); X write(2, argv[i], strlen(argv[i])); X write(2, ".\n", 2); X } X else { X if(file(argv[i])){ X write(2, "Adding ",7); X write(2, argv[i], strlen(argv[i])); X write(2, ".\n",2); X print("\necho x - "); X print(argv[i]); X print("\ngres '^X' '' > "); X print(argv[i]); X print(" << '/'\n"); X cat(fd); X }else{ X print("\necho skipped - "); X print(argv[i]); X print("\n"); X write(2, "Skipping ",9); X write(2, argv[i], strlen(argv[i])); X write(2, " non-SHAR-able file.\n",22); X } X } X } X if (index) write(1, output, index); X exit(0); X} X Xcat(fd) Xint fd; X{ X static char *current, *last; X register int r = 0; X register char *cur_pos = current; X X putchar('X'); X for (; ;) { X if (cur_pos == last) { X if ((r = read(fd, input, IO_SIZE)) <= 0) X break; X last = &input[r]; X cur_pos = input; X } X putchar(*cur_pos); X if (*cur_pos++ == '\n' && cur_pos != last) X putchar('X'); X } X print("/\n"); X (void) close(fd); X current = cur_pos; X} X Xprint(str) Xregister char *str; X{ X while (*str) X putchar(*str++); X} X Xputchar(c) Xregister char c; X{ X output[index++] = c; X if (index == IO_SIZE) { X write(1, output, index); X index = 0; X } X} X X/* file - report on file type. Author: Andy Tanenbaum */ X Xint file(name) Xchar *name; X{ X int i, fd, n, magic, second, mode, nonascii, special, funnypct, etaoins; X long engpct; X char c; X struct stat st_buf; X X printf("%s: ", name); X X /* Open the file, stat it, and read in 1 block. */ X fd = open(name, 0); X if (fd < 0) { X write(2," cannot open ",13); X return 0; X } X X n = fstat(fd, &st_buf); X if (n < 0) { X write(2," cannot stat ",13); X close(fd); X return 0; X } X mode = st_buf.st_mode; X X /* Check for directories and special files. */ X if ( (mode & S_IFMT) == S_IFDIR) { X write(2," directory ",11); X close(fd); X return 0; X } X X if ( (mode & S_IFMT) == S_IFCHR) { X write(2," character special file ",24); X close(fd); X return 0; X } X X if ( (mode & S_IFMT) == S_IFBLK) { X write(2," block special file ",20); X close(fd); X return 0; X } X X n = read(fd, buf, BLOCK_SIZE); X if (n < 0) { X write(2," cannot read ",13); X close(fd); X return 0; X } X X /* Check to see if file is an archive. */ X magic = (buf[1]<<8) | (buf[0]&0377); X if (magic == ARMAG) { X write(2," archive ",9); X close(fd); X return 0; X } X X /* Check to see if file is an executable binary. */ X if (magic == A_OUT) { X /* File is executable. Check for split I/D. */ X write(2," executable ",12); X second = (buf[3]<<8) | (buf[2]&0377); X if (second == SPLIT) X write(2," separate I & D space ",22); X else X write(2," combined I & D space ",22); X close(fd); X return 0; X } X X /* Check for ASCII data and certain punctuation. */ X nonascii = 0; X special = 0; X etaoins = 0; X for (i = 0; i < n; i++) { X c = buf[i]; X if (c & 0200) nonascii++; X if (c == ';' || c == '{' || c == '}' || c == '#') special++; X if (c == '*' || c == '<' || c == '>' || c == '/') special++; X if (c >= 'A' && c <= 'Z') c = c - 'A' + 'a'; X if (c == 'e' || c == 't' || c == 'a' || c == 'o') etaoins++; X if (c == 'i' || c == 'n' || c == 's') etaoins++; X } X X if (nonascii == 0) { X /* File only contains ASCII characters. Continue processing. */ X funnypct = 100 * special/n; X engpct = 100L * (long) etaoins/n; X if (funnypct > 1) { X write(2," C program ",11); X } else { X if (engpct > (long) ENGLISH) X write(2," English text ",14); X else X write(2," ASCII text ",12); /* ,engpct); */ X } X close(fd); X return 1; X } X X /* Check to see if file is a shell script. */ X if (mode & XBITS) { X /* Not a binary, but executable. Probably a shell script. */ X write(2," shell script ",14); X close(fd); X return 0; X } X X /* Give up. Call it data. */ X write(2," data ",6); X close(fd); X return 0; X} X / file has "x" permissions it will be