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