[comp.os.minix] more intelligent shar

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