v24i064: Purdue software product installation system, Part02/07
Rich Salz
rsalz at uunet.uu.net
Thu Mar 21 06:19:49 AEST 1991
Submitted-by: Kevin Braunsdorf <ksb at 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 at cc.purdue.edu, purdue!ksb
X * Jeff Smith, jsmith at 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 at 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 at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Comp.sources.unix
mailing list