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.