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