[comp.os.minix] A improved tar.c; cb.c; shutdown utility

rtregn@immd3.informatik.uni-erlangen.de (Robert Regn) (10/21/88)

Changing the official tar to handle stdin/out has needed more than one year -
so I don't want wait for a tar *preserving the link structure* and have
improved tar.c myself - based on cpdir. Tar also saves now time and owner.
It is tested on a SYS V machine in all modes, on Minix only in c and t mode.
Cdiff follows.

A cb(1) program was posted in comp.sys.ibm.pc - I have modified it for Minix.
The source is included.

If someone has the cut(1) program recently posted in comp.sources.unix or
another one, please send it to me.

At last, some people would like a clear and shure shutdown approach for
Minix - I too. So I wrote a program shut, which executes a shell script
/etc/shutdown. Calling shut can made by a shut login:
shut::2:2::/:/etc/shut
Shut is required because login (1) needs an executable program, not a
shell script. The shutdown script should be customized for your system.
It does:
	 umounting floppies
	 copying login, true and echo to bin - this prevents a root shell
		if Ctrl F9 is typed after shutdown
	 umounting /usr and root partition (hd3 and hd2)
	 gives messages about success
Problem: Because we have no ps(1), shutdown cannot kill processes itself.
For making the copies shut must have uid 2 or 0.
Using shut is also good for last (1), which can recognize the shutdown time
in wtmp.


----------------------------------------------cut -------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  tar.c.cdif cb.c shutdown shut.c
# Wrapped by rtregn@faui32 on Thu Oct 20 15:16:33 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'tar.c.cdif' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tar.c.cdif'\"
else
echo shar: Extracting \"'tar.c.cdif'\" \(4473 characters\)
sed "s/^X//" >'tar.c.cdif' <<'END_OF_FILE'
X*** 1.3/c.fertig/commands/tar.c	Wed Oct  5 12:40:21 1988
X--- tar.c	Thu Oct 20 12:55:16 1988
X***************
X*** 39,44 ****
X--- 39,53 ----
X  
X  HEADER header;
X  
X+ #define MAXLINKS 512
X+ 
X+ struct {
X+         unsigned short ino;
X+         unsigned short dev;
X+         char *path;
X+ } links[MAXLINKS];
X+ int nlinks = 0;
X+ 
X  #define INT_TYPE	(sizeof(header.member.m_uid))
X  #define LONG_TYPE	(sizeof(header.member.m_size))
X  
X***************
X*** 185,190 ****
X--- 194,200 ----
X  register char *file;
X  {
X    register int fd;
X+   struct stat st;
X  
X    if (header.member.m_linked == '1') {
X  	if (link(header.member.m_link, file) < 0)
X***************
X*** 205,210 ****
X--- 215,224 ----
X    (void) close(fd);
X  
X    chmod(file, (int)convert(header.member.m_mode, INT_TYPE));
X+   st.st_mtime = (int)convert(header.member.m_time, LONG_TYPE);
X+   st.st_atime = st.st_mtime;
X+   utime(file, &st.st_atime);
X+   chown(file, (int)convert(header.member.m_uid, INT_TYPE),(int)convert(header.member.m_gid, INT_TYPE));
X    flush();
X  }
X  
X***************
X*** 329,334 ****
X--- 343,349 ----
X    struct stat st;
X    struct direct dir;
X    register int fd;
X+   char *islink(), *link=NIL_PTR;
X  
X    if (stat(file, &st) < 0) {
X  	string_print(NIL_PTR, "Cannot find %s\n", file);
X***************
X*** 339,349 ****
X  	return;
X    }
X  
X!   make_header(path_name(file), &st);
X    mwrite(tar_fd, &header, sizeof(header));
X!   if (st.st_mode & S_IFREG)
X! 	copy(path_name(file), fd, tar_fd, st.st_size);
X!   else if (st.st_mode & S_IFDIR) {
X  	if (chdir(file) < 0)
X  		string_print(NIL_PTR, "Cannot chdir to %s\n", file);
X  	else {
X--- 354,371 ----
X  	return;
X    }
X  
X! 
X!   /* check for link */
X!   if ((st.st_mode & S_IFMT)!=S_IFDIR && st.st_nlink>1)
X! 	 link = islink (path_name(file), &st, header.member.m_link);
X! 
X!   make_header(path_name(file), &st ,link);
X    mwrite(tar_fd, &header, sizeof(header));
X!   if ((st.st_mode & S_IFMT) == S_IFREG)
X! 	{if (link == 0)
X! 		copy(path_name(file), fd, tar_fd, st.st_size);
X! 	}
X!   else if ((st.st_mode & S_IFMT) == S_IFDIR) {
X  	if (chdir(file) < 0)
X  		string_print(NIL_PTR, "Cannot chdir to %s\n", file);
X  	else {
X***************
X*** 363,370 ****
X    (void) close(fd);
X  }
X  
X! make_header(file, st)
X! char *file;
X  register struct stat *st;
X  {
X    register char *ptr = header.member.m_name;
X--- 385,395 ----
X    (void) close(fd);
X  }
X  
X! /* a new arg link is necessary because link must be written beetween
X!   clear_header() and checksum()	- calling islink in make_header isn't clean*/
X! 
X! make_header(file, st,link)
X! char *file, *link;
X  register struct stat *st;
X  gi    re[(ster char *ptr = header.member.m_name;
X***************
X*** 384,392 ****
X    string_print(header.member.m_gid, "%I ", st->st_gid);
X    string_print(header.member.m_size, "%L ", st->st_size);
X    string_print(header.member.m_time, "%L ", st->st_mtime);
X!   header.member.m_linked = ' ';
X    string_print(header.member.m_checksum, "%I", checksum());
X  }
X  
X  clear_header()
X  {
X--- 409,465 ----
X    string_print(header.member.m_gid, "%I ", st->st_gid);
X    string_print(header.member.m_size, "%L ", st->st_size);
X    string_print(header.member.m_time, "%L ", st->st_mtime);
X!   if (link != NIL_PTR)
X! 	{
X! 	header.member.m_linked = '1';
X! 	strncpy (header.member.m_link, link, NAME_SIZE);
X! 	}
X!   else
X! 	header.member.m_linked = ' ';
X    string_print(header.member.m_checksum, "%I", checksum());
X  }
X+ 
X+ char  *islink(file, st)
X+ 	struct stat *st;
X+ 	char *file;
X+ {
X+ 	/* Handle files that are links.
X+ 	 * Returns 0 if file must be copied.
X+ 	 * Returns 1 if file has been successfully linked.
X+ 	 */
X+ 	int i;
X+ 	int linkent;
X+ 	char *malloc();
X+ 
X+ 	linkent = -1;
X+ 	for (i=0; i<nlinks; i++)
X+ 	{
X+ 		if (links[i].dev==st->st_dev
X+ 			&& links[i].ino==st->st_ino)
X+ 				linkent=i;
X+ 	}
X+ 	if (linkent>=0) /* It's already in the link table */
X+ 	{ /* we must have copied it earlier.
X+ 	   * Don't copy it twice.
X+ 	   */
X+ 		
X+ 		return(links[linkent].path); /* Don't try to copy it */
X+ 
X+ 	} else { /* Make an entry in the link table */
X+ 		if (nlinks >= MAXLINKS)
X+ 			error("Too many links at %s\n",file);	
X+ 		links[nlinks].dev = st->st_dev;
X+ 		links[nlinks].ino = st->st_ino;
X+ 		links[nlinks].path = malloc(strlen(file)+1);
X+ 		if (links[nlinks].path == 0)
X+ 			error("No more memory at %s\n",file);
X+ 		strcpy(links[nlinks].path,file);
X+ 		nlinks++;
X+ 		/* Go ahead and copy it the first time */
X+ 		return(NIL_PTR);
X+ 	}
X+ }
X+ 
X  
X  clear_header()
X  {
END_OF_FILE
if test 4473 -ne `wc -c <'tar.c.cdif'`; then
    echo shar: \"'tar.c.cdif'\" unpacked with wrong size!
fi
# end of 'tar.c.cdif'
fi
if test -f 'cb.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cb.c'\"
else
echo shar: Extracting \"'cb.c'\" \(6929 characters\)
sed "s/^X//" >'cb.c' <<'END_OF_FILE'
X/*
X	Compiled on Manx C86 by Allen Morris 3/22/86
X
X	Modified for DeSmet C by S. Lekach 3/20/86
X
X	Modified for Lattice C Ver 1.01
X	by: John W. Kindschi Jr. (10-30-83)
X
X	Modified for Minix
X	by: Robert Regn  rtregn@faui32.uucp (12. 10. 88)
X
X	Swiped from CPIG'S UNIX system and modified to
X	run under BDS C by William C. Colley, III
X
X
X	To use the program type the following command line:
X
X		cb [file]
X
X	If no input file is specified, then the console is read
X*/
X#include <stdio.h>
X#define print printf
X
XFILE *f1;
X
Xint slevel[10];
Xint clevel;
Xint spflg[20][10];
Xint sind[20][10];
Xint siflev[10];
Xint sifflg[10];
Xint iflev;
Xint ifflg;
Xint level;
Xint eflg;
Xint paren;
Xint aflg;
Xint ct;
Xint stabs[20][10];
Xint qflg;
Xint j;
Xint sflg;
Xint bflg;
Xint peek;
Xint tabs;
X
Xstatic int ind[10] = {
X	0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Xstatic int pflg[10] = {
X	0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
X
Xchar lchar;
Xchar pchar;
Xchar *wif[2];
Xchar *welse[2];
Xchar *wfor[2];
Xchar *wds[3];
Xchar cc;
Xchar string[200];
Xint lastchar;
Xint c;
X
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X
X	/* Initialize everything here */
X	if (argc > 2){
X		printf("Usage: %s [file]\n", *argv);
X		exit(1);
X	}
X	if ( argc == 1)			/*stdin*/
X		f1 = stdin;
X	else  if ((f1 = fopen(*++argv,"r")) == NULL){
X		printf("File not found: %s\n", *argv);
X		exit(1);
X	}
X	clevel = iflev = level = eflg = paren = 0;
X	aflg = qflg = j = bflg = tabs = 0;
X	ifflg = peek = -1;
X	sflg = 1;
X	wif[0] = "if";
X	welse[0] = "else";
X	wfor[0] = "for";
X	wds[0] = "case";
X	wds[1] = "default";
X	wif[1] = welse[1] = wfor[1] = wds[2] = 0;
X
X	/* End of Initialization */
X
X	cb();
X	fclose(f1);
X}
X
Xcb()
X{
X	while ((c = getchr()) != EOF){
X		switch(c){
X		default:
X			string[j++] = c;
X			if (c != ',') lchar = c;
X			break;
X		case ' ':
X		case '\t':
X			if (lookup(welse) == 1){
X				gotelse();
X				if(sflg == 0 || j > 0)string[j++] = c;
X				putsx();
X				sflg = 0;
X				break;
X			}
X			if(sflg == 0 || j > 0) string[j++] = c;
X			break;
X		case '\n':
X			if (eflg = lookup(welse) == 1) gotelse();
X			putsx();
X			print("\n");
X			sflg = 1;
X			if (eflg == 1){
X				pflg[level]++;
X				tabs++;
X			} else
X				if(pchar == lchar)
X					aflg = 1;
X			break;
X		case '{':
X			if (lookup(welse) == 1) gotelse();
X			siflev[clevel] = iflev;
X			sifflg[clevel] = ifflg;
X			iflev = ifflg = 0;
X			clevel++;
X			if (sflg == 1 && pflg[level] != 0){
X				pflg[level]--;
X				tabs--;
X			}
X			string[j++] = c;
X			putsx();
X			getnl();
X			putsx();
X			print("\n");
X			tabs++;
X			sflg = 1;
X			if (pflg[level] > 0){
X				ind[level] = 1;
X				level++;
X				slevel[level] = clevel;
X			}
X			break;
X		case '}':
X			clevel--;
X			if ((iflev = siflev[clevel]-1) < 0) iflev = 0;
X			ifflg = sifflg[clevel];
X			putsx();
X			tabs--;
X			ptabs();
X			if ((peek = getchr()) == ';'){
X				print("%c;",c);
X				peek = -1;
X			} else print("%c",c);
X			getnl();
X			putsx();
X			print("\n");
X			sflg = 1;
X			if (clevel < slevel[level]) if (level > 0) level--;
X			if (ind[level] != 0){
X				tabs -= pflg[level];
X				pflg[level] = 0;
X				ind[level] = 0;
X			}
X			break;
X		case '"':
X		case '\'':
X			string[j++] = c;
X			while((cc = getchr()) != c){
X				string[j++] = cc;
X				if(cc == '\\'){
X					string[j++] = getchr();
X				}
X				if(cc == '\n'){
X					putsx();
X					sflg = 1;
X				}
X			}
X			string[j++] = cc;
X			if(getnl() == 1){
X				lchar = cc;
X				peek = '\n';
X			}
X			break;
X		case ';':
X			string[j++] = c;
X			putsx();
X			if(pflg[level] > 0 && ind[level] == 0){
X				tabs -= pflg[level];
X				pflg[level] = 0;
X			}
X			getnl();
X			putsx();
X			print("\n");
X			sflg = 1;
X			if(iflev > 0)
X				if(ifflg == 1){
X					iflev--;
X					ifflg = 0;
X				} 
X				else iflev = 0;
X			break;
X		case '\\':
X			string[j++] = c;
X			string[j++] = getchr();
X			break;
X		case '?':
X			qflg = 1;
X			string[j++] = c;
X			break;
X		case ':':
X			string[j++] = c;
X			if(qflg == 1){
X				qflg = 0;
X				break;
X			}
X			if(lookup(wds) == 0){
X				sflg = 0;
X				putsx();
X			} else {
X				tabs--;
X				putsx();
X				tabs++;
X			}
X			if((peek = getchr()) == ';'){
X				print(";");
X				peek = -1;
X			}
X			getnl();
X			putsx();
X			print("\n");
X			sflg = 1;
X			break;
X		case '/':
X			string[j++] = c;
X			if((peek = getchr()) != '*') break;
X			string[j++] = peek;
X			peek = -1;
X			comment();
X			break;
X		case ')':
X			paren--;
X			string[j++] = c;
X			putsx();
X			if(getnl() == 1){
X				peek = '\n';
X				if(paren != 0) aflg = 1;
X				else if(tabs > 0){
X					pflg[level]++;
X					tabs++;
X					ind[level] = 0;
X				}
X			}
X			break;
X		case '#':
X			string[j++] = c;
X			while((cc = getchr()) != '\n') string[j++] = cc;
X			string[j++] = cc;
X			sflg = 0;
X			putsx();
X			sflg = 1;
X			break;
X		case '(':
X			string[j++] = c;
X			paren++;
X			if(lookup(wfor) == 1){
X				while((c = getsx()) != ';');
X				ct = 0;
Xcont:
X				while((c = getsx()) != ')'){
X					if(c == '(') ct++;
X				}
X				if(ct != 0){
X					ct--;
X					goto cont;
X				}
X				paren--;
X				putsx();
X				if(getnl() == 1){
X					peek = '\n';
X					pflg[level]++;
X					tabs++;
X					ind[level] = 0;
X				}
X				break;
X			}
X			if(lookup(wif) == 1){
X				putsx();
X				stabs[clevel][iflev] = tabs;
X				spflg[clevel][iflev] = pflg[level];
X				sind[clevel][iflev] = ind[level];
X				iflev++;
X				ifflg = 1;
X			}
X		}
X	}
X}
X
X
Xptabs()
X{
X	int i;
X	for (i=0; i < tabs; i++) print("\t");
X}
X
Xgetchr()
X{
X	if(peek<0 && lastchar != ' ' && lastchar != '\t')pchar = lastchar;
X	lastchar = (peek < 0) ? getc(f1) : peek;
X	peek = -1;
X	return(lastchar == '\r' ? getchr() : lastchar);
X}
X
Xputsx()
X{
X	if (j > 0)
X	{
X		if (sflg != 0)
X		{
X			ptabs();
X			sflg = 0;
X			if (aflg == 1)
X			{
X				aflg = 0;
X				if (tabs > 0) print ("    ");
X			}
X		}
X		string[j] = '\0';
X		print("%s",string);
X		j = 0;
X	} else {
X		if (sflg != 0) {
X			sflg = 0;
X			aflg = 0;
X		}
X	}
X}
X
Xlookup(tab)
Xchar *tab[];
X{
X	char r;
X	int i,kk,k,l;
X	if(j < 1) return(0);
X	kk = 0;
X	while (string[kk] == ' ') kk++;
X	for (i = 0; tab[i] != 0; i++)
X	{
X		l = 0;
X		for(k=kk;(r = tab[i][l++]) == string[k] && r != '\0';k++);
X		if(r == '\0' && (string[k] < 'a' || string[k] > 'z'))return(1);
X	}
X	return(0);
X}
X
Xgetsx()
X{
X	char ch;
Xbeg:
X	if((ch = string[j++] = getchr()) == '\\')
X	{ 
X		string[j++] = getchr();
X		goto beg; 
X	}
X	if(ch == '\'' || ch == '"')
X	{
X		while((cc = string[j++] = getchr()) != ch) if(cc == '\\') string[j++] = getchr();
X		goto beg;
X	}
X	if(ch == '\n'){
X		putsx();
X		aflg = 1;
X		goto beg;
X	} else return(ch);
X}
X
Xgotelse()
X{
X	tabs = stabs[clevel][iflev];
X	pflg[level] = spflg[clevel][iflev];
X	ind[level] = sind[clevel][iflev];
X	ifflg = 1;
X}
X
Xgetnl()
X{
X	while ((peek = getchr()) == '\t' || peek == ' '){
X		string[j++] = peek;
X		peek = -1;
X	}
X	if((peek = getchr()) == '/'){
X		peek = -1;
X		if ((peek = getchr()) == '*'){
X			string[j++] = '/';
X			string[j++] = '*';
X			peek = -1;
X			comment();
X		} else string[j++] = '/';
X	}
X	if((peek = getchr()) == '\n'){
X		peek = -1;
X		return(1);
X	}
X	return(0);
X}
X
Xcomment()
X{
Xrep:
X	while ((c = string[j++] = getchr()) != '*')
X		if (c == '\n'){
X			putsx();
X			sflg = 1;
X		}
Xgotstar:
X	if ((c = string[j++] = getchr()) != '/'){
X		if (c == '*') goto gotstar;
X		goto rep;
X	}
X}
END_OF_FILE
if test 6929 -ne `wc -c <'cb.c'`; then
    echo shar: \"'cb.c'\" unpacked with wrong size!
fi
# end of 'cb.c'
fi
if test -f 'shutdown' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'shutdown'\"
else
echo shar: Extracting \"'shutdown'\" \(363 characters\)
sed "s/^X//" >'shutdown' <<'END_OF_FILE'
Xsync
Xsync
X/etc/umount /dev/fd0 2>/dev/null
X/etc/umount /dev/fd1 2>/dev/null
X/etc/umount /dev/hd2 2>/dev/null
Xcp /usr/bin/echo /tmp
Xcp /usr/bin/true /tmp
Xcp /usr/bin/login /bin
Xif	/etc/umount /dev/hd3
X	then	/tmp/echo '				' NORMAL SYSTEM SHUTDOWN
X	while /tmp/true
X	do :
X	done
X	else	/tmp/echo cannot umount hard disk -- please kill processes
X		/tmp/echo type F9
Xfi
END_OF_FILE
if test 363 -ne `wc -c <'shutdown'`; then
    echo shar: \"'shutdown'\" unpacked with wrong size!
fi
chmod +x 'shutdown'
# end of 'shutdown'
fi
if test -f 'shut.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'shut.c'\"
else
echo shar: Extracting \"'shut.c'\" \(105 characters\)
sed "s/^X//" >'shut.c' <<'END_OF_FILE'
Xmain()
X{
X	close(0);
X	open("/etc/shutdown", 0);
X	execl("/bin/sh", "sh", 0);
X	printf("shutdown failed");
X}
END_OF_FILE
if test 105 -ne `wc -c <'shut.c'`; then
    echo shar: \"'shut.c'\" unpacked with wrong size!
fi
# end of 'shut.c'
fi
echo shar: End of shell archive.
exit 0


			Robert Regn							rtregn.faui32.uucp