[comp.os.minix] Turbo C diff's for Minix 1.2; here they are ! Part 8 of 9

evas@euraiv1.UUCP (Eelco van Asperen) (10/02/87)

Here is part 8 of 9:						Eelco van Asperen.

# This is a shar archive.  Extract with sh, not csh.
# This archive ends with exit, so do not worry about trailing junk.
# --------------------------- cut here --------------------------
echo Extracting commands/kill.dif
sed 's/^X//' > commands/kill.dif << '+ END-OF-FILE 'commands/kill.dif
X33,35c33,35
X<   prints("usage: kill pid\n");
X<   exit(1);
X< }
X---
X>   prints("Usage: kill pid\n");
X>   exit(1);
X> }
+ END-OF-FILE commands/kill.dif
chmod u=rw,g=r,o=r commands/kill.dif
set `sum commands/kill.dif`
sum=$1
case $sum in
8072)	:;;
*)	echo 'Bad sum in 'commands/kill.dif >&2
esac
echo Extracting commands/ln.dif
sed 's/^X//' > commands/ln.dif << '+ END-OF-FILE 'commands/ln.dif
X11a12,13
X>   char *last_comp();
X>   char *last_comp(char *);
+ END-OF-FILE commands/ln.dif
chmod u=rw,g=r,o=r commands/ln.dif
set `sum commands/ln.dif`
sum=$1
case $sum in
4452)	:;;
*)	echo 'Bad sum in 'commands/ln.dif >&2
esac
echo Extracting commands/login.c
sed 's/^X//' > commands/login.c << '+ END-OF-FILE 'commands/login.c
X/* login - log into the system		Author: Patrick van Kleef */
X
X#include "signal.h"
X#include "sgtty.h"
X#include "pwd.h"
X
Xmain() 
X{
X	char    buf[30],
X		buf1[30],
X	       *crypt();
X	int     n, n1, bad;
X	struct sgttyb args;
X	struct passwd *pwd, *getpwnam();
X
X	args.sg_kill = '@';
X	args.sg_erase = '\b';
X	args.sg_flags = 06030;
X	ioctl (0, TIOCSETP, &args);
X
X
X	/* Get login name and passwd. */
X	for (;;) {
X		bad = 0;
X		do {
X			write(1,"login: ",7);
X			n = read (0, buf, 30);
X		} while (n < 2);
X		buf[n - 1] = 0;
X
X		/* Look up login/passwd. */
X		if ((pwd = getpwnam (buf)) == 0)
X			bad++;
X
X		if (bad || strlen (pwd->pw_passwd) != 0) {
X			args.sg_flags = 06020;
X			ioctl (0, TIOCSETP, &args);
X			write(1,"Password: ",10);
X			n1 = read (0, buf1, 30);
X			buf1[n1 - 1] = 0;
X			write(1,"\n",1);
X			args.sg_flags = 06030;
X			ioctl (0, TIOCSETP, &args);
X			if (bad || strcmp (pwd->pw_passwd, crypt(buf1, pwd->pw_passwd))) {
X				write (1,"Login incorrect\n",16);
X				continue;
X			}
X		}
X
X		/* Successful login. */
X		setgid (pwd->pw_gid);
X		setuid (pwd->pw_uid);
X		chdir (pwd->pw_dir);
X		if (pwd->pw_shell) {
X			execl(pwd->pw_shell, "-", (char *) 0);
X		}
X		execl("/bin/sh", "-", (char *) 0);
X		write(1,"exec failure\n",13);
X	}
X}
+ END-OF-FILE commands/login.c
chmod u=rw,g=r,o=r commands/login.c
set `sum commands/login.c`
sum=$1
case $sum in
20364)	:;;
*)	echo 'Bad sum in 'commands/login.c >&2
esac
echo Extracting commands/ls.dif
sed 's/^X//' > commands/ls.dif << '+ END-OF-FILE 'commands/ls.dif
X359c359,366
X< 	fprintf(stdout, "%s\n",fp->name);
X---
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");
+ END-OF-FILE commands/ls.dif
chmod u=rw,g=r,o=r commands/ls.dif
set `sum commands/ls.dif`
sum=$1
case $sum in
15300)	:;;
*)	echo 'Bad sum in 'commands/ls.dif >&2
esac
echo Extracting commands/make.dif
sed 's/^X//' > commands/make.dif << '+ END-OF-FILE 'commands/make.dif
X153c153
X< /* sysV and MONIX  and LATTICE */
X---
X> /* sysV and MINIX  and LATTICE */
X1899c1899
X< 	execl(SHELL,"sh","-c",cmd,0);
X---
X> 	execl(SHELL, "sh", "-c", cmd, (char *) 0);
+ END-OF-FILE commands/make.dif
chmod u=rw,g=r,o=r commands/make.dif
set `sum commands/make.dif`
sum=$1
case $sum in
11289)	:;;
*)	echo 'Bad sum in 'commands/make.dif >&2
esac
echo Extracting commands/makefile
sed 's/^X//' > commands/makefile << '+ END-OF-FILE 'commands/makefile
XCC=tcc
XCCOPTS=-A -mt -I..\include -Di8088 -DTURBO -G -O -c
XLN=tlink /x/n/c/d		#replace /x by /s to generate a map-file
XMXLN=$(LN) ..\mlib\crtso
X
X.c.obj:
X	$(CC) $(CCOPTS) $<
X
X.obj.out:
X	$(MXLN) $*,$*,$*,..\mlib\minix
X	dos2out -d $*
X
X.c.out:
X	$(CC) $(CCOPTS) $<
X	$(MXLN) $*,$*,$*,..\mlib\minix
X	dos2out -d $*
X
X#
X# readfs is a special case; it's wants a different path for it's include files.
X#
Xreadfs.out:	readfs.obj
X
Xreadfs.obj:	readfs.c
X	$(CC) -I.. $(CCOPTS) $*
X
X#
X#  All Commands;
X#
Xall:	AR.out BASENAME.out cal.out CAT.out CC.out CHMEM.out \
X	CHMOD.out CHOWN.out CLR.out CMP.out COMM.out \
X	CP.out cpdir.out DATE.out DD.out DF.out diff.out DOSREAD.out \
X	ECHO.out find.out fix.out fdisk.out GETLF.out GREP.out GRES.out \
X	HEAD.out KILL.out LIBPACK.out LIBUPACK.out LN.out login.out LPR.out \
X	LS.out MAKE.out mined.out MKDIR.out \
X	MKFS.out MKNOD.out more.out MOUNT.out MV.out OD.out  \
X	PASSWD.out PR.out printenv.out PWD.out readfs.out \
X	REV.out RM.out RMDIR.out ROFF.out \
X	SHAR.out SIZE.out SLEEP.out \
X	SORT.out SPLIT.out STTY.out SU.out SUM.out \
X	SYNC.out TAIL.out TAR.out TEE.out test.out TIME.out \
X	TOUCH.out TR.out UMOUNT.out UNIQ.out UPDATE.out \
X	WC.out sh.out changemem
X
X#
X#  MINED
X#
Xmined.out:	mined\mined1.obj mined\mined2.obj
X	$(MXLN) mined\mined1 mined\mined2,mined,mined,..\mlib\minix
X	dos2out -d mined
X
Xmined\mined1.obj mined\mined2.obj:	mined\mined.h
X	$(CC) $(CCOPTS) -nmined $*
X
X#
X#  SH
X#
Xsh.out:	sh\sh1.obj sh\sh2.obj sh\sh3.obj sh\sh4.obj sh\sh5.obj sh\sh6.obj
X	$(LN) ..\mlib\crtso sh\sh1 sh\sh2 sh\sh3 sh\sh4 sh\sh5 sh\sh6,sh,sh,..\mlib\minix
X	dos2out -d sh
X
X#
X# sh uses setjmp() so we can't use register var's with Turbo C;
X# the -r- option forces Turbo to ignore any register declarations
X#
Xsh\sh1.obj sh\sh2.obj sh\sh3.obj sh\sh4.obj sh\sh5.obj sh\sh6.obj:	sh\sh.h
X	$(CC) $(CCOPTS) -r- -nsh $*
X
Xchangemem:	cc.out cpdir.out dd.out diff.out df.out dosread.out find.out \
X	fix.out grep.out gres.out libpack.out libupack.out make.out mined.out \
X	mkdir.out mkfs.out mv.out pr.out readfs.out rm.out rmdir.out \
X	sh.out sort.out tail.out time.out
X	chmem =2000  cc.out
X	chmem =32000 cpdir.out
X	chmem =40000 dd.out
X	chmem =50000 diff.out
X	chmem =8000  df.out
X	chmem =32000 dosread.out
X	chmem =50000 find.out
X	chmem =50000 fix.out
X	chmem =8000  grep.out
X	chmem =8000  gres.out
X	chmem =64000 libpack.out
X	chmem =64000 libupack.out
X	chmem =20000 make.out
X	chmem =64000 mined.out
X	chmem =8000  mkdir.out
X	chmem =16000 mkfs.out
X	chmem =8000  mv.out
X	chmem =8000  pr.out
X	chmem =50000 readfs.out
X	chmem =8000  rm.out
X	chmem =8000  rmdir.out
X	chmem =8000  sh.out
X	chmem =30000 sort.out
X	chmem =2000  tail.out
X	chmem =2000  time.out
X
Xclean:
X	- del *.obj
X	- del *.map
X	- del *.lst
X
Xfast:	*.c
X	$(CC) $(CCOPTS) *.c
X
+ END-OF-FILE commands/makefile
chmod u=rw,g=r,o=r commands/makefile
set `sum commands/makefile`
sum=$1
case $sum in
18493)	:;;
*)	echo 'Bad sum in 'commands/makefile >&2
esac
if test -f commands/mined
then	echo Removing   commands/mined
	rm commands/mined
fi
if test -d commands/mined
then	:
else	echo Creating   commands/mined
	mkdir commands/mined
fi
echo Extracting commands/mined/mined1.dif
sed 's/^X//' > commands/mined/mined1.dif << '+ END-OF-FILE 'commands/mined/mined1.dif
X533c533
X<   		execl("/bin/sh", "sh", "-i", 0);
X---
X>   		execl("/bin/sh", "sh", "-i", (char *) 0);
+ END-OF-FILE commands/mined/mined1.dif
chmod u=rw,g=r,o=r commands/mined/mined1.dif
set `sum commands/mined/mined1.dif`
sum=$1
case $sum in
5823)	:;;
*)	echo 'Bad sum in 'commands/mined/mined1.dif >&2
esac
echo Extracting commands/mkfs.dif
sed 's/^X//' > commands/mkfs.dif << '+ END-OF-FILE 'commands/mkfs.dif
X5c5
X<  *	with blocksize = zonesize. During the course of action the
X---
X>  *	with blocksize = zonesize. During the course of time the
X10,12c10,12
X<  *	To compile this program for MS-DOS, say cc -DDOS mkfs.c diskio.asm
X<  *	To compile this program for UNIX, say cc -DUNIX mkfs.c
X<  *	To compile this program for MINIX, say cc mkfs.c
X---
X>  *	To compile this program for MS-DOS, use: cc -DDOS mkfs.c diskio.asm
X>  *	To compile this program for UNIX,   use: cc -DUNIX mkfs.c
X>  *	To compile this program for MINIX,  use: cc mkfs.c
X25c25,34
X< #include "/lib/c86/stdio.h"
X---
X> # ifdef TURBO
X> #  undef printf		/* defined as printk in ../fs/const.h ! */
X> #  include <stdio.h>
X> #  include <fcntl.h>
X> #  include <sys/stat.h>
X> # else
X> #  include "/lib/c86/stdio.h"
X> # endif
X> #undef major
X> #undef minor
X55d63
X< #define ZONE_MAP             3
X61,65c69,78
X< #define N_BLOCKS       32000		/* must be multiple of 8 */
X< 
X< #ifdef DOS
X< #  define BREAD		     4
X< #  define BWRITE	     5
X---
X> #define N_BLOCKS         32000		/* must be multiple of 8 */
X> 
X> #ifdef DOS
X> # ifdef TURBO
X> #  define BREAD		     O_RDONLY|O_BINARY
X> #  define BWRITE	     S_IREAD|S_IWRITE
X> # else
X> #  define BREAD		     4
X> #  define BWRITE	     5
X> # endif
X73,77c86,91
X<     nrinodes, lct=1, disk, fd, print=0, file=0, override=0, simple=0;
X< 
X< long current_time;
X< char zero[BLOCK_SIZE], *lastp;
X< char umap[(N_BLOCKS+8)/8];	/* bit map tells if block read yet */
X---
X>     nrinodes, lct=1, disk, fd, print=0, file=0, override=0, simple=0, dflag;
X> 
X> long current_time, bin_time;
X> char zero[BLOCK_SIZE], *lastp;
X> char umap[(N_BLOCKS+8)/8];	/* bit map tells if block read yet */
X> int zone_map = 3;		/* where is zone map? (depends on # inodes) */
X90d103
X< 
X106,108c119,130
X<   /* process parameters and switches */
X< 
X<   current_time = time(0L);
X---
X> 
X>   /* Get two times, the current time and the mod time of the binary of
X>    * mkfs itself.  When the -d flag is used, the later time is put into
X>    * the i_modtimes of all the files.  This feature is useful when producing
X>    * a set of file systems, and one wants all the times to be identical.
X>    * First you set the time of the mkfs binary to what you want, then go.
X>    */
X>   current_time = time(0L);	/* time mkfs is being run */
X>   stat(argv[0], &statbuf);
X>   bin_time = statbuf.st_mtime;	/* time when mkfs binary was last modified */
X> 
X>   /* process parameters and switches */
X128c150,151
X< 		  default :
X---
X> 		    case 'd' : current_time = bin_time; dflag=1; break;
X> 		    default  :
X225,226c248,249
X< 
X<   int i, inodeblks, initblks, initzones, nrzones;
X---
X>   unsigned int i, inodeblks, initblks, initzones, nrzones, bs;
X>   unsigned int map_size, bit_map_len, b_needed, b_allocated, residual;
X230,236c253,260
X< 
X<   sup= (struct super_block *) buf;
X< 
X<   sup->s_ninodes 	= inodes;
X<   sup->s_nzones 	= zones;
X<   sup->s_imap_blocks 	= (inodes + (1<<BIT_MAP_SHIFT)-1) >> BIT_MAP_SHIFT;
X<   sup->s_zmap_blocks 	= (zones + (1<<BIT_MAP_SHIFT)-1) >> BIT_MAP_SHIFT;
X---
X>  
X>   sup= (struct super_block *) buf;
X> 
X>   bs			= 1 << BIT_MAP_SHIFT;
X>   sup->s_ninodes 	= inodes;
X>   sup->s_nzones 	= zones;
X>   sup->s_imap_blocks 	= (inodes + bs)/bs;
X>   sup->s_zmap_blocks 	= (zones + bs - 1)/bs;
X261,266c285,324
X<   insert_bit(ZONE_MAP, 0, 1);	/* bit zero must always be allocated */
X<   insert_bit(INODE_MAP, 0, 1);	/* inode zero used by root-directory */
X< 
X<   /* Mark all bits beyond the end of the legal inodes/zones as allocated. */
X<   insert_bit(ZONE_MAP,nrzones-initzones+1, 8*BLOCK_SIZE-(nrzones-initzones+1));
X<   insert_bit(INODE_MAP, inodes+1, 8*BLOCK_SIZE - inodes - 1);
X---
X> 
X>  /* Mark all bits beyond the end of the legal inodes and zones as allocated.
X>   * Unfortunately, the coding the bit maps is inconsistent.  The rules are:
X>   *    For inodes:	Every i-node occupies a bit map slot, even i-node 0
X>   *			The first i-node on the disk is i-node 1, not 0
X>   *    For zones:	Zone map bit 0 is for the last i-node block on disk
X>   *			The first zone available goes with bit 1 in the map
X>   *
X>   * Thus for i-nodes, every i-node, starting at 0 occupies a bit map slot,
X>   * but for zones, only those starting with the final i-node block occupy
X>   * bit slots.  This is inconsistent.  In retrospect it would might have been
X>   * simpler to have bit 0 of the zone map be zone 0 on the disk.  Although
X>   * this would have increased the zone bit map by a few dozen bits, it would
X>   * have prevented a number of bugs in the early days.  This is an example of
X>   * what happens when one ignores the maxim:  First make it work, then make
X>   * it optimal.  For both maps, 0 = available, 1 = in use.
X>   */
X> 
X>   /* Mark bits beyond end of inodes as allocated.  (Fails if >8192 inodes). */
X>   map_size = 1 << BIT_MAP_SHIFT;
X>   bit_map_len = nrinodes + 1;	/* # bits needed in map */
X>   residual = bit_map_len % (8 * BLOCK_SIZE);
X>   if (residual == 0) residual = 8 * BLOCK_SIZE;
X>   b_needed = (bit_map_len + map_size - 1 ) >> BIT_MAP_SHIFT;
X>   zone_map += b_needed - 1;	/* if imap > 1, adjust start of zone map */
X>   insert_bit(INODE_MAP + b_needed - 1, residual, 8 * BLOCK_SIZE - residual);
X> 
X>   bit_map_len = nrzones - initzones + 1;	/* # bits needed in map */
X>   residual = bit_map_len % (8 * BLOCK_SIZE);
X>   if (residual == 0) residual = 8 * BLOCK_SIZE;
X>   b_needed = (bit_map_len + map_size - 1 ) >> BIT_MAP_SHIFT;
X>   b_allocated = (nrzones + map_size - 1 ) >> BIT_MAP_SHIFT;
X>   insert_bit(zone_map + b_needed - 1, residual, 8 * BLOCK_SIZE - residual);
X>   if (b_needed != b_allocated)  {
X> 	insert_bit(zone_map + b_allocated - 1, 0, map_size);
X>   }
X> 
X>   insert_bit(zone_map, 0, 1);	/* bit zero must always be allocated */
X>   insert_bit(INODE_MAP, 0, 1);	/* inode zero not used but must be allocated */
X> 
X365a424
X>   long timeval;
X375c434,435
X<      if (ct) add_zone (inode, z, (long) j, file_time(f) );
X---
X>      timeval = (dflag ? current_time : file_time(f) );
X>      if (ct) add_zone (inode, z, (long) j, timeval );
X448c508,509
X<   int b, off, blk[INTS_PER_BLOCK], indir, i;
X---
X>   int b, off, indir, i;
X>   zone_nr blk[NR_INDIRECTS];
X472,474c533,535
X<   for (i = 0; i < INTS_PER_BLOCK; i++)
X< 	if (blk[i] == 0) {
X< 		blk[i] = z;
X---
X>   for (i = 0; i < NR_INDIRECTS; i++)
X> 	if (blk[i] == 0) {
X> 		blk[i] = (zone_nr) z;
X546d606
X< 
X559c619
X<   insert_bit(ZONE_MAP, z - zoff, 1);
X---
X>   insert_bit(zone_map, z - zoff, 1);
X571c631
X<   char buf[BLOCK_SIZE];
X---
X>   int buf[BLOCK_SIZE/sizeof(int)];
X575,576c635,636
X< 	w = i/8;
X< 	s = i % 8;
X---
X> 	w = i / (8*sizeof(int));
X> 	s = i % (8*sizeof(int));
X622c682
X<   for (k = 0; k < MAX_TOKEN; k++) parse[k] = 0;
X---
X>   for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0;
X664a725,727
X> 	/* with Turbo C, we could use getftime() and difftime() to
X> 	* compute the time in seconds from 1/1/1970.
X> 	*/
X678c741
X<   write (2, s, s0-s );
X---
X>   write (2, s, (int)(s0-s) );
X734c797
X< 			if (dir[j].inum) 
X---
X> 			if (dir[j].inum)
X777c840
X<  *	frequently used blocks.
X---
X>  *	frequently used blocks. (for Turbo C, we use the library routines)
X829,831c892,894
X<       if ((fd=creat(string,BWRITE)) == 0)
X< 	 pexit ("Can't open special file");
X<       } 
X---
X>       if ((fd = creat(string,BWRITE)) == 0)
X> 	 pexit ("Can't open special file");
X>       }
X967c1030,1034
X< 	  err=absread (disk,sectnum,bp);
X---
X> #ifdef TURBO
X> 	  err=absread (disk,1,sectnum,bp);
X> #else
X> 	  err=absread (disk,sectnum,bp);
X> #endif
X1000c1067,1071
X< 	err=abswrite (disk,sectnum,bp);
X---
X> #ifdef TURBO
X> 	err=abswrite (disk,1,sectnum,bp);
X> #else
X> 	err=abswrite (disk,sectnum,bp);
X> #endif
+ END-OF-FILE commands/mkfs.dif
chmod u=rw,g=r,o=r commands/mkfs.dif
set `sum commands/mkfs.dif`
sum=$1
case $sum in
55507)	:;;
*)	echo 'Bad sum in 'commands/mkfs.dif >&2
esac
echo Extracting commands/more.c
sed 's/^X//' > commands/more.c << '+ END-OF-FILE 'commands/more.c
X/* more - terminal pager		Author: Brandon S. Allbery  */
X
X/* Pager commands:
X *	<space>	 display next page
X *	<return> scroll up 1 line
X *	q	 quit
X*/
X
X#define reverse()	write(1, "\033z\160", 3)	/* reverse video */
X#define normal()	write(1, "\033z\7", 3)		/* undo reverse() */
X#define clearln()	write(1, "\r\033~0", 4)		/* clear line */
X
X#define LINES		23	/* lines/screen (- 1 to retain last line) */
X#define COLS		80	/* columns/line */
X#define TABSTOP		8	/* tabstop expansion */
X
X#include <sgtty.h>
X#include <signal.h>
X
Xextern int byebye();
Xextern char *index();
X
Xint line = 0;			/* current terminal line */
Xint col = 0;			/* current terminal column */
Xint fd = -1;			/* terminal file descriptor (/dev/tty) */
Xstruct sgttyb ttymode;		/* and the terminal modes */
Xchar ibuf[1024];		/* input buffer */
Xchar obuf[1024];		/* output buffer */
Xint ibl = 0;			/* chars in input buffer */
Xint ibc = 0;			/* position in input buffer */
Xint obc = 0;			/* position in output buffer (== chars in) */
Xint isrewind = 0;		/* flag: ' command -- next input() rewind */
Xint isdone = 0;			/* flag: return EOF next read even if not */
X
Xmain(argc, argv)
Xchar **argv; {
X	char ch;
X	int fd, arg;
X
X	signal(SIGINT, byebye);
X	fd = 0;
X	cbreak();
X	if (argc < 2)
X		while ((ch = input(fd)) != 0)
X			output(ch);
X	else
X		for (arg = 1; argv[arg] != (char *) 0; arg++) {
X			if ((fd = open(argv[arg], 0)) == -1) {
X				write(1, "more: cannot open ", 18);
X				write(1, argv[arg], strlen(argv[arg]));
X				write(1, "\n", 1);
X				nocbreak();
X				exit(1);
X			}
X			while ((ch = input(fd)) != 0)
X				output(ch);
X			close(fd);
X			if (argv[arg + 1] != (char *) 0) {
X				oflush();
X				if (isdone) {	/* 'n' command */
X					reverse();
X					write(1, "*** Skipping to next file ***\n", 30);
X					normal();
X					isdone = 0;
X				}
X				reverse();
X				write(1, "--More-- (Next file: ", 21);
X				write(1, argv[arg + 1], strlen(argv[arg + 1]));
X				write(1, ")", 1);
X				normal();
X				switch (wtch()) {
X				case ' ':
X				case '\'':
X				case 'n':
X				case 'N':
X					line = 0;
X					break;
X				case '\r':
X				case '\n':
X					line = LINES - 1;
X					break;
X				case 'q':
X				case 'Q':
X					clearln();
X					byebye();
X				}
X				clearln();
X			}
X		}
X	oflush();
X	byebye();
X}
X
Xinput(fd) {
X	if (isdone) {
X		ibl = 0;
X		ibc = 0;
X		return 0;
X	}
X	if (isrewind) {
X		lseek(fd, 0L, 0);
X		ibl = 0;
X		ibc = 0;
X		isrewind = 0;
X	}
X	if (ibc == ibl) {
X		ibc = 0;
X		if ((ibl = read(fd, ibuf, sizeof ibuf)) <= 0)
X			return 0;
X	}
X	return ibuf[ibc++];
X}
X
Xoutput(c)
Xchar c; {
X	if (obc == sizeof obuf) {
X		lwrite(1, obuf, sizeof obuf);
X		obc = 0;
X	}
X	if (!isrewind)
X		obuf[obc++] = c;
X}
X
Xoflush() {
X	if (!isdone)
X		lwrite(1, obuf, obc);
X	obc = 0;
X}
X
Xlwrite(fd, buf, len)
Xchar *buf;
Xunsigned len; {
X	unsigned here, start;
X	char cmd;
X
X	start = 0;
X	here = 0;
X	while (here != len) {
X		cmd = '\0';
X		switch (buf[here++]) {
X		case '\n':
X			col = 0;
X			if (++line == LINES) {
X				write(fd, buf + start, here - start);
X				reverse();
X				write(1, "--More--", 8);
X				normal();
X				cmd = wtch();
X				clearln();
X				line = 0;
X				start = here;
X			}
X			break;
X		case '\r':
X			col = 0;
X			break;
X		case '\b':
X			if (col != 0)
X				col--;
X			else {
X				line--;
X				col = COLS - 1;
X			}
X			break;
X		case '\t':
X			do {
X				col++;
X			} while (col % TABSTOP != 0);
X			break;
X		default:
X			if (++col == COLS) {
X				col = 0;
X				if (++line == LINES) {
X					write(fd, buf + start, here - start);
X					reverse();
X					write(1, "--More--", 8);
X					normal();
X					cmd = wtch();
X					clearln();
X					line = 0;
X					start = here;
X				}
X			}
X		}
X		switch (cmd) {
X		case '\0':
X			break;
X		case ' ':
X			line = 0;
X			break;
X		case '\r':
X		case '\n':
X			line = LINES - 1;
X			break;
X		case 'q':
X		case 'Q':
X			byebye();
X		case '\'':
X			isrewind = 1;
X			reverse();
X			write(1, "*** Back ***\n", 13);
X			normal();
X			return;
X		case 'n':
X		case 'N':
X			isdone = 1;
X			return;
X		default:
X			break;
X		}
X	}
X	if (here != start)
X		write(fd, buf + start, here - start);
X}
X
Xwtch() {
X	char ch;
X
X	do {
X		read(fd, &ch, 1);
X	} while (index(" \r\nqQ'nN", ch) == (char *) 0);
X	return ch;
X}
X
Xcbreak() {
X	if (fd != -1)
X		return;
X	if ((fd = open("/dev/tty", 0)) == -1) {
X		write(2, "OOPS -- can't open /dev/tty\n", 28);
X		exit(1);
X	}
X	ioctl(fd, TIOCGETP, &ttymode);
X	ttymode.sg_flags |= CBREAK;
X	ttymode.sg_flags &= ~ECHO;
X	ioctl(fd, TIOCSETP, &ttymode);	/* NB: add TIOCSETN! */
X}
X
Xnocbreak() {
X	if (fd == -1)
X		return;
X	ttymode.sg_flags &= ~CBREAK;
X	ttymode.sg_flags |= ECHO;
X	ioctl(fd, TIOCSETP, &ttymode);
X	close(fd);
X	fd = -1;
X}
X
Xbyebye() {
X	nocbreak();
X	exit(0);
X}
+ END-OF-FILE commands/more.c
chmod u=rw,g=r,o=r commands/more.c
set `sum commands/more.c`
sum=$1
case $sum in
47880)	:;;
*)	echo 'Bad sum in 'commands/more.c >&2
esac
echo Extracting commands/mv.dif
sed 's/^X//' > commands/mv.dif << '+ END-OF-FILE 'commands/mv.dif
X1c1,4
X< /* mv - move files		Author: Adri Koppes */
X---
X> /* mv - move files		Author: Adri Koppes 
X>  *
X>  * 4/25/87 - J. Paradis		Bug fixes for directory handling
X>  */
X7c10
X< struct stat st;
X---
X> struct stat st, st1;
X26,37c29
X< 	if ((st.st_mode & S_IFMT) == S_IFDIR) {
X< 	    if (!stat(argv[2], &st) && (st.st_mode & S_IFMT) == S_IFDIR) {
X< 		std_err ("mv: target ");
X< 		std_err (argv[2]);
X< 		std_err (" exists\n");
X< 		exit (1);
X< 	    }
X< 	}
X< 	else {
X< 	    setgid (getgid ());
X< 	    setuid (getuid ());
X< 	}
X---
X> 
X41,42d32
X< 	setgid (getgid ());
X< 	setuid (getuid ());
X67a58,68
X>     char    name[64];
X> 
X>     /* It's too dangerous to fool with "." or ".." ! */
X>     if((strcmp(old, ".") == 0) || (strcmp(old, "..") == 0)) {
X> 	cant(old);
X>     }
X> 
X>     /* Don't move a file to itself. */
X>     if (stat(old, &st)==0 && stat(new, &st1)==0 && st.st_dev == st1.st_dev &&
X>         st.st_ino == st1.st_ino)
X> 	cant(old);
X73c74
X< 	char name[64], *p, *rindex();
X---
X> 	char *p, *rindex();
X91c92,94
X< 		    execl ("/bin/cp", "cp", old, new, 0);
X---
X> 		    setgid (getgid ());
X> 		    setuid (getuid ());
X> 		    execl ("/bin/cp", "cp", old, new, (char *) 0);
X103,114c106,159
X<     utime (new, &st.st_atime);
X<     unlink(old);
X< }
X< 
X< cant(name)
X< char *name;
X< {
X< 	std_err("mv: can't move ");
X< 	std_err (name);
X< 	std_err ("\n");
X< 	exit (1);
X< }
X---
X> 
X>     /* If this was a directory that we moved, then we have
X>     ** to update its ".." entry (in case it was moved some-
X>     ** where else in the tree...)
X>     */
X>     if ((st.st_mode & S_IFMT) == S_IFDIR) {
X> 	int	i;
X> 	char	parent[64], dotdot[64];
X> 
X> 	strcpy(parent, new);
X> 
X> 	/* Determine the name for the parent of
X> 	** the new name by counting back until we
X> 	** hit a '/' or the begining of the string
X> 	*/
X> 
X> 	for(i = (strlen(parent) - 1); i > 0; i--) {
X> 	    if(parent[i] == '/') break;
X> 	}
X> 
X> 	/* If there are no slashes, then the name is
X> 	** in the current directory, so its parent
X> 	** is ".".  Otherwise, the parent is the name
X> 	** up to the last slash.
X> 	*/
X> 	if(i == 0) {
X> 		strcpy(parent, ".");
X> 	}
X> 	else {
X> 		/* null-terminate name at last slash */
X> 		parent[i] = '\0';
X> 	}
X> 
X> 	/* Unlink the ".." entry */
X> 	strcpy(dotdot, new);
X> 	strcat(dotdot, "/..");
X> 	unlink(dotdot);
X> 
X> 	/* Now link it to its parent */
X> 	link(parent, dotdot);
X>     }
X> 
X>     utime (new, &st.st_atime);
X>     unlink(old);
X> }
X> 
X> cant(name)
X> char *name;
X> {
X> 	std_err("mv: can't move ");
X> 	std_err (name);
X> 	std_err ("\n");
X> 	exit (1);
X> }
+ END-OF-FILE commands/mv.dif
chmod u=rw,g=r,o=r commands/mv.dif
set `sum commands/mv.dif`
sum=$1
case $sum in
49149)	:;;
*)	echo 'Bad sum in 'commands/mv.dif >&2
esac
echo Extracting commands/od.dif
sed 's/^X//' > commands/od.dif << '+ END-OF-FILE 'commands/od.dif
X26c26
X<   if (*p == '-') {
X---
X>   if (argc > 1 && *p == '-') {
X168,169c168,169
X< bdump(words, k, c)
X< int words[8];
X---
X> bdump(bytes, k, c)
X> char bytes[16];
X174,186c174,176
X<   int c1, c2;
X< 
X<   i = 0;
X<   if (linenr++ != 1) printf("       ");
X<   while (i < k) {
X< 	c1 = words[i>>1] & 0377;
X< 	c2 = (words[i>>1]>>8) & 0377;
X< 	byte(c1, c);
X< 	i++;
X< 	if (i == k) {printf("\n"); return;}
X< 	byte(c2, c);
X< 	i++;
X<   }
X---
X> 
X>   if (linenr++ != 1) printf("       ");
X>   for (i = 0; i < k; i++) byte(bytes[i] & 0377, c);
X194c184
X<   if (c == 'b') { 
X---
X>   if (c == 'b') {
+ END-OF-FILE commands/od.dif
chmod u=rw,g=r,o=r commands/od.dif
set `sum commands/od.dif`
sum=$1
case $sum in
35589)	:;;
*)	echo 'Bad sum in 'commands/od.dif >&2
esac
echo Extracting commands/passwd.dif
sed 's/^X//' > commands/passwd.dif << '+ END-OF-FILE 'commands/passwd.dif
X50a51,54
X> 	if (password[0] == '\0') {
X> 		std_err("password cannot be null\n");
X> 		exit(1);
X> 	}
+ END-OF-FILE commands/passwd.dif
chmod u=rw,g=r,o=r commands/passwd.dif
set `sum commands/passwd.dif`
sum=$1
case $sum in
7108)	:;;
*)	echo 'Bad sum in 'commands/passwd.dif >&2
esac
echo Extracting commands/pr.dif
sed 's/^X//' > commands/pr.dif << '+ END-OF-FILE 'commands/pr.dif
X257,259c257,260
X<   		do {
X<   			putchar(c);
X<   		} while ((c = getc(filep)) != '\n' && c != EOF);
X---
X> 		while (c != '\n' && c != EOF) {
X>   			putchar(c);
X> 			c = getc(filep);
X> 		}
+ END-OF-FILE commands/pr.dif
chmod u=rw,g=r,o=r commands/pr.dif
set `sum commands/pr.dif`
sum=$1
case $sum in
11108)	:;;
*)	echo 'Bad sum in 'commands/pr.dif >&2
esac
echo Extracting commands/printenv.c
sed 's/^X//' > commands/printenv.c << '+ END-OF-FILE 'commands/printenv.c
X/* printenv - print the current environment	Author: Richard Todd */
X
Xmain ()
X{
X  extern char **environ;
X  char **sptr;
X  for (sptr = environ ; *sptr ; ++sptr) {
X	prints("%s\n",*sptr);
X  }
X}
+ END-OF-FILE commands/printenv.c
chmod u=rw,g=r,o=r commands/printenv.c
set `sum commands/printenv.c`
sum=$1
case $sum in
15422)	:;;
*)	echo 'Bad sum in 'commands/printenv.c >&2
esac
echo Extracting commands/pwd.dif
sed 's/^X//' > commands/pwd.dif << '+ END-OF-FILE 'commands/pwd.dif
X12c12,13
X< 	register char name[128], *n;
X---
X> 	register *n;
X> 	char name[128];
+ END-OF-FILE commands/pwd.dif
chmod u=rw,g=r,o=r commands/pwd.dif
set `sum commands/pwd.dif`
sum=$1
case $sum in
5696)	:;;
*)	echo 'Bad sum in 'commands/pwd.dif >&2
esac
echo Extracting commands/readfs.c
sed 's/^X//' > commands/readfs.c << '+ END-OF-FILE 'commands/readfs.c
X/* readfs - read a MINIX file system	Author: Paul Polderman */
X
X/*
XCommand: readfs - read and extract a MINIX filesystem.
X
XSyntax:  readfs [-li] block-special [directory]
X
XFlags:	 -l:	extract all directories and files from the filesystem
X		and produce a mkfs-listing on standard output.
X	 -i:	give the listing, but do not extract files.
X
XExamples: readfs /dev/fd1		# extract all files from /dev/fd1.
X	  readfs -i /dev/hd2		# see what's on /dev/hd2.
X	  readfs -l /dev/at0 rootfs	# extract and list the filesystem
X					# of /dev/at0 and put the tree
X					# in the directory `rootfs'.
X
X  Readfs reads a MINIX filesystem and extracts recursively all directories
Xand files, and (optionally) produces a mkfs-listing of them on standard output.
XThe root directory contents are placed in the current directory, unless
Xa directory is given as argument, in which case the contents are put there.
XReadfs tries to restore the attributes (mode/uid/gid/time) of the files
Xextracted to those of the original files.
XSpecial files are created as ordinary files, but the mkfs-listing
Xenables mkfs to restore them to original.
X*/
X
X#include <stdio.h>
X
X#include "fs/const.h"
X#include "h/type.h"
X#include "h/const.h"
X#include "fs/type.h"
X#include "fs/buf.h"
X#include "fs/super.h"
X
X#undef printf		/* Definition used only in the kernel */
X
Xextern file_pos lseek();
X
X/*
X * Compile with -I/user0/ast/minix
X * (i.e. the directory containing the MINIX system sources)
X *
X *	Author: Paul Polderman (polder@cs.vu.nl) April 1987
X */
X
Xchar verbose = 0;	/* give a mkfs-listing of the filesystem */
X			/* and extracts its contents. */
Xchar noaction = 0;	/* just give a mkfs-listing, do not extract files. */
X
Xstruct super_block sb;
Xchar pathname[1024];
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	switch (argc) {
X	case 2:
X		pathname[0] = '\0';
X		readfs(argv[1], pathname);
X		break;
X	case 3:
X		if (argv[1][0] == '-') {
X			get_flags(&argv[1][1]);
X			pathname[0] = '\0';
X			readfs(argv[2], pathname);
X		} else {
X			strcpy(pathname, argv[2]);
X			readfs(argv[1], pathname);
X		}
X		break;
X	case 4: if (argv[1][0] == '-') {
X			get_flags(&argv[1][1]);
X			strcpy(pathname, argv[3]);
X			readfs(argv[2], pathname);
X			break;
X		} /* else fall through .. */
X	default:
X		fprintf(stderr,"Usage: %s [-li] <special> [dirname]\n",argv[0]);
X		exit(1);
X	}
X	exit(0);
X}
X
Xget_flags(flags)
Xregister char *flags;
X{
X	while (*flags) {
X		switch (*flags) {
X		case 'L':
X		case 'l':
X			verbose = 1; break;
X		case 'I':
X		case 'i':
X			noaction = 1; verbose = 1; break;
X		default:
X			fprintf(stderr, "Bad flag: %c\n", *flags);
X			break;
X		}
X		flags++;
X	}
X}
X
Xreadfs(special_file, directory)
Xchar *special_file, *directory;
X/*
X * Readfs: opens the given special file (with MINIX filesystem),
X * and extracts its contents into the given directory.
X */
X{
X	d_inode root_inode;
X	int special, inum;
X	file_pos super_b;
X
X	umask(0);
X
X	/* Open the special file */
X	if ( (special = open(special_file, 0)) < 0) {
X		fprintf(stderr, "cannot open %s\n", special_file);
X		return;
X	}
X
X	/* Read the superblock */
X	super_b = (file_pos) SUPER_BLOCK * (file_pos) BLOCK_SIZE;
X	if (lseek(special, super_b, 0) != super_b) {
X		fprintf(stderr, "cannot seek to superblock\n");
X		return;
X	}
X
X	if (read(special, &sb, sizeof(struct super_block))
X		!= sizeof(struct super_block)) {
X			fprintf(stderr, "cannot read superblock\n");
X			return;
X	}
X
X	/* Is it really a MINIX filesystem ? */
X	if (sb.s_magic != SUPER_MAGIC) {
X		fprintf(stderr, "%s is not a valid MINIX filesystem\n",
X			special_file);
X		return;
X	}
X
X	/* Fetch the inode of the root directory */
X	if (get_inode(special, (inode_nr) ROOT_INODE, &root_inode) < 0) {
X		fprintf(stderr, "cannot get inode of root directory\n");
X		return;
X	}
X
X	/* Print number of zones and inodes */
X	if (verbose)
X		printf("boot\n%d %d\n", sb.s_nzones, sb.s_ninodes);
X
X	/* Extract (recursively) the root directory */
X	dump_dir(special, &root_inode, directory);
X}
X
X/*
X * different type of blocks:	(used in routine get_block for caching)
X */
X
X#define	B_INODE		0	/* Cache #0 is the inode cache */
X#define	B_INDIRECT	1	/* Cache #1 is the (dbl) indirect block cache */
X#define	B_DATA		2	/* No cache for data blocks (only read once) */
X
Xint get_inode(fd, inum, ip)
Xint fd;
Xinode_nr inum;
Xd_inode *ip;
X/*
X * Get inode `inum' from the MINIX filesystem. (Uses the inode-cache)
X */
X{
X	struct buf bp;
X	block_nr block;
X	block_nr ino_block;
X	unshort ino_offset;
X	int r;
X
X	/* Calculate start of i-list */
X	block = SUPER_BLOCK + 1 + sb.s_imap_blocks + sb.s_zmap_blocks;
X
X	/* Calculate block with inode inum */
X	ino_block = ((inum - 1) / INODES_PER_BLOCK);
X	ino_offset = ((inum - 1) % INODES_PER_BLOCK);
X	block += ino_block;
X
X	/* Fetch the block */
X	if (get_block(fd, block, &bp, B_INODE) == 0) {
X		bcopy(&bp.b_inode[ino_offset], ip, sizeof(d_inode));
X		return(0);
X	}
X
X	/* Oeps, foutje .. */
X	fprintf(stderr, "cannot find inode %d\n", inum);
X	return(-1);
X}
X
Xstatic int indent = 0;		/* current indent (used for mkfs-listing) */
X
Xdump_dir(special, ip, directory)
Xint special;
Xd_inode *ip;
Xchar *directory;
X/*
X * Make the given directory (if non-NULL),
X * and recursively extract its contents.
X */
X{
X	register dir_struct *dp;
X	register int n_entries;
X	register char *name;
X	block_nr b = 0;
X	d_inode dip;
X	struct buf bp;
X
X	if (verbose) {
X		show_info(directory, ip, "");
X		indent++;
X	}
X
X	if (!noaction && *directory) {
X		/* Try to make the directory if not already there */
X		if (mkdir(directory) != 0 || chdir(directory) < 0) {
X			fprintf(stderr,"mkdir %s failed\n", directory);
X			return;
X		}
X	}
X	for (name = directory; *name; name++)	/* Find end of pathname */
X		;
X	*name++ = '/';		/* Add trailing slash */
X
X	n_entries = (int) (ip->i_size / (file_pos) sizeof(dir_struct));
X	while (n_entries > 0) {
X
X		/* Read next block of the directory */
X		if (get_fileblock(special, ip, b, &bp) < 0)
X			return(-1);
X		dp = &bp.b_dir[0];
X		if (b++ == (block_nr) 0) {
X			dp += 2;	/* Skip "." and ".." */
X			n_entries -= 2;
X		}
X
X		/* Extract the files/directories listed in the block */
X		while (n_entries-- > 0 && dp < &bp.b_dir[NR_DIR_ENTRIES]) {
X			if (dp->d_inum != (inode_nr) 0) {
X				if (get_inode(special, dp->d_inum, &dip) < 0) {
X					/* Bad luck */
X					dp++;
X					continue;
X				}
X				/* Add new pathname-component to `pathname'. */
X				strncpy(name, dp->d_name, NAME_SIZE);
X				name[NAME_SIZE] = '\0';
X
X				/* Call the right routine */
X				if ((dip.i_mode & I_TYPE) == I_DIRECTORY)
X					dump_dir(special, &dip, name);
X				else
X					dump_file(special, &dip, name);
X			}
X			dp++;	/* Next entry, please. */
X		}
X	}
X	*--name = '\0';		/* Restore `pathname' to what it was. */
X	if (!noaction && *directory) {
X		chdir("..");		/* Go back up. */
X		restore(directory, ip);	/* Restore mode/owner/accesstime */
X	}
X
X	if (verbose) {
X		do_indent(--indent);	/* Let mkfs know we are done */
X		printf("$\n");		/* with this directory. */
X	}
X}
X
Xdump_file(special, ip, filename)
Xint special;
Xd_inode *ip;
Xchar *filename;
X/*
X * Extract given filename from the MINIX-filesystem,
X * and store it on the local filesystem.
X */
X{
X	dir_struct *dp;
X	int file;
X	block_nr b = 0;
X	struct buf bp;
X	file_pos size;
X
X	if (verbose)
X		show_info(filename, ip, pathname);
X
X	if (noaction) return(0);
X
X	if (access(filename, 0) == 0) {
X		/* Should not happen, but just in case .. */
X		fprintf(stderr, "Will not create %s: file exists\n", filename);
X		return(-1);
X	}
X	if ( (file = creat(filename, (ip->i_mode & ALL_MODES) )) < 0) {
X		fprintf(stderr, "cannot create %s\n", filename);
X		return(-1);
X	}
X	/* Don't try to extract /dev/hd0 */
X	if ((ip->i_mode & I_TYPE) == I_REGULAR) {
X		size = ip->i_size;
X		while (size > (file_pos) 0) {
X			/* Get next block of file */
X			if (get_fileblock(special, ip, b++, &bp) < 0) {
X				close(file);
X				return(-1);
X			}
X
X			/* Write it to the file */
X			if (size > (file_pos) BLOCK_SIZE)
X				write(file, bp.b_data, BLOCK_SIZE);
X			else
X				write(file, bp.b_data, (int) size);
X
X			size -= (file_pos) BLOCK_SIZE;
X		}
X	}
X	close(file);
X	restore(filename, ip);	/* Restore mode/owner/filetimes */
X	return(0);
X}
X
X#define	zone_shift	(sb.s_log_zone_size)	/* zone to block ratio */
X
Xint get_fileblock(special, ip, b, bp)
Xint special;
Xd_inode *ip;
Xblock_nr b;
Xstruct buf *bp;
X/*
X * Read the `b'-th block from the file whose inode is `ip'.
X */
X{
X	zone_nr zone, ind_zone;
X	block_nr z, zone_index;
X	int r;
X
X	/* Calculate zone in which the datablock number is contained */
X	zone = (zone_nr) (b >> zone_shift);
X
X	/* Calculate index of the block number in the zone */
X	zone_index = b - ((block_nr) zone << zone_shift);
X
X	/* Go get the zone */
X	if (zone < (zone_nr) NR_DZONE_NUM) {	/* direct block */
X		zone = ip->i_zone[zone];
X		z = ((block_nr) zone << zone_shift) + zone_index;
X		r = get_block(special, z, bp, B_DATA);
X		return(r);
X	}
X
X	/* The zone is not a direct one */
X	zone -= (zone_nr) NR_DZONE_NUM;
X
X	/* Is it single indirect ? */
X	if (zone < (zone_nr) NR_INDIRECTS) {	/* single indirect block */
X		ind_zone = ip->i_zone[NR_DZONE_NUM];
X	} else {				/* double indirect block */
X		/* Fetch the double indirect block */
X		ind_zone = ip->i_zone[NR_DZONE_NUM + 1];
X		r = get_block(special, (block_nr) ind_zone, bp, B_INDIRECT);
X		if (r < 0) return(r);
X
X		/* Extract the indirect zone number from it */
X		zone -= (zone_nr) NR_INDIRECTS;
X		ind_zone = bp->b_ind[zone / (zone_nr) NR_INDIRECTS];
X		zone %= (zone_nr) NR_INDIRECTS;
X	}
X	/* Extract the datablock number from the indirect zone */
X	r = get_block(special, (block_nr) ind_zone, bp, B_INDIRECT);
X	if (r < 0) return(r);
X	zone = bp->b_ind[zone];
X
X	/* Calculate datablock number to be fetched */
X	z = ((block_nr) zone << zone_shift) + zone_index;
X	r = get_block(special, z, bp, B_DATA);
X	return(r);
X}
X
X/*
X * The following routines simulate a LRU block cache.
X *
X * Definition of a cache block:
X */
X
Xstruct cache_block {
X	block_nr b_block;		/* block number of block */
X	long b_access;			/* counter value of last access */
X	char b_buf[BLOCK_SIZE];		/* buffer for block */
X};
X
X#define	NR_CACHES	2	/* total number of caches */
X#define	NR_CBLOCKS	5	/* number of blocks in a cache */
X
Xstatic struct cache_block cache[NR_CACHES][NR_CBLOCKS];
Xstatic long counter = 0L;	/* Counter used as a sense of time. */
X				/* Incremented after each cache operation. */
X
Xget_block(fd, block, bp, type)
Xint fd;
Xblock_nr block;
Xstruct buf *bp;
Xint type;
X/*
X * Get the requested block from the device with filedescriptor fd.
X * If it is in the cache, no (floppy-) disk access is needed,
X * if not, allocate a cache block and read the block into it.
X */
X{
X	register int i;
X	register struct cache_block *cache_p, *cp;
X
X	if (block == (block_nr) NO_ZONE) {
X		/* Should never happen in a good filesystem. */
X		fprintf(stderr, "get_block: NO_ZONE requested !\n");
X		return(-1);
X	}
X	if (type < 0 || type >= NR_CACHES)	/* No cache for this type */
X		return( get_rawblock(fd, block, bp) );
X
X	cache_p = cache[type];
X	cp = (struct cache_block *) 0;
X
X	/* First find out if block requested is in the cache */
X	for (i = 0; i < NR_CBLOCKS; i++) {
X		if (cache_p[i].b_block == block) {	/* found right block */
X			cp = &cache_p[i];
X			break;
X		}
X	}
X
X	if (cp == (struct cache_block *) 0) {	/* block is not in cache */
X		cp = cache_p;			/* go find oldest buffer */
X		for (i = 0; i < NR_CBLOCKS; i++) {
X			if (cache_p[i].b_access < cp->b_access)
X				cp = &cache_p[i];
X		}
X		/* Fill the buffer with the right block */
X		if (get_rawblock(fd, block, cp->b_buf) < 0)
X			return(-1);
X	}
X
X	/* Update/store last access counter */
X	cp->b_access = ++counter;
X	cp->b_block = block;
X	bcopy(cp->b_buf, bp, BLOCK_SIZE);
X	return(0);
X}
X
Xint get_rawblock(special, blockno, bufp)
Xint special;
Xblock_nr blockno;
Xchar *bufp;
X/*
X * Read a block from the disk.
X */
X{
X	int r;
X	file_pos pos;
X
X	/* Calculate the position of the block on the disk */
X	pos = (file_pos) blockno * (file_pos) BLOCK_SIZE;
X
X	/* Read the block from the disk */
X	if (lseek(special, pos, 0) == pos
X		&& read(special, bufp, BLOCK_SIZE) == BLOCK_SIZE)
X			return(0);
X
X	/* Should never get here .. */
X	fprintf(stderr, "read block %d failed\n", blockno);
X	return(-1);
X}
X
Xrestore(name, ip)
Xchar *name;
Xd_inode *ip;
X/*
X * Restores given file's attributes.
X * `ip' contains the attributes of the file on the MINIX filesystem,
X * `name' is the filename of the extracted file on the local filesystem.
X */
X{
X	long ttime[2];
X
X	chown(name, ip->i_uid, ip->i_gid);	/* Fails if not superuser */
X	chmod(name, (ip->i_mode & ALL_MODES));
X	ttime[0] = ttime[1] = ip->i_modtime;
X	utime(name, ttime);
X}
X
X/*
X * characters to use as prefix to `mkfs' mode field
X */
X
Xstatic char special_chars[] = {
X	'-',		/* I_REGULAR */
X	'c',		/* I_CHAR_SPECIAL */
X	'd',		/* I_DIRECTORY */
X	'b'		/* I_BLOCK_SPECIAL */
X};
X
Xshow_info(name, ip, path)
Xchar *name;
Xd_inode *ip;
Xchar *path;
X/*
X * Show information about the given file/dir in `mkfs'-format
X */
X{
X	char c1, c2, c3;
X
X	c1 = special_chars[(ip->i_mode >> 13) & 03];
X	c2 = ((ip->i_mode & ALL_MODES & ~RWX_MODES)==I_SET_UID_BIT) ? 'u' : '-';
X	c3 = ((ip->i_mode & ALL_MODES & ~RWX_MODES)==I_SET_GID_BIT) ? 'g' : '-';
X
X	if (*name) {
X		do_indent(indent);
X		printf("%-14s ", name);
X	}
X
X	printf("%c%c%c%03o %d %d", c1, c2, c3,
X		(ip->i_mode & RWX_MODES), ip->i_uid, ip->i_gid);
X
X	switch (ip->i_mode & I_TYPE) {
X		case I_DIRECTORY:
X			break;
X		case I_CHAR_SPECIAL:	/* Print major and minor dev numbers */
X			printf(" %d %d", (ip->i_zone[0] >> MAJOR) & 0377,
X				(ip->i_zone[0] >> MINOR) & 0377);
X			break;
X		case I_BLOCK_SPECIAL:	/* Print major and minor dev numbers */
X			printf(" %d %d", (ip->i_zone[0] >> MAJOR) & 0377,
X				(ip->i_zone[0] >> MINOR) & 0377);
X			/* Also print the number of blocks on the device */
X			printf(" %D", (ip->i_size / (file_pos) BLOCK_SIZE));
X			break;
X		default:		/* Just print the pathname */
X			printf(" %s", path);
X			break;
X	}
X	putchar('\n');
X}
X
X#define	INDENT_SIZE	4
X
Xdo_indent(i)
Xint i;
X{
X	i *= INDENT_SIZE;
X	while (i-- > 0)
X		putchar(' ');
X}
X
Xint mkdir(directory)
Xint directory;
X/*
X * Make a directory, return exit status.
X * This routine is not necessary on systems that
X * have a system call to make directories.
X */
X{
X	int pid, status;
X
X	if ( (pid = fork()) == 0) {
X		execl("/bin/mkdir", "mkdir", directory, 0);
X		execl("/usr/bin/mkdir", "mkdir", directory, 0);
X		exit(1);
X	} else if (pid < 0)
X		return(-1);
X	while (wait(&status) != pid)
X		;
X	return(status);
X}
X
Xbcopy(src, dest, bytes)
Xregister char *src, *dest;
Xregister int bytes;
X/*
X * Copy bytes from src to dest.
X * May also be in the standard libc.a on some systems.
X */
X{
X	while (bytes--)
X		*dest++ = *src++;
X}
+ END-OF-FILE commands/readfs.c
chmod u=rw,g=r,o=r commands/readfs.c
set `sum commands/readfs.c`
sum=$1
case $sum in
25630)	:;;
*)	echo 'Bad sum in 'commands/readfs.c >&2
esac
exit 0