[comp.sources.unix] v24i065: Purdue software product installation system, Part03/07

rsalz@uunet.uu.net (Rich Salz) (03/21/91)

Submitted-by: Kevin Braunsdorf <ksb@cc.purdue.edu>
Posting-number: Volume 24, Issue 65
Archive-name: pucc-install/part03

#!/bin/sh
# This is part 03 of pucc-1b
# ============= install.d/main.c ==============
if test ! -d 'install.d'; then
    echo 'x - creating directory install.d'
    mkdir 'install.d'
fi
if test -f 'install.d/main.c' -a X"$1" != X"-c"; then
	echo 'x - skipping install.d/main.c (File already exists)'
else
echo 'x - extracting install.d/main.c (Text)'
sed 's/^X//' << 'Purdue' > 'install.d/main.c' &&
/*
X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
X * 47907.  All rights reserved.
X *
X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
X *
X * This software is not subject to any license of the American Telephone
X * and Telegraph Company or the Regents of the University of California.
X *
X * Permission is granted to anyone to use this software for any purpose on
X * any computer system, and to alter it and redistribute it freely, subject
X * to the following restrictions:
X *
X * 1. Neither the authors nor Purdue University are responsible for any
X *    consequences of the use of this software.
X *
X * 2. The origin of this software must not be misrepresented, either by
X *    explicit claim or by omission.  Credit to the authors and Purdue
X *    University must appear in documentation and sources.
X *
X * 3. Altered versions must be plainly marked as such, and must not be
X *    misrepresented as being the original software.
X *
X * 4. This notice may not be removed or altered.
X */
X
/*
X * install
X *	Install a <file> and back up the existing file to a standard
X *	location (normally a sub-directory named "OLD").  The name is always
X *	"OLD/<file>".  Name clashes in OLD are resolved by renaming an existing
X *	OLD/<file> to OLD/<file><pid>.  The OLD files should be cleaned
X *	up with a script that removes aged files (see purge(1l)).
X *
X * Authors:
X *	Jeff Smith (jms) & Kevin Braunsdorf (ksb)
X *	Purdue University Computing Center
X *	Math Building, Purdue, West Lafayette, IN, 47906
X *
X *	15 Nov 1985	to	01 June 1990
X *
X * Usage
X *	install [options] file [files] destination
X *	install -d [options] directory
X *	install -R [options] file
X *	install -[Vh]
X *
X * 	file(s):	an absolute or relative path.  If > 1 file to
X *		install is specified, destination must be a directory.
X *
X *	destination:	a pathname ending in either the destination
X *		directory or a filename which may be the same as or different
X *		than the tail of file(s).
X *
X * mk(1l) stuff:
X * $Compile: make all
X * $Compile: SYS=bsd make all
X * $Compile: SYS=SYSV make all
X *
X * Environment:
X *	Set the environment variable INSTALL to any of the options to get the
X *	same effect as using them on the command line (e.g., INSTALL="-c").
X *	Command line options silently override environental variables.
X *
X * N.B.
X *	+ "OLD" directories may *not* be mount points!
X *	+ the TMPINST macro file may be removed by purge after only few hours
X *
X * BUGS:
X *	+ competing installs can (still) loose data :-{!
X *	  if two users are installing the same file at the same time
X *	  we can loose one of the two updates, use the flock(1)
X *	  command on the destination directory to avoid this in the shell.
X *	  (using flock(2) we *could* avoid this, see notes in main)
X *		flock ${BIN} install -vs ${PROG} ${BIN}
X */
X
#if !defined(lint)
static char *rcsid = "$Id: main.c,v 7.0 90/09/17 09:41:57 ksb Exp $";
#endif	/* !lint */
X
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
X
#include "configure.h"
#include "install.h"
#include "syscalls.h"
#include "special.h"
#include "file.h"
#include "dir.h"
#include "main.h"
X
#if STRINGS
#include <strings.h>
#else
#include <string.h>
#endif
X
extern char *realloc(), *malloc();
X
#include "getopt.h"		/* char *optarg; int optind;		*/
#if !defined(BADCH)		/* char getopt returns for illegal options */
#define	BADCH	((int) '\?')
#endif	/* !BADCH */
X
X
/* global variables for options
X */
char *progname;			/* tail of argv[0]			*/
char *Group = (char *)0;	/* given group ownership		*/
char *Owner = (char *)0;	/* given owner				*/
char *Mode = (char *)0;		/* given mode				*/
char *HardLinks = (char *)0;	/* hard links to installed file		*/
char *SoftLinks = (char *)0;	/* symlinks to installed file		*/
int Copy = FALSE;		/* we're copying			*/
int Destroy = FALSE;		/* user doesn't want an OLD		*/
int BuildDir = FALSE;		/* we're installing a directory		*/
int KeepTimeStamp = FALSE;	/* if preserving timestamp		*/
int fQuiet = FALSE;		/* suppress some errors, be quiet	*/
int Ranlib = FALSE;		/* if we're running ranlib(1)		*/
int Strip = FALSE;		/* if we're running strip(1)		*/
int fDelete = FALSE;		/* uninstall the given file/dir		*/
int fRecurse = FALSE;		/* Sun-like recursive dir install	*/
int fTrace = FALSE;		/* if just tracing			*/
int fVerbose = FALSE;		/* if verbose				*/
int f1Copy = FALSE;		/* only keep one copy			*/
#if defined(CONFIG)
struct passwd *pwdDef;		/* aux default owner for config file	*/
struct group *grpDef;		/* aux default group for config file	*/
char *pcSpecial = CONFIG;	/* file contains ckecked paths		*/
#endif	/* have a -C option?			*/
X
/*
X * global variables, but not option flags
X */
int bHaveRoot;			/* we have root permissions		*/
char *pcGuilty;			/* the name logged as the installer	*/
static char copyright[] =
X   "@(#) Copyright 1990 Purdue Research Foundation. All rights reserved.\n";
X
X
/*
X * Print detailed usage info
X */
static char *apcHelp[] = {
X	"1        keep exactly one backup of the installed file",
#if defined(CONFIG)
X	"C config use <config> to check for special files",
#endif /* no -C option to list			*/
X	"D        destroy <destination> (no backup)",
X	"H links  hard links to update (colon separated)",
X	"R        remove the given target",
#if HAVE_SLINKS
X	"S links  symbolic links to update (colon separated)",
#endif	/* no symbolic links to worry about	*/
X	"V        explain compiled in default modes",
X	"c        copy <file> instead of renaming it",
X	"d        install a directory (mkdir with specified mode/group/owner)",
X	"g group  install <file|directory> with group <group>",
X	"h        help (print this)",
X	"l        run ranlib(1) on <file>",
X	"m mode   install <file|directory> with mode <mode>",
X	"n        trace execution but do not do anything",
X	"o owner  install <file|directory> with owner <owner>",
X	"p        preserve timestamp of file being installed",
X	"q        if install can recover from the error be quiet",
X	"r        build all intervening directories",
X	"s        run strip(1) on <file>",
X	"v        run ls(1) on installed files and backups",
X	(char *)0
};
X
#if defined(CONFIG)
char acVArgs[] =
X	"[-C config]";
char acDArgs[] =
X	"[-nqrv] [-C config] [-g group] [-m mode] [-o owner]";
#if HAVE_SLINKS
char acOArgs[] =
X	"[-1Dclnpqsv] [-C config] [-H links] [-S links] [-g group] [-m mode] [-o owner]";
#else
char acOArgs[] =
X	"[-1Dclnpqsv] [-C config] [-H links] [-g group] [-m mode] [-o owner]";
#endif
X
#else	/* change usage messgae, reflect CONFIG	*/
char acVArgs[] =
X	"";
char acDArgs[] =
X	"[-nqrv] [-g group] [-m mode] [-o owner]";
#if HAVE_SLINKS
char acOArgs[] =
X	"[-1Dclnpqsv] [-H links] [-S links] [-g group] [-m mode] [-o owner]";
#else
char acOArgs[] =
X	"[-1Dclnpqsv] [-H links] [-g group] [-m mode] [-o owner]";
#endif
#endif /* no -C option to list			*/
X
/*
X * Output a useful, std usage message. Maybe a longer one if requested	(ksb)
X */
static void
Usage(fp, bVerbose)
FILE *fp;		/* file to output to				*/
int bVerbose;		/* should we explain options more		*/
{
X	register char **ppc;
X
X	(void)fprintf(fp, "%s: usage %s files destination\n", progname, acOArgs);
X	(void)fprintf(fp, "%s: usage -d %s directory\n", progname, acDArgs);
X	(void)fprintf(fp, "%s: usage -h\n", progname);
X	(void)fprintf(fp, "%s: usage -R [options] target\n", progname);
X	(void)fprintf(fp, "%s: usage -V %s\n", progname, acVArgs);
X	if (bVerbose) {
X		for (ppc = apcHelp; (char *)0 != *ppc; ++ppc) {
X			(void)fprintf(fp, *ppc, OLDDIR);
X			(void)fputc('\n', fp);
X		}
X		fprintf(fp, "%s", copyright);
X	}
}
X
X
/*
X * first non-nil argument						(ksb)
X */
static char *
nonnil(pc1, pc2)
char *pc1, *pc2;
{
X	if ((char *)0 != pc1)
X		return pc1;
X	if ((char *)0 != pc2)
X		return pc2;
#if defined(DEBUG)
X	Die("nil pointer in nonnil");
#endif
X	return (char *)0;
}
X
/*
X * explain to the poor user what install will use as modes here		(ksb)
X */
static void
Explain(fp)
FILE *fp;
{
X	static char acDMsg[] = "inherited";
X	auto struct passwd *pwd;	/* owner of this dir.		*/
X	auto struct group *grp;		/* group of this directory	*/
X
X	(void)fprintf(fp, "%s: version: %s\n", progname, "$Id: main.c,v 7.0 90/09/17 09:41:57 ksb Exp $");
#if defined(CONFIG)
X	(void)fprintf(fp, "%s: configuration file: %s, owner = %s, group = %s\n", progname, ((char *)0 == pcSpecial || '\000' == *pcSpecial) ? "(none)" : pcSpecial, (struct passwd *)0 != pwdDef ? pwdDef->pw_name : acDMsg, (struct group *)0 != grpDef ? grpDef->gr_name : acDMsg);
#endif
#if defined(INST_FACILITY)
X	(void)fprintf(fp, "%s: syslog facility: %d\n", progname, INST_FACILITY);
#endif
X	(void)fprintf(fp, "%s: superuser (%s) defaults:\n", progname, pcGuilty);
X	(void)fprintf(fp, "%s: owner is file=%-10s dir=%-10s %s=%s\n", progname,
X		nonnil(DEFOWNER, acDMsg),
X		nonnil(DEFDIROWNER, acDMsg),
X		OLDDIR,
X		nonnil(ODIROWNER, acDMsg)
X	);
X	(void)fprintf(fp, "%s: group is file=%-10s dir=%-10s %s=%s\n", progname,
X		nonnil(DEFGROUP, acDMsg),
X		nonnil(DEFDIRGROUP, acDMsg),
X		OLDDIR,
X		nonnil(ODIRGROUP, acDMsg)
X	);
X	(void)fprintf(fp, "%s: mode is  file=%-10s dir=%-10s %s=%s\n", progname,
X		nonnil(DEFMODE, acDMsg),
X		nonnil(DEFDIRMODE, acDMsg),
X		OLDDIR,
X		nonnil(ODIRMODE, acDMsg)
X	);
X
X	if (bHaveRoot) {
X		/* we assume the super user doesn't care about Joe User */
X		return;
X	}
X
X	(void)setpwent();
X	if ((struct passwd *)0 == (pwd = getpwuid((int) geteuid()))) {
X		(void)fprintf(stderr, "%s: getpwuid: %d (effective uid) not found\n", progname, geteuid());
X		exit(1);
X	}
X	(void)endpwent();
X
X	(void)setgrent();
X	if ((struct group *)0 == (grp = getgrgid((int) getegid()))) {
X		(void)fprintf(stderr, "%s: getgrgid: %d (effective gid) not found\n", progname, getegid());
X		exit(1);
X	}
X	(void)endgrent();
X	(void)fprintf(fp, "%s: user defaults:\n", progname);
X	(void)fprintf(fp, "%s: owner is file=%-10s dir=%-10s %s=%s\n", progname,
X		pwd->pw_name,
X		pwd->pw_name,
X		OLDDIR,
X		pwd->pw_name
X	);
X	(void)fprintf(fp, "%s: group is file=%-10s dir=%-10s %s=%s\n", progname,
X		grp->gr_name,
X		grp->gr_name,
X		OLDDIR,
X		grp->gr_name
X	);
X	(void)fprintf(fp, "%s: mode is  file=%-10s dir=%-10s %s=%s\n", progname,
X		nonnil(DEFMODE, acDMsg),
X		nonnil(DEFDIRMODE, acDMsg),
X		OLDDIR,
X		nonnil(ODIRMODE, acDMsg)
X	);
}
X
X
static char acOutMem[] = "%s: out of memory\n";
/*
X * OptAccum
X * Accumulate a string, for string options that "append with a sep"	(ksb)
X * note: arg must start out as either "(char *)0" or a malloc'd string
X */
static char *
OptAccum(pcOld, pcArg, pcSep)
char *pcOld, *pcArg, *pcSep;
{
X	register int len;
X	register char *pcNew;
X
X	/* Do not add null strings
X	 */
X	len = strlen(pcArg);
X	if (0 == len) {
X		return pcOld;
X	}
X
X	if ((char *)0 == pcOld) {
X		pcNew = malloc(len+1);
X		if ((char *)0 == pcNew) {
X			(void)fprintf(stderr, acOutMem, progname);
X			exit(1);
X		}
X		pcNew[0] = '\000';
X	} else {
X		len += strlen(pcOld)+strlen(pcSep)+1;
X		if ((char *)0 == (pcNew = realloc(pcOld, len))) {
X			(void)fprintf(stderr, acOutMem, progname);
X			exit(1);
X		}
X		(void)strcat(pcNew, pcSep);
X	}
X	pcOld = strcat(pcNew, pcArg);
X	return pcOld;
}
X
X
/*
X * parse options with getopt and install files
X */
int
main(argc, argv)
int argc;
char **argv;
{
X	extern char *getenv();	/* we want an env var			*/
X	extern char *getlogin();
X	static char Opts[] =	/* valid options			*/
X		"1cC:dDg:hH:lm:no:pqrRsS:vV";
X	auto char *pcEnv;	/* options passed through env		*/
X	auto char *Dest;	/* destination dir or filename		*/
X	auto int iOption;	/* argument pointer			*/
X	auto int iFailed;	/* installs that failed			*/
X	auto int iArgs;		/* args left after option processing	*/
X	auto int fExplain;	/* tell the user about our defaults	*/
X
X	(void)umask(022);
X
X	/* Figure out our name and fix argv[0] for getopt() if necessary.
X	 */
X	progname = StrTail(argv[0]);
X	if (NULL == progname || '\000' == *progname)
X		progname = "install";
X	/* here we become deinstall, or deinstallp
X	 * a little gem for those who like to pick through source code...
X	 */
X	if ('d' == progname[0] && 'e' == progname[1]) {
X		fDelete = TRUE;
X	}
X	iFailed = 0;
X
X	/* Check for environtment options
X	 */
X	if ((char *)0 != (pcEnv = getenv("INSTALL"))) {
X		envopt(pcEnv);
X	}
X
X	/* See if we have root permissions, this changes default modes/owners
X	 */
X	bHaveRoot = 0 == geteuid();
X
X	/* Parse command line options, set flags, etc.
X	 */
X	fExplain = FALSE;
X	while (EOF != (iOption = getopt(argc, argv, Opts))) {
X		switch (iOption) {
X		case '1':
X			f1Copy = TRUE;
X			break;
X		case 'c':	/* copy		*/
X			Copy = TRUE;
X			break;
X		case 'C':	/* check list	*/
#if defined(CONFIG)
X			pcSpecial = optarg;
X			break;
#else /* give them an error */
X			(void)fprintf(stderr, "%s: check list option not installed\n", progname);
X			exit(EXIT_OPT);
#endif	/* set check flags from config file	*/
X		case 'S':	/* soft links	*/
#if HAVE_SLINKS
X			SoftLinks = OptAccum(SoftLinks, optarg, ":");
X			break;
#else	/* no symlink, warn and use hard ones	*/
X			(void)fprintf(stderr, "%s: no symbolic links here, trying hard links\n", progname);
X			/*fall through*/
#endif	/* handle -S based on OS		*/
X		case 'H':	/* hard links	*/
X			HardLinks = OptAccum(HardLinks, optarg, ":");
X			break;
X		case 'd':	/* directory	*/
X			BuildDir = TRUE;
X			break;
X		case 'D':	/* destroy	*/
X			Destroy = TRUE;
X			break;
X		case 'g':	/* change group	*/
X			Group = optarg;
X			break;
X		case 'h':	/* help		*/
X			Usage(stdout, 1);
X			exit(0);
X			break;
X		case 'l':	/* ranlib	*/
X			Ranlib = TRUE;
X			break;
X		case 'm':	/* change mode	*/
X			Mode = optarg;
X			break;
X		case 'n':	/* execution trace */
X			fTrace = TRUE;
X			break;
X		case 'o':	/* change owner	*/
X			Owner = optarg;
X			break;
X		case 'p':	/* preserve time */
X			KeepTimeStamp = TRUE;
X			break;
X		case 'q':	/* be quiet */
X			fQuiet = TRUE;
X			break;
X		case 'r':	/* install -d -r /a/b build /a and /a/b */
X			fRecurse = TRUE;
X			break;
X		case 'R':	/* deintstall	*/
X			fDelete = TRUE;
X			break;
X		case 's':	/* strip(1)	*/
X			Strip = TRUE;
X			break;
X		case 'v':	/* run ls(1)	*/
X			fVerbose = TRUE;
X			break;
X		case 'V':
X			fExplain = TRUE;
X			break;
X		case BADCH:	/* illegal option */
X			Usage(stderr, 0);
X			exit(EXIT_OPT);
X			break;
X		/* Since getopt should have caught all problems, this has
X		 * to be an error
X		 */
X		default:
X			Die("command line parsing bug");
X		}
X	}
X
X	/* Usage checks.  If installing > 1 file, the destination
X	 * must be a directory which already exists.
X	 */
X	if (FALSE != Strip && FALSE != Ranlib) {
X		(void)fprintf(stderr, "%s: options `-l\' and `-s\' are incompatible\n", progname);
X		exit(EXIT_OPT);
X	}
X	if (FALSE != Ranlib && FALSE != KeepTimeStamp) {
X		(void)fprintf(stderr, "%s: option `-l\' suppresses `-p\'\n", progname);
X	}
X	if ((char *)0 != Mode) {
X		auto char *pcMsg; /* error, build a b,c,s,l,p message	*/
X		auto int mMust;	  /* bits in mode to build		*/
X		auto int m_Opt;	  /* discard optional bits		*/
X		auto char chType;
X		auto char *pcUse;
X		auto char acShow[20];
X
X		CvtMode(Mode, & mMust, & m_Opt);
X		pcMsg = NodeType(mMust, &chType);
X		switch (chType) {
X		case 'd':
X			BuildDir = TRUE;
X			break;
X		case '-':
X			break;
X		case 's':
X			for (;;) {
X				pcUse = "a server";
X				break;
X		case 'l':
X				pcUse = "ln -s";
X				break;
X		case 'p':
X		case 'b':
X		case 'c':
X				(void)sprintf(acShow, "mknod %c", chType);
X				pcUse = acShow;
X				break;
X			}
X		default:
X			(void)fprintf(stderr, "%s: to build a %s use %s\n", progname, pcMsg, pcUse);
X			exit(1);
X		}
X	}
X
#if defined(INST_FACILITY)
X	if (bHaveRoot && FALSE == fTrace) {
X		openlog(progname, 0, INST_FACILITY);
X	}
#endif	/* we need to start syslog		*/
X	pcGuilty = getlogin();
X	if ((char *)0 == pcGuilty || '\000' == *pcGuilty) {
X		pcGuilty = getenv("USER");
X		if ((char *)0 == pcGuilty || '\000' == *pcGuilty)
X			pcGuilty = "root\?";
X	}
X
#if defined(CONFIG)
X	InitCfg((char *)0, (char *)0);
#endif
X
X	iArgs = argc - optind;
X	if (FALSE != fExplain) {
X		Explain(stdout);
X	} else if (FALSE != BuildDir) {
X		auto char *pcSlash, *pcDir;
X
X		/* this check keeps Joe Bogus from having
X		 *  INSTALL=-vd
X		 * in the environment break every program that uses install.
X		 */
X		if (1 != iArgs) {
X			(void)fprintf(stderr, "%s: only a single directory name may be given with -d\n", progname);
X			Usage(stderr, 0);
X			exit(EXIT_OPT);
X		}
X		if ((char *)0 != HardLinks) {
X			(void)fprintf(stderr, "%s: directories cannot have mulitple hard links, use -S\n", progname);
X			exit(EXIT_OPT);
X		}
X		if ((FALSE != Destroy || FALSE != f1Copy) && FALSE == fQuiet) {
X			(void)fprintf(stderr, "%s: -d ignores -D and -1\n", progname);
X		}
X		if ((FALSE != Strip || FALSE != Ranlib) && FALSE != fQuiet) {
X			(void)fprintf(stderr, "%s: -d cannot strip or ranlib a directory\n", progname);
X		}
X
X		/* StrTail cuts trailing '/'s
X		 * If we are building an OLD dir do it correctly
X		 */
X		pcDir = argv[argc-1];
X		if (0 == strcmp(OLDDIR, StrTail(pcDir))) {
X			pcSlash = strrchr(pcDir, '/');
X			if ((char *)0 == pcSlash) {
X				/* nothing to do, in `pwd` */;
X			} else if (pcSlash == pcDir) {
X				/* build "/", sure... done */;
X			} else if (FALSE != fRecurse) {
X				*pcSlash = '\000';
X				if (!fDelete && FAIL == DirInstall(pcDir, Owner, Group, Mode, DEFDIROWNER, DEFDIRGROUP, DEFDIRMODE, (char *)0, 0)) {
X					exit(1);
X				}
X				*pcSlash = '/';
X				/* yeah, odd... but -n look right this way */
X				fRecurse = FALSE;
X			}
X			/* letting the user symlink to an OLD dir is very
X			 * bogus, we do it only because I cannot think
X			 * of a good error message.... (ksb)
X			 */
X			if (FAIL == DirInstall(pcDir, FALSE == bHaveRoot ? (char *)0 : ODIROWNER, FALSE == bHaveRoot ? (char *)0 : ODIRGROUP, ODIRMODE, (char *)0, (char *)0, (char *)0, SoftLinks, fDelete)) {
X				exit(1);
X			}
X		} else if (FAIL == DirInstall(pcDir, Owner, Group, Mode, DEFDIROWNER, DEFDIRGROUP, DEFDIRMODE, SoftLinks, fDelete)) {
X			exit(1);
X		}
X	} else if (fDelete) {
X		if (iArgs != 1) {
X			(void)fprintf(stderr, "%s: just give one target to remove\n", progname);
X			Usage(stderr, 0);
X			exit(EXIT_OPT);
X		}
X		if (FALSE != Destroy) {
X			(void)fprintf(stderr, "%s: -D changed to -1 to preserve last copy of target\n", progname);
X			Destroy = FALSE;
X			f1Copy = TRUE;
X		}
X		if (FAIL == Install("-", argv[optind], HardLinks, SoftLinks)) {
X			++iFailed;
X		}
X	} else {
X		if (iArgs < 2) {
X			(void)fprintf(stderr, "%s: need both source and destination\n", progname);
X			Usage(stderr, 0);
X			exit(EXIT_OPT);
X		}
X
X		Dest = argv[argc - 1];
X		if (iArgs > 2 && IsDir(Dest) == FALSE) {
X			(void)fprintf(stderr, "%s: `%s\' must be an existing directory to install multiple files or directories\n", progname, Dest);
X			Usage(stderr, 0);
X			exit(EXIT_OPT);
X		}
X
X		if (iArgs > 2 && ((char *)0 != HardLinks || (char *)0 != SoftLinks)) {
X			(void)fprintf(stderr, "%s: -H or -S option ambiguous with multiple source files\n", progname);
X			exit(EXIT_OPT);
X		}
X
X		/* install the files
X		 */
X		for (--argc; optind < argc; optind++) {
X			if (FAIL == Install(argv[optind], Dest, HardLinks, SoftLinks)) {
X				(void)fprintf(stderr, "%s: installation of `%s\' failed\n", progname, argv[optind]);
X				++iFailed;
X			}
X		}
X	}
X
#if defined(INST_FACILITY)
X	if (bHaveRoot && FALSE == fTrace) {
X		closelog();
X	}
#endif	/* close-m up for now			*/
X
X	exit(iFailed);
}
Purdue
chmod 0444 install.d/main.c ||
echo 'restore of install.d/main.c failed'
Wc_c="`wc -c < 'install.d/main.c'`"
test 19085 -eq "$Wc_c" ||
	echo 'install.d/main.c: original size 19085, current size' "$Wc_c"
fi
# ============= install.d/syscalls.c ==============
if test -f 'install.d/syscalls.c' -a X"$1" != X"-c"; then
	echo 'x - skipping install.d/syscalls.c (File already exists)'
else
echo 'x - extracting install.d/syscalls.c (Text)'
sed 's/^X//' << 'Purdue' > 'install.d/syscalls.c' &&
/*
X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
X * 47907.  All rights reserved.
X *
X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
X *
X * This software is not subject to any license of the American Telephone
X * and Telegraph Company or the Regents of the University of California.
X *
X * Permission is granted to anyone to use this software for any purpose on
X * any computer system, and to alter it and redistribute it freely, subject
X * to the following restrictions:
X *
X * 1. Neither the authors nor Purdue University are responsible for any
X *    consequences of the use of this software.
X *
X * 2. The origin of this software must not be misrepresented, either by
X *    explicit claim or by omission.  Credit to the authors and Purdue
X *    University must appear in documentation and sources.
X *
X * 3. Altered versions must be plainly marked as such, and must not be
X *    misrepresented as being the original software.
X *
X * 4. This notice may not be removed or altered.
X */
X
/*
X * filer the unix system calls so they are more verbose or ineffective	(ksb)
X * under some options
X */
#if !defined(lint)
static char *rcsid = "$Id: syscalls.c,v 7.2 90/10/23 11:01:40 ksb Exp $";
#endif	/* !lint */
X
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
X
#include "configure.h"
#include "install.h"
#include "main.h"
X
#if STRINGS
#include <strings.h>
#else
#include <string.h>
#endif
X
extern char *malloc();
X
X
#if !defined(BINCHGRP)
#define BINCHGRP	"/bin/chgrp"
#endif
X
static char acChgrp[] =		/* full path name to chgrp		*/
X	BINCHGRP;
X
X
static int iSigsBlocked = 0;	/* count nested calls			*/
X
#if defined(pdp11) || defined(SYSV) || defined(HPUX7)
#else	/* BSD */
static int OldSigMask;		/* old signal mask			*/
#endif	/* mask singals old way */
/*
X * Mask all maskable signals					     (jsmith)
X * is we mask CHLD ranlib breaks (actually the shell does)
X */
void
BlockSigs()
{
X	if (0 == iSigsBlocked++) {
#if defined(pdp11) || defined(SYSV) || defined(HPUX7)
X		register int	i;
X		for (i = 0; i < NSIG; i++) {
X			signal(i, SIG_IGN);
X		}
#else	/* BSD */
X		register int Mask;
X		Mask = sigmask(SIGHUP)|sigmask(SIGTERM)|
X			sigmask(SIGINT)|sigmask(SIGTSTP)|sigmask(SIGQUIT);
X		OldSigMask = sigsetmask(Mask);
#endif	/* do signal stuff */
X	}
}
X
X
/*
X * Return the signal mask to what it was in before BlockSigs()	     (jsmith)
X */
void
UnBlockSigs()
{
X	if (0 == --iSigsBlocked) {
#if defined(pdp11) || defined(SYSV) || defined(HPUX7)
X		register int i;
X
X		for (i = 0; i < NSIG; i++) {
X			signal(i, SIG_DFL);
X		}
#else	/* BSD */
X		(void)sigsetmask(OldSigMask);
#endif	/* more signal stuff */
X	}
}
X
X
/*
X * install suffers an internal error and exits abruptly			(ksb)
X * (really just a good break point for dbx/gdb/sdb)
X */
void
Die(pcError)
char *pcError;		/* error message, last gasp as we croak		*/
{
X	(void)fprintf(stderr, "%s: internal error: %s\n", progname, pcError);
X	exit(EXIT_INTER);
}
X
X
#define safecopy(Mdst, Msrc, Mfield, Mpc) \
X	if ((char *)0 != Msrc->Mfield) { \
X		Mdst->Mfield = Mpc; \
X		(void)strcpy(pc, Msrc->Mfield); \
X		Mpc = strchr(Mpc, '\000')+1; \
X	} else { \
X		Mdst->Mfield = (char *)0;\
X	}
X
X
/*
X * this routine saves a group entry in malloced memory			(ksb)
X * simply free it when you are done with it
X */
struct group *
savegrent(pGR)
struct group *pGR;
{
X	register struct group *pGRNew;
X	register int size, i;
X	register char *pc;
X	auto char **ppc;
X
X	if ((struct group *)0 == pGR) {
X		return (struct group *)0;
X	}
X
X	size = sizeof(struct group);
X	if ((char *)0 != pGR->gr_name)
X		size += strlen(pGR->gr_name)+1;
X	if ((char *)0 != pGR->gr_passwd)
X		size += strlen(pGR->gr_passwd)+1;
X	for (i = 0; (char *)0 != pGR->gr_mem[i]; ++i) {
X		size += sizeof(char *) + strlen(pGR->gr_mem[i]) + 1;
X	}
X	size += sizeof(char *);
X
X	if ((char *)0 == (pc = malloc(size))) {
X		return (struct group *)0;
X	}
X
X	pGRNew = (struct group *)pc;
X	pc += sizeof(struct group);
X
X	ppc = (char **) pc;
X	pc += (1+i) * sizeof(char *);
X
X	safecopy(pGRNew, pGR, gr_name, pc);
X	safecopy(pGRNew, pGR, gr_passwd, pc);
X
X	pGRNew->gr_gid = pGR->gr_gid;
X
X	pGRNew->gr_mem = ppc;
X	for (i = 0; (char *)0 != pGR->gr_mem[i]; ++i) {
X		*ppc++ = pc;
X		(void)strcpy(pc, pGR->gr_mem[i]);
X		pc = strchr(pc, '\000')+1;
X	}
X	*ppc = (char *)0;
X
X	return pGRNew;
}
X
X
/*
X * this routine saves a passwd entry in malloced memory			(ksb)
X * simply free it when you are done with it
X */
struct passwd *
savepwent(pPW)
struct passwd *pPW;
{
X	register struct passwd *pPWNew;
X	register int size;
X	register char *pc;
X
X	if ((struct passwd *)0 == pPW) {
X		return (struct passwd *)0;
X	}
X	size = sizeof(struct passwd);
X	if ((char *)0 != pPW->pw_name)
X		size += strlen(pPW->pw_name) +1;
X	if ((char *)0 != pPW->pw_passwd)
X		size += strlen(pPW->pw_passwd) +1;
X	if ((char *)0 != pPW->pw_comment)
X		size += strlen(pPW->pw_comment) +1;
X	if ((char *)0 != pPW->pw_gecos)
X		size += strlen(pPW->pw_gecos) +1;
X	if ((char *)0 != pPW->pw_dir)
X		size += strlen(pPW->pw_dir) +1;
X	if ((char *)0 != pPW->pw_shell)
X		size += strlen(pPW->pw_shell) +1;
X
X	if ((char *)0 == (pc = malloc(size))) {
X		return (struct passwd *)0;
X	}
X	pPWNew = (struct passwd *)pc;
X	pc += sizeof(struct passwd);
X	safecopy(pPWNew, pPW, pw_name, pc);
X	safecopy(pPWNew, pPW, pw_passwd, pc);
X	pPWNew->pw_uid = pPW->pw_uid;
X	pPWNew->pw_gid = pPW->pw_gid;
#if HAVE_QUOTA
X	pPWNew->pw_quota = pPW->pw_quota;
#endif
X
X	safecopy(pPWNew, pPW, pw_comment, pc);
X	safecopy(pPWNew, pPW, pw_gecos, pc);
X	safecopy(pPWNew, pPW, pw_dir, pc);
X	safecopy(pPWNew, pPW, pw_shell, pc);
X
X	return pPWNew;
}
X
#undef	safecopy
X
X
X
/*
X * ChMode()
X *	run chmod(2) on file, or trace doing so
X */
void
ChMode(pcFile, mMode)
char *pcFile;		/* pathname of file to change			*/
int mMode;		/* mode to change to				*/
{
X	mMode = PERM_BITS(mMode);
X	if (FALSE != fTrace) {
X		(void)printf("%s: chmod %o %s\n", progname, mMode, pcFile);
X	} else if (-1 == chmod(pcFile, mMode)) {
X		(void)fprintf(stderr, "%s: chmod (%04o): %s: %s\n", progname, mMode, pcFile, strerror(errno));
X	}
}
X
X
/*
X * ChGroup()
X *	run chgrp(1) on file (for when we are NOT root)
X *
X * Globals:
X *	Group	- character string specifying the group owner
X */
void
ChGroup(pcFile, pgroup)
char *pcFile;		/* pathname of file to change group of		*/
struct group *pgroup;	/* info on group				*/
{
X	if (RunCmd(acChgrp, pgroup->gr_name, pcFile) != 0) {
X		(void)fprintf(stderr, "%s: `%s %s %s\' failed\n", progname, acChgrp, pgroup->gr_name, pcFile);
X	}
}
X
X
/*
X * ChOwnGrp()
X *	Change the ownership and group of a file (must be root)
X */
void
ChOwnGrp(pcFile, powner, pgroup)
char *pcFile;		/* the pathname of the file to change		*/
struct passwd *powner;	/* info for owner of file			*/
struct group *pgroup;	/* info for group of file			*/
{
X	if (FALSE != fTrace) {
X		(void)printf("%s: chown %s %s\n", progname, powner->pw_name, pcFile);
X		(void)printf("%s: chgrp %s %s\n", progname, pgroup->gr_name, pcFile);
X	} else if (-1 == chown(pcFile, powner->pw_uid, pgroup->gr_gid)) {
X		(void)fprintf(stderr, "%s: chown: %s: %s\n", progname, pcFile, strerror(errno));
X		/*return anyway*/
X	}
}
X
X
/*
X * ChTimeStamp()
X *	Change the time stamp of an installed file to match the original
X *	timestamp of the file to install
X */
void
ChTimeStamp(pcFile, pSTTimes)
char *pcFile; 		/* the pathname of the file to change		*/
struct stat *pSTTimes;	/* stat buffer containing timestamp of exemplar	*/
{
#if defined(SYSV) || defined(HPUX7)
X	auto time_t tv[2];
X
X	tv[0] = pSTTimes->st_atime;
X	tv[1] = pSTTimes->st_mtime;
X	if (-1 == utime(pcFile, tv)) {
X		(void)fprintf(stderr, "%s: utime: %s: %s\n", progname, pcFile, strerror(errno));
X	}
#else /* BSD */
X	auto struct timeval tv[2];
X
X	tv[0].tv_sec = pSTTimes->st_atime;
X	tv[1].tv_sec = pSTTimes->st_mtime;
X	tv[0].tv_usec = tv[1].tv_usec = 0;
X	if (-1 == utimes(pcFile, tv)) {
X		(void)fprintf(stderr, "%s: utimes: %s: %s\n", progname, pcFile, strerror(errno));
X	}
#endif	/* BSD */
}
X
/*
X * DoCopy()
X *	Copy the file "File" to file "Dest"
X */
int
DoCopy(File, Dest)
char *File;		/* the file to copy				*/
char *Dest;		/* the target (destination) file		*/
{
X	register int fdSrc;	/* file descriptors			*/
X	register int fdDest;	/* file to dopy to			*/
X	register int n;		/* number of chars read			*/
X	register int fStdin;	/* are we doing stdin			*/
X	auto char acBlock[BLKSIZ];
X	auto struct stat statb_File;
X
X
X	fStdin = '-' == File[0] && '\000' == File[1];
X
X	if (FALSE != fTrace) {
X		if (fStdin)
X			(void)printf("%s: cat - >%s\n", progname, Dest);
X		else
X			(void)printf("%s: cp %s %s\n", progname, File, Dest);
X		return SUCCEED;
X	}
X
X	if (fStdin)
X		fdSrc = fileno(stdin);
X	else
#if defined(pdp11) || defined(SYSV)
X	if (-1 == (fdSrc = open(File, O_RDONLY))) {
X		(void)fprintf(stderr, "%s: open: %s: %s\n", progname, File, strerror(errno));
X	}
#else	/* BSD */
X	if (-1 == (fdSrc = open(File, O_RDONLY, 0400))) {
X		(void)fprintf(stderr, "%s: open: %s: %s\n", progname, File, strerror(errno));
X	}
#endif	/* do an open */
X
X	if (fstat(fdSrc, &statb_File) < 0) {
X		(void)fprintf(stderr, "%s: fstat: %s: %s\n", progname, File, strerror(errno));
X		if (!fStdin)
X			(void)close(fdSrc);
X		return FAIL;
X	}
X
X	/* we have to have rw- on the file to strip it later		(ksb)
X	 */
X	if (-1 == (fdDest = creat(Dest, (int)statb_File.st_mode|0600))) {
X		(void)fprintf(stderr, "%s: create: %s: %s\n", progname, Dest, strerror(errno));
X		if (!fStdin)
X			(void)close(fdSrc);
X		return FAIL;
X	}
X
X	/* Do the copy here
X	 */
X	while (0 != (n = read(fdSrc, acBlock, BLKSIZ))) {
X		if (-1 == n) {
X			(void)fprintf(stderr, "%s: read: %s: %s\n", progname, File, strerror(errno));
X			if (!fStdin)
X				(void)close(fdSrc);
X			(void)close(fdDest);
X			(void)unlink(Dest);
X			return FAIL;
X		}
X		if (write(fdDest, acBlock, n) != n) {
X			(void)fprintf(stderr, "%s: write: %s: %s\n", progname, Dest, strerror(errno));
X			if (!fStdin)
X				(void)close(fdSrc);
X			(void)close(fdDest);
X			(void)unlink(Dest);
X			return FAIL;
X		}
X	}
X
X	if (!fStdin)
X		(void)close(fdSrc);
X	(void)close(fdDest);
X
X	return SUCCEED;
}
X
X
/*
X * StrTail()
X *	return last element of a pathname
X */
char *
StrTail(pcPath)
register char *pcPath;	/* pathname to get tail of			*/
{
X	register char *pcTemp;
X
X	/* don't hand strlen() or strrchr() a null pointer
X	 */
X	if ((char *) NULL == pcPath) {
X		return (char *)NULL;
X	}
X
X	/* make sure we weren't handed something like "/a/b/" or "/a/b//".
X	 * If we were we don't want to return ++pcTemp
X	 */
X	while ('/' == *(pcTemp = (pcPath + strlen(pcPath)) - 1)) {
X		if (pcTemp == pcPath)
X			break;
X		*pcTemp = '\000';
X	}
X
X	/* return last element
X	 */
X	if ((char *) NULL == (pcTemp = strrchr(pcPath, '/')))
X		return pcPath;
X	return ++pcTemp;
}
X
X
/*
X * call mktemp is fTrace is not set, else replace XXXX... with $$	(ksb)
X */
char *
Mytemp(pcFile)
char *pcFile;
{
X	register char *pcRet;
X	extern char *mktemp();
X
X	if (FALSE != fTrace) {
X		if ((char *)0 == (pcRet = strchr(pcFile, '\000'))) {
X			Die("strchr: nil pointer");
X		}
X		while (pcRet > pcFile && 'X' == pcRet[-1])
X			--pcRet;
X		(void)strcpy(pcRet, "$$");
X		pcRet = pcFile;
X	} else if ((char *)0 == (pcRet = mktemp(pcFile))) {
X		Die("mktemp: nil pointer");
X	}
X	return pcRet;
}
X
X
/*
X * MungName()
X *	Mangle a pathname to make it unique (we hope)
X * (note that the pathname passed must be in a large buffer)
X */
void
MungName(pcName)
char	*pcName; 	/* the name of the file we want to change	*/
{
X	register char	*pcPat = PATMKTEMP;
X
#if defined(pdp11) || defined(SYSV)
#if defined(SYSV)
#define MAXNAMLEN	14
#endif	/* max path component length */
X	register char	*pcTemp;
X	register int	iPatLen;
X
X	/* Pathname components must be no longer than 14 chars on 2.9bsd
X	 * systems.  If necessary truncate the filename after the first
X	 * 8 chars so we can append "XXXXXX" for Mytemp()
X	 */
X	if ((pcTemp = strrchr(pcName, '/')) != (char *) 0) {
X		pcName = ++pcTemp;
X	}
X
X	iPatLen = strlen(pcPat);
X	if (strlen(pcName) + iPatLen > MAXNAMLEN) {
X		*(pcName + (MAXNAMLEN - iPatLen)) = '\000';
X	}
X
#endif	/* path name limits */
X
X	if (MAXPATHLEN < (strlen(pcName) + strlen(pcPat))) {	/* sanity */
X		(void)fprintf(stderr, "%s: unreasonably long pathname `%s\'\n", progname, pcName);
X		exit(EXIT_OPT);
X	}
X
X	/* This is real simple on reasonable operating systems
X	 */
X	(void)strcat(pcName, pcPat);
X	(void)Mytemp(pcName);
}
X
X
#if HAVE_SLINKS
/*
X * CopySLink()
X *	Copy a symbolic link; here we know that pcLink is a symbolic link,
X *	and pcCopy needs to be clone of it.
X *
X * Side Effects
X *	We might MungName our second argument, if we have to.
X */
int
CopySLink(pcLink, pcCopy)
char *pcLink, *pcCopy;
{
X	auto char acUcb[MAXPATHLEN+1];
X	auto int iUcbLen;
#if defined(DYNIX)
X	auto char acAtt[MAXPATHLEN+1];
X	auto int iAttLen;
#endif	/* conditional symbolic links			*/
X
#if defined(DYNIX)
X	if ((iAttLen = readclink(pcLink, acAtt, MAXPATHLEN, U_ATT)) <= 0) {
X		goto std_link;
X	} else if ((iUcbLen = readclink(pcLink, acUcb, MAXPATHLEN, U_UCB)) < 0) {
X		(void)fprintf(stderr, "%s: readclink(ucb): %s: %s\n", progname, pcLink, strerror(errno));
X		return FAIL;
X	}
X	acAtt[iAttLen] = '\000';
X	acUcb[iUcbLen] = '\000';
X	if ('/' != acAtt[0]) {
X		if ('/' != acUcb[0]) {
X			(void)fprintf(stderr, "%s: neither branch of `%s\' is a full path, link will not point the correct place in OLD\n", progname, pcLink);
X		} else {
X			(void)fprintf(stderr, "%s: att branch of `%s\' is not a full path, it will not point the correct place in OLD\n", progname, pcLink);
X		}
X	} else if ('/' != acUcb[0]) {
X		(void)fprintf(stderr, "%s: ucb branch of `%s\' is not a full path, it will not point the correct place in OLD\n", progname, pcLink);
X	}
X	if (FALSE != fTrace) {
X		(void)printf("%s: ln -c att=%s ucb=%s %s\n", progname, acAtt, acUcb, pcCopy);
X		return SUCCEED;
X	}
X	if (0 == csymlink(acUcb, acAtt, pcCopy)) {
X		return SUCCEED;
X	}
X	if (errno != EEXIST) {
X		(void)fprintf(stderr, "%s: csymlink: %s: %s\n", progname, pcCopy, strerror(errno));
X		return FAIL;
X	}
X	MungName(pcCopy);
X	if (0 != csymlink(acUcb, acAtt, pcCopy)) {
X		(void)fprintf(stderr, "%s: csymlink: %s: %s\n", progname, pcCopy, strerror(errno));
X		return FAIL;
X	}
X	return SUCCEED;
X
std_link:
X	/* dynix link code finds a nornal ucb link to copy -- fall into */;
#endif	/* might have to copy a csymlink	*/
X
X	if ((iUcbLen = readlink(pcLink, acUcb, MAXPATHLEN)) < 0) {
X		(void)fprintf(stderr, "%s: readlink: %s: %s\n", progname, pcLink, strerror(errno));
X		return FAIL;
X	}
X
X	acUcb[iUcbLen] = '\000';
X	if ('/' != acUcb[0]) {
X		(void)fprintf(stderr, "%s: link `%s\' is not a full path, it will not point the correct place in OLD\n", progname, pcLink);
X	}
X	if (FALSE != fTrace) {
X		(void)printf("%s: ln -s %s %s\n", progname, acUcb, pcCopy);
X		return SUCCEED;
X	}
X	if (0 == symlink(acUcb, pcCopy)) {
X		return SUCCEED;
X	}
X	if (errno != EEXIST) {
X		(void)fprintf(stderr, "%s: symlink: %s: %s\n", progname, pcCopy, strerror(errno));
X		return FAIL;
X	}
X	MungName(pcCopy);
X	if (0 != symlink(acUcb, pcCopy)) {
X		(void)fprintf(stderr, "%s: symlink: %s: %s\n", progname, pcCopy, strerror(errno));
X		return FAIL;
X	}
X	return SUCCEED;
}
#endif	/* don't handle links at all */
X
X
/*
X * Rename()
X *	Simulate the vax rename() syscall using link/unlink, or fTrace
X */
int
Rename(pcOrig, pcNew, pcNote)
char *pcOrig;		/* the original file name			*/
char *pcNew;		/* the name file will have after the rename	*/
char *pcNote;		/* tell the user always?			*/
{
X	register int fRet;
X
X	BlockSigs();
X
X	if ((char *)0 != pcNote) {
X		(void)printf("%s: %s %s to %s\n", progname, pcNote, pcOrig, pcNew);
X	}
X
X	fRet = SUCCEED;
X	if (FALSE != fTrace) {
X		(void)printf("%s: mv %s %s\n", progname, pcOrig, pcNew);
X	} else {
#if defined(pdp11) || defined(SYSV)
X		(void)unlink(pcNew);
X		if (-1 == link(pcOrig, pcNew)) {
X			(void)fprintf(stderr, "%s: link: %s to %s: %s\n", progname, pcOrig, pcNew, strerror(errno));
X			fRet = FAIL;
X		} else if (-1 == unlink(pcOrig)) {
X			(void)fprintf(stderr, "%s: unlink: %s: %s\n", progname, pcOrig, strerror(errno));
X			fRet = FAIL;
X		}
#else	/* have rename to call		*/
X		if (-1 == rename(pcOrig, pcNew)) {
X			(void)fprintf(stderr, "%s: rename: %s to %s: %s\n", progname, pcOrig, pcNew, strerror(errno));
X			fRet = FAIL;
X		}
#endif	/* need to invent rename	*/
X	}
X
X	UnBlockSigs();
X
X	return fRet;
}
X
/*
X * IsDir()
X *	find out if a file is a directory, or a symlink to a directory
X */
int
IsDir(dest)
char *dest;
{
X	auto struct stat statb;
X
X	if (-1 == stat(dest, &statb)) {
X		return FALSE;
X	}
X
X	if (S_IFDIR == (statb.st_mode & S_IFMT)) {
X		return TRUE;
X	}
X	return FALSE;
}
X
X
/*
X * MyWait()
X *	loop waiting until given child exits, return the childs status
X */
int
MyWait(pid)
int pid;		/* process id to wait for			*/
{
X	auto int wpid;
#if defined(pdp11) || defined(SYSV) || defined(HPUX7)
X	auto int status;
#else	/* BSD */
X	auto union wait	status;
#endif	/* set up for a wait */
X
X	while ((wpid = wait(&status)) != pid) {
X		if (wpid == -1)
X			break;
X	}
X
X	if (wpid == -1) {
X		/* this happens on the ETA, where did the kid go?
X		 */
X		if (ECHILD == errno)
X			return 0;
X		(void)fprintf(stderr, "%s: wait: %s\n", progname, strerror(errno));
X		return 1;
X	}
X
#if defined(pdp11) || defined(SYSV) || defined(HPUX7)
X	return status;
#else	/* BSD */
X	return status.w_status;
#endif	/* return value from wait */
}
X
X
/*
X * RunCmd()
X *	Vfork's & exec's a command and wait's for it to finish
X *	we return 1 for FAIL here, not FAIL, caller compares to 0
X *	(as this is the sh(1) convention).
X */
int
RunCmd(cmd, arg1, arg2)
char *cmd;		/* full pathname of the command			*/
char *arg1;		/* first argument to cmd			*/
char *arg2;		/* second argument to cmd (can be nil)		*/
{
X	auto char *arg0;	/* basename of cmd			*/
X	register int pid;
X
X	arg0 = StrTail(cmd);
X	if (FALSE != fTrace) {
X		(void)printf("%s: %s %s", progname, arg0, arg1);
X		if ((char *)0 != arg2)
X			(void)printf(" %s", arg2);
X		(void)fputc('\n', stdout);
X		return 0;
X	}
X
X	(void)fflush(stdout);
X	(void)fflush(stderr);
X	switch ((pid = vfork())) {
X	case 0:		/* child					*/
X		execl(cmd, arg0, arg1, arg2, (char *)0);
X		(void)fprintf(stderr, "%s: execl: `%s\': %s\n", progname, cmd, strerror(errno));
X		exit(1);
X	case -1:	/* error					*/
X		(void)fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
X		exit(EXIT_FSYS);
X	default:	/* parent					*/
X		break;
X	}
X
X	return MyWait(pid);
}
Purdue
chmod 0444 install.d/syscalls.c ||
echo 'restore of install.d/syscalls.c failed'
Wc_c="`wc -c < 'install.d/syscalls.c'`"
test 18260 -eq "$Wc_c" ||
	echo 'install.d/syscalls.c: original size 18260, current size' "$Wc_c"
fi
# ============= instck/main.c ==============
if test ! -d 'instck'; then
    echo 'x - creating directory instck'
    mkdir 'instck'
fi
if test -f 'instck/main.c' -a X"$1" != X"-c"; then
	echo 'x - skipping instck/main.c (File already exists)'
else
echo 'x - extracting instck/main.c (Text)'
sed 's/^X//' << 'Purdue' > 'instck/main.c' &&
/*
X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
X * 47907.  All rights reserved.
X *
X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
X *
X * This software is not subject to any license of the American Telephone
X * and Telegraph Company or the Regents of the University of California.
X *
X * Permission is granted to anyone to use this software for any purpose on
X * any computer system, and to alter it and redistribute it freely, subject
X * to the following restrictions:
X *
X * 1. Neither the authors nor Purdue University are responsible for any
X *    consequences of the use of this software.
X *
X * 2. The origin of this software must not be misrepresented, either by
X *    explicit claim or by omission.  Credit to the authors and Purdue
X *    University must appear in documentation and sources.
X *
X * 3. Altered versions must be plainly marked as such, and must not be
X *    misrepresented as being the original software.
X *
X * 4. This notice may not be removed or altered.
X */
static char copyright[] =
X "@(#) Copyright 1990 Purdue Research Foundation.\nAll rights reserved.\n";
X
/*
X * instck - check for improperly installed files			(ksb)
X *
X * Usage
X *	instck -h
X *	instck -G [-Ldv] [-g group] [-o owner] [-m mode] [dirs] >check.cf
X *	instck [-dlvS] [-C check] [dirs] >errors.log
X *
X * 	dirs(s):	an absolute or relative paths to check-in or gen-for
X *
X * mk(1l) stuff:
X *	$Compile: make all
X *	$Compile: SYS=bsd make all
X *	$Compile: SYS=SYSV make all
X *
X * Environment:
X *	Set the environment variable INSTCK to any of the options to get the
X *	same effect as using them on the command line (e.g., INSTCK="-v").
X *	Command line options silently override environental variables.
X *
X * N.B.
X *	See the main.c file in the source for install(1L).
X */
X
#if !defined(lint)
static char *rcsid = "$Id: main.c,v 7.0 90/09/17 10:09:23 ksb Exp $";
#endif	/* !lint */
X
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/dir.h>
#include <a.out.h>
#include <ar.h>
X
X
#include "configure.h"
#include "install.h"
#include "main.h"
#include "special.h"
#include "syscalls.h"
#include "instck.h"
X
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
X
#include "getopt.h"		/* char *optarg; int optind;		*/
#if !defined(BADCH)		/* char getopt returns for illegal options */
#define	BADCH (int) '\?'
#endif	/* !BADCH */
X
X
/* global variables for options
X */
char *progname;			/* tail of argv[0]			*/
int fDirs = TRUE;		/* scan into dirs while building	*/
int fLongList = FALSE;		/* list long, list leftovers		*/
int fInteract;			/* ask the user if we should fix things	*/
int fTrace = FALSE;		/* keep install part happy		*/
int fVerbose = FALSE;		/* if verbose				*/
int fGen = FALSE;		/* generate a .cf file for dirs		*/
int bHaveRoot;			/* are we the super user		*/
int fLinks = FALSE;		/* record links in link format		*/
char *pcGuilty;			/* who is su'd root			*/
char *pcSpecial = CONFIG;	/* file contains ckecked paths		*/
char *pcMode = DEFMODE;		/* default mode on all files		*/
char *pcDefMode;		/* string mode we need (this dir)	*/
X
X
/*
X * Print detailed usage info
X */
char *apcHelp[] = {
X	"C config use config to check for special files",
X	"d        do not scan given directories for files",
X	"g group  set the default group for all files",
X	"G        generate a check list for the given dirs on stdout",
X	"h        print this message",
X	"i        interactively repair the installed files",
X	"l        list left over files (those that were not checked)",
X	"L        record all links in link format",
X	"m mode   set the default mode for installed files",
X	"o owner  set the default owner for installed files",
X	"S        run as if we were the superuser",
X	"v        be more verbose",
X	"V        show version information",
X	(char *)0
};
X
char acOArgs[] =
X	"[-dGhilLvV] [-C config] [-g group] [-m mode] [-o owner]";
X
/*
X * Usage
X *	Output a useful, std usage message. Maybe a longer one if requested
X */
int
Usage(fp, bVerbose)
FILE *fp;		/* file to output to				*/
int bVerbose;		/* should we explain options more		*/
{
X	register char **ppc;
X
X	(void)fprintf(fp, "%s: usage %s [dirs]\n", progname, acOArgs);
X	if (bVerbose) {
X		for (ppc = apcHelp; (char *)0 != *ppc; ++ppc) {
X			(void)fprintf(fp, *ppc, OLDDIR);
X			(void)fputc('\n', fp);
X		}
X		(void)fprintf(fp, "%s", copyright);
X	}
}
X
X
/*
X * parse options with getopt and install files
X */
int
main(argc, argv)
int argc;
char **argv;
{
X	extern char *getenv();	/* we want an env var			*/
X	static char Opts[] =	/* valid options			*/
X		"C:dGg:hilLm:o:SvV";
X	auto char *pcEnv;	/* options passed through env		*/
X	auto int iOption;	/* argument pointer			*/
X	auto char acMBuf[20];	/* mode buffer				*/
X	auto int iM, iO;	/* more mode buffers			*/
X	auto int fVersion;	/* we should just output version info	*/
X	auto char *pcOwner;	/* login name for default owner		*/
X	auto char *pcGroup;	/* group name for default group		*/
X
X	/* Figure out our name and fix argv[0] for getopt() if necessary.
X	 */
X	progname = StrTail(argv[0]);
X	if (NULL == progname || NULL == *progname)
X		progname = "instck";
X
X	/* Check for environtment options
X	 */
X	if ((char *)0 != (pcEnv = getenv("INSTCK"))) {
X		envopt(pcEnv);
X	}
X
X	/* are we the superuser
X	 */
X	bHaveRoot = 0 == geteuid();
X
X	/* Parse command line options, set flags, etc.
X	 */
X	fVersion = FALSE;
X	pcGroup = pcOwner = (char *)0;
X	while (EOF != (iOption = getopt(argc, argv, Opts))) {
X		switch (iOption) {
X		case 'C':	/* check list	*/
X			pcSpecial = optarg;
X			break;
X		case 'd':	/* don't drop down into given dirs	*/
X			fDirs = FALSE;
X			break;
X		case 'g':	/* new default group			*/
X			pcGroup = optarg;
X			break;
X		case 'G':	/* output a new .cf file for dirs	*/
X			fGen = TRUE;
X			break;
X		case 'h':	/* help		*/
X			Usage(stdout, 1);
X			exit(0);
X			break;
X		case 'i':
X			fInteract = TRUE;
X			break;
X		case 'l':	/* long list */
X			fLongList = TRUE;
X			break;
X		case 'L':	/* link format */
X			fLinks = TRUE;
X			break;
X		case 'm':	/* set mode */
X			pcMode = optarg;
X			break;
X		case 'o':	/* set default owner			*/
X			pcOwner = optarg;
X			break;
X		case 'S':	/* we *are* the superuser		*/
X			bHaveRoot = TRUE;
X			break;
X		case 'v':	/* run ls(1), and insert comments	*/
X			fVerbose = TRUE;
X			break;
X		case 'V':
X			fVersion = TRUE;
X			break;
X		case BADCH:	/* illegal option */
X			Usage(stderr, 0);
X			exit(EXIT_OPT);
X			break;
X		}
X	}
X
X
X	/* set the files we need, instck the dirs we were asked to, end clean
X	 */
X	(void)setpwent();
X	(void)setgrent();
X	InitCfg(pcOwner, pcGroup);
X
X	pcDefMode = acMBuf;
X	acMBuf[0] = '-';
X	if ((char *)0 == pcMode || '\000' == pcMode[0]) {
X		pcMode = (char *)0;
X	} else {
X		CvtMode(pcMode, & iM, & iO);
X		ModetoStr(pcDefMode+1, iM, iO);
X	}
X
X	argc -= optind;
X	argv += optind;
X	argc = ElimDups(argc, argv);
X
X	if (fVersion) {
X		static char acInh[] = "inherited";
X
X		printf("%s: version: $Id: main.c,v 7.0 90/09/17 10:09:23 ksb Exp $\n", progname);
X		printf("%s: configuration file: %s\n", progname, pcSpecial);
#if defined(INST_FACILITY)
X		printf("%s: syslog facility: %d\n", progname, INST_FACILITY);
#endif
X		printf("%s: defaults: owner=%-10s group=%-10s mode=%s\n", progname, (struct passwd *)0 != pwdDef ? pwdDef->pw_name : acInh, (struct group *)0 != grpDef ? grpDef->gr_name : acInh, (char *)0 != pcMode ? pcDefMode : acInh);
X	} else if (fGen) {
X		GenCk(argc, argv);
X	} else {
#if defined(INST_FACILITY)
X		if (bHaveRoot && fInteract) {
X			extern char *getlogin();
X			openlog(progname, 0, INST_FACILITY);
X			pcGuilty = getlogin();
X			if ((char *)0 == pcGuilty || '\000' == *pcGuilty) {
X				pcGuilty = getenv("USER");
X				if ((char *)0 == pcGuilty || '\000' == *pcGuilty)
X					pcGuilty = getenv("LOGNAME");
X				if ((char *)0 == pcGuilty || '\000' == *pcGuilty)
X					pcGuilty = "root\?";
X			}
X		}
#endif
X		argc = FilterOld(argc, argv, & CLCheck);
X		InstCk(argc, argv, pcSpecial, & CLCheck);
#if defined(INST_FACILITY)
X		if (bHaveRoot && fInteract) {
X			closelog();
X		}
#endif
X	}
X
X	(void)endpwent();
X	(void)endgrent();
X
X	exit(0);
}
Purdue
chmod 0444 instck/main.c ||
echo 'restore of instck/main.c failed'
Wc_c="`wc -c < 'instck/main.c'`"
test 8078 -eq "$Wc_c" ||
	echo 'instck/main.c: original size 8078, current size' "$Wc_c"
fi
# ============= instck/main.h ==============
if test -f 'instck/main.h' -a X"$1" != X"-c"; then
	echo 'x - skipping instck/main.h (File already exists)'
else
echo 'x - extracting instck/main.h (Text)'
sed 's/^X//' << 'Purdue' > 'instck/main.h' &&
/*
X * $Id: main.h,v 7.1 90/09/17 10:25:39 ksb Exp $
X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
X * 47907.  All rights reserved.
X *
X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
X *
X * This software is not subject to any license of the American Telephone
X * and Telegraph Company or the Regents of the University of California.
X *
X * Permission is granted to anyone to use this software for any purpose on
X * any computer system, and to alter it and redistribute it freely, subject
X * to the following restrictions:
X *
X * 1. Neither the authors nor Purdue University are responsible for any
X *    consequences of the use of this software.
X *
X * 2. The origin of this software must not be misrepresented, either by
X *    explicit claim or by omission.  Credit to the authors and Purdue
X *    University must appear in documentation and sources.
X *
X * 3. Altered versions must be plainly marked as such, and must not be
X *    misrepresented as being the original software.
X *
X * 4. This notice may not be removed or altered.
X */
X
/*
X * paths, names and options of tools we need to fork
X */
X
/* global variables for options
X */
extern char *progname;		/* tail of argv[0]			*/
extern char *pcGuilty;		/* who is su'd root?			*/
extern char *pcMode;		/* given mode				*/
extern char *pcSpecial;		/* .cf file for normal mode		*/
extern int fDirs;		/* scan dirs or not			*/
extern int fInteract;		/* ask the user if we should fix things	*/
extern int fLongList;		/* long list, list leftovers		*/
extern int fTrace;		/* keep install part happy		*/
extern int fVerbose;		/* if verbose				*/
extern int fLinks;		/* record links in special link format	*/
extern int bHaveRoot;		/* we are the superuser			*/
extern char *pcDefMode;		/* string mode we need (this dir)	*/
X
#define INSTCK	1		/* we are not install, we are instck	*/
Purdue
chmod 0444 instck/main.h ||
echo 'restore of instck/main.h failed'
Wc_c="`wc -c < 'instck/main.h'`"
test 1858 -eq "$Wc_c" ||
	echo 'instck/main.h: original size 1858, current size' "$Wc_c"
fi
# ============= install.cf/install.cf ==============
if test ! -d 'install.cf'; then
    echo 'x - creating directory install.cf'
    mkdir 'install.cf'
fi
if test -f 'install.cf/install.cf' -a X"$1" != X"-c"; then
	echo 'x - skipping install.cf/install.cf (File already exists)'
else
echo 'x - extracting install.cf/install.cf (Text)'
sed 's/^X//' << 'Purdue' > 'install.cf/install.cf' &&
# $Id: install.cf,v 7.2 90/11/08 11:00:36 ksb Exp $
# This file tells install(1l) what files to check as special
# file		modes		owner	group	strip?	comment
X
# protect dirs in the std search path
/		dr?xr-xr-x	root	*	-
/bin		"		"	"	"
/usr		"		"	"	"
/etc		"		"	"	"
/lib		"		"	"	"
/usr/bin	"		"	"	"
/usr/lib	"		"	"	"
/usr/etc	"		"	"	"
/usr/local/bin	"		"	"	"
X
# protect user file systems
/user?		dr?xr-xr-x	root	*	-
/home		"		"	"	"
/users		"		"	"	"
/home/*		"		"	"	"
X
# (unix and variants)
/unix		-r?-r--r--	root	*	n	new kernel
/vmunix		"		"	"	"	"
/dynix		"		"	"	"	"
/hp-ux		"		"	"	"	"
vmunix		"		"	"	"	new client kernel
X
# important special binaries
/bin/sh		-rwx?-x?-x	*	*	?
/bin/su		-rws?-x?-?	root	*	?
/bin/init	-rwx?--?-- 	root	*	?
/etc/init	"	 	"	*	?
X
# important data files
/etc/shadow     drwx------      root    *	-
/etc/shadow/OLD drwx????-?	"   	*	-
/etc/passwd	-r?-r--r--	"	"	-
/etc/shadow/passwd "	        "       "	"
/etc/group	"		"	"	"
/etc/shadow/*   "               "       "       "
X
# one might make a directory with install
/tmp		drwxrwxrwt 	root	system	-
/usr/tmp	" 		"	"	-
lost+found	drwxr-xr-x	"	"	-	for fcsk(8)
X
# new files should be owner by the installer for tickle(8)
/usr/new/bin/OLD drwxr-xr-x	root	*	-
/usr/new/bin/*	-rwxr-x?-?/7000	!root	*	?	test installation
/usr/new/etc/OLD drwxr-xr-x	root	*	-
/usr/new/etc/*	-rwxr-x?-?/7000	!root	*	?	test installation
X
# these cannot be stripped (and must have the world read bit)
saved_kcl	-rwxr-xr-x	*	*	n
X
# protect from default execute bit
/usr/lib/libg.a -r?-r--r--	*	*	n	not a library
*.a		-r?-??-??-	*	*	l	library
*.so.[0-9]*	"		"	"	n	dynamic library
*.o		"		*	*	n
*.ln		"		*	*	n
*.[hc]		"		"	"	"
Purdue
chmod 0444 install.cf/install.cf ||
echo 'restore of install.cf/install.cf failed'
Wc_c="`wc -c < 'install.cf/install.cf'`"
test 1669 -eq "$Wc_c" ||
	echo 'install.cf/install.cf: original size 1669, current size' "$Wc_c"
fi
true || echo 'restore of install.d/install.1l failed'
echo End of part 3, continue with part 4
exit 0

exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.