[comp.sources.unix] v24i064: Purdue software product installation system, Part02/07

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

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

#!/bin/sh
# This is part 02 of pucc-1b
# ============= install.d/file.c ==============
if test ! -d 'install.d'; then
    echo 'x - creating directory install.d'
    mkdir 'install.d'
fi
if test -f 'install.d/file.c' -a X"$1" != X"-c"; then
	echo 'x - skipping install.d/file.c (File already exists)'
else
echo 'x - extracting install.d/file.c (Text)'
sed 's/^X//' << 'Purdue' > 'install.d/file.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 *	      Jeff Smith, jsmith@cc.purdue.edu, purdue!jsmith
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 a file
X */
#if !defined(lint)
static char *rcsid = "$Id: file.c,v 7.2 90/10/22 11:46:31 ksb Exp $";
#endif	/* !lint */
X
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.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"
#include "dir.h"
#include "syscalls.h"
#include "special.h"
X
#if STRINGS
#include <strings.h>
#else
#include <string.h>
#endif
X
X
/*
X * paths, names and options of tools we need to fork
X */
#if !defined(BINSTRIP)
#define BINSTRIP	"/bin/strip"
#endif
X
static char acStrip[] =	BINSTRIP;
X
#if HAVE_RANLIB
#if !defined(BINRANLIB)
#define BINRANLIB	"/usr/bin/ranlib"
#endif
X
static char acRanlib[] =	BINRANLIB;
#endif	/* sysV site do not have to run ranlib	*/
X
#if !defined(LSARGS)
#if defined(SYSV) || defined(HPUX7)
#define LSARGS		"-l"
#else	/* bsd needs a -g option to show group	*/
#define LSARGS		"-lg"
#endif	/* how does ls(1) show both owner&group	*/
#endif
X
static char acLsArgs[] =	LSARGS;
X
X
/* If the backup directory doesn't exist, create it.  We didn't
X * check for this until now because we don't know the name of the
X * backup directory till now, and if there is really a file to install.
X * lop off last component of pcBackPath...
X */
void
MkOld(pcBackPath)
char *pcBackPath;		/* full backup path			*/
{
X	register char *pcTemp;
X	auto char acDD[MAXPATHLEN+1];
X	auto struct stat statb;		/* stat of OLD directory	 */
X	auto struct stat statb_dd;	/* stat of OLD/.. directory	 */
X
X	pcTemp = strrchr(pcBackPath, '/');
X	if (pcTemp == (char *)0) {
X		Die("MkOld");
X	}
X
X	/* This is a bit of a kludge.  mkdir(1) under 2.9bsd can't
X	 * stand trailing '/' chars in pathnames.
X	 */
X	while ('/' == *pcTemp && pcTemp > pcBackPath) {
X		--pcTemp;
X	}
X
X	if ('/' != *pcTemp)
X		++pcTemp;
X	*pcTemp = '\000';
X	if ('\000' == pcBackPath[0]) {
X		/* slash must exist! */;
X	} else if (-1 == LSTAT(pcBackPath, &statb)) {
X		/* we don't want to use the mode specified with -m for
X		 * the OLD directory since that probably wasn't what they
X		 * wanted, so use a reasonable compile-time default
X		 */
X		if (FAIL == DirInstall(pcBackPath, FALSE == bHaveRoot ? (char *)0 : ODIROWNER, FALSE == bHaveRoot ? (char *)0 : ODIRGROUP, ODIRMODE, (char *)0, (char *)0, (char *)0, (char *)0, 0)) {
X			(void)fprintf(stderr, "%s: can\'t create `%s\'\n", progname, pcBackPath);
X			exit(EXIT_FSYS);
X		}
X		if (fVerbose != FALSE) {
X			(void)fprintf(stderr, "%s: had to create `%s\'\n", progname, pcBackPath);
X		}
X	} else if (S_IFDIR != (statb.st_mode & S_IFMT)) {
X		(void)fprintf(stderr, "%s: %s must be a directory\n", progname, pcBackPath);
X		exit(EXIT_OPT);
X	} else {
X		(void)strcpy(acDD, pcBackPath);
X		(void)strcat(acDD, "/..");
X		if (-1 == LSTAT(acDD, &statb_dd)) {
X			(void)fprintf(stderr, "%s: stat: %s: %s\n", progname, acDD, strerror(errno));
X			exit(EXIT_OPT);
X		}
X		if (statb.st_dev != statb_dd.st_dev) {
X			(void)fprintf(stderr, "%s: `%s\' is a mount point!\n", progname, pcBackPath);
X			exit(EXIT_OPT);
X		}
X	}
X	*pcTemp = '/';
}
X
X
X
/*
X * DoBackup()
X *	Actually backs up the file by renaming it
X */
/*ARGSUSED*/
static int
DoBackup(bWasLink, pcDestPath, pcBackPath, pcNewBack, pcTellNew)
int bWasLink;		/* file was a symlink				*/
char *pcDestPath;	/* file that will be clobbered			*/
char *pcBackPath;	/* filename to try as backup name		*/
char *pcNewBack;	/* if we moved $DEST/OLD/foo, new name		*/
char *pcTellNew;	/* tell the user the new backup name for OLD/foo*/
{
X	auto struct stat statb_backup;	/* stat of OLD/name		 */
X
X	pcNewBack[0] = '\000';		/* didn't have to move it	*/
X
X	MkOld(pcBackPath);
X
X	if (FALSE != bWasLink) {
#if HAVE_SLINKS
X		if (CopySLink(pcDestPath, pcBackPath)) {
X			return SUCCEED;
X		}
#endif	/* can copy what we do not have?	*/
X		return FAIL;
X	}
X
X	/* backup target already exists, mv it
X	 */
X	if (-1 != stat(pcBackPath, &statb_backup)) {
X		(void)strcpy(pcNewBack, pcBackPath);
X		MungName(pcNewBack);
X		if (FAIL == Rename(pcBackPath, pcNewBack, pcTellNew)) {
X			/* rename output an error message for us */
X			return FAIL;
X		}
X	}
X
X	/* Just link the backup file to the current file to avoid the window
X	 * that results from renaming the backup before the new file is
X	 * installed.  Resolve collisions if necessary.  If we can't link, copy.
X	 */
X	if (FALSE != fTrace) {
X		(void)printf("%s: ln %s %s\n", progname, pcDestPath, pcBackPath);
X	} else if (-1 == link(pcDestPath, pcBackPath)) {
X		if (FAIL == DoCopy(pcDestPath, pcBackPath)) {
X			(void)fprintf(stderr, "%s: can\'t link or copy `%s\' to `%s\'\n", progname, pcBackPath, pcDestPath);
X			return FAIL;
X		}
X	}
X
X	return SUCCEED;
}
X
X
/*
X * MakeNames()
X *	Given the file to install and the destination, return the full path of
X *	the destination and the full path of the backup file.  This is somewhat
X *	complicated since the destination may be a directory or a full path, and
X *	the full path may end in a filename that exists or not.
X */
void
MakeNames(fStdin, pcFTI, pcDest, pcFull, pcBack)
int fStdin;		/* we are doing stdin here	(in )		*/
char *pcFTI;		/* File To Install		(in )		*/
char *pcDest;		/* Destination of pcFTI		(in )		*/
char *pcFull;		/* full pathname of destination (out)		*/
char *pcBack;		/* full pathname of the backup	(out)		*/
{
X	register char *pcTailFTI;	/* tail of pcFTI		*/
X	register char *pcDestDir;	/* destination directory	*/
X	register char *pcTailDest;	/* tail of pcDest		*/
X
X	/* Get tail of file to install
X	 */
X	if ((pcTailFTI = strrchr(pcFTI, '/')) == (char *)0) {
X		pcTailFTI = pcFTI;
X	} else {
X		++pcTailFTI;
X	}
X
X	/* Get the name of the destination directory and the name the file
X	 * to install will have in that directory.  If the destination we were
X	 * passed is a directory then the destination dir is just pcDest
X	 * and the filename is the tail of the file to install.  If the
X	 * destination isn't a directory, then either they gave a pathname
X	 * (something with '/' in it) for the file to install, in which case
X	 * the destination directory is the head of that path and the filename
X	 * is the tail, or they're installing the file in the current directory
X	 * with a different name.  Note that this can't be the case where they
X	 * say "install foo bar" and bar is a directory because we already
X	 * took care of that in the first case.
X	 * (trailing slashes used to choke us, now we remove them first)
X	 */
X	while ((char *)0 != (pcTailDest = strrchr(pcDest, '/')) && pcDest != pcTailDest && '\000' == pcTailDest[1]) {
X		*pcTailDest = '\000';
X	}
X	if (FALSE != IsDir(pcDest)) {
X		pcDestDir = pcDest;
X		pcTailDest = pcTailFTI;
X		if (fStdin) {
X			if (fDelete) {
X				(void)fprintf(stderr, "%s: use \"%s -R -d%s %s\" to remove a directory\n", progname, progname, fVerbose ? "v" : "", pcDest);
X			} else {
X				(void)fprintf(stderr, "%s: cannot intuit destination name for `-\' (stdin)\n", progname);
X			}
X			exit(1);
X		}
X	} else if ((char *)0 != pcTailDest) {
X		pcDestDir = pcDest;
X		*pcTailDest++ = '\000';
X	} else {
X		pcDestDir = ".";
X		pcTailDest = pcDest;
X	}
X
X	/* make pathname of file to back up.
X	 */
X	(void)sprintf(pcBack, "%s/%s/%s", pcDestDir, OLDDIR, pcTailDest);
X
X	/* Make the pathname the file to install will have
X	 */
X	(void)sprintf(pcFull, "%s/%s", pcDestDir, pcTailDest);
}
X
X
#define HARD	0		/* type of link to make			*/
#define SOFT	1
static char *apcLType[] = {
X	"hard",
X	"symbolic"
};
static char *apcLText[] = {
X	"ln",
X	"ln -s"
};
X
/*
X * build the links, no errors allowed!					(ksb)
X */
int
DoLinks(pST, pcFullFile, pcLinks, eType, pwd, grp)
struct stat *pST;		/* stat of file we were linked to	*/
char *pcFullFile;		/* name of file we were linked to	*/
char *pcLinks;			/* links to build			*/
int eType;			/* type of link to build		*/
struct passwd *pwd;		/* owner for file			*/
struct group *grp;		/* group for file			*/
{
X	static char acColon[] = ":";	/* last time through loop	*/
X	register char *pcColon;		/* skip through the ':' list	*/
X	register char *pcLink;		/* skip through the ':' list	*/
X	auto char *pcBusy;		/* used to cut up OLD name	*/
X	auto char *pcFile;		/* file name to link to		*/
X	auto char *pcBase;		/* just the base of the target	*/
X	auto struct stat statb_link;	/* statbuf for stat'ing links	*/
X	auto struct stat statb_p2;	/* statbuf for what link -> to	*/
X	auto int fRet;			/* value to return		*/
X	auto int iLen;			/* lenght of link text		*/
X	auto int bBackup;		/* backup the older link	*/
X	auto int bSymbolic;		/* existing link it symlink	*/
X	auto char *pcMsg;		/* error message flags		*/
X	auto char acLink[MAXPATHLEN+1];	/* link text from readlink	*/
X	auto char acOld[MAXPATHLEN+1];	/* backup of a link		*/
X	auto char acBusy[MAXPATHLEN+1];	/* temp name for last link case	*/
X
X	fRet = SUCCEED;
X	pcBase = strrchr(pcFullFile, '/');
X	if ((char *)0 == pcBase)
X		Die("nil pointer");
X	++pcBase;
X	for (pcLink = pcLinks; '\000' != pcLink[0]; *pcColon = ':', pcLink = pcColon+1) {
X		if ((char *)0 == (pcColon = strchr(pcLink, ':'))) {
X			pcColon = acColon;
X		}
X		*pcColon = '\000';
X
X		/* if we are building a soft link with no slashes
X		 * in it we can just use a basename change -- else
X		 * use the full path.  We used to stat to see if they
X		 * pointed to the same directory, but that might change.
X		 * (( after we make the link... *sigh* ))
X		 */
X		if (SOFT != eType || (char *)0 != strchr(pcLink, '/')) {
X			pcFile = pcFullFile;
X		} else {
X			pcFile = pcBase;
X		}
X		if (-1 != LSTAT(pcLink, &statb_link)) {
X			pcMsg = NodeType(statb_link.st_mode, (char *)0);
X			bBackup = FALSE;
X			switch (statb_link.st_mode & S_IFMT) {
#if HAVE_SLINKS
X			case S_IFLNK:	/* symbolic link */
X				bSymbolic = TRUE;
X				if (HARD == eType) {
X					if (FALSE == fQuiet)
X						(void)fprintf(stderr, "%s: existing symbolic link %s becomes a link hard\n", progname, pcLink);
X					bBackup = TRUE;
X				}
X				iLen = readlink(pcLink, acLink, MAXPATHLEN);
X				if (-1 == iLen) {
X					(void)fprintf(stderr, "%s: readlink: %s: %s\n", progname, pcLink, strerror(errno));
X					continue;
X				}
X				acLink[iLen] = '\000';
X				if (-1 == stat(acLink, & statb_p2)) {
X					if ((struct stat *)0 != pST || ENOENT != errno) {
X						(void)fprintf(stderr, "%s: stat: %s: %s\n", progname, acLink, strerror(errno));
X					}
X					bBackup = TRUE;
X				} else if (! EQUAL(pcFile, acLink)) {
X					if (FALSE == fQuiet)
X						(void)fprintf(stderr, "%s: link `%s\' spelled `%s\', not `%s\'\n", progname, pcLink, acLink, pcFile);
X					bBackup = TRUE;
X				} else if (HARD != eType) {
X					/* if delete is set dink it */
X					if (fDelete) {
X						break;
X					}
X					if (grp->gr_gid != statb_link.st_gid || (bHaveRoot && pwd->pw_uid != statb_link.st_uid)) {
X						goto fix_mode;
X					}
X					/* OK, looks good, leave it be */
X					continue;
X				}
X				break;
#endif	/* no links to think about	*/
#if defined(S_IFIFO)
X			case S_IFIFO:	/* fifo */
#endif	/* no fifos */
#if defined(S_IFSOCK)
X			case S_IFSOCK:	/* socket */
#endif	/* no sockets */
X			case S_IFDIR:	/* directory */
X			case S_IFCHR:	/* character special */
X			case S_IFBLK:	/* block special */
X				(void)fprintf(stderr, "%s: %s link %s is a %s, fail\n", progname, apcLType[eType], pcLink, pcMsg);
X				fRet = FAIL;
X				continue;
X
X			case 0:
X			case S_IFREG:	/* regular */
X				bSymbolic = FALSE;
X				if ((struct stat *)0 != pST && (pST->st_dev != statb_link.st_dev || pST->st_ino != statb_link.st_ino)) {
X					(void)fprintf(stderr, "%s: existing hard link %s doesn\'t point to old file\n", progname, pcLink);
X					bBackup = TRUE;
X				}
#if HAVE_SLINKS
X				if (SOFT == eType) {
X					if (FALSE == fQuiet)
X						(void)fprintf(stderr,"%s: supposed symbolic link %s was a hard link\n", progname, pcLink);
X					/* go on and remove it */
X					bBackup = TRUE;
X				}
#endif
X				break;
X
X			default:
X				(void)fprintf(stderr, "%s: unrecognized file type on %s\n", progname, pcLink);
X				exit(1);
X			}
X			MakeNames(FALSE, pcLink, ".", acLink, acOld);
X			if (bBackup && FAIL == DoBackup(bSymbolic, pcLink, acOld, acLink, (char *)0)) {
X				(void)fprintf(stderr, "%s: backup failed for link `%s\', skipped\n", progname, pcLink);
X				continue;
X			}
X			if (fTrace) {
X				(void)printf("%s: rm -f %s\n", progname, pcLink);
X			} else if (-1 != unlink(pcLink)) {
X				/* OK */;
X			} else if (ETXTBSY != errno) {
X				(void)fprintf(stderr, "%s: unlink: %s: %s\n", progname, pcLink, strerror(errno));
X				continue;
X			} else {
X				/* might be the last link to a running binary
X				 * link to a bogus name and try again...
X				 */
X				pcBusy = strrchr(acOld, '/');
X				if ((char *)0 == pcBusy) {
X					Die("nil pointer");
X				}
X				*pcBusy = '\000';
X				(void)sprintf(acBusy, "%s/%s", acOld, TMPBOGUS);
X				*pcBusy = '/';
X				MkOld(acBusy);
X				Mytemp(acBusy);
X				if (-1 == Rename(pcLink, acBusy, fVerbose ? "moving busy link" : (char *)0)) {
X					continue;
X				}
X			}
X		} else if (ENOENT != errno) {
X			(void)fprintf(stderr, "%s: stat: %s: %s\n", progname, pcLink, strerror(errno));
X			fRet = FAIL;
X			continue;
X		}
X		if (FALSE != fDelete) {
X			continue;
X		}
X		if (fTrace) {
X			(void)printf("%s: %s %s %s\n", progname, apcLText[eType], pcFile, pcLink);
X		} else if (HARD == eType) {
X			if (-1 == link(pcFile, pcLink)) {
X				(void)fprintf(stderr, "%s: link: %s to %s: %s\n", progname, pcFile, pcLink, strerror(errno));
X				fRet = FAIL;
X			}
X		} else {
#if HAVE_SLINKS
X			if (-1 == symlink(pcFile, pcLink)) {
X				(void)fprintf(stderr, "%s: symlink: %s to %s: %s\n", progname, pcFile, pcLink, strerror(errno));
X				fRet = FAIL;
X			}
X		}
X		if (SOFT == eType) {
fix_mode:
X			if (FALSE != bHaveRoot) {
X				ChOwnGrp(pcLink, pwd, grp);
X			} else {
X				ChGroup(pcLink, grp);
X			}
#else
X			(void)fprintf(stderr, "%s: symbolic links not supported\n", progname);
X			fRet = FAIL;
#endif
X		}
X	}
X	return fRet;
}
X	
/*
X * start a links process for the -S or -H options			(ksb)
X */
int
LaunchLinks(pST, pcDestPath, pcHLink, pcSLink, mMode, pwd, grp)
char *pcDestPath;
struct stat *pST;		/* old file, if one exists	*/
char *pcHLink;
char *pcSLink;
int mMode;
struct group *grp;
struct passwd *pwd;
{
X	static char acDot[] = ".";
X	static char acSlash[] = "/";
X	register int iChild;	/* child we forked, for wait	*/
X	register char *pcDir;	/* change to dir		*/
X	register char *pcLash;	/* last slash in file path	*/
X
X	/* We fork a child to do the linking because we have to
X	 * chdir and umask and stuff.  We may not be able to chdir
X	 * back to where we are (worst case).
X	 */
X	(void)fflush(stdout);
X	(void)fflush(stderr);
X	switch (iChild = fork()) {
X	case -1:	/* system error				*/
X		(void)fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
X		exit(EXIT_FSYS);
X	case 0:		/* child, go do linking			*/
X		/* cee dee to the destination directory
X		 */
X		pcDir = pcDestPath;
X		if ((char *)0 == (pcLash = strrchr(pcDir, '/'))) {
X			pcDir = acDot;
X		} else if (pcDestPath != pcLash) {
X			*pcLash = '\000';
X		} else {
X			pcDir = acSlash;
X		}
X		if (fTrace) {
X			(void)printf("%s: ( cd %s\n", progname, pcDir);
X		}
X		/* we really want to cd, even while just tracing
X		 */
X		if (-1 == chdir(pcDir)) {
X			(void)fprintf(stderr, "%s: chdir: %s: %s\n", progname, pcDir, strerror(errno));
X			exit(1);
X		}
X		if (pcLash != acSlash && pcLash != acDot) {
X			*pcLash = '/';
X		}
X
X		/* we are in the correct directory,
X		 * now we must build the links
X		 */
X		if ((char *)0 != pcHLink) {
X			if (FAIL == DoLinks(pST, pcDestPath, pcHLink, HARD, pwd, grp))
X				exit(1);
X		}
#if HAVE_SLINKS
X		/* symbolic links must be made with the correct umask
X		 * we cannot chmod them
X		 */
X		if ((char *)0 != pcSLink) {
X			if (fTrace) {
X				(void)printf("%s: umask %03o\n", progname, (~mMode) & 0777);
X			}
X			(void)umask((~mMode) & 0777);
X
X			if (FAIL == DoLinks(pST, pcDestPath, pcSLink, SOFT, pwd, grp))
X				exit(1);
X		}
#endif	/* symbiloc links */
X		if (fTrace) {
X			(void)printf("%s: )\n", progname);
X		}
X		exit(0);
X	default:	/* parrent, wait around a while		*/
X		break;
X	}
X	return 0 != MyWait(iChild);
}
X
X
static char acFCreated[] = "file `%s\' created %s.%s(%04o) by %s\n";
static char acFUpdated[] = "file `%s\' updated %s.%s(%04o) by %s\n";
static char acFRemoved[] = "file `%s\' removed %s.%s(%04o) by %s\n";
X
static char *apcFrom[] = {		/* where did we get data from	*/
#define FROM_CMD	0
X	"given on the command line",
#define FROM_OLD	1
X	"from the previously installed file",
#define FROM_DEF	2
X	"from the compiled in defaults",
#define FROM_SRC	3
X	"from the source file",
#define FROM_DIR	4
X	"from the destination directory"
};
X
/*
X * backs up the current file and installs a new one			(ksb)
X *
X * if fDelete is set we install a message and remove it,
X * in this case our caller passes "-" as the file to install.
X */
int
Install(pcFilePath, pcDestPath, pcHLink, pcSLink)
char *pcFilePath; 	/* the file to be installed			*/
char *pcDestPath;	/* the destination directory or file		*/
char *pcHLink;		/* hard links to make				*/
char *pcSLink;		/* symlinks to make				*/
{
X	auto int iOFrom;		/* owner from which source	*/
X	auto int iGFrom;		/* group from which source	*/
X	auto int iMFrom;		/* mode from which source	*/
X	auto int mMode, mOptMode;	/* mode to install with		*/
X	auto int bLocalCopy;		/* should we copy or rename	*/
X	auto int bDestExists;		/* destination file exists?	*/
X	auto int bWasLink;		/* was the file a symlink?	*/
X	auto int bBackup;		/* we're backing up this file	*/
X	auto int bCollide;		/* cd OLD; install foo .. (fix)	*/
X	auto int bStdin;		/* copy ``-'' (stdin) to dest	*/
X	auto char *pcSlash;		/* last slash in $DEST/OLD/foo	*/
X	auto struct passwd *pwd;	/* /etc/passwd info		*/
X	auto struct group *grp;		/* /etc/group info		*/
X	auto struct stat statb_file;	/* stat(2) the file to install	*/
X	auto struct stat statb_dest;	/* stat(2) the destination	*/
X	auto char *pcMsg;		/* flags for error message	*/
X	auto char acDestPath[MAXPATHLEN+1];/* pathname of file to install*/
X	auto char acBackPath[MAXPATHLEN+1];/* pathname of backup file	*/
X	auto char acNewBack[MAXPATHLEN+1];/* where DoBackup put OLD/foo	*/
X	auto char acTempPath[MAXPATHLEN+1];/* pathname for copy & link	*/
X	auto char acBusyPath[MAXPATHLEN+1];/* pathname for busy link	*/
#if defined(CONFIG)
X	auto CHLIST Check;
#endif	/* we need a check list entry		*/
#if defined(INST_FACILITY)
X	auto char *pcLogStat;
X	auto char acLogBuf[MAXLOGLINE];
#endif	/* we should syslog changes		*/
X
X	if ((char *)0 == pcFilePath) {
X		Die("nil filepath");
X	}
X
X	/* We always assume we'll back up the file unless we were
X	 * told not to.  We may find out later there isn't anything
X	 * to back up...
X	 */
X	bBackup = (Destroy == FALSE) ? TRUE : FALSE;
X
X	/* See if the file to install exists and it isn't a directory.
X	 * This is a problem under 2.9bsd Unix since root can unlink
X	 * directories that aren't empty, damaging the file system.
X	 * (we also need to set the bLocalCopy flag here)
X	 */
X	bStdin = '-' == pcFilePath[0] && '\000' == pcFilePath[1];
X
X	/* Figure out the final destination name of the file to install
X	 */
X	MakeNames(bStdin, pcFilePath, pcDestPath, acDestPath, acBackPath);
X	if ((char *)0 == (pcSlash = strrchr(acBackPath, '/'))) {
X		Die("nil from strrchr");
X	}
X
X	/* if we are trying to deinstall a file, built a bogus one to
X	 * install in it's place, then remove the bogus one.  This temp
X	 * file is treated as `stdin' to the real install process.
X	 */
X	if (fDelete) {
X		register FILE *fpRm;
X		auto int afd[2];
X
X		if (-1 == pipe(afd)) {
X			fprintf(stderr, "%s: pipe: %s\n", progname, strerror(errno));
X			return FAIL;
X		}
X		fflush(stdout);
X		fflush(stderr);
X		switch (fork()) {
X		case -1:
X			fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
X			return FAIL;
X		default:		/* parent: install rm script	*/
X			close(0);
X			dup(afd[0]);
X			close(afd[0]);
X			close(afd[1]);
X			break;
X		case 0:			/* child: output message	*/
X			close(afd[0]);
X			if ((FILE *)0 == (fpRm = fdopen(afd[1], "w"))) {
X				Die("fdopen");
X			}
X			(void)fprintf(fpRm, "#!/bin/cat\nThis file, %s, is being removed (by %s)\n", acDestPath, pcGuilty);
X			(void)fflush(fpRm);
X			(void)fclose(fpRm);
X			exit(0);
X		}
X	}
X	if (bStdin) {
X		if (-1 == fstat(fileno(stdin), &statb_file)) {
X			(void)fprintf(stderr, "%s: fstat: stdin: %s\n", progname, strerror(errno));
X			return FAIL;
X		}
X	} else if (-1 == LSTAT(pcFilePath, &statb_file)) {
X		(void)fprintf(stderr, "%s: stat: %s: %s\n", progname, pcFilePath, strerror(errno));
X		return FAIL;
X	}
X
X	bWasLink = FALSE;
X	bLocalCopy = Copy || bStdin;
X	pcMsg = NodeType(statb_file.st_mode, (char *)0);
X	if (!bStdin) switch (statb_file.st_mode & S_IFMT) {
#if HAVE_SLINKS
X	case S_IFLNK:	/* symbolic link */
#if SLINKOK
X		if (FALSE == fQuiet)
X			(void)fprintf(stderr, "%s: source `%s\' is a symbolic link, coping as plain file\n", progname, pcFilePath);
X		break;
#endif	/* think about links */
#endif	/* no links to think about */
#if defined(S_IFIFO)
X	case S_IFIFO:	/* fifo */
#endif	/* no fifos */
#if defined(S_IFSOCK)
X	case S_IFSOCK:	/* socket */
#endif	/* no sockets */
X	case S_IFDIR:	/* directory */
X		(void)fprintf(stderr, "%s: source `%s\' is a %s, fail\n", progname, pcFilePath, pcMsg);
X		return FAIL;
X
X	case S_IFCHR:	/* character special */
X	case S_IFBLK:	/* block special */
X		/* always copy special files, don't remove them.
X		 */
X		if (FALSE != fVerbose && FALSE == bLocalCopy && FALSE == fQuiet) {
X			(void)printf("%s: copying special file %s\n", progname, pcFilePath);
X		}
X		bLocalCopy = TRUE;
X		break;
X
X	case 0:
X	case S_IFREG:	/* regular/plain file */
X		break;
X
X	default:
X		(void)fprintf(stderr, "%s: unrecognized file type on %s\n", progname, pcFilePath);
X		return FAIL;
X	}
X
X	/* There is a bad case here, the user is in $DEST/OLD trying to
X	 *	$ install foo ..
X	 * (`casue $DEST/foo is hosed).  We should move
X	 * $DEST/OLD/foo to a foo$$ to make room for the backup, then
X	 * link $DEST/foo to $DEST/OLD/foo and copy the broken one back
X	 * into place!  Eak.  We warn the user about this case and fix it.
X	 */
X	if (-1 != stat(acBackPath, &statb_dest) &&
X	    statb_file.st_dev == statb_dest.st_dev &&
X	    statb_file.st_ino == statb_dest.st_ino) {
X		if (FALSE == fQuiet)
X			(void)fprintf(stderr, "%s: source `%s\' will be renamed before installation\n", progname, acBackPath);
X		bCollide = TRUE;
X	} else {
X		bCollide = FALSE;
X	}
X
#if defined(CONFIG)
X	/* If the file is one we recognize trap bogus modes/strip
X	 */
X	Special(acDestPath, pcSpecial, & Check);
#endif	/* set check list flags from config file */
X
X	/* Make sure we don't install a file on top of itself.  If the stat()
X	 * fails then it doesn't exist and we're ok.  Otherwise, if the device
X	 * and inode numbers are the same we gripe and die.
X	 *
X	 * See if there's anything to back up (i.e., an existing file with
X	 * the same name as acDestPath).  If this is an initial installation
X	 * there won't be anything to back up, but that isn't an error, so we
X	 * just note it.
X	 *
X	 * If they said "-D" (destroy current binary) there's no sense in
X	 * complaining that there's nothing to back up...
X	 */
X	if (-1 != LSTAT(acDestPath, &statb_dest)) {
X		bDestExists = TRUE;
X		/* Check and see if source and dest are the
X		 * same file, or there are extra links to the
X		 * existing file and report that (after file type)
X		 */
X		if (statb_file.st_dev == statb_dest.st_dev
X			&& statb_file.st_ino == statb_dest.st_ino) {
X			(void)fprintf(stderr, "%s: will not move %s onto itself (%s)\n", progname, pcFilePath, acDestPath);
X			exit(EXIT_OPT);
X		}
X
X		/* Here we take note of funny file types, we don't want the
X		 * destination to be a funny file (because people shouldn't
X		 * live like that -- ksb)
X		 */
X		pcMsg = NodeType(statb_dest.st_mode, (char *)0);
X		switch (statb_dest.st_mode & S_IFMT) {
#if HAVE_SLINKS
X		case S_IFLNK:	/* symbolic link */
#if DLINKOK
X			if (FALSE == fQuiet)
X				(void)fprintf(stderr,"%s: destination %s was a symbolic link\n", progname, acDestPath);
X			bWasLink = TRUE;
X			/* for backup of all links, we might be wrong
X			 * in even installing it!
X			 */
X			bBackup = TRUE;
X			break;
#endif	/* think about links */
#endif	/* no links to think about */
#if defined(S_IFIFO)
X		case S_IFIFO:	/* fifo */
#endif	/* no fifos */
#if defined(S_IFSOCK)
X		case S_IFSOCK:	/* socket */
#endif	/* no sockets */
X		case S_IFDIR:	/* directory */
X		case S_IFCHR:	/* character special */
X		case S_IFBLK:	/* block special */
X			(void)fprintf(stderr, "%s: destination `%s\' is a %s, fail\n", progname, acDestPath, pcMsg);
X			return FAIL;
X
X		case 0:
X		case S_IFREG:	/* regular */
X			break;
X
X		default:
X			(void)fprintf(stderr, "%s: unrecognized file type on `%s\'\n", progname, acDestPath);
X			return FAIL;
X		}
#if defined(INST_FACILITY)
X		pcLogStat = acFUpdated;
#endif	/* we should syslog changes		*/
X	} else if (ENOENT != errno) {
X		(void)fprintf(stderr, "%s: stat: %s: %s\n", progname, acDestPath, strerror(errno));
X		exit(EXIT_FSYS);
X	} else if (fDelete) {
X		(void)fprintf(stderr, "%s: no `%s\' to remove\n", progname, acDestPath);
X		return FAIL;
X	} else {
X		bDestExists = FALSE;
X		bBackup = FALSE;
X		if (FALSE == fQuiet) {
X			(void)fprintf(stderr, "%s: no `%s\' to %s\n", progname, acDestPath, Destroy != FALSE ? "overwrite" : "back up");
X		}
X		/* we need to set statb_dest.st_dev so we know what
X		 * device the destination will be on, so we can force
X		 * a copy rather than a rename
X		 * (we might also copy its mode/group/owner if no defaults)
X		 */
X		*pcSlash = '\000';
X		if (-1 == stat(acBackPath, &statb_dest)) {
X			register char *pcHelp;
X			if ((char *)0 == (pcHelp = strrchr(acDestPath, '/'))) {
X				Die("nil pointer");
X			}
X			*pcHelp = '\000';
X			if (-1 == stat(acDestPath, &statb_dest)) {
X				fprintf(stderr, "%s: stat: %s: %s\n", progname, acDestPath, strerror(errno));
X				exit(EXIT_OPT);
X			}
X			*pcHelp = '/';
X		}
X		*pcSlash = '/';
#if defined(INST_FACILITY)
X		pcLogStat = acFCreated;
#endif	/* we should syslog changes		*/
X	}
#if defined(INST_FACILITY)
X	if (FALSE != fDelete) {
X		pcLogStat = acFRemoved;
X	}
#endif	/* we should syslog changes		*/
X
X	/* if they've specified an owner, group or mode we take it,
X	 * if the destination file already exists use that,
X	 * otherwise, use a reasonable default.
X	 */
X	(void)setpwent();
X	if ((char *)0 != Owner) {
X		if ((struct passwd *)0 == (pwd = getpwnam(Owner))) {
X			(void)fprintf(stderr, "%s: no passwd entry for %s\n", progname, Owner);
X			exit(EXIT_OPT);
X		}
X		if (FALSE == bHaveRoot && pwd->pw_uid != geteuid()) {
X			(void)fprintf(stderr, "%s: effective uid cannot make destination owned by %s (%d != %d)\n", progname, Owner, geteuid(), pwd->pw_uid);
X			exit(EXIT_OPT);
X		}
X		iOFrom = FROM_CMD;
X	} else if (bDestExists != FALSE) {
X		if ((struct passwd *)0 == (pwd = getpwuid((int) statb_dest.st_uid))) {
X			(void)fprintf(stderr, "%s: destination owner %d doesn\'t exist\n", progname, statb_dest.st_uid);
X			exit(EXIT_OPT);
X		}
X		iOFrom = FROM_OLD;
X	} else if (bHaveRoot) {
X		if ((char *)0 != DEFOWNER) {
X			if ((struct passwd *)0 == (pwd = getpwnam(DEFOWNER))) {
X				(void)fprintf(stderr, "%s: default owner `%s\' doesn\'t exist\n", progname, DEFOWNER);
X				exit(EXIT_OPT);
X			}
X			iOFrom = FROM_DEF;
X		} else {
X			if ((struct passwd *)0 == (pwd = getpwuid((int) statb_dest.st_uid))) {
X				(void)fprintf(stderr, "%s: destination directory owner %d doesn\'t exist\n", progname, statb_dest.st_uid);
X				exit(EXIT_OPT);
X			}
X			iOFrom = FROM_DIR;
X		}
X	} else if ((struct passwd *)0 == (pwd = getpwuid((int) statb_file.st_uid))) {
X		(void)fprintf(stderr, "%s: no passwd entry for source owner %d\n", progname, statb_file.st_uid);
X		exit(EXIT_OPT);
X		/*NOTREACHED*/
X	} else {
X		iOFrom = FROM_SRC;
X	}
X	pwd = savepwent(pwd);
X	(void)endpwent();
X
X	/* take specified group or existing destination file's group
X	 * if destination exists, duplicate its group
X	 * else leave group the same as the file to install
X	 */
X	(void)setgrent();
X	if ((char *)0 != Group) {
X		grp = getgrnam(Group);
X		if ((struct group *)0 == grp) {
X			(void)fprintf(stderr, "%s: no group entry for %s\n", progname, Group);
X			exit(EXIT_OPT);
X		}
X		iGFrom = FROM_CMD;
X	} else if (bDestExists != FALSE) {
X		grp = getgrgid((int) statb_dest.st_gid);
X		if ((struct group *)0 == grp) {
X			(void)fprintf(stderr, "%s: no group entry for destination group %d\n", progname, statb_dest.st_gid);
X			exit(EXIT_OPT);
X		}
X		iGFrom = FROM_OLD;
X	} else if (bHaveRoot) {
X		if ((char *)0 != DEFOWNER) {
X			if ((struct group *)0 == (grp = getgrnam(DEFGROUP))) {
X				(void)fprintf(stderr, "%s: no group entry for default group %s\n", progname, DEFGROUP);
X				exit(EXIT_OPT);
X			}
X			iGFrom = FROM_DEF;
X		} else {
X			grp = getgrgid((int) statb_dest.st_gid);
X			if ((struct group *)0 == grp) {
X				(void)fprintf(stderr, "%s: no group entry for destination directory group %d\n", progname, statb_dest.st_gid);
X				exit(EXIT_OPT);
X			}
X			iGFrom = FROM_DIR;
X		}
X	} else if ((struct group *)0 == (grp = getgrgid((int) getegid()))) {
X		(void)fprintf(stderr, "%s: no group entry effective group %d\n", progname, getegid());
X		exit(EXIT_OPT);
X		/*NOTREACHED*/
X	} else {
X		iGFrom = FROM_SRC;
X	}
X	grp = savegrent(grp);
X	(void)endgrent();
X
X	/* take specified mode, use destination mode, or default
X	 * (we never take the source modes, user uses root defaults)
X	 */
X	if ((char *)0 != Mode) {
X		CvtMode(Mode, & mMode, & mOptMode);
X		iMFrom = FROM_CMD;
X		/* here is some magic, if the user is a real install
X		 * wiz. he may have left us to tune the final modes...
X		 */
X		if (0 != mOptMode) {
X			mMode |= statb_dest.st_mode & mOptMode;
X		}
X	} else if (FALSE != bDestExists) {
#if DLINKOK
X		if (FALSE != bWasLink) {
X			(void)fprintf(stderr, "%s: mode on existing symbolic link `%s\' cannot be used as install mode\n", progname, acDestPath);
X			return FAIL;
X		}
#endif
X		mMode = statb_dest.st_mode &~ S_IFMT;
X		iMFrom = FROM_OLD;
X	} else if ((char *)0 != DEFMODE) {
X		CvtMode(DEFMODE, & mMode, & mOptMode);
X		iMFrom = FROM_DEF;
X		if (0 != mOptMode) {
X			mMode |= statb_dest.st_mode & mOptMode;
X		}
X	} else {
X		mMode = statb_dest.st_mode &~ (S_IFMT|S_ISUID|S_ISGID|S_ISVTX);
X		iMFrom = FROM_DIR;
X	}
X
X	/* if a file is already installed warn of potential differences in
X	 * mode bits, owner, or group
X	 */
X	if (bDestExists != FALSE) {
X		if (pwd->pw_uid != statb_dest.st_uid && FALSE == fQuiet) {
X			(void)fprintf(stderr, "%s: `%s\' owner mismatch (%d != %d)\n", progname, acDestPath, pwd->pw_uid, statb_dest.st_uid);
X		}
X
X		if (grp->gr_gid != statb_dest.st_gid && FALSE == fQuiet) {
X			(void)fprintf(stderr, "%s: `%s\' group mismatch (%d != %d)\n", progname, acDestPath, grp->gr_gid, statb_dest.st_gid);
X		}
X
X		if (PERM_RWX(mMode) != PERM_RWX(statb_dest.st_mode) && FALSE == fQuiet) {
X			(void)fprintf(stderr, "%s: `%s\' mode mismatch (%04o != %04o)\n", progname, acDestPath, mMode, statb_dest.st_mode &~ S_IFMT);
X		}
X		if ((S_ISUID & mMode) != (S_ISUID & statb_dest.st_mode)) {
X			(void)fprintf(stderr, "%s: `%s\' setuid bit changed, now %s\n", progname, acDestPath, apcOO[0 != (S_ISUID & mMode)]);
X		}
X		if ((S_ISGID & mMode) != (S_ISGID & statb_dest.st_mode)) {
X			(void)fprintf(stderr, "%s: `%s\' setgid bit changed, now %s\n", progname, acDestPath, apcOO[0 != (S_ISGID & mMode)]);
X		}
X		if ((S_ISVTX & mMode) != (S_ISVTX & statb_dest.st_mode)) {
X			(void)fprintf(stderr, "%s: `%s\' sticky bit changed, now %s\n", progname, acDestPath, apcOO[0 != (S_ISVTX & mMode)]);
X		}
X	}
X
X	/* here we really want to check against the default stuff if the
X	 * modes (owner, group, mode) of the file are not what the default
X	 * would give, choke a little (and the modes are not from the cmd line)
X	 * but this would be too much work; let instck -G save us
X	 * in the broken cases.
X	 */
X
#if defined(CONFIG)
X	/* time to chekc the group and owner against our check list
X	 */
X	if (Check.ffound) {
X		register int bFail = FALSE;
X
X		if ((char *)0 != Check.pclink) {
X			(void)fprintf(stderr, "%s: `%s\' be a %s link to `%s\'\n", progname, acDestPath, ':' == Check.pclink[0] ? "hard" : "symbolic", Check.pclink+1);
X			bFail = TRUE;
X			goto quit;
X		}
X		if ('*' == Check.acowner[0]) {
X			/* OK no check */;
X		} else if (Check.fbangowner) {
X			if (Check.uid == pwd->pw_uid) {
X				(void)fprintf(stderr, "%s: `%s\' should not have owner %s\n", progname, acDestPath, Check.acowner);
X				bFail = TRUE;
X			}
X		} else if (Check.uid != pwd->pw_uid) {
X			(void)fprintf(stderr, "%s: `%s\' should have owner %s (not %s)\n", progname, acDestPath, Check.acowner, pwd->pw_name);
X			bFail = TRUE;
X		}
X
X		if ('*' == Check.acgroup[0]) {
X			/*OK */;
X		} else if (Check.fbanggroup) {
X			if (Check.gid == grp->gr_gid) {
X				(void)fprintf(stderr, "%s: `%s\' should not have group %s\n", progname, acDestPath, Check.acgroup);
X				bFail = TRUE;
X			}
X		} else if (Check.gid != grp->gr_gid) {
X			(void)fprintf(stderr, "%s: `%s\' should have group %s (not %s)\n", progname, acDestPath, Check.acgroup, grp->gr_name);
X			bFail = TRUE;
X		}
X
X		switch (Check.acmode[0]) {
X		case '?':
X		case '*':
X			/*OK*/;
X		case '-':
X			if (Check.mmust != (mMode & Check.mmust)) {
X				(void)fprintf(stderr, "%s: `%s\' mode %04o doesn\'t have bits to match %s (%04o)\n", progname, acDestPath, mMode, Check.acmode, Check.mmust);
X				bFail = TRUE;
X			} else if (0 != (mMode &~ (Check.mmust|Check.moptional))) {
X				(void)fprintf(stderr, "%s: `%s\' mode %04o has too many bits to match %s (%04o)\n", progname, acDestPath, mMode, Check.acmode, Check.mmust|Check.moptional);
X				bFail = TRUE;
X			}
X			if (0 != (S_ISUID & mMode) ? 0 == (S_ISUID & (Check.mmust|Check.moptional)) : 0 != (S_ISUID & Check.mmust)) {
X				(void)fprintf(stderr, "%s: `%s\' setuid bit must be %s\n", progname, acDestPath, apcOO[0 == (S_ISUID & mMode)]);
X				bFail = TRUE;
X			}
X			if (0 != (S_ISGID & mMode) ? 0 == (S_ISGID & (Check.mmust|Check.moptional)) : 0 != (S_ISGID & Check.mmust)) {
X				(void)fprintf(stderr, "%s: `%s\' setgid bit must be %s\n", progname, acDestPath, apcOO[0 == (S_ISGID & mMode)]);
X				bFail = TRUE;
X			}
X			if (0 != (S_ISVTX & mMode) ? 0 == (S_ISVTX & (Check.mmust|Check.moptional)) : 0 != (S_ISVTX & Check.mmust)) {
X				(void)fprintf(stderr, "%s: `%s\' sticky bit must be %s\n", progname, acDestPath, apcOO[0 == (S_ISVTX & mMode)]);
X				bFail = TRUE;
X			}
X			break;
X		default:
X			(void)fprintf(stderr, "%s: `%s\' must be a %s\n", progname, acDestPath, NodeType(Check.mtype, (char *)0));
X			bFail = TRUE;
X			break;
X		case '!':
X			if (fDelete) {
X				break;
X			}
X			/* fall through */
X		case '~':
X			(void)fprintf(stderr, "%s: `%s\' should not be %s", progname, acDestPath, fDelete ? "removed" : "installed");
X			if ((char *)0 != Check.pcmesg && '\000' != Check.pcmesg[0])
X				(void)fprintf(stderr, ", %s", Check.pcmesg);
X			(void)fputc('\n', stderr);
X			bFail = TRUE;
X			break;
X		}
X
X		switch (Check.chstrip) {
X		case CF_ANY:
X			break;
X		case CF_STRIP:
X			if (!fDelete && !Strip) {
X				(void)fprintf(stderr, "%s: `%s\' must be strip\'ed (use -s)\n", progname, acDestPath);
X				bFail = TRUE;
X			}
X			break;
X		case CF_RANLIB:
X			if (!fDelete && !Ranlib) {
X				(void)fprintf(stderr, "%s: `%s\' must be ranlib\'ed (use -l)\n", progname, acDestPath);
X				bFail = TRUE;
X			}
X			break;
X		case CF_NONE:
X			if (!fDelete && (Strip || Ranlib)) {
X				(void)fprintf(stderr, "%s: `%s\' must not be strip\'ed or ranlib\'ed (do not use -l or -s)\n", progname, acDestPath);
X				bFail = TRUE;
X			}
X			break;
X		}
X
X	quit:
X		if (FALSE != bFail) {
X			(void)fprintf(stderr, "%s: `%s\' failed check in `%s\'\n", progname, acDestPath, pcSpecial);
X			return FAIL;
X		}
X		if (fDelete) {
X			(void)printf("%s: %s(%d) %s pattern `%s\'\n", progname, Check.pcspecial, Check.iline, 0 == strcmp(Check.pcpat, acDestPath) ? "remove" : "check", Check.pcpat);
X		}
#if defined(PARANOID)
X	} else if (bHaveRoot && 0 != (mMode & (S_ISUID|S_ISGID)) && (char *)0 != pcSpecial) {
X		fprintf(stderr, "%s: set%cid `%s\' ", progname, (S_ISUID & mMode) ? 'u' : 'g', acDestPath);
X		if (FROM_OLD != iMFrom) {
X			if ('\000' == *pcSpecial) {
X				fprintf(stderr, "needs check list file\n");
X			} else {
X				fprintf(stderr, "not found in check list %s\n", pcSpecial);
X			}
X			return FAIL;
X		} else if ('\000' == *pcSpecial) {
X			fprintf(stderr, "needs to be added to a check list file\n");
X		} else {
X			fprintf(stderr, "needs to be added to the check list %s\n", pcSpecial);
X		}
#endif	/* all setuid programs must be in check	*/
X	}
#endif	/* have check list entry to compare	*/
X
X	/* if we are removing the file, don't strip/ranlib it
X	 */
X	if (fDelete) {
X		Ranlib = Strip = FALSE;
X		mMode = PERM_RWX(mMode);
X	}
X
X	/* Now we back up the old file if we're supposed to
X	 * there might be nothing to backup because of -D
X	 * but we've warned them about links and checked for funny file types
X	 */
X	if (bBackup != FALSE) {
X		if (FAIL == DoBackup(bWasLink, acDestPath, acBackPath, acNewBack, FALSE == f1Copy && (FALSE != fVerbose || (Check.ffound && '\000' != Check.pcmesg[0])) ? "rename" : (char *)0)) {
X			return FAIL;
X		}
X		/* see comment where bCollide is set above
X		 */
X		if (bCollide) {
X			pcFilePath = acNewBack;
X		}
X	} else {
X		acNewBack[0] = '\000';
X	}
X
X	/* Copy the file to the fs the dest is on, so we can just rename it.
X	 */
X	if (bLocalCopy != FALSE || statb_dest.st_dev != statb_file.st_dev) {
X		/* cut backup at last slash, copy to buffer,
X		 * concat on a Mytemp (mktemp) template
X		 */
X		*pcSlash = '\000';
X		(void)sprintf(acTempPath, "%s/%s", acBackPath, TMPINST);
X		*pcSlash = '/';
X		MkOld(acTempPath);
X		(void)Mytemp(acTempPath);
X		if (FAIL == DoCopy(pcFilePath, acTempPath)) {
X			(void)fprintf(stderr, "%s: copy of %s to %s failed\n", progname, pcFilePath, acDestPath);
X			if ('\000' != acNewBack[0]) {
X				(void)Rename(acNewBack, acBackPath, "return");
X			}
X			return FAIL;
X		}
X		if (FALSE == bLocalCopy) {
X			if (FALSE != fTrace) {
X				(void)printf("%s: rm -f %s\n", progname, pcFilePath);
X			} else if (-1 == unlink(pcFilePath)) {
X				if (ETXTBSY != errno) {
X					(void)fprintf(stderr, "%s: unlink: %s: %s\n", progname, pcFilePath, strerror(errno));
X					if ('\000' != acNewBack[0]) {
X						(void)Rename(acNewBack, acBackPath, "return");
X					}
X					return FAIL;
X				}
X				/* not quiet because we `failed' here */
X				fprintf(stderr, "%s: %s is running, not removed\n", progname, pcFilePath);
X			}
X		}
X		pcFilePath = acTempPath;
X	}
X
X	/* if a file is set{u,g}id check for shell script magic number!
X	 * and mixing modes from one source with group/owner of another
X	 */
X	if (0 != ((S_ISUID|S_ISGID) & mMode)) {
X		register char chSet;		/* 'g' or 'u', set?id	*/
X		register char *pcSet;		/* "group" or "owner"	*/
X		register int iFrom;		/* where set came from	*/
X		register FILE *fpCheck;		/* file we install	*/
X
X		chSet = (S_ISUID & mMode) ? 'u' : 'g';
X		pcSet = (S_ISUID & mMode) ? "owner" : "group";
X		if ((FILE *)0 != (fpCheck = fopen(pcFilePath, "r"))) {
X			if ('#' == getc(fpCheck) && '!' == getc(fpCheck)) {
X				(void)fprintf(stderr, "%s: `%s\' is set%cid and loaded with a `#!\'\n", progname, acDestPath, chSet);
X			}
X			(void)fclose(fpCheck);
X		} else {
X			(void)fprintf(stderr, "%s: cannot check magic number on set%cid `%s\'\n", progname, chSet, acDestPath);
X		}
X
X		iFrom = (0 != (S_ISUID & mMode)) ? iOFrom : iGFrom;
X		if (iMFrom != iFrom) {
X			(void)fprintf(stderr, "%s: `%s\' will not set%cid based on mode %s and %s %s\n", progname, acDestPath, chSet, apcFrom[iMFrom], pcSet, apcFrom[iFrom]);
X			if ('\000' != acNewBack[0]) {
X				(void)Rename(acNewBack, acBackPath, "return");
X			}
X			return FAIL;
X		}
X	}
X
X	/* Unlink the current file (which DoBackup() linked to the backup
X	 * file) but only if it exists.
X	 */
X	if (FALSE != bDestExists) {
X		if (FALSE != fTrace) {
X			(void)printf("%s: rm -f %s\n", progname, acDestPath);
X		} else if (-1 != unlink(acDestPath)) {
X			/* OK */;
X		} else if (ETXTBSY != errno) {
X			(void)fprintf(stderr, "%s: unlink: %s: %s\n", progname, acDestPath, strerror(errno));
X			if ('\000' != acNewBack[0]) {
X				(void)Rename(acNewBack, acBackPath, "return");
X			}
X			return FAIL;
X		} else {
X			/* might be the last link to a running binary under
X			 * sys5, sigh, link to a bogus name and try again...
X			 */
X			*pcSlash = '\000';
X			(void)sprintf(acBusyPath, "%s/%s", acBackPath, TMPBOGUS);
X			*pcSlash = '/';
X			MkOld(acBusyPath);
X			(void)Mytemp(acBusyPath);
X			if (-1 == Rename(acDestPath, acBusyPath, fVerbose ? "moving busy file" : (char *)0)) {
X				if ('\000' != acNewBack[0]) {
X					(void)Rename(acNewBack, acBackPath, "return");
X				}
X				return FAIL;
X			}
X		}
X	}
X
X	BlockSigs();
X
X	if (FAIL == Rename(pcFilePath, acDestPath, (char *)0)) {
X		/*
X		 * OUCH! why can't we rename this puppy? Here we are in
X		 * big trouble: can't go back in some cases, can't go
X		 * forward in others.  Let the user figure it out.
X		 */
X		(void)fprintf(stderr, "%s: no currently installed file, aborting\n", progname);
X		exit(99);
X	}
X
X	/* We have moved the file in, we are commited.
X	 * We *must* complete the installation at all costs now.
X	 * There is no turning back from here on; no more return FAIL.
X	 */
X	if (FALSE != f1Copy && pcFilePath != acNewBack && '\000' != acNewBack[0]) {
X		if (FALSE != fTrace) {
X			(void)printf("%s: rm -f %s\n", progname, acNewBack);
X		} else if (-1 != unlink(acNewBack)) {
X			/* OK */;
X		} else if (ETXTBSY != errno) {
X			(void)fprintf(stderr, "%s: unlink: %s: %s\n", progname, acNewBack, strerror(errno));
X		} else {
X			/* the last link to a running binary (SYSV)
X			 * move it to a bogus name
X			 */
X			*pcSlash = '\000';
X			(void)sprintf(acBusyPath, "%s/%s", acBackPath, TMPBOGUS);
X			*pcSlash = '/';
X			/* the MkOld below is unneeded
X			 * (we know of at least one file in there)
X			 */
X			MkOld(acBusyPath);
X			(void)Mytemp(acBusyPath);
X			if (-1 == Rename(acNewBack, acBusyPath, "moving busy backup file")) {
X				(void)fprintf(stderr, "%s: rename %s to %s: %s\n", progname, acNewBack, acBusyPath, strerror(errno));
X			}
X		}
X	}
X
X	/* If requested, strip the installed File or ranlib it.  Have to do this
X	 * before ChOwnGrp and ChGroup or 2.9BSD drops the setuid bits...
X	 */
X	if (FALSE != Strip) {
X		if (FALSE != fVerbose) {
X			(void)printf("%s: %s %s\n", progname, acStrip, acDestPath);
X		}
X		if (0 != RunCmd(acStrip, acDestPath, (char *)0)) {
X			(void)fprintf(stderr, "%s: `%s %s\' failed, run strip by hand\?\n", progname, acStrip, acDestPath);
X		}
X	}
X
X	if (FALSE != Ranlib) {
#if HAVE_RANLIB
X		/* on the pdp11/70 this kludge made the ranlib command work
X		 * I don't think we ever knew why... now I don't have an 11
X		 * to find out if we still need it.  Maybe chmod changed
X		 * the times on the file?
X		 */
#if defined(pdp11)
X		ChMode(acDestPath, mMode);
#endif
X		if (FALSE != fVerbose) {
X			(void)printf("%s: %s %s\n", progname, acRanlib, acDestPath);
X		}
X		if (0 != RunCmd(acRanlib, acDestPath, (char *)0)) {
X			(void)fprintf(stderr, "%s: `%s %s\' failed, run ranlib by hand\?\n", progname, acRanlib, acDestPath);
X		}
#else	/* on sysV fake it, same cmd that way	*/
X		if (FALSE != fVerbose) {
X			(void)printf("%s: ranlib for `%s\' done by ar(1)\n", progname, acDestPath);
X		}
#endif	/* do we really run ranlib(1)		*/
X	}
X
X	if ((char *)0 != pcHLink || (char *)0 != pcSLink) {
X		if (LaunchLinks(bDestExists ? & statb_dest : (struct stat *)0, acDestPath, pcHLink, pcSLink, mMode, pwd, grp)) {
X		
X			(void)fprintf(stderr, "%s: links failed, finishing installation anyway\n", progname);
X		}
X	}
X
X	/* Change ownership, group, timestamp, and mode of installed file
X	 * (chmod must be done last or setuid bits are dropped under 2.9bsd)
X	 */
X	if (FALSE != bHaveRoot) {
X		ChOwnGrp(acDestPath, pwd, grp);
X	} else {
X		ChGroup(acDestPath, grp);
X	}
X	if (FALSE != KeepTimeStamp) {
X		ChTimeStamp(acDestPath, & statb_file);
X	}
X	ChMode(acDestPath, mMode);
X
X	UnBlockSigs();
X
X	/* re-stat, we may have changed link count
X	 */
X	if (-1 != stat(acBackPath, & statb_dest) && 1 != statb_dest.st_nlink) {
X		if ((char *)0 != pcHLink) {
X			(void)printf("%s: -H option may not have listed all the links to %s, still %d left\n", progname, acDestPath, statb_dest.st_nlink - 1);
X		} else {
X			(void)printf("%s: %s may still be installed someplace, link count is too big (%d)\n", progname, acBackPath, statb_dest.st_nlink);
X		}
X		*pcSlash = '\000';
X		(void)printf("%s: use `instck -i %s' to repair link counts\n", progname, acBackPath);
X		*pcSlash = '/';
X	}
X
X	/*
X	 * and turn off special bits on backup -- in case installation
X	 * was security related
X	 */
X	if (FALSE != bDestExists && FALSE != bBackup && 0 != (statb_dest.st_mode & ~SAFEMASK)) {
X		ChMode(acBackPath, (int)statb_dest.st_mode & SAFEMASK);
X	}
X
#if defined(INST_FACILITY)
X	/*
X	 * syslog out change if we are the superuser and we really changed
X	 * something
X	 */
X	if (bHaveRoot && FALSE == fTrace) {
X		(void)sprintf(acLogBuf, pcLogStat, acDestPath, pwd->pw_name, grp->gr_name, mMode, pcGuilty);
X		syslog(LOG_INFO, acLogBuf);
X	}
#endif	/* we should syslog changes		*/
X
#if defined(CONFIG)
X	/* if the file is in a check list report installation message
X	 */
X	if (Check.ffound && '\000' != Check.pcmesg[0]) {
X		(void)printf("%s: %s: %s\n", progname, acDestPath, Check.pcmesg);
X	}
#endif	/* have check list to output a comment	*/
X
X	/* if we are supposed to dink it, do it now, else
X	 * if requested, show the results of the installation with ls(1)
X	 */
X	if (fDelete) {
X		if (fTrace) {
X			(void)printf("%s: rm -f %s\n", progname, acDestPath);
X		} else if (-1 == unlink(acDestPath)) {
X			fprintf(stderr, "%s: unlink: %s: %s\n", progname, acDestPath, strerror(errno));
X			return FAIL;
X		}
X		(void)RunCmd(acLs, acLsArgs, acBackPath);
X	} else if (FALSE != fVerbose) {
X		if (FALSE != bBackup) {
X			(void)RunCmd(acLs, acLsArgs, acBackPath);
X		}
X		(void)RunCmd(acLs, acLsArgs, acDestPath);
X	}
X
X	return SUCCEED;
}
Purdue
chmod 0444 install.d/file.c ||
echo 'restore of install.d/file.c failed'
Wc_c="`wc -c < 'install.d/file.c'`"
test 46361 -eq "$Wc_c" ||
	echo 'install.d/file.c: original size 46361, current size' "$Wc_c"
fi
# ============= instck/instck.h ==============
if test ! -d 'instck'; then
    echo 'x - creating directory instck'
    mkdir 'instck'
fi
if test -f 'instck/instck.h' -a X"$1" != X"-c"; then
	echo 'x - skipping instck/instck.h (File already exists)'
else
echo 'x - extracting instck/instck.h (Text)'
sed 's/^X//' << 'Purdue' > 'instck/instck.h' &&
/*
X * $Id: instck.h,v 7.1 90/09/17 10:25:38 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
#define PATCH_LEVEL	0
X
/*
X * configure the maxfreq routines for instck				(ksb)
X */
X
typedef struct PDnode {
X	short fseen;
} PATH_DATA;
extern void PUInit();
X
#if !defined(BINCHMOD)
#define BINCHMOD	"/bin/chmod"
#endif
X
#if !defined(BINCHGRP)
#define BINCHGRP	"/bin/chgrp"
#endif
X
#if !defined(BINCHOWN)
#define BINCHOWN	"/etc/chown"
#endif
X
#if !defined(BINRANLIB)
#define BINRANLIB	"/usr/bin/ranlib"
#endif
X
#if !defined(BINSTRIP)
#define BINSTRIP	"/bin/strip"
#endif
X
#if !defined(BINRM)
#define BINRM		"/bin/rm"
#endif
X
#if !defined(BINLN)
#define BINLN		"/bin/ln"
#endif
X
X
#if !defined(MAXANS)
#define MAXANS		20		/* answer for QExec prompt	*/
#endif
X
X
extern CHLIST CLCheck;
extern int iMatches;
X
#define fpOut		stdout		/* so we could make it a file	*/
X
#if HAVE_PROTO
extern int ElimDups(int, char **);
extern void NoMatches(char *);
extern void BadSet(int, int, char *, char *);
extern int FileMatch(char *, char *, int (*)());
extern int IsStripped(int, struct stat *);
extern int IsRanlibbed(int, struct stat *);
extern int DoCk(char *);
extern void InstCk(int, char **, char *, CHLIST *);
extern void OldCk(int, char **, CHLIST *);
extern int FilterOld(int, char **, CHLIST *);
#else
extern int ElimDups();
extern void NoMatches();
extern void BadSet();
extern int FileMatch();
extern int IsStripped();
extern int IsRanlibbed();
extern int DoCk();
extern void InstCk();
extern void OldCk();
extern int FilterOld();
#endif
Purdue
chmod 0444 instck/instck.h ||
echo 'restore of instck/instck.h failed'
Wc_c="`wc -c < 'instck/instck.h'`"
test 2505 -eq "$Wc_c" ||
	echo 'instck/instck.h: original size 2505, current size' "$Wc_c"
fi
true || echo 'restore of install.d/main.c failed'
echo End of part 2, continue with part 3
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.