[comp.os.minix] V1.3c posting #4 - commands

ast@cs.vu.nl (Andy Tanenbaum) (09/28/88)

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'date.c'
sed 's/^X//' > 'date.c' << '+ END-OF-FILE ''date.c'
X/* date - print or set time and date		Author: Jan Looyen */
X
X#include <stdio.h>
X#include <time.h>
X
X#define	MIN	60L		/* # seconds in a minute */
X#define	HOUR	(60 * MIN)	/* # seconds in an hour */
X#define	DAY	(24 * HOUR)	/* # seconds in a day */
X#define	YEAR	(365 * DAY)	/* # seconds in a year */
X
Xchar *ctime();
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X  int qflag;
X  long t, time();
X  char time_buf[15];
X
X  if (argc  > 2) usage();
X  if (argc == 2) {
X	if (*argv[1] == '-' && (argv[1][1] | 0x60) == 'q') {
X		freopen(stdin, "/dev/tty0", "r");
X		printf("\nPlease enter date: MMDDYYhhmmss. Then hit RETURN.\n");
X		gets(time_buf);
X		set_time(time_buf);
X	}
X	else
X		set_time(argv[1]);
X  }
X  time(&t);
X  printf("%s", ctime(&t)); 
X  exit(0);
X}
X
X
Xset_time(t)
Xchar *t;
X{
X  char *tp;
X  long ct, time();
X  int len;
X  static int days_per_month[] = {
X	  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
X  };
X  struct tm *p, *localtime();
X
X  time(&ct);
X  p = localtime(&ct);
X  p->tm_year -= 1970;
X  p->tm_mon++;
X  len = strlen(t);
X  if (len != 12 && len != 10 && len != 6 && len != 4) usage();
X  tp = t;
X  while (*tp)
X	if (!isdigit(*tp++))
X		bad();
X  if (len == 6 || len == 12) 
X  	p->tm_sec = conv(&tp, 59);
X  p->tm_min = conv(&tp, 59);
X  p->tm_hour = conv(&tp, 23);
X  if (len == 12 || len == 10) {
X  	p->tm_year = conv(&tp, 99);
X  	p->tm_mday = conv(&tp, 31);
X  	p->tm_mon = conv(&tp, 12);
X  	p->tm_year -= 70;
X	if (p->tm_year < 0)
X		p->tm_year += 100;
X  }
X  ct = p->tm_year * YEAR;
X  ct += ((p->tm_year + 1) / 4) * DAY;
X  days_per_month[1] = 28;
X  if (((p->tm_year + 2) % 4) == 0)
X	days_per_month[1]++;
X  len = 0;
X  p->tm_mon--;
X  while (len < p->tm_mon)
X	ct += days_per_month[len++] * DAY;
X  ct += --p->tm_mday * DAY;
X  ct += p->tm_hour * HOUR;
X  ct += p->tm_min * MIN;
X  ct += p->tm_sec;
X  if (stime(&ct))
X	fprintf(stderr, "Set date not allowed\n");
X}
X
Xconv(ptr, max)
Xchar **ptr;
Xint max;
X{
X  int buf;
X
X  *ptr -=2;
X  buf = atoi(*ptr);
X  **ptr = 0;
X  if (buf < 0 || buf > max)
X	bad();
X  return(buf);
X}
X
Xbad()
X{
X  fprintf(stderr, "Date: bad conversion\n");
X  exit(1);
X}
X
Xusage()
X{
X  fprintf(stderr, "Usage: date [-q] [[MMDDYY]hhmm[ss]]\n");
X  exit(1);
X}
X
Xisdigit(c)
Xchar c;
X{
X  if (c >= '0' && c <= '9')
X	return(1);
X  else
X	return(0);
X}
+ END-OF-FILE date.c
chmod 'u=rw,g=r,o=r' 'date.c'
set `wc -c 'date.c'`
count=$1
case $count in
2223)	:;;
*)	echo 'Bad character count in ''date.c' >&2
		echo 'Count should be 2223' >&2
esac
echo Extracting 'df.c.cdif'
sed 's/^X//' > 'df.c.cdif' << '+ END-OF-FILE ''df.c.cdif'
X*** /local/ast/minix/tape3b/commands/df.c	Wed Jul 13 13:10:51 1988
X--- df.c	Sun Sep 25 15:24:55 1988
X***************
X*** 178,187 ****
X  char *p;
X  {
X    char c;
X  
X    while (1) {
X! 	c = getchar();
X! 	if (c < 0) exit(0);
X  	if (c == ' ') c = 0;
X  	*p++ = c;
X  	if (c == '\n') return;
X--- 178,189 ----
X  char *p;
X  {
X    char c;
X+   char ch;
X  
X    while (1) {
X! 	ch = getchar();
X! 	if (ch == EOF) exit(0);
X! 	c = (char) ch;
X  	if (c == ' ') c = 0;
X  	*p++ = c;
X  	if (c == '\n') return;
+ END-OF-FILE df.c.cdif
chmod 'u=rw,g=r,o=r' 'df.c.cdif'
set `wc -c 'df.c.cdif'`
count=$1
case $count in
487)	:;;
*)	echo 'Bad character count in ''df.c.cdif' >&2
		echo 'Count should be 487' >&2
esac
echo Extracting 'diskcheck.c.cdif'
sed 's/^X//' > 'diskcheck.c.cdif' << '+ END-OF-FILE ''diskcheck.c.cdif'
X*** /local/ast/minix/tape3b/commands/diskcheck.c	Wed Jul 13 13:10:51 1988
X--- diskcheck.c	Sun Sep 25 15:24:55 1988
X***************
X*** 15,20 ****
X--- 15,21 ----
X  int pfd;			/* file descriptor for purging */
X  int fd;				/* file descriptor for data I/O */
X  unsigned initblock;		/* first block to test */
X+ unsigned curblock;		/* current block */
X  unsigned limit;			/* first block beyond test zone */
X  unsigned errors;		/* # errors so far */
X  unsigned ct;			/* # blocks read so far */
X***************
X*** 62,67 ****
X--- 63,69 ----
X  			write(fd, buf, BLOCK_SIZE);
X  		}
X  	}
X+ 	curblock = b;
X  	ct++;
X  	if (ct % PRINTFREQ == 0) status();
X    }
X***************
X*** 120,126 ****
X  
X  status()
X  {
X!   printf("%5u blocks tested, %u errors detected\n",ct,errors);
X  }
X  
X  nonfatal(s, b)
X--- 122,129 ----
X  
X  status()
X  {
X!   printf("%5u blocks tested, %u errors detected (last block tested = %5u)\n",
X! 						ct,errors,curblock);
X  }
X  
X  nonfatal(s, b)
+ END-OF-FILE diskcheck.c.cdif
chmod 'u=rw,g=r,o=r' 'diskcheck.c.cdif'
set `wc -c 'diskcheck.c.cdif'`
count=$1
case $count in
956)	:;;
*)	echo 'Bad character count in ''diskcheck.c.cdif' >&2
		echo 'Count should be 956' >&2
esac
echo Extracting 'dosread.c'
sed 's/^X//' > 'dosread.c' << '+ END-OF-FILE ''dosread.c'
X/* dos{read|write|dir} - handle DOS disks	Author: Michiel Huisjes */
X
X/* dosdir - list MS-DOS directories.
X * doswrite - write stdin to DOS-file
X * dosread - read DOS-file to stdout
X *
X * Author: Michiel Huisjes.
X * 
X * Usage: dos... [-lra] drive [file/dir]
X *	  l: Give long listing.
X *	  r: List recursively.
X *	  a: Set ASCII bit.
X *
X *	Modified by Tim Kachel 4-88
X *		drive can be 0,1, a, b, c, d, e, f
X *		program will automatically configure to different hard disks
X *		  and the partitions for such (could change drive name for
X *		  a second hard disk if you have one)
X *			(has been tested on a 16 bit FAT AT drive)
X *			(High density AT diskettes and regular 360K)
X *		compile with cc -O -i
X *		hard disk is named /dev/hd0 to avoid accidents
X *		  To test FAT sizes on your hard disk first try dir -lr c
X *			(or what ever your dos partition is)  if this works
X *			properly then all the rest should be okay.
X *		If there are any problems there is debugging information
X *		  in fdinit() -- please let me know of any problems
X */
X
X#include <sys/stat.h>
X
X#define DRIVE0		"/dev/at0"
X#define DRIVE1		"/dev/at1"
X#define FDRIVE		"/dev/hd0"
X
X#define DDDD	0xFD
X#define DDHD	0xF9
X#define DDFD	0xF8
X
X#define	MAX_CLUSTER_SIZE	4096
X#define MAX_FAT_SIZE		23552	/* 46 sectoren */
X#define HMASK		0xFF00
X#define LMASK		0x00FF
X
X#define MAX_ROOT_ENTRIES	512	/* 32 sectoren */
X#define FAT_START		512L	/* After bootsector */
X#define clus_add(cl_no)		((long) (((long) cl_no - 2L) \
X					* (long) cluster_size \
X					+ (long) data_start \
X				       ))
Xstruct dir_entry {
X	unsigned char d_name[8];
X	unsigned char d_ext[3];
X	unsigned char d_attribute;
X	unsigned char d_reserved[10];
X	unsigned short d_time;
X	unsigned short d_date;
X	unsigned short d_cluster;
X	unsigned long d_size;
X};
X
Xtypedef struct dir_entry DIRECTORY;
X
X#define NOT_USED	0x00
X#define ERASED		0xE5
X#define DIR		0x2E
X#define DIR_SIZE	(sizeof (struct dir_entry))
X#define SUB_DIR		0x10
X#define NIL_DIR		((DIRECTORY *) 0)
X
X#define LAST_CLUSTER	0x0FFF
X#define MASK		0xFF8		/* FF8 - FFF are last cluster */
X#define FREE		0x000
X#define BAD		0xFF0		/* Includes reserved */
X
X#define LAST_16		0xFFFF
X#define MASK_16		0xFFF8
X#define FREE_16		0x0000
X#define BAD_16		0xFFF0		/* Includes reserved */
X
Xtypedef char BOOL;
X
X#define TRUE	1
X#define FALSE	0
X#define NIL_PTR	((char *) 0)
X
X#define DOS_TIME	315532800L     /* 1970 - 1980 */
X
X#define READ			0
X#define WRITE			1
X#define disk_read(s, a, b)	disk_io(READ, s, a, b)
X#define disk_write(s, a, b)	disk_io(WRITE, s, a, b)
X
X#define FIND	3
X#define LABEL	4
X#define ENTRY	5
X#define find_entry(d, e, p)	directory(d, e, FIND, p)
X#define list_dir(d, e, f)	(void) directory(d, e, f, NIL_PTR)
X#define label()			directory(root, root_entries, LABEL, NIL_PTR)
X#define new_entry(d, e)		directory(d, e, ENTRY, NIL_PTR)
X
X#define is_dir(d)		((d)->d_attribute & SUB_DIR)
X
X#define EOF			0400
X#define EOF_MARK		'\032'
X#define STD_OUT			1
X#define flush()			print(STD_OUT, NIL_PTR, 0)
X
Xshort disk;
Xunion tbl
X{
X	unsigned char  twelve[4096];
X	unsigned short sixteen[MAX_FAT_SIZE / 2 ];
X} fat;
X
XDIRECTORY root[MAX_ROOT_ENTRIES], save_entry, *directory(), *read_cluster();
Xchar null[MAX_CLUSTER_SIZE], *device, path[128];
Xshort total_clusters, cluster_size, fat_size, root_entries, sub_entries;
X
XBOOL Rflag, Lflag, Aflag, dos_read, dos_write, dos_dir, Tfat = TRUE;
X
Xunsigned short free_cluster(), next_cluster();
Xchar *make_name(), *num_out(), *slash(), *brk();
Xlong mark, data_start, lseek(), time(), f_start;
X
Xleave(nr)
Xshort nr;
X{
X	(void) umount(device);
X	exit(nr);
X}
X
Xusage(prog_name)
Xregister char *prog_name;
X{
X	print_string(TRUE, "Usage: %s [%s\n", prog_name,
X		     dos_dir ? "-lr] drive [dir]" : "-a] drive file");
X	exit(1);
X}
X
Xmain(argc, argv)
Xint argc;
Xregister char *argv[];
X{
X	register char *arg_ptr = slash(argv[0]);
X	DIRECTORY *entry;
X	short index = 1;
X	char dev_nr;
X	unsigned char fat_type, fat_check;
X	BOOL fdisk = FALSE;
X	int i;
X
X	if (!strcmp(arg_ptr, "dosdir"))
X		dos_dir = TRUE;
X	else if (!strcmp(arg_ptr, "dosread"))
X		dos_read = TRUE;
X	else if (!strcmp(arg_ptr, "doswrite"))
X		dos_write = TRUE;
X	else {
X		print_string(TRUE, "Program should be named dosread, doswrite or dosdir.\n");
X		exit(1);
X	}
X
X	if (argc == 1)
X		usage(argv[0]);
X
X	if (argv[1][0] == '-') {
X		for (arg_ptr = &argv[1][1]; *arg_ptr; arg_ptr++) {
X			if (*arg_ptr == 'l' && dos_dir)
X				Lflag = TRUE;
X			else if (*arg_ptr == 'r' && dos_dir)
X				Rflag = TRUE;
X			else if (*arg_ptr == 'a' && !dos_dir)
X				Aflag = TRUE;
X			else
X				usage(argv[0]);
X		}
X		index++;
X	}
X
X	if (index == argc)
X		usage(argv[0]);
X
X	switch (dev_nr = *argv[index++])
X	{
X		case '0':
X		case 'a':	device = DRIVE0; break;
X		case '1':
X		case 'b':	device = DRIVE1; break;
X		case 'c':
X		case 'd':
X		case 'e':
X		case 'f':	fdisk = TRUE; device = FDRIVE; break;
X		default :	usage(argv[0]);
X	}
X
X	if ((disk = open(device, 2)) < 0) {
X		print_string(TRUE, "Cannot open %s\n", device);
X		exit(1);
X	}
X
X	if (fdisk) {		/* fixed disk */
X		fdinit(dev_nr);
X		disk_read(f_start, &fat_type, sizeof(fat_type));
X		if (fat_type != DDFD) {
X			print_string(TRUE, "Fixed disk is not DOS\n");
X			leave(1);
X		}
X	}
X	else {		/* use standard start for floppies */
X		f_start = FAT_START;
X		disk_read(f_start, &fat_type, sizeof(fat_type));
X		if (fat_type == DDDD) {		/* Double-sided double-density 9 s/t */
X			total_clusters = 355;	/* 720 - 7 - 2 - 2 - 1 */
X			cluster_size = 1024;	/* 2 sectors per cluster */
X			fat_size = 1024;	/* 2 sectors */
X			data_start = 6144L;	/* Starts on sector #12 */
X			root_entries = 112;	
X			sub_entries = 32;	/* 1024 / 32 */
X		}
X		else if (fat_type == DDHD) {	/* Double-sided high-density 15 s/t */
X			total_clusters = 2372;	/* 2400 - 14 - 7 - 7 - 1 */
X			cluster_size = 512;	/* 1 sector per cluster */
X			fat_size = 3584;	/* 7 sectors */
X			data_start = 14848L;	/* Starts on sector #29 */
X			root_entries = 224;	
X			sub_entries = 16;	/* 512 / 32 */
X		}
X		else {
X        		print_string(TRUE, "Diskette is not DOS 2.0 360K or 1.2M\n");
X			leave(1);
X		}
X	}
X
X	disk_read(f_start + (long) fat_size, &fat_check, sizeof(fat_check));
X	if (fat_check != fat_type) {
X		print_string(TRUE, "Disk type in FAT copy differs from disk type in FAT original.\n");
X		leave(1);
X	}
X
X	if (Tfat)	/* twelve bit FAT entries */
X		disk_read(f_start, fat.twelve, fat_size);
X	else		/* sixteen bit */
X		disk_read(f_start, fat.sixteen, fat_size);
X/*******
X	for (i=0; i<= 30; i++){
X		printf("%x\t%c", fat.sixteen[i], (i % 10) ? ' ':'\n');
X	}
X	leave(1);
X/*******/
X	disk_read(f_start + 2L * (long) fat_size, root, DIR_SIZE * root_entries);
X/*******
X	for (i=0; i<2; i++){
X		printf("%s d_name\n", root[i].d_name);
X		printf("%s d_ext\n",  root[i].d_ext);
X		printf("%d d_attr\n",  root[i].d_attribute);
X		printf("%s d_reserved\n",  root[i].d_reserved);
X		printf("%d d_time\n",  root[i].d_time);
X		printf("%d d_date\n",  root[i].d_date);
X		printf("%d d_cluster\n",  root[i].d_cluster);
X		printf("%D d_size\n",  root[i].d_size);
X	}
X
X
X/*********/
X	if (dos_dir) {
X		entry = label();
X		print_string(FALSE, "Volume in drive %c ", dev_nr);
X		if (entry == NIL_DIR)
X			print(STD_OUT, "has no label.\n\n", 0);
X		else
X			print_string(FALSE, "is %S\n\n", entry->d_name);
X	}
X
X	if (argv[index] == NIL_PTR) {
X		if (!dos_dir)
X			usage(argv[0]);
X		print(STD_OUT, "Root directory:\n", 0);
X		list_dir(root, root_entries, FALSE);
X		free_blocks();
X		flush();
X		leave(0);
X	}
X
X	for (arg_ptr = argv[index]; *arg_ptr; arg_ptr++)
X		if (*arg_ptr == '\\')
X			*arg_ptr = '/';
X		else if (*arg_ptr >= 'a' && *arg_ptr <= 'z')
X			*arg_ptr += ('A' - 'a');
X	if (*--arg_ptr == '/')
X		*arg_ptr = '\0';       /* skip trailing '/' */
X
X	add_path(argv[index], FALSE);
X	add_path("/", FALSE);
X
X	if (dos_dir)
X		print_string(FALSE, "Directory %s:\n", path);
X
X	entry = find_entry(root, root_entries, argv[index]);
X
X	if (dos_dir) {
X		list_dir(entry, sub_entries, FALSE);
X		free_blocks();
X	}
X	else if (dos_read)
X		extract(entry);
X	else {
X		if (entry != NIL_DIR) {
X			flush();
X			if (is_dir(entry))
X				print_string(TRUE, "%s is a directory.\n", path);
X			else
X				print_string(TRUE, "%s already exists.\n", argv[index]);
X			leave(1);
X		}
X
X		add_path(NIL_PTR, TRUE);
X
X		if (*path)
X			make_file(find_entry(root, root_entries, path),
X				  sub_entries, slash(argv[index]));
X		else
X			make_file(root, root_entries, argv[index]);
X	}
X
X	(void) close(disk);
X	flush();
X	leave(0);
X}
X
Xfdinit(part_nr)		/* Fixed Disk Initializations */
Xchar part_nr;
X{
X
X#define	SECSIZE        512        /* sector size        */
X#define TABLEOFFSET    0x1be      /* offset in boot sector*/
X
X	/*
X	 * Description of entry in partition table
X	 */
X	struct part_entry {
X	    char    bootind;    /* boot indicator 0/0x80    */
X	    char    start_head;    /* head value for first sector    */
X	    char    start_sec;    /* sector value for first sector*/
X	    char    start_cyl;    /* track value for first sector    */
X	    char    sysind;        /* system indicator 00=?? 01=DOS*/
X	    char    last_head;    /* head value for last sector    */
X	    char    last_sec;    /* sector value for last sector    */
X	    char    last_cyl;    /* track value for last sector    */
X	    long    lowsec;        /* logical first sector        */
X	    long    size;        /* size of partion in sectors    */
X	} *pe;
X
X	char    secbuf[SECSIZE];
X
X	/*
X	 *	Description of the boot block
X	 */
X	struct {
X		unsigned char jump[3];
X		unsigned char oem[8];
X		unsigned char bytes_sector[2];
X		unsigned char cluster_size;
X		unsigned char res_sectors[2];
X		unsigned char num_fats;
X		unsigned char root_entries[2];
X		unsigned char logical_sectors[2];
X		unsigned char media_type;
X		unsigned char fat_sectors[2];
X		unsigned char track_sectors[2];
X		unsigned char num_heads[2];
X		unsigned char hidden_sectors[2];
X	} boot;
X
X	short block_size, reserved;	long boot_loc;
X
X	disk_read(0L, secbuf, SECSIZE);	/* get boot sector */
X		/* offset into boot sector for the partition table */
X	pe = (struct part_entry *)&secbuf[TABLEOFFSET];
X		/* get the proper partition */
X	switch(part_nr) {
X		case 'f': pe++;
X		case 'e': pe++;
X		case 'd': pe++;
X		case 'c': boot_loc = pe->lowsec * 512L; break;
X        	default:  printf("Error: unknown partition\n"); leave();
X	}
X		/* now read the boot block for the partition needed */
X	disk_read(boot_loc, &boot, sizeof(boot));
X
X	/* this section can be used to print drive information */
X/**************
X	printf("OEM = %s\n", boot.oem);
X	printf("Bytes/sector = %d\n",
X		(boot.bytes_sector[1] << 8 & HMASK) + (boot.bytes_sector[0] & LMASK)); 
X	printf("Sectors/cluster = %d\n", boot.cluster_size);
X	printf("Number of Reserved Clusters = %d\n",
X		(boot.res_sectors[1] << 8 & HMASK) + (boot.res_sectors[0] & LMASK));
X	printf("Number of FAT's = %d\n", boot.num_fats);
X	printf("Number of root-directory entries = %d\n",
X		(boot.root_entries[1] << 8 & HMASK) + (boot.root_entries[0] & LMASK));
X	printf("Total sectors in logical volume = %D\n",
X		(long) (boot.logical_sectors[1] << 8 & HMASK) + (boot.logical_sectors[0] & LMASK));
X	printf("Media Descriptor = %x\n", boot.media_type);
X	printf("Number of sectors/FAT = %d\n",
X		(boot.fat_sectors[1] << 8 & HMASK) + (boot.fat_sectors[0] & LMASK));
X	printf("Sectors/track = %d\n",
X		(boot.track_sectors[1] << 8 & HMASK) + (boot.track_sectors[0] & LMASK));
X	printf("Number of Heads = %d\n",
X		(boot.num_heads[1] << 8 & HMASK) + (boot.num_heads[0] & LMASK));
X	printf("Number of hidden sectors = %d\n",
X		(boot.hidden_sectors[1]  << 8 & HMASK) + (boot.hidden_sectors[0] & LMASK));
X	leave(1);
X/**************/
X	if (boot.media_type != DDFD) {
X		printf("DISK is not DOS Format.\n");
X		leave(1);
X	}
X	if (boot.num_fats != 2) {
X		printf("Disk does not have two FAT Tables!\n");
X		leave(1);
X	}
X	block_size = (boot.bytes_sector[1] << 8 & HMASK) +
X			 (boot.bytes_sector[0] & LMASK);
X	if ((cluster_size = block_size * boot.cluster_size)
X					> MAX_CLUSTER_SIZE) {
X		printf("Cluster size is larger than MAX_CLUSTER_SIZE.\n");
X		leave(1);
X	}
X	reserved =  ((boot.res_sectors[1] << 8 & HMASK) +
X			(boot.res_sectors[0] & LMASK));
X	f_start = boot_loc + (long) block_size * (long) reserved;
X	root_entries = (boot.root_entries[1] << 8 & HMASK) +
X			(boot.root_entries[0] & LMASK);
X	fat_size = (boot.fat_sectors[1] << 8 & HMASK) +
X			 (boot.fat_sectors[0] & LMASK);
X		/* (sectors - rootdir - fats - reserved) / blocks/cluster */
X	total_clusters = (int) ((long) ((boot.logical_sectors[1] << 8 & HMASK) +
X				   (boot.logical_sectors[0] & LMASK)) - 
X		  (root_entries * 32 / block_size) -
X		  (fat_size * 2) - reserved) / boot.cluster_size;
X	if (total_clusters > 4096)
X		Tfat = FALSE;		/* sixteen bit fat entries */
X	if ( (fat_size *= block_size) > MAX_FAT_SIZE) {
X		printf("Disk FAT is larger than MAX_FAT_SIZE.\n");
X		leave(1);
X	}
X	sub_entries = cluster_size / 32;
X	data_start = f_start + (long) (fat_size * 2L) +
X			(long) (root_entries * 32L);
X/**********
X	printf("f_start = %D\n", f_start);
X	printf("total_clusters = %d\n", total_clusters);
X	printf("cluster_size = %d\n", cluster_size);
X	printf("fat_size = %d\n", fat_size);
X	printf("data_start = %D\n", data_start);
X	printf("root_entries = %d\n", root_entries);
X	printf("sub_entries = %d\n", sub_entries);
X	printf("Tfat = %d\n", Tfat);
X	leave(1);
X/*********/
X}
X
XDIRECTORY *directory(dir, entries, function, pathname)
XDIRECTORY *dir;
Xshort entries;
XBOOL function;
Xregister char *pathname;
X{
X	register DIRECTORY *dir_ptr = dir;
X	DIRECTORY *mem = NIL_DIR;
X	unsigned short cl_no = dir->d_cluster;
X	unsigned short type, last;
X	char file_name[14];
X	char *name;
X	int i = 0;
X
X	if (function == FIND) {
X        while (*pathname != '/' && *pathname && i < 12)
X			file_name[i++] = *pathname++;
X		while (*pathname != '/' && *pathname)
X			pathname++;
X		file_name[i] = '\0';
X	}
X
X	do {
X		if (entries != root_entries) {
X			mem = dir_ptr = read_cluster(cl_no);
X			last = cl_no;
X			cl_no = next_cluster(cl_no);
X		}
X
X		for (i = 0; i < entries; i++, dir_ptr++) {
X			type = dir_ptr->d_name[0] & 0x0FF;
X			if (function == ENTRY) {
X				if (type == NOT_USED || type == ERASED) {
X					mark = lseek(disk, 0L, 1) -
X						(long) cluster_size +
X						(long) i * (long) DIR_SIZE;
X					if (!mem)
X						mark += (long) cluster_size - (long) (root_entries * sizeof (DIRECTORY));
X					return dir_ptr;
X				}
X				continue;
X			}
X			if (type == NOT_USED)
X				break;
X			if (dir_ptr->d_attribute & 0x08) {
X				if (function == LABEL)
X					return dir_ptr;
X				continue;
X			}
X			if (type == DIR || type == ERASED || function == LABEL)
X				continue;
X			type = is_dir(dir_ptr);
X			name = make_name(dir_ptr, (function == FIND) ?
X					 FALSE : type);
X			if (function == FIND) {
X				if (strcmp(file_name, name) != 0)
X					continue;
X				if (!type) {
X					if (dos_dir || *pathname) {
X						flush();
X						print_string(TRUE, "Not a directory: %s\n", file_name);
X						leave(1);
X					}
X				}
X				else if (*pathname == '\0' && dos_read) {
X					flush();
X					print_string(TRUE, "%s is a directory.\n", path);
X					leave(1);
X				}
X				if (*pathname) {
X					dir_ptr = find_entry(dir_ptr,
X						   sub_entries, pathname + 1);
X				}
X				if (mem) {
X					if (dir_ptr) {
X						bcopy(dir_ptr, &save_entry, DIR_SIZE);
X						dir_ptr = &save_entry;
X					}
X					(void) brk(mem);
X				}
X				return dir_ptr;
X			}
X			else {
X				if (function == FALSE)
X					show(dir_ptr, name);
X				else if (type) {	/* Recursive */
X					print_string(FALSE, "Directory %s%s:\n", path, name);
X					add_path(name, FALSE);
X					list_dir(dir_ptr, sub_entries, FALSE);
X					add_path(NIL_PTR, FALSE);
X				}
X			}
X		}
X		if (mem)
X			(void) brk(mem);
X	} while ((Tfat && cl_no != LAST_CLUSTER && mem) ||
X		 (!Tfat && cl_no != LAST_16 && mem));
X
X	switch (function) {
X		case FIND:
X			if (dos_write && *pathname == '\0')
X				return NIL_DIR;
X			flush();
X			print_string(TRUE, "Cannot find `%s'.\n", file_name);
X			leave(1);
X		case LABEL:
X			return NIL_DIR;
X		case ENTRY:
X			if (!mem) {
X				flush();
X				print_string(TRUE, "No entries left in root directory.\n");
X				leave(1);
X			}
X
X			cl_no = free_cluster(TRUE);
X			link_fat(last, cl_no);
X			if (Tfat)
X				link_fat(cl_no, LAST_CLUSTER);
X			else
X				link_fat(cl_no, LAST_16);
X			disk_write(clus_add(cl_no), null, cluster_size);
X
X			return new_entry(dir, entries);
X		case FALSE:
X			if (Rflag) {
X				print(STD_OUT, "\n", 0);
X				list_dir(dir, entries, TRUE);
X			}
X	}
X}
X
Xextract(entry)
Xregister DIRECTORY *entry;
X{
X	register unsigned short cl_no = entry->d_cluster;
X	char buffer[MAX_CLUSTER_SIZE];
X	short rest;
X
X	if (entry->d_size == 0)	       /* Empty file */
X		return;
X
X	do {
X		disk_read(clus_add(cl_no), buffer, cluster_size);
X		rest = (entry->d_size > (long) cluster_size) ? cluster_size : (short) entry->d_size;
X		print(STD_OUT, buffer, rest);
X		entry->d_size -= (long) rest;
X		cl_no = next_cluster(cl_no);
X		if ((Tfat && cl_no == BAD) || (!Tfat && cl_no == BAD_16)){
X			flush();
X			print_string(TRUE, "Reserved cluster value encountered.\n");
X			leave(1);
X		}
X	} while ((Tfat && entry->d_size && cl_no != LAST_CLUSTER) ||
X		 (!Tfat && entry->d_size && cl_no != LAST_16));
X
X	if ((Tfat && cl_no != LAST_CLUSTER) || (!Tfat && cl_no != LAST_16))
X		print_string(TRUE, "Too many clusters allocated for file.\n");
X	else if (entry->d_size != 0)
X		print_string(TRUE, "Premature EOF: %L bytes left.\n",
X			     entry->d_size);
X}
X
Xprint(fd, buffer, bytes)
Xshort fd;
Xregister char *buffer;
Xregister short bytes;
X{
X	static short index;
X	static BOOL lf_pending = FALSE;
X	static char output[MAX_CLUSTER_SIZE + 1];
X
X	if (buffer == NIL_PTR) {
X		if (dos_read && Aflag && lf_pending) {
X			output[index++] = '\r';
X			lf_pending = FALSE;
X		}
X		if (write(fd, output, index) != index)
X			bad();
X		index = 0;
X		return;
X	}
X
X	if (bytes == 0)
X		bytes = strlen(buffer);
X
X	while (bytes--) {
X		if (index >= MAX_CLUSTER_SIZE) {
X			if (write(fd, output, index) != index)
X				bad ();
X			index = 0;
X		}
X		if (dos_read && Aflag) {
X			if (*buffer == '\r') {
X				if (lf_pending)
X					output[index++] = *buffer++;
X				else {
X					lf_pending = TRUE;
X					buffer++;
X				}
X			}
X			else if (*buffer == '\n') {
X				output[index++] = *buffer++;
X				lf_pending = FALSE;
X			}
X			else if (lf_pending) {
X				output[index++] = '\r';
X				output[index++] = *buffer++;
X			}
X			else if ((output[index++] = *buffer++) == EOF_MARK) {
X				if (lf_pending) {
X					output[index - 1] = '\r';
X					index++;
X					lf_pending = FALSE;
X				}
X				index--;
X				return;
X			}
X		}
X		else
X			output[index++] = *buffer++;
X	}
X}
X
Xmake_file(dir_ptr, entries, name)
XDIRECTORY *dir_ptr;
Xint entries;
Xchar *name;
X{
X	register DIRECTORY *entry = new_entry(dir_ptr, entries);
X	register char *ptr;
X	char buffer[MAX_CLUSTER_SIZE];
X	unsigned short cl_no, next;
X	short i, r;
X	long size = 0L;
X
X    bcopy("           ",&entry->d_name[0],11);    /* clear entry */
X    for (i = 0, ptr = name; i < 8 && *ptr != '.' && *ptr; i++)
X        entry->d_name[i] = *ptr++;
X    while (*ptr != '.' && *ptr)
X        ptr++;
X    if (*ptr == '.')
X        ptr++;
X    for (i=0;i < 3 && *ptr; i++)
X        entry->d_ext[i] = *ptr++;
X
X	for (i = 0; i < 10; i++)
X		entry->d_reserved[i] = '\0';
X	entry->d_attribute = '\0';
X
X	entry->d_cluster = 0;
X
X	while ((r = fill(buffer)) > 0) {
X		if ((next = free_cluster(FALSE)) > total_clusters) {
X			print_string(TRUE, "Disk full. File truncated.\n");
X			break;
X		}
X
X		disk_write(clus_add(next), buffer, r);
X
X		if (entry->d_cluster == 0)
X			cl_no = entry->d_cluster = next;
X		else {
X			link_fat(cl_no, next);
X			cl_no = next;
X		}
X
X		size += r;
X	}
X
X	if (entry->d_cluster != 0) {
X		if (Tfat)
X			link_fat(cl_no, LAST_CLUSTER);
X		else
X			link_fat(cl_no, LAST_16);
X	}
X
X	entry->d_size = Aflag ? (size - 1) : size;	/* Strip added ^Z */
X	fill_date(entry);
X	disk_write(mark, entry, DIR_SIZE);
X	if (Tfat) {
X		disk_write(f_start, fat.twelve, fat_size);
X		disk_write(f_start + (long) fat_size, fat.twelve, fat_size);
X	} else {
X		disk_write(f_start, fat.sixteen, fat_size);
X		disk_write(f_start + (long) fat_size, fat.sixteen, fat_size);
X	}
X}
X
X
X#define SEC_MIN	60L
X#define SEC_HOUR	(60L * SEC_MIN)
X#define SEC_DAY	(24L * SEC_HOUR)
X#define SEC_YEAR	(365L * SEC_DAY)
X#define SEC_LYEAR	(366L * SEC_DAY)
X
Xshort mon_len[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
X
Xfill_date(entry)
XDIRECTORY *entry;
X{
X	register long cur_time = time((long *) 0) - DOS_TIME;
X	unsigned short year = 0, month = 1, day, hour, minutes, seconds;
X	int i;
X	long tmp;
X
X	if (cur_time < 0)	       /* Date not set on booting ... */
X		cur_time = 0;
X	for (;;) {
X		tmp = (year % 4 == 0) ? SEC_LYEAR : SEC_YEAR;
X		if (cur_time < tmp)
X			break;
X		cur_time -= tmp;
X		year++;
X	}
X
X	day = (unsigned short) (cur_time / SEC_DAY);
X	cur_time -= (long) day *SEC_DAY;
X
X	hour = (unsigned short) (cur_time / SEC_HOUR);
X	cur_time -= (long) hour *SEC_HOUR;
X
X	minutes = (unsigned short) (cur_time / SEC_MIN);
X	cur_time -= (long) minutes *SEC_MIN;
X
X	seconds = (unsigned short) cur_time;
X
X	mon_len[1] = (year % 4 == 0) ? 29 : 28;
X	i = 0;
X	while (day >= mon_len[i]) {
X		month++;
X        day -= mon_len[i++];
X	}
X	day++;
X
X	entry->d_date = (year << 9) | (month << 5) | day;
X	entry->d_time = (hour << 11) | (minutes << 5) | seconds;
X}
X
Xchar *make_name(dir_ptr, dir_fl)
Xregister DIRECTORY *dir_ptr;
Xshort dir_fl;
X{
X	static char name_buf[14];
X	register char *ptr = name_buf;
X	short i;
X
X	for (i = 0; i < 8; i++)
X		*ptr++ = dir_ptr->d_name[i];
X
X	while (*--ptr == ' ');
X
X	ptr++;
X	if (dir_ptr->d_ext[0] != ' ') {
X		*ptr++ = '.';
X		for (i = 0; i < 3; i++)
X			*ptr++ = dir_ptr->d_ext[i];
X		while (*--ptr == ' ');
X		ptr++;
X	}
X	if (dir_fl)
X		*ptr++ = '/';
X	*ptr = '\0';
X
X	return name_buf;
X}
X
Xfill(buffer)
Xregister char *buffer;
X{
X	static BOOL eof_mark = FALSE;
X	char *last = &buffer[cluster_size];
X	char *begin = buffer;
X	register short c;
X
X	if (eof_mark)
X		return 0;
X
X	while (buffer < last) {
X		if ((c = get_char()) == EOF) {
X			eof_mark = TRUE;
X			if (Aflag)
X				*buffer++ = EOF_MARK;
X			break;
X		}
X		*buffer++ = c;
X	}
X
X    return (int) (buffer - begin);
X}
X
Xget_char()
X{
X	static short read_chars, index;
X	static char input[MAX_CLUSTER_SIZE];
X	static BOOL new_line = FALSE;
X
X	if (new_line == TRUE) {
X		new_line = FALSE;
X		return '\n';
X	}
X
X	if (index == read_chars) {
X		if ((read_chars = read(0, input, cluster_size)) == 0)
X			return EOF;
X		index = 0;
X	}
X
X	if (Aflag && input[index] == '\n') {
X		new_line = TRUE;
X		index++;
X		return '\r';
X	}
X
X	return input[index++];
X}
X
X#define HOUR	0xF800		       /* Upper 5 bits */
X#define MIN	0x07E0		       /* Middle 6 bits */
X#define YEAR	0xFE00		       /* Upper 7 bits */
X#define MONTH	0x01E0		       /* Mid 4 bits */
X#define DAY	0x01F		       /* Lowest 5 bits */
X
Xchar *month[] = {
X		 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X		 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
X};
X
Xmodes(mode)
Xregister unsigned char mode;
X{
X	print_string(FALSE, "\t%c%c%c%c%c", (mode & SUB_DIR) ? 'd' : '-',
X		     (mode & 02) ? 'h' : '-', (mode & 04) ? 's' : '-',
X		     (mode & 01) ? '-' : 'w', (mode & 0x20) ? 'a' : '-');
X}
X
Xshow(dir_ptr, name)
XDIRECTORY *dir_ptr;
Xchar *name;
X{
X	register unsigned short e_date = dir_ptr->d_date;
X	register unsigned short e_time = dir_ptr->d_time;
X	unsigned short next;
X	char bname[20];
X	short i = 0;
X
X	while (*name && *name != '/')
X		bname[i++] = *name++;
X	bname[i] = '\0';
X	if (!Lflag) {
X		print_string(FALSE, "%s\n", bname);
X		return;
X	}
X	modes(dir_ptr->d_attribute);
X	print_string(FALSE, "\t%s%s", bname, strlen(bname) < 8 ? "\t\t" : "\t");
X	i = 1;
X	if (is_dir(dir_ptr)) {
X		next = dir_ptr->d_cluster;
X		while (((next = next_cluster(next)) != LAST_CLUSTER && Tfat) ||
X			(!Tfat && next != LAST_16))
X			i++;
X		print_string(FALSE, "%L", (long) i * (long) cluster_size);
X	}
X	else
X		print_string(FALSE, "%L", dir_ptr->d_size);
X	print_string(FALSE, "\t%N:%N %P %s %d\n", ((e_time & HOUR) >> 11),
X		     ((e_time & MIN) >> 5), (e_date & DAY),
X	   month[((e_date & MONTH) >> 5) - 1], ((e_date & YEAR) >> 9) + 1980);
X}
X
Xfree_blocks()
X{
X	register unsigned short cl_no;
X	register short free = 0;
X	short bad = 0;
X	if (Tfat)
X		for (cl_no = 2; cl_no <= total_clusters; cl_no++) {
X			switch (next_cluster(cl_no)) {
X				case FREE:
X					free++;
X					break;
X				case BAD:
X					bad++;
X			}
X		}
X	else
X		for (cl_no = 2; cl_no <= total_clusters; cl_no++) {
X			switch (next_cluster(cl_no)) {
X				case FREE_16:
X					free++;
X					break;
X				case BAD_16:
X					bad++;
X			}
X		}
X
X	print_string(FALSE, "Free space: %L bytes.\n", (long) free * (long) cluster_size);
X	if (bad)
X		print_string(FALSE, "Bad sectors: %L bytes.\n", (long) bad * (long) cluster_size);
X}
X
Xchar *num_out(number)
Xregister long number;
X{
X	static char num_buf[13];
X	char temp[13];
X	register short i = 0;
X	short j;
X
X	if (number == 0)
X		temp[i++] = '0';
X
X	while (number) {
X		temp[i++] = (char) (number % 10L + '0');
X		number /= 10L;
X	}
X
X	for (j = 0; j < 11; j++)
X		num_buf[j] = temp[i - j - 1];
X
X	num_buf[i] = '\0';
X	return num_buf;
X}
X
X/* VARARGS */
Xprint_string(err_fl, fmt, args)
XBOOL err_fl;
Xchar *fmt;
Xint args;
X{
X	char buf[200];
X	register char *buf_ptr = buf;
X	char *scan_ptr;
X	register int *arg_ptr = &args;
X	short i;
X
X	while (*fmt) {
X		if (*fmt == '%') {
X			fmt++;
X			if (*fmt == 'c') {
X				*buf_ptr++ = (char) *arg_ptr++;
X				fmt++;
X				continue;
X			}
X			if (*fmt == 'S') {
X				scan_ptr = (char *) *arg_ptr;
X				for (i = 0; i < 11; i++)
X					*buf_ptr++ = *scan_ptr++;
X				fmt++;
X				continue;
X			}
X			if (*fmt == 's')
X				scan_ptr = (char *) *arg_ptr;
X			else if (*fmt == 'L') {
X				scan_ptr = num_out(*((long *) arg_ptr));
X				arg_ptr++;
X			}
X			else {
X				scan_ptr = num_out((long) *arg_ptr);
X				if (*fmt == 'P' && *arg_ptr < 10)
X					*buf_ptr++ = ' ';
X				else if (*fmt == 'N' && *arg_ptr < 10)
X					*buf_ptr++ = '0';
X			}
X			while (*buf_ptr++ = *scan_ptr++);
X			buf_ptr--;
X			arg_ptr++;
X			fmt++;
X		}
X		else
X			*buf_ptr++ = *fmt++;
X	}
X
X	*buf_ptr = '\0';
X
X	if (err_fl) {
X		flush();
X        write(2, buf, (int) (buf_ptr - buf));
X	}
X	else
X		print(STD_OUT, buf, 0);
Xflush();
X}
X
XDIRECTORY *read_cluster(cluster)
Xregister unsigned short cluster;
X{
X	register DIRECTORY *sub_dir;
X	extern char *sbrk();
X
X	if ((sub_dir = (DIRECTORY *) sbrk(cluster_size)) < 0) {
X		print_string(TRUE, "Cannot set break!\n");
X		leave(1);
X	}
X	disk_read(clus_add(cluster), sub_dir, cluster_size);
X
X	return sub_dir;
X}
X
Xunsigned short free_cluster(leave_fl)
XBOOL leave_fl;
X{
X	static unsigned short cl_index = 2;
X
X	if (Tfat)
X		while (cl_index <= total_clusters && next_cluster(cl_index) != FREE)
X			cl_index++;
X	else		/* Sixteen bit */
X		while (cl_index <= total_clusters && next_cluster(cl_index) != FREE_16)
X			cl_index++;
X
X	if (leave_fl && cl_index > total_clusters) {
X		flush();
X		print_string(TRUE, "Disk full. File not added.\n");
X		leave(1);
X	}
X
X	return cl_index++;
X}
X
X/* ****************FIX FOR SIXTEEN BIT ***************** */
Xlink_fat(cl_1, cl_2)
Xunsigned short cl_1;
Xregister unsigned short cl_2;
X{
X	if (Tfat) {
X		register unsigned char *fat_index = &fat.twelve[(cl_1 >> 1) * 3 + 1];
X		if (cl_1 & 0x01) {
X			*(fat_index + 1) = cl_2 >> 4;
X			*fat_index = (*fat_index & 0x0F) | ((cl_2 & 0x0F) << 4);
X		}
X		else {
X			*(fat_index - 1) = cl_2 & 0x0FF;
X			*fat_index = (*fat_index & 0xF0) | (cl_2 >> 8);
X		}
X	}
X	else {
X		fat.sixteen[cl_1] = cl_2;
X	}
X}
X
X
Xunsigned short next_cluster(cl_no)
Xregister unsigned short cl_no;
X{
X	if (Tfat) {
X		register unsigned char *fat_index = &fat.twelve[(cl_no >> 1) * 3 + 1];
X
X		if (cl_no & 0x01)
X			cl_no = (*(fat_index + 1) << 4) | (*fat_index >> 4);
X		else
X			cl_no = ((*fat_index & 0x0F) << 8) | *(fat_index - 1);
X
X		if ((cl_no & MASK) == MASK)
X			cl_no = LAST_CLUSTER;
X		else if ((cl_no & BAD) == BAD)
X			cl_no = BAD;
X	}
X	else {
X		/*cl_no = fat.sixteen[cl_no << 1];*/
X		cl_no = fat.sixteen[cl_no];
X		if ((cl_no & MASK_16) == MASK_16)
X			cl_no = LAST_16;
X		else if ((cl_no & BAD_16) == BAD_16)
X			cl_no = BAD_16;
X	}
X
X	return cl_no;
X}
X
Xchar *slash(str)
Xregister char *str;
X{
X	register char *result = str;
X
X	while (*str)
X		if (*str++ == '/')
X			result = str;
X
X	return result;
X}
X
Xadd_path(file, slash_fl)
Xregister char *file;
XBOOL slash_fl;
X{
X	register char *ptr = path;
X
X	while (*ptr)
X		ptr++;
X
X	if (file == NIL_PTR) {
X		ptr--;
X		do {
X			ptr--;
X		} while (*ptr != '/' && ptr != path);
X		if (ptr != path && !slash_fl)
X			ptr++;
X		*ptr = '\0';
X	}
X	else
X		while (*ptr++ = *file++);
X}
X
Xbcopy(src, dest, bytes)
Xregister char *src, *dest;
Xshort bytes;
X{
X	while (bytes--)
X		*dest++ = *src++;
X}
X
Xdisk_io(op, seek, address, bytes)
Xregister BOOL op;
Xunsigned long seek;
XDIRECTORY *address;
Xregister unsigned bytes;
X{
X	unsigned int r;
X
X	if (lseek(disk, seek, 0) < 0L) {
X		flush();
X		print_string(TRUE, "Bad lseek\n");
X		leave(1);
X	}
X
X	if (op == READ)
X		r = read(disk, address, bytes);
X	else
X		r = write(disk, address, bytes);
X
X	if (r != bytes)
X		bad();
X}
X
Xbad()
X{
X	flush();
X	perror("I/O error");
X	leave(1);
X}
+ END-OF-FILE dosread.c
chmod 'u=rw,g=r,o=r' 'dosread.c'
set `wc -c 'dosread.c'`
count=$1
case $count in
28473)	:;;
*)	echo 'Bad character count in ''dosread.c' >&2
		echo 'Count should be 28473' >&2
esac
echo Extracting 'factor.c.cdif'
sed 's/^X//' > 'factor.c.cdif' << '+ END-OF-FILE ''factor.c.cdif'
X*** /local/ast/minix/tape3b/commands/factor.c	Wed Jul 13 13:10:54 1988
X--- factor.c	Sun Sep 25 15:24:59 1988
X***************
X*** 1,3 ****
X--- 1,5 ----
X+ /* factor - print the prime factors of a number      Author: Andy Tanenbaum */
X+ 
X  main(argc, argv)
X  int argc;
X  char *argv[];
+ END-OF-FILE factor.c.cdif
chmod 'u=rw,g=r,o=r' 'factor.c.cdif'
set `wc -c 'factor.c.cdif'`
count=$1
case $count in
282)	:;;
*)	echo 'Bad character count in ''factor.c.cdif' >&2
		echo 'Count should be 282' >&2
esac
echo Extracting 'fgrep.c.cdif'
sed 's/^X//' > 'fgrep.c.cdif' << '+ END-OF-FILE ''fgrep.c.cdif'
X*** /local/ast/minix/tape3b/commands/fgrep.c	Wed Jul 13 13:10:55 1988
X--- fgrep.c	Sun Sep 25 15:24:59 1988
X***************
X*** 25,31 ****
X    int find();
X    void exparg();
X    void getargs();
X-   void maktbl();
X    void gotone();
X  
X    argc=oargc;
X--- 25,30 ----
X***************
X*** 72,77 ****
X--- 71,77 ----
X  void getargs()
X  {
X    int tmp;
X+   void maktbl();
X    for (i=1; i< argc && argv[i][0]=='-'; i++) {
X      switch (argv[i][1]) {
X      case 'e':
+ END-OF-FILE fgrep.c.cdif
chmod 'u=rw,g=r,o=r' 'fgrep.c.cdif'
set `wc -c 'fgrep.c.cdif'`
count=$1
case $count in
457)	:;;
*)	echo 'Bad character count in ''fgrep.c.cdif' >&2
		echo 'Count should be 457' >&2
esac
echo Extracting 'file.c.cdif'
sed 's/^X//' > 'file.c.cdif' << '+ END-OF-FILE ''file.c.cdif'
X*** /local/ast/minix/tape3b/commands/file.c	Wed Jul 13 13:10:55 1988
X--- file.c	Sun Sep 25 15:25:00 1988
X***************
X*** 28,33 ****
X--- 28,34 ----
X  char *name;
X  {
X    int i, fd, n, magic, second, mode, nonascii, special, funnypct, etaoins;
X+   int symbols;
X    long engpct;
X    char c;
X    struct stat st_buf;
X***************
X*** 86,97 ****
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! 	printf("executable ");
X  	second = (buf[3]<<8) | (buf[2]&0377);
X  	if (second == SPLIT)
X! 		printf(" separate I & D space\n");
X  	else
X! 		printf(" combined I & D space\n");
X  	close(fd);
X   	return;
X    }
X--- 87,103 ----
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! 	printf("executable");
X  	second = (buf[3]<<8) | (buf[2]&0377);
X  	if (second == SPLIT)
X! 		printf("   separate I & D space");
X  	else
X! 		printf("   combined I & D space");
X! 	symbols = buf[28] | buf[29] | buf[30] | buf[31];
X! 	if (symbols != 0)
X! 		printf("   not stripped\n");
X! 	else
X! 		printf("   stripped\n");
X  	close(fd);
X   	return;
X    }
+ END-OF-FILE file.c.cdif
chmod 'u=rw,g=r,o=r' 'file.c.cdif'
set `wc -c 'file.c.cdif'`
count=$1
case $count in
1189)	:;;
*)	echo 'Bad character count in ''file.c.cdif' >&2
		echo 'Count should be 1189' >&2
esac
echo Extracting 'getlf.c.cdif'
sed 's/^X//' > 'getlf.c.cdif' << '+ END-OF-FILE ''getlf.c.cdif'
X*** /local/ast/minix/tape3b/commands/getlf.c	Wed Jul 13 13:10:56 1988
X--- getlf.c	Sun Sep 25 15:25:01 1988
X***************
X*** 1,3 ****
X--- 1,5 ----
X+ /* getlf - get a line feed		Author: Andy Tanenbaum */
X+ 
X  main(argc, argv)
X  int argc;
X  char *argv[];
+ END-OF-FILE getlf.c.cdif
chmod 'u=rw,g=r,o=r' 'getlf.c.cdif'
set `wc -c 'getlf.c.cdif'`
count=$1
case $count in
255)	:;;
*)	echo 'Bad character count in ''getlf.c.cdif' >&2
		echo 'Count should be 255' >&2
esac
echo Extracting 'help.c.new'
sed 's/^X//' > 'help.c.new' << '+ END-OF-FILE ''help.c.new'
X/* help - provide assistance about keywords	Author: Wolf N. Paul */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#define MAXLINE    134
X#define HELPDIR    "/usr/lib"      /* Added by John Plocher */
X#define HELPFILE   "helpfile"      /* .. */
X#define INDEX      ".idx"          /* .. */
X
Xchar *helpfilename = "/usr/lib/helpfile";
Xchar *helpidxname  = "/usr/lib/helpfile.idx";
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X   struct
X   {
X       char name[15];
X       long offset;
X   } entry;                /* helpindex entries for each command */
X
X   struct stat sbuf1, sbuf2;   /* stat buffers for helpfile & helpindex */
X   char *command, *line, Line[MAXLINE];
X   register char   *cp;        /* John Plocher */
X   extern char *getenv();      /* .. */
X   int status;
X   FILE *ifp, *hfp;        /* file pointers for helpfile and helpindex */
X   
X   if (argc > 2) {
X	fprintf(stderr, "Usage: help subject\n");
X	exit(1);
X   }
X
X   if ( argc == 1 )        /* If no arguments, ... */
X       command = "help";   /* ... default to "help help" */
X   else
X       command = argv[1];  /* else look for command in argv[1] */
X
X   stat(helpfilename, &sbuf1); /* get mtime for helpfile */
X   status=access(helpidxname, 0);
X   if ( status == 0 )  /* if helpindex exists ... */
X   {
X       stat(helpidxname, &sbuf2);  /* get mtime for helpindex */
X   }
X   if ( (status != 0) ||           /* if there is no helpindex ... */
X       (sbuf1.st_mtime > sbuf2.st_mtime) )
X                                   /* or if it is older than helpfile */
X   {
X       buildindex();       /* build a new helpindex */
X   }
X
X   system("clr");		/* clear the screen */
X
X   if ( (ifp=fopen(helpidxname, "r")) == NULL )
X   {
X       fprintf(stderr, "Can't read %s\n", helpidxname);
X       exit(-1);
X   }
X   
X   while ( 1 )     /* look for index entry for "command" */
X   {
X       status=fread(&entry, sizeof(entry), 1, ifp);
X       if ( status==0 ) /* quit at end of index file */
X       {
X           fprintf(stderr, "No help for %s\n", command);
X           fclose(ifp);
X           exit(1);        }
X       if ( strcmp(entry.name, command) == 0 ) /* quit when we find it */
X       {
X           fclose(ifp);
X           break;
X       }
X   }
X
X   if ((hfp=fopen(helpfilename, "r")) == NULL )
X   {
X       fprintf(stderr, "Can't open %s\n", helpfilename);
X       exit(-1);
X   }
X
X   fseek(hfp, entry.offset, 0);    /* go to the help entry */
X
X   while ( 1 )         /* just copy lines to stdout */
X   {
X       line = fgets(Line, MAXLINE, hfp);
X       if ( line == (char *) NULL || line[0] == '#' )
X                       /* until another entry starts */
X           break;
X       fputs(line,stdout);
X   }
X
X   fclose(hfp);
X}
X
Xbuildindex()
X{
X   FILE *hfp, *ifp;
X   struct {
X       char name[15];
X       long offset;
X   } entry;
X   char Line[MAXLINE];
X   char *line;
X   int i,j;
X
X
X   unlink(helpidxname); /* remove old index file */
X   if ( (hfp=fopen(helpfilename, "r")) == NULL )
X   {
X       fprintf(stderr,"buildindex: Can't read %s\n", helpfilename);
X       exit(-1);
X   }
X   if ( (ifp=fopen(helpidxname, "w")) == NULL )
X   {
X       fprintf(stderr, "buildindex: Can't write %s\n", helpidxname);
X       exit(-1);
X   }
X
X   while (1)   /* Read thru helpfile ... */
X   {
X       entry.offset=(long) 0;
X       line = fgets(Line, MAXLINE, hfp);
X       if ( line == (char *) NULL ) break;
X       if ( line[0] == '#' )   /* and for each help entry ... */
X       {
X           line++;
X           while ( isspace(line[0]) ) line++;
X           i=j=0;
X           while ( line[i] != '\0' )
X           {
X               if ( line[i] == '\n' ) break;
X               while ( line[i] == ' ' || line[i] == ',' ) i++;
X               while ( !isspace(line[i] ) &&
X                       line[i] != ',') /* save its name ... */
X               {
X                   entry.name[j] = line[i];
X                   i++; j++;
X               }
X               while ( j < 15 )
X                   entry.name[j++] = '\0';
X               j = 0;
X               entry.offset=ftell(hfp);    /* and its offset ... */
X               fwrite(&entry, sizeof(entry), 1, ifp);
X                                       /* and write it to indexfile */
X           }
X       }
X   }
X   fclose(hfp);
X   fclose(ifp);
X}
+ END-OF-FILE help.c.new
chmod 'u=rw,g=r,o=r' 'help.c.new'
set `wc -c 'help.c.new'`
count=$1
case $count in
4249)	:;;
*)	echo 'Bad character count in ''help.c.new' >&2
		echo 'Count should be 4249' >&2
esac
echo Extracting 'libupack.c.cdif'
sed 's/^X//' > 'libupack.c.cdif' << '+ END-OF-FILE ''libupack.c.cdif'
X*** /local/ast/minix/tape3b/commands/libupack.c	Wed Jul 13 13:10:58 1988
X--- libupack.c	Sun Sep 25 15:25:03 1988
X***************
X*** 1,3 ****
X--- 1,5 ----
X+ /* libupack - unpack a packed .s file		Author: Andy Tanenbaum */
X+ 
X  char *table[] = {
X  "push ax",
X  "ret",
+ END-OF-FILE libupack.c.cdif
chmod 'u=rw,g=r,o=r' 'libupack.c.cdif'
set `wc -c 'libupack.c.cdif'`
count=$1
case $count in
267)	:;;
*)	echo 'Bad character count in ''libupack.c.cdif' >&2
		echo 'Count should be 267' >&2
esac
echo Extracting 'login.c'
sed 's/^X//' > 'login.c' << '+ END-OF-FILE ''login.c'
X/* login - log into the system		Author: Patrick van Kleef */
X
X/* Peter S. Housel   Jan. 1988
X *  - Set up $USER, $HOME and $TERM.
X *  - Set signals to SIG_DFL.
X *
X * Terrence W. Holm   June 1988
X *  - Allow a username as an optional argument.
X *  - Time out if a password is not typed within 30 seconds.
X *  - Perform a dummy delay after a bad username is entered.
X *  - Don't allow a login if "/etc/nologin" exists.
X *  - Cause a failure on bad "pw_shell" fields.
X *  - Record the login in "/usr/adm/wtmp".
X */
X
X#include <signal.h>
X#include <sgtty.h>
X#include <pwd.h>
X#include <sys/stat.h>
X
X#define  NULL   (char *) 0
X#define WTMPSIZE           8
X#define DIGIT 3
X
Xextern char *crypt();
Xextern struct passwd *getpwnam();
Xextern long time();
Xextern long lseek();
Xint Time_out();
X
Xint  time_out;
X
Xchar user[ 32 ];
Xchar logname[ 35 ];
Xchar home[ 64 ];
Xchar shell[ 64 ];
X
Xchar *env[] = {
X	      user,
X	      logname,
X	      home,
X	      shell,
X	      "TERM=minix",
X	      NULL
X};
Xchar wtmpfile[] = {"/usr/adm/wtmp"};
Xchar ttyname[] = {"tty?"};
X
X
Xmain( argc, argv ) 
Xint   argc;
Xchar *argv[];
X{
X	char    name[30];
X	char	password[30];
X	int     bad;
X	int	n;
X	int 	ttynr;
X	struct  sgttyb args;
X	struct  passwd *pwd;
X	struct stat statbuf;
X	char   *sh = "/bin/sh";
X
X	/* Reset some of the line parameters in case they have been mashed */
X	if ( ioctl(0, TIOCGETP, &args) < 0 ) exit( 1 );
X
X	args.sg_kill  = '@';
X	args.sg_erase = '\b';
X	args.sg_flags = (args.sg_flags & 01700) | XTABS | CRMOD | ECHO;
X	ioctl (0, TIOCSETP, &args);
X
X	/* Get login name and passwd. */
X	for (;;) {
X		bad = 0;
X
X		if ( argc > 1 ) {
X		    strcpy( name, argv[1] );
X		    argc = 1;
X		} else {
X		    do {
X			write(1,"login: ",7);
X			n = read (0, name, 30);
X		    } while (n < 2);
X		    name[n - 1] = 0;
X		}
X
X		/* Look up login/passwd. */
X		if ((pwd = getpwnam (name)) == 0) bad++;
X
X		/* If login name wrong or password exists, ask for pw. */
X		if (bad || strlen (pwd->pw_passwd) != 0) {
X			args.sg_flags &= ~ECHO;
X			ioctl (0, TIOCSETP, &args);
X			write(1,"Password: ",10);
X
X			time_out = 0;
X			signal( SIGALRM, Time_out );
X			alarm( 30 );
X
X			n = read (0, password, 30);
X
X			alarm( 0 );
X			if ( time_out ) {
X				n = 1;
X				bad++;
X			}
X
X			password[n - 1] = 0;
X			write(1,"\n",1);
X			args.sg_flags |= ECHO;
X			ioctl (0, TIOCSETP, &args);
X
X			if (bad && crypt(password, "aaaa") ||
X			 strcmp (pwd->pw_passwd, crypt(password, pwd->pw_passwd))) {
X				write (1,"Login incorrect\n",16);
X				continue;
X			}
X		}
X
X		/*  Check if the system is going down  */
X		if ( access( "/etc/nologin", 0 ) == 0  &&  
X						strcmp( name, "root" ) != 0 ) {
X			write( 1, "System going down\n\n", 19 );
X			continue;
X		}
X
X
X		/* Look up /dev/tty number. */
X		fstat(0, &statbuf);
X		ttynr = statbuf.st_rdev & 0377;
X		ttyname[DIGIT] = '0' + ttynr;
X
X		/*  Write login record to /usr/adm/wtmp  */
X		wtmp(ttyname, name);
X
X		setgid( pwd->pw_gid );
X		setuid( pwd->pw_uid );
X
X		if (pwd->pw_shell[0]) sh = pwd->pw_shell;
X
X		/*  Set the environment  */
X		strcpy( user,  "USER=" );
X		strcat( user,   name );
X		strcpy( logname, "LOGNAME=" );
X		strcat( logname, name );
X		strcpy( home,  "HOME=" );
X		strcat( home,  pwd->pw_dir );
X		strcpy( shell, "SHELL=" );
X		strcat( shell, sh );
X
X		chdir( pwd->pw_dir );
X
X		/* Reset signals to default values. */
X
X		for ( n = 1;  n <= NR_SIGS;  ++n )
X		    signal( n, SIG_DFL );
X
X		execle( sh, "-", NULL, env );
X		write(1,"exec failure\n",13);
X		exit(1);
X	}
X}
X
X
X
XTime_out( )
X{
X  time_out = 1;
X}
X
Xwtmp(tty, name)
X{
X/* Make an entry in /usr/adm/wtmp. */
X
X  int i, fd;
X  long t, time();
X  char ttybuff[WTMPSIZE], namebuff[WTMPSIZE];
X
X  fd = open(wtmpfile, 2);
X  if (fd < 0) return;		/* if wtmp does not exist, no accounting */
X  lseek(fd, 0L, 2);		/* append to file */
X
X  for (i = 0; i < WTMPSIZE; i++) {
X	ttybuff[i] = 0;
X	namebuff[i] = 0;
X  }
X  strncpy(ttybuff, tty, 8);
X  strncpy(namebuff, name, 8);
X  time(&t);
X  write(fd, ttybuff, WTMPSIZE);
X  write(fd, namebuff, WTMPSIZE);
X  write(fd, &t, sizeof(t));
X  close(fd);
X}
+ END-OF-FILE login.c
chmod 'u=rw,g=r,o=r' 'login.c'
set `wc -c 'login.c'`
count=$1
case $count in
3973)	:;;
*)	echo 'Bad character count in ''login.c' >&2
		echo 'Count should be 3973' >&2
esac
echo Extracting 'ls.c.cdif'
sed 's/^X//' > 'ls.c.cdif' << '+ END-OF-FILE ''ls.c.cdif'
X*** /local/ast/minix/tape3b/commands/ls.c	Wed Jul 13 13:11:02 1988
X--- ls.c	Sun Sep 25 15:25:05 1988
X***************
X*** 1,4 ****
X--- 1,5 ----
X  /* ls - list files and directories 	Author: Andy Tanenbaum */
X+ /* Version: Minix 1.3 */
X  
X  #include <stdio.h>
X  #include <sys/types.h>
X***************
X*** 23,28 ****
X--- 24,30 ----
X    long modtime;
X    long size;
X    short link;
X+   char is_path;			/* 1 => fp_name is null terminated */
X  } file[NFILE+1];
X  
X  struct dir {
X***************
X*** 99,105 ****
X    statflag = (topfiles == 0 ? 0 : 1);
X    if (present('c') || present('t') || present('u')) statflag = 1;
X    if (present('s') || present('l')) statflag = 1;
X!   while (k < argc) fill_file("", argv[k++], statflag);
X  }
X  
X  
X--- 101,107 ----
X    statflag = (topfiles == 0 ? 0 : 1);
X    if (present('c') || present('t') || present('u')) statflag = 1;
X    if (present('s') || present('l')) statflag = 1;
X!   while (k < argc) fill_file("", argv[k++], statflag,1);
X  }
X  
X  
X***************
X*** 212,218 ****
X  	fp = &file[sort_index[k]];
X  	if (present('l') || present('s') || present('i'))
X  		if (fp->size == -1L)	/* -1 means stat not done */
X! 			if (stat_file(dirname, fp) < 0) continue;
X  
X  	m = fp->mode & I_TYPE;	/* 'm' may be junk if 'expand' = 0 */
X  	if (present('f')) m = I_DIRECTORY;
X--- 214,220 ----
X  	fp = &file[sort_index[k]];
X  	if (present('l') || present('s') || present('i'))
X  		if (fp->size == -1L)	/* -1 means stat not done */
X! 			if (stat_file(dirname, fp, fp->is_path) < 0) continue;
X  
X  	m = fp->mode & I_TYPE;	/* 'm' may be junk if 'expand' = 0 */
X  	if (present('f')) m = I_DIRECTORY;
X***************
X*** 223,229 ****
X  		/* Expand and print directory. */
X  		exp_dir(fp);
X  		sort(nrf, nrfiles - nrf, 0);
X! 		if (topfiles > 1) fprintf(stdout, "\n%s:\n", fp->name);
X  		print_total(nrf, nrfiles - nrf);
X  		print(nrf, nrfiles - nrf, 0, fp->name);	/* recursion ! */
X  		nrfiles = nrf;
X--- 225,235 ----
X  		/* Expand and print directory. */
X  		exp_dir(fp);
X  		sort(nrf, nrfiles - nrf, 0);
X! 		if (topfiles > 1) {
X! 			fprintf(stdout, "\n");
X! 			pfname(fp->name,fp->is_path);
X! 			fprintf(stdout, ":\n");
X! 		}
X  		print_total(nrf, nrfiles - nrf);
X  		print(nrf, nrfiles - nrf, 0, fp->name);	/* recursion ! */
X  		nrfiles = nrf;
X***************
X*** 270,276 ****
X  			if (*p == '.' && *(p+1) == 0) continue;
X  			if (*p == '.' && *(p+1) == '.' && *(p+2) == 0) continue;
X  		}
X! 		fill_file(fp->name, p, statflag);
X  	}
X    }
X    close(fd);
X--- 276,282 ----
X  			if (*p == '.' && *(p+1) == 0) continue;
X  			if (*p == '.' && *(p+1) == '.' && *(p+2) == 0) continue;
X  		}
X! 		fill_file(fp->name, p, statflag,0);
X  	}
X    }
X    close(fd);
X***************
X*** 280,288 ****
X  
X  
X  
X! fill_file(prefix, postfix, statflag)
X  char *prefix, *postfix;
X! int statflag;
X  {
X  /* Fill the next 'file' struct entry with the file whose name is formed by
X   * concatenating 'prefix' and 'postfix'.  Stat only if needed.
X--- 286,294 ----
X  
X  
X  
X! fill_file(prefix, postfix, statflag, pathflag)
X  char *prefix, *postfix;
X! int statflag, pathflag;
X  {
X  /* Fill the next 'file' struct entry with the file whose name is formed by
X   * concatenating 'prefix' and 'postfix'.  Stat only if needed.
X***************
X*** 297,304 ****
X    }
X    fp = &file[nrfiles++];
X    fp->name = postfix;
X    if(statflag) {
X! 	if (stat_file(prefix, fp) < 0) nrfiles--;
X    } else {
X  	fp->size = -1L;		/* mark file as not yet stat'ed */
X    }
X--- 303,311 ----
X    }
X    fp = &file[nrfiles++];
X    fp->name = postfix;
X+   fp->is_path = pathflag;
X    if(statflag) {
X! 	if (stat_file(prefix, fp, pathflag) < 0) nrfiles--;
X    } else {
X  	fp->size = -1L;		/* mark file as not yet stat'ed */
X    }
X***************
X*** 308,315 ****
X  
X  
X  
X! print_line(fp)
X  struct file *fp;
X  {
X    int blks, m, prot, s;
X    char *p1, *p2, *p3, c;
X--- 315,323 ----
X  
X  
X  
X! print_line(fp,is_path)
X  struct file *fp;
X+ int  is_path;
X  {
X    int blks, m, prot, s;
X    char *p1, *p2, *p3, c;
X***************
X*** 358,376 ****
X  
X  	/* Print file name. */
X  	m = 0;
X! 	p1 = fp->name;
X! 	while (*p1 != 0 && (m < DIRNAMELEN || *p1 == '/') ) {
X! 		fprintf(stdout, "%c", *p1);
X! 		m = (*p1 == '/' ? 0 : m + 1);
X! 		p1++;
X! 	}
X  	fprintf(stdout, "\n");
X  }
X  
X  
X  
X  
X- 
X  owngrp(fp)
X  struct file *fp;
X  {
X--- 366,394 ----
X  
X  	/* Print file name. */
X  	m = 0;
X! 	pfname(fp->name,fp->is_path);
X  	fprintf(stdout, "\n");
X  }
X  
X+ pfname(ptr,pathflag)
X+ char *ptr;
X+ int  pathflag;
X+ {
X+ 	int  m;
X+ 	if (pathflag) {
X+ 		fprintf(stdout,"%s",ptr);
X+ 	} else {
X+ 		/* dirname entry is null terminated if length < 14 */
X+ 		m = 0;
X+ 		while (*ptr && m < DIRNAMELEN) {
X+ 			putc(*ptr++, stdout);
X+ 			++m;
X+ 		}
X+ 	}
X+ }
X  
X  
X  
X  owngrp(fp)
X  struct file *fp;
X  {
X***************
X*** 393,405 ****
X  
X  
X  
X! int stat_file(prefix, fp)
X  char *prefix;
X  struct file *fp;
X  {
X  /* Stat a file and enter it in 'file'. */
X  
X!   char namebuf[MAXPATHLEN], *p, *org, *q;
X    struct stat sbuf;
X    int m, ctr;
X  
X--- 411,424 ----
X  
X  
X  
X! int stat_file(prefix, fp, pathflag)
X  char *prefix;
X  struct file *fp;
X+ int pathflag;
X  {
X  /* Stat a file and enter it in 'file'. */
X  
X!   char namebuf[MAXPATHLEN], *p, *q;
X    struct stat sbuf;
X    int m, ctr;
X  
X***************
X*** 408,421 ****
X    q = prefix;
X    while (*q != 0 && p - namebuf < MAXPATHLEN) *p++ = *q++;
X    if (*prefix != 0) *p++ = '/';
X-   org = fp->name;
X    q = fp->name;
X    ctr = 0;
X!   while (*q != 0 && p - namebuf < MAXPATHLEN) {
X! 	ctr++;
X! 	if (*q == '/') ctr = 0;
X! 	if (ctr > DIRNAMELEN) break;
X! 	*p++ = *q++;
X    }
X    *p = 0;
X  
X--- 427,445 ----
X    q = prefix;
X    while (*q != 0 && p - namebuf < MAXPATHLEN) *p++ = *q++;
X    if (*prefix != 0) *p++ = '/';
X    q = fp->name;
X    ctr = 0;
X! 
X!   if (pathflag) {
X! 	/* fp->name is null terminated */
X! 	while (*q) *p++ = *q++;
X!   } else {
X! 	/* fp->name is char[14] */
X! 	while (*q != 0 && p - namebuf < MAXPATHLEN) {
X! 		ctr++;
X! 		if (ctr > DIRNAMELEN) break;
X! 		*p++ = *q++;
X! 	}
X    }
X    *p = 0;
X  
+ END-OF-FILE ls.c.cdif
chmod 'u=rw,g=r,o=r' 'ls.c.cdif'
set `wc -c 'ls.c.cdif'`
count=$1
case $count in
5992)	:;;
*)	echo 'Bad character count in ''ls.c.cdif' >&2
		echo 'Count should be 5992' >&2
esac
exit 0