add sup to the tree
authorderaadt <deraadt@openbsd.org>
Sat, 16 Dec 1995 11:46:37 +0000 (11:46 +0000)
committerderaadt <deraadt@openbsd.org>
Sat, 16 Dec 1995 11:46:37 +0000 (11:46 +0000)
47 files changed:
usr.bin/Makefile
usr.bin/sup/Makefile [new file with mode: 0644]
usr.bin/sup/Makefile.inc [new file with mode: 0644]
usr.bin/sup/src/Makefile.save [new file with mode: 0644]
usr.bin/sup/src/atoo.c [new file with mode: 0644]
usr.bin/sup/src/c.h [new file with mode: 0644]
usr.bin/sup/src/ci.c [new file with mode: 0644]
usr.bin/sup/src/crypt.diffs [new file with mode: 0644]
usr.bin/sup/src/crypt.info [new file with mode: 0644]
usr.bin/sup/src/cvt.c [new file with mode: 0644]
usr.bin/sup/src/errmsg.c [new file with mode: 0644]
usr.bin/sup/src/expand.c [new file with mode: 0644]
usr.bin/sup/src/ffilecopy.c [new file with mode: 0644]
usr.bin/sup/src/filecopy.c [new file with mode: 0644]
usr.bin/sup/src/libc.h [new file with mode: 0644]
usr.bin/sup/src/log.c [new file with mode: 0644]
usr.bin/sup/src/netcryptvoid.c [new file with mode: 0644]
usr.bin/sup/src/nxtarg.c [new file with mode: 0644]
usr.bin/sup/src/path.c [new file with mode: 0644]
usr.bin/sup/src/quit.c [new file with mode: 0644]
usr.bin/sup/src/run.c [new file with mode: 0644]
usr.bin/sup/src/salloc.c [new file with mode: 0644]
usr.bin/sup/src/scan.c [new file with mode: 0644]
usr.bin/sup/src/scm.c [new file with mode: 0644]
usr.bin/sup/src/scmio.c [new file with mode: 0644]
usr.bin/sup/src/skipto.c [new file with mode: 0644]
usr.bin/sup/src/stree.c [new file with mode: 0644]
usr.bin/sup/src/sup.1 [new file with mode: 0644]
usr.bin/sup/src/sup.h [new file with mode: 0644]
usr.bin/sup/src/supcdefs.h [new file with mode: 0644]
usr.bin/sup/src/supcmain.c [new file with mode: 0644]
usr.bin/sup/src/supcmeat.c [new file with mode: 0644]
usr.bin/sup/src/supcmisc.c [new file with mode: 0644]
usr.bin/sup/src/supcname.c [new file with mode: 0644]
usr.bin/sup/src/supcparse.c [new file with mode: 0644]
usr.bin/sup/src/supcvers.c [new file with mode: 0644]
usr.bin/sup/src/supfilesrv.c [new file with mode: 0644]
usr.bin/sup/src/supmsg.c [new file with mode: 0644]
usr.bin/sup/src/supmsg.h [new file with mode: 0644]
usr.bin/sup/src/supscan.c [new file with mode: 0644]
usr.bin/sup/src/supservers.8 [new file with mode: 0644]
usr.bin/sup/src/sysent.h [new file with mode: 0644]
usr.bin/sup/src/time.h [new file with mode: 0644]
usr.bin/sup/src/vprintf.c [new file with mode: 0644]
usr.bin/sup/sup/Makefile [new file with mode: 0644]
usr.bin/sup/supfilesrv/Makefile [new file with mode: 0644]
usr.bin/sup/supscan/Makefile [new file with mode: 0644]

index 79e1e99..055304a 100644 (file)
@@ -1,5 +1,5 @@
 #      from: @(#)Makefile      5.8.1.1 (Berkeley) 5/8/91
-#      $Id: Makefile,v 1.2 1995/11/06 21:42:19 deraadt Exp $
+#      $Id: Makefile,v 1.3 1995/12/16 11:46:37 deraadt Exp $
 
 SUBDIR=        apply apropos asa at banner basename bdes biff cal calendar cap_mkdb \
        checknr chflags chpass cksum cmp col colcrt colrm column comm \
@@ -13,7 +13,7 @@ SUBDIR=       apply apropos asa at banner basename bdes biff cal calendar cap_mkdb \
        rdist renice rev rlogin rpcgen rpcinfo rs \
        rsh rup ruptime rusers rwall rwho \
        script sed shar showmount skey skeyinit soelim split strings \
-       su systat tail talk tcopy tee telnet tftp time \
+       su sup systat tail talk tcopy tee telnet tftp time \
        tip tn3270 touch tput tr true tset tsort tty ul uname unexpand \
        unifdef uniq units unvis users uudecode uuencode \
        vacation vgrind vi vis vmstat w wall wc what whatis whereis \
diff --git a/usr.bin/sup/Makefile b/usr.bin/sup/Makefile
new file mode 100644 (file)
index 0000000..b6045b6
--- /dev/null
@@ -0,0 +1,5 @@
+#      $Id: Makefile,v 1.1 1995/12/16 11:46:39 deraadt Exp $
+
+SUBDIR=        sup supscan supfilesrv
+
+.include <bsd.subdir.mk>
diff --git a/usr.bin/sup/Makefile.inc b/usr.bin/sup/Makefile.inc
new file mode 100644 (file)
index 0000000..b8c97c5
--- /dev/null
@@ -0,0 +1,2 @@
+
+CFLAGS+=-UCMUCS -UCMU -UMACH -DVAR_TMP -DHAS_DAEMON -DHAS_POSIX_DIR
diff --git a/usr.bin/sup/src/Makefile.save b/usr.bin/sup/src/Makefile.save
new file mode 100644 (file)
index 0000000..0aad1c0
--- /dev/null
@@ -0,0 +1,136 @@
+# Copyright (c) 1992,1991 Carnegie Mellon University
+# All Rights Reserved.
+# 
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+# CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+#
+# Carnegie Mellon requests users of this software to return to
+#
+#  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+#  School of Computer Science
+#  Carnegie Mellon University
+#  Pittsburgh PA 15213-3890
+#
+# any improvements or extensions that they make and grant Carnegie the rights
+# to redistribute these changes.
+######################################################################
+# Makefile to build sup (the client side), supfilesrv (the repository
+# side, and supscan (used by the repository. If you only want to sup
+# files from CMU, just build sup.
+# The header files: c.h, libc.h and sysent.h are only
+# necessary if you are compiling on a non-Mach system. Likewise the
+# files in libextra.a are normally found in libcs.a on a Mach system.
+# DOPRINT_VA is used by vprintf.c and should be defined if your version
+# of libc/doprnt.c defines the routine _doprnt_va. If it defines _doprnt
+# instead, leave DORPINT_VA undefined.
+######################################################################
+#
+# If you need to build a sup for export outside of North America use
+#      "make EXPORTABLE_SYSTEM=true"
+# this will remove (not use) any vestiges of crypt code that is present
+# on the system.
+#
+# If you have crypt/crypt.c and /usr/lib/libcrypt.a, you will be building
+# a system that uses the SUP crypt mechanism by default.
+#
+SITE                   = NETBSD
+#SITE                  = CMUCS
+NETBSD_DEFINES         = -UMACH -DVAR_TMP -DHAS_DAEMON -DHAS_POSIX_DIR
+AFS_DEFINES            = -DAFS -I/usr/afsws/include
+OSF_DEFINES            = -UMACH -DOSF -D_BSD -noshrlib -g -DNEED_VSNPRINTF -DVAR_TMP
+CMUCS_DEFINES          = -DMACH -DDOPRINT_VA -DNEED_VPRINTF
+NON_MACH_DEFINES       = -UMACH
+#DEFS                  = -UCMUCS -UCMU  ${${SITE}_DEFINES}
+DEFS                   = -UCMUCS -UCMU  ${NETBSD_DEFINES}
+
+#INSTALLATION PARAMETERS
+NETBSD_BINDIR          = /usr/local/sbin
+NETBSD_MAN1            = /usr/local/man/man1
+NETBSD_MAN8            = /usr/local/man/man8
+
+CFLAGS                 = ${DEFS} -O -I.
+
+SUPCL                  = supcmain.o supcvers.o supcparse.o supcname.o \
+                         supcmisc.o supcmeat.o
+SUPS                   = scm.o scmio.o stree.o log.o supmsg.o netcrypt.o
+EXTRA                  = atoo.o errmsg.o expand.o ffilecopy.o filecopy.o nxtarg.o  \
+                         path.o quit.o run.o salloc.o skipto.o  vprintf.o
+
+
+PROGRAMS               = sup supscan supfilesrv
+MAN1                   = sup.1
+MAN8                   = supservers.8
+
+AFS_LIBPATH            = /usr/afs/lib
+AFS_LIBS               = -L${AFS_LIBPATH}/afs -lkauth -lprot -L${AFS_LIBPATH} -lubik -lauth -lrxkad -lsys -ldes -lrx -llwp -lcmd -lcom_err -lc ${AFS_LIBPATH}/afs/util.a
+
+.if exists(/usr/lib/libcrypt.a) && exists(${.CURDIR}/crypt/crypt.c) && !defined(EXPORTABLE_SYSTEM)
+USE_CRYPT              = yes
+.endif
+
+NETBSD_LIBS            = -lcrypt -lutil
+CMUCS_LIBS             = -lsys
+OSF_LIBS               = -lbsd
+LIBS                   = libextra.a
+sup_OFILES             = ${SUPCL} ${SUPS}
+supfilesrv_OFILES      = supfilesrv.o scan.o ${SUPS}
+supfilesrv_LIBS                = libextra.a 
+supscan_OFILES         = supscan.o stree.o scan.o
+
+
+all: ${PROGRAMS}
+.if defined(USE_CRYPT)
+       @echo "WARNING: You have built a NON-exportable version of sup because it uses crypt()!"
+       @echo " To build a crypt-clean version define EXPORTABLE_SYSTEM=true and make."
+.endif
+
+sup: ${sup_OFILES} ${LIBS}
+       ${CC} ${CFLAGS} -o sup ${sup_OFILES} ${LIBS} ${NETBSD_LIBS}
+
+supfilesrv: ${supfilesrv_OFILES} ${supfilesrv_LIBS}
+       ${CC} ${CFLAGS} -o supfilesrv ${supfilesrv_OFILES} ${supfilesrv_LIBS} ${NETBSD_LIBS}
+
+supscan:  ${supscan_OFILES} ${LIBS}
+       ${CC} ${CFLAGS} -o supscan ${supscan_OFILES} ${LIBS} ${NETBSD_LIBS}
+
+libextra.a: ${EXTRA}
+       ar r libextra.a $?
+       ranlib libextra.a
+
+clean cleandir:
+       rm -f ${PROGRAMS} libextra.a netcrypt.c *.o core a.out
+
+install: ${PROGRAMS}
+       install -cs -m 555 -o bin -g bin ${PROGRAMS} ${NETBSD_BINDIR}
+       install -c -m 444 -o bin -g bin ${MAN1} ${NETBSD_MAN1}
+       install -c -m 444 -o bin -g bin ${MAN8} ${NETBSD_MAN8}
+
+netcrypt.c: crypt.diffs
+.if defined(USE_CRYPT)
+       ed - crypt/crypt.c < crypt.diffs
+.else
+       @echo "[ Using netcryptvoid.c ]"
+       cp netcryptvoid.c netcrypt.c
+.endif
+
+scan.o:        sup.h
+scm.o: sup.h
+scmio.o: sup.h supmsg.h
+stree.o: sup.h
+supcmain.o: sup.h supmsg.h supcdefs.h
+supcmeat.o: sup.h supmsg.h supcdefs.h
+supcmisc.o: sup.h supmsg.h supcdefs.h
+supcname.o: sup.h supmsg.h supcdefs.h
+supcparse.o: sup.h supmsg.h supcdefs.h
+supfilesrv.o: sup.h supmsg.h
+supmsg.o: sup.h supmsg.h
+supscan.o: sup.h
+netcryptvoid.o: sup.h supmsg.h
+netcrypt.o: sup.h supmsg.h
diff --git a/usr.bin/sup/src/atoo.c b/usr.bin/sup/src/atoo.c
new file mode 100644 (file)
index 0000000..eac0764
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*  atoo  --  convert ascii to octal
+ *
+ *  Usge:  i = atoo (string);
+ *     unsigned int i;
+ *     char *string;
+ *
+ *  Atoo converts the value contained in "string" into an
+ *  unsigned integer, assuming that the value represents
+ *  an octal number.
+ *
+ *  HISTORY
+ * 20-Nov-79  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Rewritten for VAX.
+ *
+ */
+
+unsigned int atoo(ap)
+char *ap;
+{
+       register unsigned int n;
+       register char *p;
+
+       p = ap;
+       n = 0;
+       while(*p == ' ' || *p == '      ')
+               p++;
+       while(*p >= '0' && *p <= '7')
+               n = n * 8 + *p++ - '0';
+       return(n);
+}
diff --git a/usr.bin/sup/src/c.h b/usr.bin/sup/src/c.h
new file mode 100644 (file)
index 0000000..801331d
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*
+ * Standard C macros
+ *
+ **********************************************************************
+ * HISTORY
+ * 02-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added check to allow multiple or recursive inclusion of this
+ *     file.  Added bool enum from machine/types.h for regular users
+ *     that want a real boolean type.
+ *
+ * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Also change spacing of MAX and MIN to coincide with that of
+ *     sys/param.h.
+ *
+ * 19-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changed the number of tabs between TRUE, FALSE and their
+ *     respective values to match those in sys/types.h.
+ *
+ * 17-Dec-84  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Only define TRUE and FALSE if not defined.  Added caseE macro
+ *     for using enumerated types in switch statements.
+ *
+ * 23-Apr-81  Mike Accetta (mja) at Carnegie-Mellon University
+ *     Added "sizeofS" and "sizeofA" macros which expand to the size
+ *     of a string constant and array respectively.
+ *
+ **********************************************************************
+ */
+
+#ifndef        _C_INCLUDE_
+#define        _C_INCLUDE_
+
+#define ABS(x) ((x)>=0?(x):-(x))
+#define        MIN(a,b) (((a)<(b))?(a):(b))
+#define        MAX(a,b) (((a)>(b))?(a):(b))
+
+#ifndef        FALSE
+#define FALSE  0
+#endif FALSE
+#ifndef        TRUE
+#define TRUE   1
+#endif TRUE
+
+#define        CERROR          (-1)
+
+#ifndef        bool
+typedef enum   { false = 0, true = 1 } bool;
+#endif bool
+
+#define        sizeofS(string) (sizeof(string) - 1)
+#define sizeofA(array) (sizeof(array)/sizeof(array[0]))
+
+#define caseE(enum_type)       case (int)(enum_type)
+
+#endif _C_INCLUDE_
diff --git a/usr.bin/sup/src/ci.c b/usr.bin/sup/src/ci.c
new file mode 100644 (file)
index 0000000..8960eb5
--- /dev/null
@@ -0,0 +1,847 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*  ci  -- command interpreter
+ *
+ *  Usage (etc.)
+ *
+ * HISTORY
+ * 22-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Removed checks for VIRTUE window manager.  If they don't like
+ *     it then they can fix the more program.
+ *
+ * 08-May-85  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Increased MAXENTRIES and MAXHELPS from 200 to 400.
+ *
+ * 30-Apr-85  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Adapted for 4.2 UNIX.  Added calls to check for
+ *     using window manager of VIRTUE.
+ *
+ * 29-Apr-85  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Added two small bug fixes (courtesy of Richard Cohn).
+ *
+ * 14-Aug-84  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Added fflush(stdout) after printing prompt, before asking for input line.
+ *
+ * 01-Jul-83  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Bug fix: whitespace now required before ">filename" and not permitted
+ *     within or after filename.
+ *
+ * 06-Jun-83  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Bug fix: added line to initialize "redirected" to 0.
+ *
+ * 20-May-83  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Added quiet bits CINOSEM, CINOFILE, CIFIRSTEQUAL to allow user to
+ *     have special characters ; > = treated as normal data (except =
+ *     after first argument, which still means "variable assignment").
+ *     Also added output redirection via >filename on input line.
+ *
+ * 07-Mar-83  Dave McKeown (dmm) at Carnegie-Mellon University
+ *     (Slight alterations by Steve Shafer.)
+ *     Made cidepth a global, used for recursive and nested calls to
+ *     ci(), and accessable to the user.  Added '@x' command, similar
+ *     to '^x' except that the previous command interpreter name is
+ *     remembered and after 'x' is executed, the previous command
+ *     interpreter is reinvoked.  Users who plan to use this feature
+ *     must save the name of the previous ci in global variable 
+ *     'ciprev' after exit from the ci().  ie.  
+ *             ci(.........);
+ *             strcpy(ciprev,"ci-name");
+ *     Added ci state CICMDNOINDENT to allow for no indentation of the
+ *     command line prompt based on cidepth.
+ *     Reduced amount of indentation on source code.
+ *     Bug: the "depth" argument is now a no-op, retained for backward
+ *     compatibility.  Cidepth is initialized to zero, and incremented
+ *     upon invocation of a ci().  If cidepth is <1 then you are not
+ *     in a ci() instantiation.
+ *
+ * 21-Feb-83  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Added up-arrow (^) command (and variable cinext).  ^x is used when
+ *     you have a ci program in which one command invokes ci with a
+ *     new set of commands (i.e. a subsystem of the program).  Inside the
+ *     subsystem, ^x will exit the subsystem, and cause the main level
+ *     to execute the command line "x" before reading more input lines.
+ *     The cinext variable is used to implement this.  Cinext can also be
+ *     used by any user code which desires to force ci to execute a
+ *     specific command before reading more input from the current file.
+ *
+ * 16-Jul-82  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Added extra code in _ci_help to eliminate duplicate help file
+ *     names.  This way, if several directories are specified and there
+ *     is are files with the same name in more than one directory, only
+ *     the first of each file will be included in the help list.
+ *     
+ *     It would have been nice to do this after the qsort instead of
+ *     before (in ci_help).  However, qsort does not ensure that
+ *     "equivalent" entries are kept in the same relative
+ *     order; thus there would be no way to ensure that the
+ *     file being used was the first such file found.
+ *
+ * 07-Jul-82  William Chiles (wpc) at Carnegie-Mellon University
+ *     Modified so that "!" invokes shell commands from the type of 
+ *      shell specified by the environment variable SHELL.  If SHELL
+ *     is not defined the standard shell is used.
+ *
+ * 21-Sep-81  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Increased LINELENGTH (input buffer length) to 1100 to satisfy
+ *     voracious requirements of a certain user whose name I won't mention
+ *     but whose initials are "faa".
+ *
+ * 08-Oct-80  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Added class variables:  ci_tclass cases in ci_show and ci_set.
+ *     Also added CICMDFPEEK in addition to existing CISETPEEK.
+ *
+ * 22-May-80  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Ci now sorts help topics into alphabetical order.  Some interrupt
+ *     handling has been added, but there are bugs, for example, when
+ *     you interrupt "*" (the listing of command names).  The right thing
+ *     happens, but bogus messages are printed.
+ *
+ * 16-Apr-80  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Ci now prints lists of names with prstab().  This uses multiple
+ *     columns when appropriate.
+ *
+ * 12-Mar-80  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Added code to skip over leading blanks and tabs in the argument list
+ *     when executing commands, and setting and displaying variables.
+ *     Also fixed meta-help, which mysteriously disappeared.
+ *
+ * 19-Feb-80  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Added "if (0) del();" to force del() routine to be loaded.  This is
+ *     the safest way I know of to define the external int "_del_".  If you
+ *     don't believe it, think again about separately compiled files.
+ *
+ * 28-Jan-80  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Created.  Patterned (somewhat) after ci() on PDP-11.
+ *
+ */
+
+
+#include <strings.h>
+#include <libc.h>
+#include <ci.h>
+#include <del.h>
+
+char *index(),*getenv(),*rindex();
+extern char _argbreak;
+long atol();
+double atof();
+static int ci_help(), ci_show();
+static int _ci_sho(), _ci_set(), ci_set();
+
+/*************************
+ ***    M A C R O S    ***
+ *************************/
+
+#define LINELENGTH 1100                /* max length of input line */
+#define MAXENTRIES 400         /* max entries in entry list */
+#define MAXHELPS 400           /* max help files available */
+#define METAHELP "/usr/lib/ci.help"    /* standard help file */
+
+/*********************************************
+ ***    G L O B A L   V A R I A B L E S    ***
+ *********************************************/
+
+int ciquiet = 0;               /* init globals */
+int ciexit  = 0;
+int cidepth = 0;
+int ciback  = 0;               /* for use in '@' command */
+FILE *ciinput;
+
+char cinext[LINELENGTH] = "";
+char ciprev[LINELENGTH] = "";
+
+static char *delchoice[] = {   /* breakpoint choices */
+       "abort          abort command file",
+       "breakpoint     break to tty, then resume command file",
+       0};
+
+/*************************************
+ ***    M A I N   R O U T I N E    ***
+ *************************************/
+
+ci (prompt,fil,depth,list,helppath,cmdfpath)
+char *prompt;                  /* prompt message */
+FILE *fil;                     /* input file */
+int depth;                     /* recursion depth */
+CIENTRY *list;                 /* entry list */
+char *helppath;                        /* search list for help files */
+char *cmdfpath;                        /* search list for command files */
+
+{
+
+  FILE *savfile;         /* input file for calling instance of ci */
+  int savquiet, savexit;  /* globals for calling instance of ci */
+  char *p,*q,*cmd,*arg;          /* temps for parsing input */
+  int i;                       /* temp */
+  char line[LINELENGTH];       /* input line buffer */
+  int firststmt;       /* temp */
+  char *equals,*star;  /* index of = and * in input line */
+  char cfnam[200];     /* name of command file */
+  char *name[MAXENTRIES];      /* name list for entries */
+  char *vname[MAXENTRIES];     /* name list for just variables */
+  int vnum[MAXENTRIES];        /* correspondence list for variables */
+  int nv;                      /* number of variables */
+  int helpcmd;         /* "help" command index */
+  FILE *newfile;               /* command file just opened */
+  char bprompt[100];   /* breakpoint prompt */
+  char *tname[MAXENTRIES];     /* temp name list */
+  int tnum;            /* # entries in tname */
+  char *Shell;            /* holds SHELL value from .login */
+  int redirected;      /* 1 iff currently redirected output */
+  FILE savestdout;             /* place to save normal std. output */
+  FILE *outfile;               /* current output file */
+  char *outname;               /* output file name */
+  
+
+  /* force del() routine to be declared */
+  if (0) del();
+  /* save globals on stack */
+  cidepth++;   /* bump the global depth, first CI() is 1 */
+  savquiet = ciquiet;
+  savexit = ciexit;
+  savfile = ciinput;
+  ciexit = 0;          /* don't exit until this is set */
+  ciinput = (fil ? fil : stdin);               /* new input file */
+
+  /* construct name lists for stablk */
+
+  nv = 0;
+  for (i=0; list[i].ci_etyp != ci_tend; i++) {
+       name[i] = list[i].ci_enam;
+       if (list[i].ci_etyp != ci_tcmd) {       /* is variable */
+               vname[nv] = name[i];
+               vnum[nv] = i;
+               nv++;
+       }
+  }
+  helpcmd = i++;               /* force-feed "help" onto list */
+  name[helpcmd] = "help";
+  name[i] = 0;
+  vname[nv] = 0;
+
+  /* loop for input lines */
+
+  redirected = 0;
+  while (!ciexit) {
+
+    if (*cinext) {             /* get line from ^ command */
+       if (ciback) { 
+         sprintf(line,"%s;%s",cinext,ciprev);  
+         ciback = 0;
+       }
+       else {
+         strcpy (line,cinext);
+       }
+       strcpy (cinext,"");
+       p = line;
+    }
+    else {                     /* else read file */
+       if ((ciinput == stderr) || (ciinput == stdin) || (!(ciquiet&CICMDFPROMPT))) {
+         if (!(ciquiet &CICMDNOINDENT)) {
+           for (i=1; i<cidepth; i++) {
+               printf ("    ");
+           }
+         }
+         printf ("%s ",prompt);
+         if ((ciinput == stderr) || (ciinput == stdin))  fflush (stdout);
+       }
+       p = fgets (line,LINELENGTH,ciinput);    /* read input line */
+       if (p == 0) {           /* EOF */
+         if (_del_) {
+               DELCLEAR;
+               strcpy (line,"");
+               p = line;
+         }
+         else {
+               ciexit = 1;
+               if ((ciinput==stdin) || (ciinput==stderr) || 
+                 (!(ciquiet&CICMDFECHO))) printf ("\n");
+         }
+       }
+       else {
+               if ((ciinput != stderr) && (ciinput != stdin) && 
+                 (!(ciquiet&CICMDFECHO))) printf ("%s",line);
+
+               for (p=line; (*p) && (*p != '\n'); p++) ;
+               *p = 0;         /* kill trailing newline */
+               p = line;       /* points to start of line */
+       }
+    }
+
+    /* check for redirection of output */
+
+    if (!ciexit) {
+       outname = rindex (p,'>');
+           if (outname) {
+            if (outname == p || *(outname+1) == 0
+             || ((*(outname-1) != ' ') && (*(outname-1) != '\t'))) {
+               outname = 0;
+            }
+           else {
+               for (q=outname+1; *q && (*q != ' ') && (*q != '\t'); q++) ;
+               if (*q)  outname = 0;
+            }
+        }
+        if (outname && !(ciquiet&CINOFILE)) {
+           *outname++ = 0;
+           outfile = fopen (outname,"w");
+           if (outfile == 0) {
+                   printf ("ci: Can't create output file %s\n",outname);
+                   p = "";
+           }
+           else {
+                   fflush (stdout);
+                   savestdout = *stdout;
+                   *stdout = *outfile;
+                   redirected = 1;
+           }
+        }
+    }
+
+    /* loop for each command */
+
+    firststmt = 1;             /* first time through loop */
+    while ((!ciexit) && (((ciquiet&CINOSEM) && firststmt) || *(cmd=nxtarg(&p,";")) || _argbreak)) {
+
+       if (ciquiet & CINOSEM) {
+           cmd = p;
+           firststmt = 0;
+       }
+
+       switch (*cmd) {         /* what kind of line? */
+
+       case ':':               /* :  comment */
+       case 0:                 /*    null line */
+         break;
+
+       case '!':               /* !  shell command */
+         cmd = skipover (cmd+1," ");
+         if ((Shell = getenv("SHELL")) == 0) Shell = "sh";
+         if (*cmd)     runp (Shell, Shell, "-c", cmd, 0);
+         else          runp (Shell, Shell, 0);
+         if (!(ciquiet&CISHEXIT))  printf ("Back to %s\n",prompt);
+         break;
+
+       case '?':               /* ?  help */
+         cmd = skipover (cmd+1," ");
+         ci_help (cmd,helppath);
+         break;
+
+       case '<':               /* <  command file */
+         arg = cmd + 1;
+         cmd = nxtarg (&arg,0);        /* parse name */
+         if (*cmd == 0) printf ("ci: missing filename\n");
+         else {
+           if (cmdfpath)  newfile = fopenp (cmdfpath,cmd,cfnam,"r");
+           else           newfile = fopen (cmd,"r");
+
+           if (newfile == 0) 
+             printf ("ci: can't open command file %s\n",cmd);
+           else {
+             if (!(ciquiet&CICMDFECHO))  printf ("\n");
+             ci (prompt,newfile,cidepth,list,helppath,cmdfpath);
+             fclose (newfile);
+             if (!(ciquiet&CICMDFEXIT))  printf ("End of file\n\n");
+           }
+         }
+         break;
+       
+       case '^':               /* exit and do command */
+       case '@':
+         if (cidepth > 1) {
+           if (*cmd == '@') ciback = 1;
+           if (_argbreak == ';')  *(cmd+strlen(cmd)) = ';';
+           ciexit = 1;
+           cmd = skipover(cmd+1," ");
+           strcpy (cinext,cmd);
+         }
+         else printf ("ci: ^ not allowed at top level of ci\n");
+         break;
+
+       default:                /* list cmds, etc. */
+         equals = index (cmd,'=');
+         if (equals == cmd)  cmd++;
+
+         if (equals) {
+           if (*(equals+1) == 0)  *equals = 0;
+           else  *equals = ' ';
+         }
+
+         arg = cmd;    /* parse first word */
+         cmd = nxtarg (&arg,0);
+         if ((ciquiet&CIFIRSTEQUAL) && equals && equals>arg) {
+               *equals = '=';  /* if user doesn't want extra =, kill */
+               equals = 0;
+         }
+         star = index (cmd,'*');
+         if (star)  *star = 0;
+         if (star && equals) { /* list vars */
+           printf ("\n");
+           for (i=0; vname[i]; i++) {
+             if (stlmatch (vname[i],cmd)) {
+               ci_show (list[vnum[i]],arg,CIPEEK);
+             }
+             DELBREAK;
+           }
+           printf ("\n");
+         }
+         else if (star) {      /* list cmds */
+           printf ("\n");
+           tnum = 0;
+           for (i=0;name[i]; i++) {
+             if ((i==helpcmd || list[i].ci_etyp == ci_tcmd) && 
+               stlmatch (name[i],cmd)) {
+                 tname[tnum++] = name[i];
+             }
+           }
+           tname[tnum] = 0;
+           prstab (tname);
+           if (_del_)  {_DELNOTE_}
+           printf ("\n");
+         }
+       else if (equals) {      /* set var */
+         i = stablk (cmd,vname,0);
+         if (i >= 0)  ci_set (list[vnum[i]],skipover(arg," \t"));
+       }
+      else {
+       i = stablk (cmd,name,0);
+
+       if (i == helpcmd) ci_help (arg,helppath);
+       else if (i >= 0) {
+         if (list[i].ci_etyp == ci_tcmd) {
+           (* (int(*)()) (list[i].ci_eptr)) (skipover(arg," \t"));
+         }
+         else ci_show (list[i],skipover(arg," \t"),CISHOW);
+       }
+      }
+    }
+
+       /* end of command */
+
+       /* DEL trapping */
+
+   if (_del_) {
+       if (ciinput == stdin) {
+         DELCLEAR;     /* already at tty level */
+         }
+       else {
+         _del_ = 0;
+         i = getstab ("INTERRUPT:  abort or breakpoint?",delchoice,"abort");
+         if (i == 0) ciexit = 1;       /* abort */
+         else {                /* breakpoint */
+           sprintf (bprompt,"Breakpoint for %s",prompt);
+           ci (bprompt,0,cidepth,list,helppath,cmdfpath);
+           }
+         }
+       }
+
+       /* end of loop for commands */
+
+    }
+
+    /* end of loop for lines of input file */
+
+    if (redirected) {
+       fflush (stdout);
+       fclose (stdout);
+       *stdout = savestdout;
+       redirected = 0;
+    }
+
+  }
+
+  /* restore globals */
+  cidepth --;          /* update current depth */
+  ciinput = savfile;
+  ciquiet = savquiet;
+  ciexit = savexit;
+}
+
+/********************************************
+ ***    P R I N T   H E L P   F I L E     ***
+ ********************************************/
+
+static int _h_found;   /* how many matching names? */
+static char **_h_list;         /* list of matching names */
+static char (*_h_nlist)[20];  /* list of filename part of names */
+
+static int _ci_help (filspec)
+/* called by searchp to expand filspec, adding names to _h_list */
+char *filspec;
+{
+  register int i,j,result;
+  char dir[200];
+
+  result = expand (filspec, _h_list + _h_found, MAXHELPS - _h_found);
+  if (result > 0) { 
+    for (i=0; i<result; ) {            /* elim duplicates */
+      path (_h_list[i+_h_found],dir,_h_nlist[i+_h_found]);
+      for (j=0;
+         j<_h_found && strcmp(_h_nlist[j],_h_nlist[i+_h_found]) != 0;
+          j++) ;
+       if (j < _h_found) {     /* is duplicate */
+         --result;
+         strcpy (_h_list[i+_h_found],_h_list[result+_h_found]);
+         }
+       else i++;       /* isn't duplicate */
+       }
+
+  _h_found += result;
+  }
+  
+  return (1);  /* keep searching */
+}
+
+/*  for use in sorting help file names */
+static ci_hcomp (p,q)
+char **p,**q;
+{
+  char dir[200],file1[20],file2[20];
+  path ((*p),dir,file1);
+  path ((*q),dir,file2);
+  return (strcmp(file1,file2));
+}
+
+static ci_help (topic,helppath)
+char *topic,*helppath;
+{
+  char *fnames[MAXHELPS];              /* names of matching files */
+  char names[MAXHELPS][20];    /* stripped filenames */
+  char *nptr[MAXHELPS+1];              /* list of ptrs for stablk */
+  char dir[200];                       /* temp */
+  char shstr[300];             /* shell string for system */
+  int i;
+  char *star;
+  FILE *f;
+
+  if (*topic == 0) {           /* wants meta-help */
+       f = fopen (METAHELP,"r");
+       if (f == 0) {
+               printf ("Yikes!!  Can't open standard help file!\n");
+       }
+       else {
+               printf ("\n");
+               runp("more","more",METAHELP,0);
+               if (_del_)  {_DELNOTE_}
+               printf ("\n");
+               fclose (f);
+       }
+       if (helppath && (*helppath) && (!getbool("Do you want a list of help topics?",1))) {
+               return;
+       }
+  }
+  else {                               /* chop at * */
+       star = index (topic,'*');
+       if (star)  *star = 0;
+  }
+
+  if (helppath == 0) {         /* no help at all */
+       printf ("Sorry, no specific help is available for this program.\n");
+  }
+  else {
+       _h_found = 0;
+       _h_list = fnames;
+       _h_nlist = names;
+       searchp (helppath,"*",dir,_ci_help);    /* find file names */
+       qsort (fnames,_h_found,sizeof(char *),ci_hcomp);
+
+       for (i=0; i<_h_found; i++) {    /* strip pathnames */
+               path (fnames[i],dir,names[i]);
+               nptr[i] = names[i];
+       }
+       nptr[i] = 0;
+
+       if (*topic) {           /* request some topic */
+         if (_h_found == 0) {
+           printf ("No help for %s.  Type '?*' for list of help messages.\n",topic);
+           }
+         else {
+           i = stablk (topic,nptr,1);
+           if (i < 0)  i = stabsearch (topic,nptr,0);
+           if (i >= 0) {
+             f = fopen (fnames[i],"r");
+             if (f == 0) 
+               printf ("Yikes!  Can't open help file %s\n",fnames[i]);
+             else {
+               printf ("\n");
+               runp("more","more",fnames[i],0);
+               if (_del_)  {_DELNOTE_}
+               printf ("\n");
+               fclose (f);
+               }
+             }
+           }
+       }
+       else {                  /* request topic list */
+         printf ("\nHelp is available for these topics:\n");
+         prstab (nptr);
+         if (_del_)  {_DELNOTE_}
+         printf ("\n");
+       }
+
+       for (i=0; i<_h_found; i++)  free (fnames[i]);
+
+  }
+}
+
+/*********************************************************
+ ***    S H O W   V A L U E   O F   V A R I A B L E    ***
+ *********************************************************/
+
+static ci_show (entry,arg,mode)
+CIENTRY entry;                 /* entry to display */
+char *arg;             /* arg for variable procedures */
+CIMODE mode;           /* mode (CIPEEK or CISHOW) */
+{
+  if (entry.ci_etyp == ci_tproc) {     /* procedure */
+       (* (int(*)()) (entry.ci_eptr)) (mode,arg);
+  }
+  else if (entry.ci_etyp == ci_tclass) {       /* class variable */
+       (* (int(*)()) (entry.ci_eptr)) (mode,arg,entry.ci_evar,entry.ci_enam);
+  }
+  else {
+       printf ("%-14s \t",entry.ci_enam);
+       _ci_sho (entry.ci_etyp, entry.ci_eptr);
+       printf ("\n");
+  }
+}
+
+static _ci_sho (etype,eptr)
+ci_type etype;
+ci_union *eptr;
+{
+  int i;
+  unsigned int u;
+
+  switch (etype) {
+
+  case ci_tint:
+       printf ("%d",eptr->ci_uint);
+       break;
+  case ci_tshort:
+       printf ("%d",eptr->ci_ushort);
+       break;
+  case ci_tlong:
+       printf ("%D",eptr->ci_ulong);
+       break;
+  case ci_toct:
+       if (eptr->ci_uoct)  printf ("0");
+       printf ("%o",eptr->ci_uoct);
+       break;
+  case ci_thex:
+       if (eptr->ci_uhex)  printf ("0x");
+       printf ("%x",eptr->ci_uhex);
+       break;
+  case ci_tdouble:
+       printf ("%g",eptr->ci_udouble);
+       break;
+  case ci_tfloat:
+       printf ("%g",eptr->ci_ufloat);
+       break;
+  case ci_tbool:
+       if (eptr->ci_ubool)     printf ("yes");
+       else                    printf ("no");
+       break;
+  case ci_tstring:
+       printf ("%s",(char *)eptr);
+       break;
+  case ci_tcint:
+       printf ("%d",*(eptr->ci_ucint.ci_ival));
+       break;
+  case ci_tcshort:
+       printf ("%d",*(eptr->ci_ucshort.ci_sval));
+       break;
+  case ci_tclong:
+       printf ("%D",*(eptr->ci_uclong.ci_lval));
+       break;
+  case ci_tcoct:
+       u = *(eptr->ci_ucoct.ci_uval);
+       if (u)  printf ("0");
+       printf ("%o",u);
+       break;
+  case ci_tchex:
+       u = *(eptr->ci_uchex.ci_uval);
+       if (u)  printf ("0x");
+       printf ("%x",u);
+       break;
+  case ci_tcdouble:
+       printf ("%g",*(eptr->ci_ucdouble.ci_dval));
+       break;
+  case ci_tcfloat:
+       printf ("%g",*(eptr->ci_ucfloat.ci_fval));
+       break;
+  case ci_tcbool:
+       i = *(eptr->ci_ucbool.ci_bval);
+       if (i)  printf ("yes");
+       else    printf ("no");
+       break;
+  case ci_tcchr:
+       i = *(eptr->ci_ucchr.ci_cval);
+       printf ("%c",eptr->ci_ucchr.ci_cleg[i]);
+       break;
+  case ci_tcstring:
+       printf ("%s",eptr->ci_ucstring.ci_pval);
+       break;
+  case ci_tctab:
+       i = *(eptr->ci_ucstab.ci_tval);
+       printf ("%s",eptr->ci_ucstab.ci_ttab[i]);
+       break;
+  case ci_tcsearch:
+       i = *(eptr->ci_ucsearch.ci_tval);
+       printf ("%s",eptr->ci_ucsearch.ci_ttab[i]);
+       break;
+  default:
+       printf ("Yeek!  Illegal cientry type %d!\n",(int) etype);
+  }
+}
+
+/*************************************************************
+ ***    A S S I G N   V A L U E   T O   V A R I A B L E    ***
+ *************************************************************/
+
+static ci_set (entry,arg)
+CIENTRY entry;
+char *arg;
+{
+  if (entry.ci_etyp == ci_tproc) {     /* variable procedure */
+       (* (int(*)()) (entry.ci_eptr)) (CISET,arg);
+  }
+  else if (entry.ci_etyp == ci_tclass) {       /* class variable */
+       (* (int(*)()) (entry.ci_eptr)) (CISET,arg,entry.ci_evar,entry.ci_enam);
+  }
+  else {
+       _ci_set (entry.ci_etyp, entry.ci_eptr, arg);
+       if (!(ciquiet & (((ciinput==stdin)||(ciinput==stderr)) ? CISETPEEK : CICMDFPEEK)))
+               ci_show (entry,arg,CIPEEK);
+  }
+}
+
+static _ci_set (etype,eptr,arg)
+ci_type etype;
+ci_union *eptr;
+char *arg;
+{
+  int i;
+  unsigned int u;
+  char *p;
+
+  if (etype == ci_tstring) {
+       strcpy ((char *)eptr,arg);
+       return;
+  }
+  if (etype == ci_tcstring) {
+       strarg (&arg, ";", eptr->ci_ucstring.ci_pmsg,
+       eptr->ci_ucstring.ci_pval,eptr->ci_ucstring.ci_pval);
+       return;
+  }
+
+  p = arg;             /* parse first word */
+  arg = nxtarg (&p,0);
+
+  switch (etype) {
+
+  case ci_tint:
+       eptr->ci_uint = atoi (arg);
+       break;
+  case ci_tshort:
+       eptr->ci_ushort = atoi (arg);
+       break;
+  case ci_tlong:
+       eptr->ci_ulong = atol (arg);
+       break;
+  case ci_toct:
+       eptr->ci_uoct = atoo (arg);
+       break;
+  case ci_thex:
+       if (stlmatch(arg,"0x") || stlmatch(arg,"0X"))  arg += 2;
+       eptr->ci_uhex = atoh (arg);
+       break;
+  case ci_tdouble:
+       eptr->ci_udouble = atof (arg);
+       break;
+  case ci_tfloat:
+       eptr->ci_ufloat = atof (arg);
+       break;
+  case ci_tbool:
+       eptr->ci_ubool = (index("yYtT",*arg) != 0);
+       break;
+  case ci_tcint:
+       *(eptr->ci_ucint.ci_ival) =
+       intarg (&arg,0,eptr->ci_ucint.ci_imsg,eptr->ci_ucint.ci_imin,
+       eptr->ci_ucint.ci_imax,*(eptr->ci_ucint.ci_ival));
+       break;
+  case ci_tcshort:
+       *(eptr->ci_ucshort.ci_sval) =
+       shortarg (&arg,0,eptr->ci_ucshort.ci_smsg,eptr->ci_ucshort.ci_smin,
+       eptr->ci_ucshort.ci_smax,*(eptr->ci_ucshort.ci_sval));
+       break;
+  case ci_tclong:
+       *(eptr->ci_uclong.ci_lval) =
+       longarg (&arg,0,eptr->ci_uclong.ci_lmsg,eptr->ci_uclong.ci_lmin,
+       eptr->ci_uclong.ci_lmax,*(eptr->ci_uclong.ci_lval));
+       break;
+  case ci_tcoct:
+       *(eptr->ci_ucoct.ci_uval) =
+       octarg (&arg,0,eptr->ci_ucoct.ci_umsg,eptr->ci_ucoct.ci_umin,
+       eptr->ci_ucoct.ci_umax,*(eptr->ci_ucoct.ci_uval));
+       break;
+  case ci_tchex:
+       *(eptr->ci_uchex.ci_uval) =
+       hexarg (&arg,0,eptr->ci_uchex.ci_umsg,eptr->ci_uchex.ci_umin,
+       eptr->ci_uchex.ci_umax,*(eptr->ci_uchex.ci_uval));
+       break;
+  case ci_tcdouble:
+       *(eptr->ci_ucdouble.ci_dval) =
+       doublearg (&arg,0,eptr->ci_ucdouble.ci_dmsg,eptr->ci_ucdouble.ci_dmin,
+       eptr->ci_ucdouble.ci_dmax,*(eptr->ci_ucdouble.ci_dval));
+       break;
+  case ci_tcfloat:
+       *(eptr->ci_ucfloat.ci_fval) =
+       floatarg (&arg,0,eptr->ci_ucfloat.ci_fmsg,eptr->ci_ucfloat.ci_fmin,
+       eptr->ci_ucfloat.ci_fmax,*(eptr->ci_ucfloat.ci_fval));
+       break;
+  case ci_tcbool:
+       *(eptr->ci_ucbool.ci_bval) =
+       boolarg (&arg,0,eptr->ci_ucbool.ci_bmsg,*(eptr->ci_ucbool.ci_bval));
+       break;
+  case ci_tcchr:
+       *(eptr->ci_ucchr.ci_cval) =
+       chrarg (&arg,0,eptr->ci_ucchr.ci_cmsg,eptr->ci_ucchr.ci_cleg,
+       eptr->ci_ucchr.ci_cleg[*(eptr->ci_ucchr.ci_cval)]);
+       break;
+  case ci_tctab:
+       *(eptr->ci_ucstab.ci_tval) =
+       stabarg (&arg,0,eptr->ci_ucstab.ci_tmsg,eptr->ci_ucstab.ci_ttab,
+       eptr->ci_ucstab.ci_ttab[*(eptr->ci_ucstab.ci_tval)]);
+       break;
+  case ci_tcsearch:
+       *(eptr->ci_ucsearch.ci_tval) =
+       searcharg (&arg,0,eptr->ci_ucsearch.ci_tmsg,
+       eptr->ci_ucsearch.ci_ttab,
+       eptr->ci_ucsearch.ci_ttab[*(eptr->ci_ucsearch.ci_tval)]);
+       break;
+  default:;
+  }
+}
diff --git a/usr.bin/sup/src/crypt.diffs b/usr.bin/sup/src/crypt.diffs
new file mode 100644 (file)
index 0000000..c1201ce
--- /dev/null
@@ -0,0 +1,87 @@
+118,$c
+void encode (in,out,count)
+char *in,*out;
+int count;
+{
+       decode (in,out,count);
+}
+.
+109,113c
+                       nr2 = n2;
+.
+103c
+               *outp++ = i;
+.
+95,101c
+       while(count -- > 0) {
+               i = *inp++;
+               nr1 = n1;
+.
+93a
+       inp = in;
+       outp = out;
+.
+86,90c
+       return (SCMOK);
+}
+
+void decode (in,out,count)
+char *in,*out;
+register int count;
+{
+       register i, n1, n2, nr1, nr2;
+       char *inp, *outp;
+.
+81,84c
+       if (cryptflag == 0) {
+               if (cryptsize > 0)  free (cryptbuf);
+               cryptsize = 0;
+       } else if (x > cryptsize) {
+               if (cryptsize > 0)  free (cryptbuf);
+               cryptbuf = malloc ((unsigned)x+1);
+               if (cryptbuf == NULL)
+                       return (scmerr (-1,"Can't allocate encryption buffer"));
+               cryptsize = x;
+.
+78,79c
+       static int cryptsize = 0;       /* size of current cryptbuf */
+.
+75,76c
+int getcryptbuf (x)
+int x;
+.
+72a
+       return (SCMOK);
+.
+54d
+42,48c
+       cryptflag = 1;
+       for (i=0; i<ROTORSZ; i++)  t1[i] = t2[i] = t3[i] = 0;
+       (void) strncpy(buf, pw, 8);
+       (void) strncpy(buf, crypt(buf, buf), 13);
+.
+27,40c
+       if (pw == NULL) {
+               cryptflag = 0;
+               (void) getcryptbuf (0);
+               return (SCMOK);
+.
+23d
+19c
+netcrypt(pw)
+.
+12,17c
+static char t1[ROTORSZ];
+static char t2[ROTORSZ];
+static char t3[ROTORSZ];
+static char buf[13];
+int cryptflag = 0;             /* whether to encrypt/decrypt data */
+char *cryptbuf;                        /* buffer for data encryption/decryption */
+.
+9a
+#include "sup.h"
+
+extern char *malloc();
+
+.
+w netcrypt.c
diff --git a/usr.bin/sup/src/crypt.info b/usr.bin/sup/src/crypt.info
new file mode 100644 (file)
index 0000000..badffcc
--- /dev/null
@@ -0,0 +1,15 @@
+The sup programs can be built with or without crypting functionality.
+If the file  netcryptvoid.c is used no crypting code will be used.
+If the file netcrypt.c is used, an engima engine crypting scheme
+taken from the BSD 4.3 (1/25/85) file /usr/bin/crypt.c will be used. Since,
+this code is both licensed and under U.S. foreign trade restrictions,
+we cannot make this code available for anonymous FTP. 
+
+If you want to build a sup client which can encrypt data and you
+are a domestic site who has a 4.3 BSD license, we can mail you
+a copy of then netcrypt.c file. Just send mail to mach@cs.cmu.edu
+requesting the file. 
+
+If you have a crypt.c file available, copy it to the directory
+./crypt and the makefile file apply the diff in crypt.diffs to
+generate the netcrypt.c file.
diff --git a/usr.bin/sup/src/cvt.c b/usr.bin/sup/src/cvt.c
new file mode 100644 (file)
index 0000000..0551a26
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Quick hack to convert old binary sup when.collection files into 
+ * the new ascii format.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int
+main(argc, argv)
+       int argc;
+       char *argv[];
+{
+       long b;
+       FILE *fp;
+       int fd;
+
+       if (argc != 2) {
+               (void) fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
+               return 1;
+       }
+
+       if ((fd = open(argv[1], O_RDWR)) == -1) {
+               perror("open");
+               return 1;
+       }
+
+       if (read(fd, &b, sizeof(b)) != sizeof(b)) {
+               perror("read");
+               return 1;
+       }
+
+       if (lseek(fd, 0, SEEK_SET) == -1) {
+               perror("lseek");
+               return 1;
+       }
+
+       (void) close(fd);
+
+       if ((fp = fopen(argv[1], "w")) == NULL) {
+               perror("fopen");
+               return 1;
+       }
+
+       if (fprintf(fp, "%ld\n", b) < 0) {
+               perror("fprintf");
+               return 1;
+       }
+       if (fclose(fp) != 0) {
+               perror("fclose");
+               return 1;
+       }
+
+       return 0;
+}
diff --git a/usr.bin/sup/src/errmsg.c b/usr.bin/sup/src/errmsg.c
new file mode 100644 (file)
index 0000000..0ca7c9d
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*****************************************************************
+ * HISTORY
+ * 04-Mar-85  Rudy Nedved (ern) at Carnegie-Mellon University
+ *     Create a CMU version of the BBN errmsg routine from scratch. It
+ *     differs from the BBN errmsg routine in the fact that it uses a
+ *     negative value to indicate using the current errno value...the
+ *     BBN uses a negative OR zero value.
+ */
+
+extern int     errno;
+extern int     sys_nerr;
+extern char    *sys_errlist[];
+
+static char *itoa(p,n)
+char *p;
+unsigned n;
+{
+    if (n >= 10)
+       p =itoa(p,n/10);
+    *p++ = (n%10)+'0';
+    return(p);
+}
+
+char *errmsg(cod)
+int cod;
+{
+       static char unkmsg[] = "Unknown error ";
+       static char unk[sizeof(unkmsg)+11];             /* trust us */
+
+       if (cod < 0) cod = errno;
+
+       if((cod >= 0) && (cod < sys_nerr))
+           return(sys_errlist[cod]);
+
+       strcpy(unk,unkmsg);
+       *itoa(&unk[sizeof(unkmsg)-1],cod) = '\0';
+
+       return(unk);
+}
diff --git a/usr.bin/sup/src/expand.c b/usr.bin/sup/src/expand.c
new file mode 100644 (file)
index 0000000..0014ebb
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*
+ *  expand - expand wildcard filename specifications
+ *
+ *  Usage:
+ *     int expand(spec, buffer, bufsize);
+ *     char *spec, **buffer;
+ *     int bufsize;
+ *
+ *  Expand takes a file specification, and expands it into filenames
+ *  by resolving the characters '*', '?', '[', ']', '{', '}' and '~'
+ *  in the same manner as the shell.  You provide "buffer", which is
+ *  an array of char *'s, and you tell how big it is in bufsize.
+ *  Expand will compute the corresponding filenames, and will fill up
+ *  the entries of buffer with pointers to malloc'd strings.
+ *
+ *  The value returned by expand is the number of filenames found.  If
+ *  this value is -1, then malloc failed to allocate a string.  If the
+ *  value is bufsize + 1, then too many names were found and you can try
+ *  again with a bigger buffer.
+ *
+ *  This routine was basically created from the csh sh.glob.c file with
+ *  the following intended differences:
+ *
+ *     Filenames are not sorted.
+ *     All expanded filenames returned exist.
+ *
+ **********************************************************************
+ * HISTORY
+ * 13-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Replaced a stat() with lstat() and changed glob() to only call
+ *     matchdir() for directories.
+ *
+ * 20-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Created from csh glob() function and 4.1 expand() function.
+ *
+ **********************************************************************
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAS_POSIX_DIR
+#include <dirent.h>
+#else
+#include <sys/dir.h>
+#endif
+#include <pwd.h>
+#include <ctype.h>
+#include <libc.h>
+#include <setjmp.h>
+
+static jmp_buf sjbuf;
+
+static char    pathbuf[MAXPATHLEN];
+static char    *path, *pathp, *lastpathp;
+
+static char    *globchars = "{[*?";    /* meta characters */
+static char    *entp;                  /* current dir entry pointer */
+
+static char    **BUFFER;               /* pointer to the buffer */
+static int     BUFSIZE;                /* maximum number in buffer */
+static int     bufcnt;                 /* current number in buffer */
+
+static void glob();
+static void matchdir();
+static int execbrc();
+static int match();
+static int amatch();
+static void addone();
+static int addpath();
+static int gethdir();
+
+int expand(spec, buffer, bufsize)
+       register char *spec;
+       char **buffer;
+       int bufsize;
+{
+       pathp = path = pathbuf;
+       *pathp = 0;
+       lastpathp = &path[MAXPATHLEN - 2];
+       BUFFER = buffer;
+       BUFSIZE = bufsize;
+       bufcnt = 0;
+       if (setjmp(sjbuf) == 0)
+           glob(spec);
+       return(bufcnt);
+}
+
+static void glob(as)
+       char *as;
+{
+       register char *cs;
+       register char *spathp, *oldcs;
+       struct stat stb;
+
+       spathp = pathp;
+       cs = as;
+       if (*cs == '~' && pathp == path) {
+               if (addpath('~')) goto endit;
+               for (cs++; isalnum(*cs) || *cs == '_' || *cs == '-';)
+                       if (addpath(*cs++)) goto endit;
+               if (!*cs || *cs == '/') {
+                       if (pathp != path + 1) {
+                               *pathp = 0;
+                               if (gethdir(path + 1)) goto endit;
+                               strcpy(path, path + 1);
+                       } else
+                               strcpy(path, (char *)getenv("HOME"));
+                       pathp = path;
+                       while (*pathp) pathp++;
+               }
+       }
+       while (*cs == 0 || index(globchars, *cs) == 0) {
+               if (*cs == 0) {
+                       if (lstat(path, &stb) >= 0) addone(path, "");
+                       goto endit;
+               }
+               if (addpath(*cs++)) goto endit;
+       }
+       oldcs = cs;
+       while (cs > as && *cs != '/')
+               cs--, pathp--;
+       if (*cs == '/')
+               cs++, pathp++;
+       *pathp = 0;
+       if (*oldcs == '{') {
+               execbrc(cs, NULL);
+               return;
+       }
+       /* this should not be an lstat */
+       if (stat(path, &stb) >= 0 && (stb.st_mode&S_IFMT) == S_IFDIR)
+               matchdir(cs);
+endit:
+       pathp = spathp;
+       *pathp = 0;
+       return;
+}
+
+static void matchdir(pattern)
+       char *pattern;
+{
+#ifdef HAS_POSIX_DIR
+       register struct dirent *dp;
+#else
+       register struct direct *dp;
+#endif
+       DIR *dirp;
+
+       dirp = opendir(path);
+       if (dirp == NULL)
+               return;
+       while ((dp = readdir(dirp)) != NULL) {
+#ifdef HAS_POSIX_DIR
+               if (dp->d_fileno == 0) continue;
+#else
+               if (dp->d_ino == 0) continue;
+#endif
+               if (match(dp->d_name, pattern))
+                       addone(path, dp->d_name);
+       }
+       closedir(dirp);
+       return;
+}
+
+static int execbrc(p, s)
+       char *p, *s;
+{
+       char restbuf[MAXPATHLEN + 1];
+       register char *pe, *pm, *pl;
+       int brclev = 0;
+       char *lm, savec, *spathp;
+
+       for (lm = restbuf; *p != '{'; *lm++ = *p++)
+               continue;
+       for (pe = ++p; *pe; pe++)
+       switch (*pe) {
+       case '{':
+               brclev++;
+               continue;
+       case '}':
+               if (brclev == 0) goto pend;
+               brclev--;
+               continue;
+       case '[':
+               for (pe++; *pe && *pe != ']'; pe++)
+                       continue;
+               if (!*pe) break;
+               continue;
+       }
+pend:
+       if (brclev || !*pe) return (0);
+       for (pl = pm = p; pm <= pe; pm++)
+               switch (*pm & 0177) {
+               case '{':
+                       brclev++;
+                       continue;
+               case '}':
+                       if (brclev) {
+                               brclev--;
+                               continue;
+                       }
+                       goto doit;
+               case ',':
+                       if (brclev) continue;
+doit:
+                       savec = *pm;
+                       *pm = 0;
+                       strcpy(lm, pl);
+                       strcat(restbuf, pe + 1);
+                       *pm = savec;
+                       if (s == 0) {
+                               spathp = pathp;
+                               glob(restbuf);
+                               pathp = spathp;
+                               *pathp = 0;
+                       } else if (amatch(s, restbuf))
+                               return (1);
+                       pl = pm + 1;
+                       continue;
+
+               case '[':
+                       for (pm++; *pm && *pm != ']'; pm++)
+                               continue;
+                       if (!*pm) break;
+                       continue;
+               }
+       return (0);
+}
+
+static int match(s, p)
+       char *s, *p;
+{
+       register int c;
+       register char *sentp;
+
+       if (*s == '.' && *p != '.') return(0);
+       sentp = entp;
+       entp = s;
+       c = amatch(s, p);
+       entp = sentp;
+       return (c);
+}
+
+static int amatch(s, p)
+       register char *s, *p;
+{
+       register int scc;
+       int ok, lc;
+       char *spathp;
+       struct stat stb;
+       int c, cc;
+
+       for (;;) {
+               scc = *s++ & 0177;
+               switch (c = *p++) {
+               case '{':
+                       return (execbrc(p - 1, s - 1));
+               case '[':
+                       ok = 0;
+                       lc = 077777;
+                       while (cc = *p++) {
+                               if (cc == ']') {
+                                       if (ok) break;
+                                       return (0);
+                               }
+                               if (cc == '-') {
+                                       if (lc <= scc && scc <= *p++)
+                                               ok++;
+                               } else
+                                       if (scc == (lc = cc))
+                                               ok++;
+                       }
+                       if (cc == 0) return (0);
+                       continue;
+               case '*':
+                       if (!*p) return (1);
+                       if (*p == '/') {
+                               p++;
+                               goto slash;
+                       }
+                       for (s--; *s; s++)
+                               if (amatch(s, p))
+                                       return (1);
+                       return (0);
+               case 0:
+                       return (scc == 0);
+               default:
+                       if (c != scc) return (0);
+                       continue;
+               case '?':
+                       if (scc == 0) return (0);
+                       continue;
+               case '/':
+                       if (scc) return (0);
+slash:
+                       s = entp;
+                       spathp = pathp;
+                       while (*s)
+                               if (addpath(*s++)) goto pathovfl;
+                       if (addpath('/')) goto pathovfl;
+                       if (stat(path, &stb) >= 0 &&
+                           (stb.st_mode&S_IFMT) == S_IFDIR)
+                               if (*p == 0)
+                                       addone(path, "");
+                               else
+                                       glob(p);
+pathovfl:
+                       pathp = spathp;
+                       *pathp = 0;
+                       return (0);
+               }
+       }
+}
+
+static void addone(s1, s2)
+       register char *s1, *s2;
+{
+       register char *ep;
+
+       if (bufcnt >= BUFSIZE) {
+               bufcnt = BUFSIZE + 1;
+               longjmp(sjbuf, 1);
+       }
+       ep = (char *)malloc(strlen(s1) + strlen(s2) + 1);
+       if (ep == 0) {
+               bufcnt = -1;
+               longjmp(sjbuf, 1);
+       }
+       BUFFER[bufcnt++] = ep;
+       while (*s1) *ep++ = *s1++;
+       while (*ep++ = *s2++);
+}
+
+static int addpath(c)
+       char c;
+{
+       if (pathp >= lastpathp)
+               return(1);
+       *pathp++ = c;
+       *pathp = 0;
+       return(0);
+}
+
+static int gethdir(home)
+       char *home;
+{
+       struct passwd *getpwnam();
+       register struct passwd *pp = getpwnam(home);
+
+       if (pp == 0)
+               return(1);
+       strcpy(home, pp->pw_dir);
+       return(0);
+}
diff --git a/usr.bin/sup/src/ffilecopy.c b/usr.bin/sup/src/ffilecopy.c
new file mode 100644 (file)
index 0000000..e683423
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*  ffilecopy  --  very fast buffered file copy
+ *
+ *  Usage:  i = ffilecopy (here,there)
+ *     int i;
+ *     FILE *here, *there;
+ *
+ *  Ffilecopy is a very fast routine to copy the rest of a buffered
+ *  input file to a buffered output file.  Here and there are open
+ *  buffers for reading and writing (respectively); ffilecopy
+ *  performs a file-copy faster than you should expect to do it
+ *  yourself.  Ffilecopy returns 0 if everything was OK; EOF if
+ *  there was any error.  Normally, the input file will be left in
+ *  EOF state (feof(here) will return TRUE), and the output file will be
+ *  flushed (i.e. all data on the file rather in the core buffer).
+ *  It is not necessary to flush the output file before ffilecopy.
+ *
+ *  HISTORY
+ * 20-Nov-79  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Created for VAX.
+ *
+ */
+
+#include <stdio.h>
+int filecopy();
+
+int ffilecopy (here,there)
+FILE *here, *there;
+{
+       register int i, herefile, therefile;
+
+       herefile = fileno(here);
+       therefile = fileno(there);
+
+       if (fflush (there) == EOF)              /* flush pending output */
+               return (EOF);
+
+#if    defined(__386BSD__) || defined(__NetBSD__)
+       if ((here->_r) > 0) {                   /* flush buffered input */
+               i = write (therefile, here->_p, here->_r);
+               if (i != here->_r)  return (EOF);
+               here->_p = here->_bf._base;
+               here->_r = 0;
+       }
+#else
+       if ((here->_cnt) > 0) {                 /* flush buffered input */
+               i = write (therefile, here->_ptr, here->_cnt);
+               if (i != here->_cnt)  return (EOF);
+               here->_ptr = here->_base;
+               here->_cnt = 0;
+       }
+#endif
+       i = filecopy (herefile, therefile);     /* fast file copy */
+       if (i < 0)  return (EOF);
+
+#if    defined(__386BSD__) || defined(__NetBSD__)
+       (here->_flags) |= __SEOF;               /* indicate EOF */
+#else
+       (here->_flag) |= _IOEOF;                /* indicate EOF */
+#endif
+       return (0);
+}
diff --git a/usr.bin/sup/src/filecopy.c b/usr.bin/sup/src/filecopy.c
new file mode 100644 (file)
index 0000000..553becb
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*  filecopy  --  copy a file from here to there
+ *
+ *  Usage:  i = filecopy (here,there);
+ *     int i, here, there;
+ *
+ *  Filecopy performs a fast copy of the file "here" to the
+ *  file "there".  Here and there are both file descriptors of
+ *  open files; here is open for input, and there for output.
+ *  Filecopy returns 0 if all is OK; -1 on error.
+ *
+ *  I have performed some tests for possible improvements to filecopy.
+ *  Using a buffer size of 10240 provides about a 1.5 times speedup
+ *  over 512 for a file of about 200,000 bytes.  Of course, other
+ *  buffer sized should also work; this is a rather arbitrary choice.
+ *  I have also tried inserting special startup code to attempt
+ *  to align either the input or the output file to lie on a
+ *  physical (512-byte) block boundary prior to the big loop,
+ *  but this presents only a small (about 5% speedup, so I've
+ *  canned that code.  The simple thing seems to be good enough.
+ *
+ *  HISTORY
+ * 20-Nov-79  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Rewritten for VAX; same as "filcopy" on PDP-11.  Bigger buffer
+ *     size (20 physical blocks) seems to be a big win; aligning things
+ *     on block boundaries seems to be a negligible improvement at
+ *     considerable cost in complexity.
+ *
+ */
+
+#define BUFFERSIZE 10240
+
+int filecopy (here,there)
+int here,there;
+{
+       register int kount;
+       char buffer[BUFFERSIZE];
+       kount = 0;
+       while (kount == 0 && (kount=read(here,buffer,BUFFERSIZE)) > 0)
+               kount -= write (there,buffer,kount);
+       return (kount ? -1 : 0);
+}
diff --git a/usr.bin/sup/src/libc.h b/usr.bin/sup/src/libc.h
new file mode 100644 (file)
index 0000000..bac8444
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*
+ **********************************************************************
+ * HISTORY
+ * $Log: libc.h,v $
+ * Revision 1.1  1995/12/16 11:46:46  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:17  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.7  89/04/03  11:10:45  vanryzin
+ *     Changed definition of qsort for c++ to indicate the procedure
+ *     passed to qsort has parameters.  Since we were unsure if ANSI C
+ *     could handle the syntax I placed the new definition within #if
+ *     defined(c_plusplus) conditionals.  This may not be necessary
+ *     and perhaps should be fixed at a later time.
+ *     [89/04/03            vanryzin]
+ * 
+ * Revision 1.6  89/02/05  15:55:57  gm0w
+ *     Added extern char *errmsg().
+ *     [89/02/04            gm0w]
+ * 
+ * Revision 1.5  89/01/20  15:34:40  gm0w
+ *     Moved all of the STDC changes to other existing include files
+ *     back into this one.  Added non-STDC extern declarations for
+ *     all functions without int return values to match those defined
+ *     by STDC.  Added include of sysent.h.  Removed obsolete cdate
+ *     extern declaration.
+ *     [88/12/17            gm0w]
+ * 
+ * Revision 1.4  88/12/22  16:58:56  mja
+ *     Correct __STDC__ parameter type for getenv().
+ *     [88/12/20            dld]
+ * 
+ * Revision 1.3  88/12/14  23:31:42  mja
+ *     Made file reentrant.  Added declarations for __STDC__.
+ *     [88/01/06            jjk]
+ * 
+ * 30-Apr-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added pathof() extern.
+ *
+ * 01-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added getname() extern.
+ *
+ * 29-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added lseek() extern.
+ *
+ * 02-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added salloc() extern.
+ *
+ * 14-Aug-81  Mike Accetta (mja) at Carnegie-Mellon University
+ *     Created.
+ *
+ **********************************************************************
+ */
+
+#ifndef        _LIBC_H_
+#define        _LIBC_H_ 1
+
+#ifndef _TYPES_
+#include <sys/types.h>
+#endif /* _TYPES_ */
+
+#ifndef        _SYSENT_H_
+#include <sysent.h>
+#endif /* _SYSENT_H_ */
+
+#ifndef        FILE
+#include <stdio.h>
+#endif /* FILE */
+
+#ifndef        _STRINGS_H_
+#include <strings.h>
+#endif /* _STRINGS_H_ */
+
+#ifndef        _TIME_H_
+#include <time.h>
+#endif /* _TIME_H_ */
+
+/*  CMU stdio additions */
+#if defined(__STDC__)
+extern FILE *fopenp(const char*, const char*, char*, char*);
+extern FILE *fwantread(const char*, const char*, const char*, const char*);
+extern FILE *fwantwrite(const char*, const char*, const char*, const char*,
+                       int);
+#else  /* __STDC__ */
+extern FILE *fopenp();
+extern FILE *fwantread();
+extern FILE *fwantwrite();
+#endif /* __STDC__ */
+
+/* CMU string routines */
+#if defined(__STDC__)
+extern char* foldup(char*, const char*);
+extern char* folddown(char*, const char*);
+extern char* sindex(const char*, const char*);
+extern char* skipto(const char*, const char*);
+extern char* skipover(const char*, const char*);
+extern char* nxtarg(char**, const char*);
+extern char _argbreak;
+extern char* getstr(const char*, char*, char*);
+extern int getstab(const char*, const char**, const char*);
+extern int getsearch(const char*, const char**, const char*);
+extern char* strarg(const char**, const char*, const char*, char*, char*);
+extern int stabarg(const char**, const char*, const char*, const char**,
+                  const char*);
+extern int searcharg(const char**, const char*, const char*, const char**,
+                    const char*);
+extern int getint(const char*, int, int, int);
+extern int intarg(const char**, const char*, const char*, int, int, int);
+extern long getlong(const char*, long, long, long);
+extern long longarg(const char**, const char*, const char*, long, long, long);
+extern short getshort(const char*, short, short, short);
+extern short shortarg(const char**, const char*, const char*,
+                     short, short, short);
+extern float getfloat(const char*, float, float, float);
+extern float floatarg(const char**, const char*, const char*,
+                     float, float, float);
+extern double getdouble(const char*, double, double, double);
+extern double doublearg(const char**, const char*, const char*,
+                       double, double, double);
+extern unsigned int getoct(const char*, unsigned int, unsigned int,
+                          unsigned int);
+extern unsigned int octarg(const char**, const char*, const char*,
+                          unsigned int, unsigned int, unsigned int);
+extern unsigned int gethex(const char*, unsigned int, unsigned int,
+                          unsigned int);
+extern unsigned int hexarg(const char**, const char*, const char*,
+                          unsigned int, unsigned int, unsigned int);
+extern unsigned int atoo(const char*);
+extern unsigned int atoh(const char*);
+extern char *salloc(const char*);
+extern char *concat(const char*, int, ...);
+#else  /* __STDC__ */
+extern char *foldup(), *folddown();
+extern char *sindex(), *skipto(), *skipover(), *nxtarg();
+extern char *getstr(), *strarg();
+extern long getlong(), longarg();
+extern short getshort(), shortarg();
+extern float getfloat(), floatarg();
+extern double getdouble(), doublearg();
+extern unsigned int getoct(), octarg(), gethex(), hexarg();
+extern unsigned int atoo(), atoh();
+extern char *salloc();
+extern char *concat();
+#endif /* __STDC__ */
+
+/* CMU library routines */
+#if defined(__STDC__)
+extern char *getname(int);
+extern char *pathof(char *);
+extern char *errmsg(int);
+#else  /* __STDC__ */
+extern char *getname();
+extern char *pathof();
+extern char *errmsg();
+#endif /* __STDC__ */
+
+/*  CMU time additions */
+#if defined(__STDC__)
+extern long gtime(const struct tm*);
+extern long atot(const char*);
+#else  /* __STDC__ */
+extern long gtime();
+extern long atot();
+#endif /* __STDC__ */
+
+/* 4.3 BSD standard library routines; taken from man(3) */
+#if defined(__STDC__)
+typedef int (*PFI)();
+#if defined(c_plusplus)
+typedef int (*PFI2)(...);
+#endif /* c_plusplus */
+#if 0
+extern void abort(void);
+extern int abs(int);
+extern double atof(const char *);
+extern int atoi(const char *);
+extern long atol(const char *);
+extern void bcopy(const void *, void *, int);
+extern int bcmp(const void *, const void *, int);
+extern void bzero(void *, int);
+extern int ffs(int);
+extern char *crypt(const char *, const char *);
+extern void setkey(char *);
+extern void encrypt(char *, int);
+extern char *ecvt(double, int, int *, int *);
+extern char *fcvt(double, int, int *, int *);
+extern char *gcvt(double, int, char *);
+extern int execl(const char *, ...);
+extern int execv(const char *, const char **);
+extern int execle(const char *, ...);
+extern int exect(const char *, const char **, const char **);
+extern void exit(int);
+extern char *getenv(const char *);
+extern char *getlogin(void);
+extern int getopt(int, const char **, const char *);
+extern char *getpass(const char *);
+extern char *getusershell(void);
+extern void setusershell(void);
+extern void endusershell(void);
+extern char *getwd(char *);
+extern int initgroups(const char *, gid_t);
+extern void *malloc(unsigned);
+extern void free(void *);
+extern void *realloc(void *, unsigned);
+extern void *calloc(unsigned, unsigned);
+extern void *alloca(int);
+extern char *mktemp(char *);
+extern int mkstemp(char *);
+extern void monitor(PFI, PFI, short *, int, int);
+extern void monstartup(PFI, PFI);
+extern void moncontrol(int);
+extern int pause(void);
+#if defined(c_plusplus)
+extern void qsort(void *, int, int, PFI2);
+#else /* c_plusplus */
+extern void qsort(void *, int, int, PFI);
+#endif /* c_plusplus */
+extern long random(void);
+extern int srandom(int);
+extern void *initstate(unsigned, void *, int);
+extern void *setstate(void *);
+extern int rcmd(char **, int, const char *, const char *, const char *, int);
+extern int rresvport(int *);
+extern int ruserok(char *, int, const char *, const char *);
+extern char *re_comp(char *);
+extern int re_exec(char *);
+extern int rexec(char **, int, const char *, const char *, const char *,
+                int *);
+extern int setuid(uid_t);
+extern int seteuid(uid_t);
+extern int setruid(uid_t);
+extern int setgid(gid_t);
+extern int setegid(gid_t);
+extern int setrgid(gid_t);
+extern void sleep(unsigned);
+extern void swab(void *, void *, int);
+extern int system(const char *);
+extern char *ttyname(int);
+extern int isatty(int);
+extern int ttyslot(void);
+extern unsigned ualarm(unsigned, unsigned);
+extern void usleep(unsigned);
+#endif
+#else  /* __STDC__ */
+extern double atof();
+extern long atol();
+extern char *crypt();
+extern char *ecvt();
+extern char *fcvt();
+extern char *gcvt();
+extern char *getenv();
+extern char *getlogin();
+extern char *getpass();
+extern char *getusershell();
+extern char *getwd();
+extern char *malloc();
+extern char *realloc();
+extern char *calloc();
+extern char *alloca();
+extern char *mktemp();
+extern long random();
+extern char *initstate();
+extern char *setstate();
+extern char *re_comp();
+extern char *ttyname();
+extern unsigned ualarm();
+#endif /* __STDC__ */
+#endif /* not _LIBC_H_ */
diff --git a/usr.bin/sup/src/log.c b/usr.bin/sup/src/log.c
new file mode 100644 (file)
index 0000000..4a0ab60
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Logging support for SUP
+ **********************************************************************
+ * HISTORY
+ * $Log: log.c,v $
+ * Revision 1.1  1995/12/16 11:46:47  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:17  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.5  92/08/11  12:03:43  mrt
+ *     Brad's delinting and variable argument list usage
+ *     changes. Added copyright.
+ * 
+ * Revision 1.3  89/08/15  15:30:37  bww
+ *     Updated to use v*printf() in place of _doprnt().
+ *     From "[89/04/19            mja]" at CMU.
+ *     [89/08/15            bww]
+ * 
+ * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added check to allow logopen() to be called multiple times.
+ *
+ * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Created.
+ *
+ **********************************************************************
+ */
+
+#include <stdio.h>
+#include <sys/syslog.h>
+#include <c.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "sup.h"
+
+#ifdef lint
+/*VARARGS1*//*ARGSUSED*/
+static void quit(status) {};
+#endif /* lint */
+
+static int opened = 0;
+
+logopen(program)
+char *program;
+{
+       if (opened)  return;
+       openlog(program,LOG_PID,LOG_DAEMON);
+       opened++;
+}
+
+#if __STDC__
+logquit(int retval,char *fmt,...)
+#else
+/*VARARGS*//*ARGSUSED*/
+logquit(va_alist)
+va_dcl
+#endif
+{
+#if !__STDC__
+       int retval;
+       char *fmt;
+#endif
+       char buf[STRINGLENGTH];
+       va_list ap;
+
+#if __STDC__
+       va_start(ap,fmt);
+#else
+       va_start(ap);
+       retval = va_arg(ap,int);
+       fmt = va_arg(ap,char *);
+#endif
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+       if (opened) {
+               syslog (LOG_ERR,buf);
+               closelog ();
+               exit (retval);
+       }
+       quit (retval,"SUP: %s\n",buf);
+}
+
+#if __STDC__
+logerr(char *fmt,...)
+#else
+/*VARARGS*//*ARGSUSED*/
+logerr(va_alist)
+va_dcl
+#endif
+{
+#if !__STDC__
+       char *fmt;
+#endif
+       char buf[STRINGLENGTH];
+       va_list ap;
+
+#if __STDC__
+       va_start(ap,fmt);
+#else
+       va_start(ap);
+       fmt = va_arg(ap,char *);
+#endif
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+       if (opened) {
+               syslog (LOG_ERR,buf);
+               return;
+       }
+       fprintf (stderr,"SUP: %s\n",buf);
+       (void) fflush (stderr);
+}
+
+#if __STDC__
+loginfo(char *fmt,...)
+#else
+/*VARARGS*//*ARGSUSED*/
+loginfo(va_alist)
+va_dcl
+#endif
+{
+#if !__STDC__
+       char *fmt;
+#endif
+       char buf[STRINGLENGTH];
+       va_list ap;
+
+#if __STDC__
+       va_start(ap,fmt);
+#else
+       va_start(ap);
+       fmt = va_arg(ap,char *);
+#endif
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+       if (opened) {
+               syslog (LOG_INFO,buf);
+               return;
+       }
+       printf ("%s\n",buf);
+       (void) fflush (stdout);
+}
diff --git a/usr.bin/sup/src/netcryptvoid.c b/usr.bin/sup/src/netcryptvoid.c
new file mode 100644 (file)
index 0000000..4676df9
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/**********************************************************************
+ * HISTORY
+ * $Log: netcryptvoid.c,v $
+ * Revision 1.1  1995/12/16 11:46:47  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:17  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 2.2  92/09/09  22:04:34  mrt
+ *     Created.
+ *     [92/09/09            mrt]
+ * 
+ */
+/*
+ * DATA ENCRYPTION
+ *     netcrypt (key)          turn on/off encryption of strings and files
+ *       char *key;                    encryption key
+ *
+ */
+
+/*
+ * Replacement for subroutine version of "crypt" program
+ *  for foreign and non-BSD-licensed sites. With this code
+ *  you can only run unencrypted sups
+ */
+
+#include <libc.h>
+#include "sup.h"
+#include "supmsg.h"
+
+/*********************************************
+ ***    G L O B A L   V A R I A B L E S    ***
+ *********************************************/
+
+int cryptflag = 0;             /* whether to encrypt/decrypt data */
+char *cryptbuf;                        /* buffer for data encryption/decryption */
+
+int netcrypt (pword)
+char *pword;
+{
+       if (pword == NULL || (strcmp(pword,PSWDCRYPT) == 0)) {
+               cryptflag = 0;
+               (void) getcryptbuf (0);
+               return (SCMOK);
+       }
+       return (SCMERR);
+}
+int getcryptbuf (x)
+int x;
+{
+       static int cryptsize = 0;       /* size of current cryptbuf */
+
+       if (cryptflag == 0) {
+               return(SCMOK);
+       } else 
+               return (SCMERR);
+}
+
+void decode (in,out,count)
+char *in,*out;
+int count;
+{
+}
+
+
+void encode (in,out,count)
+char *in,*out;
+int count;
+{
+}
diff --git a/usr.bin/sup/src/nxtarg.c b/usr.bin/sup/src/nxtarg.c
new file mode 100644 (file)
index 0000000..9e93c28
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*
+ *  nxtarg -- strip off arguments from a string
+ *
+ *  Usage:  p = nxtarg (&q,brk);
+ *     char *p,*q,*brk;
+ *     extern char _argbreak;
+ *
+ *     q is pointer to next argument in string
+ *     after call, p points to string containing argument,
+ *     q points to remainder of string
+ *
+ *  Leading blanks and tabs are skipped; the argument ends at the
+ *  first occurence of one of the characters in the string "brk".
+ *  When such a character is found, it is put into the external
+ *  variable "_argbreak", and replaced by a null character; if the
+ *  arg string ends before that, then the null character is
+ *  placed into _argbreak;
+ *  If "brk" is 0, then " " is substituted.
+ *
+ *  HISTORY
+ * 01-Jul-83  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Bug fix: added check for "back >= front" in loop to chop trailing
+ *     white space.
+ *
+ * 20-Nov-79  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Rewritten for VAX.  By popular demand, a table of break characters
+ *     has been added (implemented as a string passed into nxtarg).
+ *
+ *  Originally from klg (Ken Greer); IUS/SUS UNIX.
+ */
+
+char _argbreak;
+char *skipto();
+
+char *nxtarg (q,brk)
+char **q,*brk;
+{
+       register char *front,*back;
+       front = *q;                     /* start of string */
+       /* leading blanks and tabs */
+       while (*front && (*front == ' ' || *front == '\t')) front++;
+       /* find break character at end */
+       if (brk == 0)  brk = " ";
+       back = skipto (front,brk);
+       _argbreak = *back;
+       *q = (*back ? back+1 : back);   /* next arg start loc */
+       /* elim trailing blanks and tabs */
+       back -= 1;
+       while ((back >= front) && (*back == ' ' || *back == '\t')) back--;
+       back++;
+       if (*back)  *back = '\0';
+       return (front);
+}
diff --git a/usr.bin/sup/src/path.c b/usr.bin/sup/src/path.c
new file mode 100644 (file)
index 0000000..f982268
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*  path  --  break filename into directory and file
+ *
+ *  path (filename,direc,file);
+ *  char *filename,*direc,*file;
+ *  filename is input; direc and file are output (user-supplied).
+ *  file will not have any trailing /; direc might.
+ *
+ *  Note these rules:
+ *  1.  trailing / are ignored (except as first character)
+ *  2.  x/y is x;y where y contains no / (x may contain /)
+ *  3.  /y  is /;y where y contains no /
+ *  4.  y   is .;y where y contains no /
+ *  5.      is .;. (null filename)
+ *  6.  /   is /;. (the root directory)
+ *
+ * Algorithm is this:
+ *  1.  delete trailing / except in first position
+ *  2.  if any /, find last one; change to null; y++
+ *      else y = x;            (x is direc; y is file)
+ *  3.  if y is null, y = .
+ *  4.  if x equals y, x = .
+ *      else if x is null, x = /
+ *
+ *  HISTORY
+ * 20-Nov-79  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Copied verbatim from PDP-11.  Still as messy as ever.
+ *     Some people have asked for a modification (I think that's a better
+ *     idea than a new routine) which will change the directory name
+ *     into an absolute pathname if it isn't one already.  The change
+ *     involves doing a getwd() and prepending that if appropriate, with
+ *     a "/" in between that and the directory part of the path.
+ *     If you want to be cute, you can also resolve ".."s at that time.
+ *
+ */
+
+path (original,direc,file)
+char *original,*direc,*file;
+{
+       register char *y;
+       /* x is direc */
+       register char *p;
+
+       /* copy and note the end */
+       p = original;
+       y = direc;
+       while (*y++ = *p++) ;           /* copy string */
+       /* y now points to first char after null */
+       --y;    /* y now points to null */
+       --y;    /* y now points to last char of string before null */
+
+       /* chop off trailing / except as first character */
+       while (y>direc && *y == '/') --y;       /* backpedal past / */
+       /* y now points to char before first trailing / or null */
+       *(++y) = 0;                             /* chop off end of string */
+       /* y now points to null */
+
+       /* find last /, if any.  If found, change to null and bump y */
+       while (y>direc && *y != '/') --y;
+       /* y now points to / or direc.  Note *direc may be / */
+       if (*y == '/') {
+               *y++ = 0;
+       }
+
+       /* find file name part */
+       if (*y)  strcpy (file,y);
+       else     strcpy (file,".");
+
+       /* find directory part */
+       if (direc == y)        strcpy (direc,".");
+       else if (*direc == 0)  strcpy (direc,"/");
+       /* else direc already has proper value */
+}
diff --git a/usr.bin/sup/src/quit.c b/usr.bin/sup/src/quit.c
new file mode 100644 (file)
index 0000000..e867c8b
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*
+ *  quit  --  print message and exit
+ *
+ *  Usage:  quit (status,format [,arg]...);
+ *     int status;
+ *     (... format and arg[s] make up a printf-arglist)
+ *
+ *  Quit is a way to easily print an arbitrary message and exit.
+ *  It is most useful for error exits from a program:
+ *     if (open (...) < 0) then quit (1,"Can't open...",file);
+ *
+ **********************************************************************
+ * HISTORY
+ * $Log: quit.c,v $
+ * Revision 1.1  1995/12/16 11:46:49  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:17  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.2  88/12/13  13:52:41  gm0w
+ *     Rewritten to use varargs.
+ *     [88/12/13            gm0w]
+ * 
+ **********************************************************************
+ */
+
+#include <stdio.h>
+#include <varargs.h>
+
+quit (status, fmt, va_alist)
+int status;
+char *fmt;
+va_dcl
+{
+       va_list args;
+
+       fflush(stdout);
+       va_start(args);
+       (void) vfprintf(stderr, fmt, args);
+       va_end(args);
+       exit(status);
+}
diff --git a/usr.bin/sup/src/run.c b/usr.bin/sup/src/run.c
new file mode 100644 (file)
index 0000000..7f625c1
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*  run, runv, runp, runvp --  execute process and wait for it to exit
+ *
+ *  Usage:
+ *     i = run (file, arg1, arg2, ..., argn, 0);
+ *     i = runv (file, arglist);
+ *     i = runp (file, arg1, arg2, ..., argn, 0);
+ *     i = runvp (file, arglist);
+ *     i = runio (argv, in, out, err);
+ *
+ *  Run, runv, runp and runvp have argument lists exactly like the
+ *  corresponding routines, execl, execv, execlp, execvp.  The run
+ *  routines perform a fork, then:
+ *  IN THE NEW PROCESS, an execl[p] or execv[p] is performed with the
+ *  specified arguments.  The process returns with a -1 code if the
+ *  exec was not successful.
+ *  IN THE PARENT PROCESS, the signals SIGQUIT and SIGINT are disabled,
+ *  the process waits until the newly forked process exits, the
+ *  signals are restored to their original status, and the return
+ *  status of the process is analyzed.
+ *  All run routines return:  -1 if the exec failed or if the child was
+ *  terminated abnormally; otherwise, the exit code of the child is
+ *  returned.
+ *
+ **********************************************************************
+ * HISTORY
+ * $Log: run.c,v $
+ * Revision 1.1  1995/12/16 11:46:49  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.2  1995/06/24 16:21:33  christos
+ * - Don't use system(3) to fork processes. It is a big security hole.
+ * - Encode the filenames in the scan files using strvis(3), so filenames
+ *   that contain newlines or other weird characters don't break the scanner.
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:17  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.1  89/10/14  19:53:39  rvb
+ * Initial revision
+ * 
+ * Revision 1.2  89/08/03  14:36:46  mja
+ *     Update run() and runp() to use <varargs.h>.
+ *     [89/04/19            mja]
+ * 
+ * 23-Sep-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Merged old runv and runvp modules.
+ *
+ * 22-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added check and kill if child process was stopped.
+ *
+ * 30-Apr-85  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Adapted for 4.2 BSD UNIX:  Conforms to new signals and wait.
+ *
+ * 15-July-82 Mike Accetta (mja) and Neal Friedman (naf)
+ *                               at Carnegie-Mellon University
+ *     Added a return(-1) if vfork fails.  This should only happen
+ *     if there are no more processes available.
+ *
+ * 28-Jan-80  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Added setuid and setgid for system programs' use.
+ *
+ * 21-Jan-80  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Changed fork to vfork.
+ *
+ * 20-Nov-79  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Created for VAX.  The proper way to fork-and-execute a system
+ *     program is now by "runvp" or "runp", with the program name
+ *     (rather than an absolute pathname) as the first argument;
+ *     that way, the "PATH" variable in the environment does the right
+ *     thing.  Too bad execvp and execlp (hence runvp and runp) don't
+ *     accept a pathlist as an explicit argument.
+ *
+ **********************************************************************
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <varargs.h>
+
+#ifndef __STDC__
+#ifndef const
+#define const
+#endif
+#endif
+
+static int dorun();
+
+int run (name,va_alist)
+char *name;
+va_dcl
+{
+       int val;
+       va_list ap;
+
+       va_start(ap);
+       val = runv (name,ap);
+       va_end(ap);
+       return(val);
+}
+
+int runv (name,argv)
+char *name,**argv;
+{
+       return (dorun (name, argv, 0));
+}
+
+int runp (name,va_alist)
+char *name;
+va_dcl
+{
+       int val;
+       va_list ap;
+
+       va_start(ap);
+       val = runvp (name,ap);
+       va_end(ap);
+       return (val);
+}
+
+int runvp (name,argv)
+char *name,**argv;
+{
+       return (dorun (name, argv, 1));
+}
+
+static
+int dorun (name,argv,usepath)
+char *name,**argv;
+int usepath;
+{
+       int wpid;
+       register int pid;
+       struct sigvec ignoresig,intsig,quitsig;
+       union wait status;
+       int execvp(), execv();
+       int (*execrtn)() = usepath ? execvp : execv;
+
+       if ((pid = vfork()) == -1)
+               return(-1);     /* no more process's, so exit with error */
+
+       if (pid == 0) {                 /* child process */
+               setgid (getgid());
+               setuid (getuid());
+               (*execrtn) (name,argv);
+               fprintf (stderr,"run: can't exec %s\n",name);
+               _exit (0377);
+       }
+
+       ignoresig.sv_handler = SIG_IGN; /* ignore INT and QUIT signals */
+       ignoresig.sv_mask = 0;
+       ignoresig.sv_onstack = 0;
+       sigvec (SIGINT,&ignoresig,&intsig);
+       sigvec (SIGQUIT,&ignoresig,&quitsig);
+       do {
+               wpid = wait3 (&status.w_status, WUNTRACED, 0);
+               if (WIFSTOPPED (status)) {
+                   kill (0,SIGTSTP);
+                   wpid = 0;
+               }
+       } while (wpid != pid && wpid != -1);
+       sigvec (SIGINT,&intsig,0);      /* restore signals */
+       sigvec (SIGQUIT,&quitsig,0);
+
+       if (WIFSIGNALED (status) || status.w_retcode == 0377)
+               return (-1);
+
+       return (status.w_retcode);
+}
+
+/*
+ * Like system(3), but with an argument list and explicit redirections
+ * that does not use the shell
+ */
+int
+runio(argv, infile, outfile, errfile)
+       char *const argv[];
+       const char *infile;
+       const char *outfile;
+       const char *errfile;
+{
+       int     fd;
+       pid_t   pid;
+       int     status;
+
+       switch ((pid = fork())) {
+       case -1:
+               return -1;
+
+       case 0:
+               if (infile) {
+                       (void) close(0);
+                       if ((fd = open(infile, O_RDONLY)) == -1)
+                               exit(1);
+                       if (fd != 0)
+                               (void) dup2(fd, 0);
+               }
+
+               if (outfile) {
+                       (void) close(1);
+                       if ((fd = open(outfile, O_RDWR|O_CREAT|O_TRUNC,
+                                      0666)) == -1)
+                               exit(1);
+                       if (fd != 1)
+                               (void) dup2(fd, 1);
+               }
+
+               if (errfile) {
+                       (void) close(2);
+                       if ((fd = open(errfile, O_RDWR|O_CREAT|O_TRUNC,
+                                      0666)) == -1)
+                               exit(1);
+                       if (fd != 2)
+                               (void) dup2(fd, 2);
+               }
+
+               execvp(argv[0], argv);
+               exit(1);
+               /*NOTREACHED*/
+               return 0;
+       
+       default:
+               if (waitpid(pid, &status, 0) == -1)
+                       return -1;
+               return status;
+       }
+}
diff --git a/usr.bin/sup/src/salloc.c b/usr.bin/sup/src/salloc.c
new file mode 100644 (file)
index 0000000..bd0e804
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*
+ **********************************************************************
+ * HISTORY
+ * 09-Apr-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changed to save length and use bcopy instead of strcpy.
+ *
+ * 02-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Created from routine by same name in Steve Shafer's sup program.
+ *
+ **********************************************************************
+ */
+char *malloc();
+
+char *salloc(p)
+char *p;
+{
+       register char *q;
+       register int l;
+
+       q = malloc(l = strlen(p) + 1);
+       if (q != 0)
+               bcopy(p, q, l);
+       return(q);
+}
diff --git a/usr.bin/sup/src/scan.c b/usr.bin/sup/src/scan.c
new file mode 100644 (file)
index 0000000..8e634e2
--- /dev/null
@@ -0,0 +1,1024 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * scan.c - sup list file scanner
+ *
+ **********************************************************************
+ * HISTORY
+ * $Log: scan.c,v $
+ * Revision 1.1  1995/12/16 11:46:50  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.4  1995/10/29 23:54:45  christos
+ * - runio fails when result != 0 not only < 0
+ * - print vis-encoded file in the scanner.
+ *
+ * Revision 1.3  1995/06/24 16:21:42  christos
+ * - Don't use system(3) to fork processes. It is a big security hole.
+ * - Encode the filenames in the scan files using strvis(3), so filenames
+ *   that contain newlines or other weird characters don't break the scanner.
+ *
+ * Revision 1.2  1994/01/03 14:47:25  brezak
+ * Change <sys/dir.h> to <dirent.h>
+ *
+ * Revision 1.1.1.1  1993/05/21  14:52:17  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.8  92/08/11  12:04:28  mrt
+ *     Brad's changes: delinted, added forward declarations of static
+ *     functions.Added Copyright.
+ *     [92/07/24            mrt]
+ * 
+ * 18-Mar-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added host=<hostfile> support to releases file.
+ *
+ * 11-Mar-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added "rsymlink" recursive symbolic link quoting directive.
+ *
+ * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code for "release" support.
+ *
+ * 26-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Lets see if we'll be able to write the scan file BEFORE
+ *     we collect the data for it.  Include sys/file.h and use
+ *     new definitions for access check codes.
+ *
+ * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added type casting information for lint.
+ *
+ * 21-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added check for newonly upgrade when lasttime is the same as
+ *     scantime.  This will save us the trouble of parsing the scanfile
+ *     when the client has successfully received everything in the
+ *     scanfile already.
+ *
+ * 16-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Clear Texec pointers in execT so that Tfree of execT will not
+ *     free command trees associated with files in listT.
+ *
+ * 06-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to omit scanned files from list if we want new files
+ *     only and they are old.
+ *
+ * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Major rewrite for protocol version 4.  Added version numbers to
+ *     scan file.  Also added mode of file in addition to flags.
+ *     Execute commands are now immediately after file information.
+ *
+ * 13-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added comments to list file format.
+ *
+ * 08-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to implement omitany.  Currently doesn't know about
+ *     {a,b,c} patterns.
+ *
+ * 07-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Created.
+ *
+ **********************************************************************
+ */
+
+#include <libc.h>
+#include <c.h>
+#include <vis.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#ifdef HAS_POSIX_DIR
+#include <dirent.h>
+#else
+#include <sys/dir.h>
+#endif
+#include <sys/file.h>
+#include "sup.h"
+
+/*************************
+ ***    M A C R O S    ***
+ *************************/
+
+#define SPECNUMBER 1000
+       /* number of filenames produced by a single spec in the list file */
+
+/*******************************************
+ ***    D A T A   S T R U C T U R E S    ***
+ *******************************************/
+
+typedef enum {                 /* release options */
+       ONEXT,          OPREFIX,        OLIST,          OSCAN,
+       OHOST
+} OPTION;
+
+static char *options[] = {
+       "next",         "prefix",       "list",         "scan",
+       "host",
+       0
+};
+
+typedef enum {                 /* <collection>/list file lines */
+       LUPGRADE,       LOMIT,          LBACKUP,        LEXECUTE,
+       LINCLUDE,       LNOACCT,        LOMITANY,       LALWAYS,
+       LSYMLINK,       LRSYMLINK
+} LISTTYPE;
+
+static char *ltname[] = {
+       "upgrade",      "omit",         "backup",       "execute",
+       "include",      "noaccount",    "omitany",      "always",
+       "symlink",      "rsymlink",
+       0
+};
+
+#define FALWAYS                FUPDATE
+
+/* list file lines */
+static TREE *upgT;                     /* files to upgrade */
+static TREE *flagsT;                   /* special flags: BACKUP NOACCT */
+static TREE *omitT;                    /* recursize file omition list */
+static TREE *omanyT;                   /* non-recursize file omition list */
+static TREE *symT;                     /* symbolic links to quote */
+static TREE *rsymT;                    /* recursive symbolic links to quote */
+static TREE *execT;                    /* execute command list */
+
+/*************************
+ ***    E X T E R N    ***
+ *************************/
+
+#ifdef lint
+static char _argbreak;
+#else
+extern char _argbreak;                 /* break character from nxtarg */
+#endif
+
+extern TREELIST *listTL;               /* list of trees for scanning */
+extern TREE *listT;                    /* final list of files in collection */
+extern TREE *refuseT;                  /* files refused by client */
+
+extern char *collname;                 /* collection name */
+extern char *basedir;                  /* base directory name */
+extern char *prefix;                   /* collection pathname prefix */
+extern long lasttime;                  /* time of last upgrade */
+extern long scantime;                  /* time of this scan */
+extern int trace;                      /* trace directories */
+extern int newonly;                    /* new files only */
+
+#ifdef RCSSTAT
+extern char *rcs_branch;
+extern int candorcs;
+#endif
+
+extern long time();
+
+/*************************************************
+ ***   STATIC   R O U T I N E S    ***
+ *************************************************/
+
+static makescan();
+static getscan();
+static doscan();
+static readlistfile();
+static expTinsert();
+static listone();
+static listentry();
+static listname();
+static listdir();
+static omitanyone();
+static anyglob();
+static int getscanfile();
+static chkscanfile();
+static makescanfile();
+static recordone();
+static recordexec();
+
+/*************************************************
+ ***    L I S T   S C A N   R O U T I N E S    ***
+ *************************************************/
+
+static
+passdelim (ptr,delim)          /* skip over delimiter */
+char **ptr,delim;
+{
+       *ptr = skipover (*ptr, " \t");
+       if (_argbreak != delim && **ptr == delim) {
+               (*ptr)++;
+               *ptr = skipover (*ptr, " \t");
+       }
+}
+
+static
+char *parserelease(tlp,relname,args)
+TREELIST **tlp;
+char *relname,*args;
+{
+       register TREELIST *tl;
+       register char *arg;
+       register OPTION option;
+       int opno;
+       char *nextrel;
+
+       tl = (TREELIST *) malloc (sizeof(TREELIST));
+       if ((*tlp = tl) == NULL)
+               goaway ("Couldn't allocate TREELIST");
+       tl->TLnext = NULL;
+       tl->TLname = salloc (relname);
+       tl->TLprefix = NULL;
+       tl->TLlist = NULL;
+       tl->TLscan = NULL;
+       tl->TLhost = NULL;
+       nextrel = NULL;
+       args = skipover (args," \t");
+       while (*(arg=nxtarg(&args," \t="))) {
+               for (opno = 0; options[opno] != NULL; opno++)
+                       if (strcmp (arg,options[opno]) == 0)
+                               break;
+               if (options[opno] == NULL)
+                       goaway ("Invalid release option %s for release %s",
+                               arg,relname);
+               option = (OPTION) opno;
+               switch (option) {
+               case ONEXT:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       nextrel = salloc (arg);
+                       break;
+               case OPREFIX:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       tl->TLprefix = salloc (arg);
+                       break;
+               case OLIST:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       tl->TLlist = salloc (arg);
+                       break;
+               case OSCAN:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       tl->TLscan = salloc (arg);
+                       break;
+               case OHOST:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       tl->TLhost = salloc (arg);
+                       break;
+               }
+       }
+       return (nextrel);
+}
+
+getrelease (release)
+char *release;
+{
+       TREELIST *tl;
+       char buf[STRINGLENGTH];
+       char *p,*q;
+       int rewound;
+       FILE *f;
+
+       if (release == NULL)
+               release = salloc (DEFRELEASE);
+       listTL = NULL;
+
+       (void) sprintf (buf,FILERELEASES,collname);
+       f = fopen (buf,"r");
+       if (f != NULL) {
+               rewound = TRUE;
+               for (;;) {
+                       p = fgets (buf,sizeof(buf),f);
+                       if (p == NULL) {
+                               if (rewound)
+                                       break;
+                               rewind (f);
+                               rewound = TRUE;
+                               continue;
+                       }
+                       q = index (p,'\n');
+                       if (q)  *q = 0;
+                       if (index ("#;:",*p))  continue;
+                       q = nxtarg (&p," \t");
+                       if (strcmp (q,release) != 0)
+                               continue;
+                       release = parserelease (&tl,release,p);
+                       if (tl->TLprefix == NULL)
+                               tl->TLprefix = prefix;
+                       else if (chdir (tl->TLprefix) < 0)
+                               return (FALSE);
+                       else
+                               (void) chdir (basedir);
+                       tl->TLnext = listTL;
+                       listTL = tl;
+                       if (release == NULL)
+                               break;
+                       rewound = FALSE;
+               }
+               (void) fclose (f);
+       }
+       if (release == NULL)
+               return (TRUE);
+       if (strcmp (release,DEFRELEASE) != 0)
+               return (FALSE);
+       (void) parserelease (&tl,release,"");
+       tl->TLprefix = prefix;
+       tl->TLnext = listTL;
+       listTL = tl;
+       return (TRUE);
+}
+
+makescanlists ()
+{
+       TREELIST *tl;
+       char buf[STRINGLENGTH];
+       char *p,*q;
+       FILE *f;
+       char *saveprefix = prefix;
+       int count = 0;
+
+       (void) sprintf (buf,FILERELEASES,collname);
+       f = fopen (buf,"r");
+       if (f != NULL) {
+               while (p = fgets (buf,sizeof(buf),f)) {
+                       q = index (p,'\n');
+                       if (q)  *q = 0;
+                       if (index ("#;:",*p))  continue;
+                       q = nxtarg (&p," \t");
+                       (void) parserelease (&tl,q,p);
+                       if ((prefix = tl->TLprefix) == NULL)
+                               prefix = saveprefix;
+                       if (prefix != NULL) {
+                               if (chdir (prefix) < 0)
+                                       goaway ("Can't chdir to %s",prefix);
+                               (void) chdir (basedir);
+                       }
+                       makescan (tl->TLlist,tl->TLscan);
+                       free ((char *)tl);
+                       count++;
+               }
+               (void) fclose (f);
+       }
+       if (count == 0)
+               makescan ((char *)NULL,(char *)NULL);
+}
+
+static
+scanone (t)
+register TREE *t;
+{
+       register TREE *newt;
+
+       if (newonly && (t->Tflags&FNEW) == 0)
+               return (SCMOK);
+       newt = Tinsert (&listT,t->Tname,FALSE);
+       if (newt == NULL)
+               return (SCMOK);
+       newt->Tmode = t->Tmode;
+       newt->Tflags = t->Tflags;
+       newt->Tmtime = t->Tmtime;
+       return (SCMOK);
+}
+
+getscanlists ()
+{
+       TREELIST *tl,*stl;
+
+       stl = listTL;
+       listTL = NULL;
+       while ((tl = stl) != NULL) {
+               prefix = tl->TLprefix;
+               getscan (tl->TLlist,tl->TLscan);
+               tl->TLtree = listT;
+               stl = tl->TLnext;
+               tl->TLnext = listTL;
+               listTL = tl;
+       }
+       listT = NULL;
+       for (tl = listTL; tl != NULL; tl = tl->TLnext)
+               (void) Tprocess (tl->TLtree,scanone);
+}
+
+static
+makescan (listfile,scanfile)
+char *listfile,*scanfile;
+{
+       listT = NULL;
+       chkscanfile (scanfile);         /* can we can write a scan file? */
+       doscan (listfile);              /* read list file and scan disk */
+       makescanfile (scanfile);        /* record names in scan file */
+       Tfree (&listT);                 /* free file list tree */
+}
+
+static
+getscan (listfile,scanfile)
+char *listfile,*scanfile;
+{
+        struct tm *utc_time;
+        
+       listT = NULL;
+       if (!getscanfile(scanfile)) {   /* check for pre-scanned file list */
+               scantime = time ((long *)NULL);
+               doscan (listfile);      /* read list file and scan disk */
+       }
+}
+
+static
+doscan (listfile)
+       char *listfile;
+{
+       char buf[STRINGLENGTH];
+       int listone ();
+
+       upgT = NULL;
+       flagsT = NULL;
+       omitT = NULL;
+       omanyT = NULL;
+       execT = NULL;
+       symT = NULL;
+       rsymT = NULL;
+       if (listfile == NULL)
+               listfile = FILELISTDEF;
+       (void) sprintf (buf,FILELIST,collname,listfile);
+       readlistfile (buf);             /* get contents of list file */
+       (void) Tprocess (upgT,listone); /* build list of files specified */
+       cdprefix ((char *)NULL);
+       Tfree (&upgT);
+       Tfree (&flagsT);
+       Tfree (&omitT);
+       Tfree (&omanyT);
+       Tfree (&execT);
+       Tfree (&symT);
+       Tfree (&rsymT);
+}
+
+static
+readlistfile (fname)
+char *fname;
+{
+       char buf[STRINGLENGTH+MAXPATHLEN*4+1],*p;
+       register char *q,*r;
+       register FILE *f;
+       register int ltn,n,i,flags;
+       register TREE **t;
+       register LISTTYPE lt;
+       char *speclist[SPECNUMBER];
+
+       f = fopen (fname,"r");
+       if (f == NULL)  goaway ("Can't read list file %s",fname);
+       cdprefix (prefix);
+       while (p = fgets (buf,sizeof(buf),f)) {
+               if (q = index (p,'\n'))  *q = '\0';
+               if (index ("#;:",*p))  continue;
+               q = nxtarg (&p," \t");
+               if (*q == '\0') continue;
+               for (ltn = 0; ltname[ltn] && strcmp(q,ltname[ltn]) != 0; ltn++);
+               if (ltname[ltn] == NULL)
+                       goaway ("Invalid list file keyword %s",q);
+               lt = (LISTTYPE) ltn;
+               flags = 0;
+               switch (lt) {
+               case LUPGRADE:
+                       t = &upgT;
+                       break;
+               case LBACKUP:
+                       t = &flagsT;
+                       flags = FBACKUP;
+                       break;
+               case LNOACCT:
+                       t = &flagsT;
+                       flags = FNOACCT;
+                       break;
+               case LSYMLINK:
+                       t = &symT;
+                       break;
+               case LRSYMLINK:
+                       t = &rsymT;
+                       break;
+               case LOMIT:
+                       t = &omitT;
+                       break;
+               case LOMITANY:
+                       t = &omanyT;
+                       break;
+               case LALWAYS:
+                       t = &upgT;
+                       flags = FALWAYS;
+                       break;
+               case LINCLUDE:
+                       while (*(q=nxtarg(&p," \t"))) {
+                               cdprefix ((char *)NULL);
+                               n = expand (q,speclist,SPECNUMBER);
+                               for (i = 0; i < n && i < SPECNUMBER; i++) {
+                                       readlistfile (speclist[i]);
+                                       cdprefix ((char *)NULL);
+                                       free (speclist[i]);
+                               }
+                               cdprefix (prefix);
+                       }
+                       continue;
+               case LEXECUTE:
+                       r = p = q = skipover (p," \t");
+                       do {
+                               q = p = skipto (p," \t(");
+                               p = skipover (p," \t");
+                       } while (*p != '(' && *p != '\0');
+                       if (*p++ == '(') {
+                               *q = '\0';
+                               do {
+                                       q = nxtarg (&p," \t)");
+                                       if (*q == 0)
+                                               _argbreak = ')';
+                                       else
+                                               expTinsert (q,&execT,0,r);
+                               } while (_argbreak != ')');
+                               continue;
+                       }
+                       /* fall through */
+               default:
+                       goaway ("Error in handling list file keyword %d",ltn);
+               }
+               while (*(q=nxtarg(&p," \t"))) {
+                       if (lt == LOMITANY)
+                               (void) Tinsert (t,q,FALSE);
+                       else
+                               expTinsert (q,t,flags,(char *)NULL);
+               }
+       }
+       (void) fclose (f);
+}
+
+static
+expTinsert (p,t,flags,exec)
+char *p;
+TREE **t;
+int flags;
+char *exec;
+{
+       register int n, i;
+       register TREE *newt;
+       char *speclist[SPECNUMBER];
+       char buf[STRINGLENGTH];
+
+       n = expand (p,speclist,SPECNUMBER);
+       for (i = 0; i < n && i < SPECNUMBER; i++) {
+               newt = Tinsert (t,speclist[i],TRUE);
+               newt->Tflags |= flags;
+               if (exec) {
+                       (void) sprintf (buf,exec,speclist[i]);
+                       (void) Tinsert (&newt->Texec,buf,FALSE);
+               }
+               free (speclist[i]);
+       }
+}
+
+static
+listone (t)            /* expand and add one name from upgrade list */
+TREE *t;
+{
+       listentry(t->Tname,t->Tname,(char *)NULL,(t->Tflags&FALWAYS) != 0);
+       return (SCMOK);
+}
+
+static
+listentry(name,fullname,updir,always)
+register char *name, *fullname, *updir;
+int always;
+{
+       struct stat statbuf;
+       int link = 0;
+       int omitanyone ();
+
+       if (Tlookup (refuseT,fullname))  return;
+       if (!always) {
+               if (Tsearch (omitT,fullname))  return;
+               if (Tprocess (omanyT,omitanyone,fullname) != SCMOK)
+                       return;
+       }
+       if (lstat(name,&statbuf) < 0)
+               return;
+       if ((statbuf.st_mode&S_IFMT) == S_IFLNK) {
+               if (Tsearch (symT,fullname)) {
+                       listname (fullname,&statbuf);
+                       return;
+               }
+               if (Tlookup (rsymT,fullname)) {
+                       listname (fullname,&statbuf);
+                       return;
+               }
+               if (updir) link++;
+               if (stat(name,&statbuf) < 0) return;
+       }
+       if ((statbuf.st_mode&S_IFMT) == S_IFDIR) {
+               if (access(name,R_OK|X_OK) < 0) return;
+               if (chdir(name) < 0) return;
+               listname (fullname,&statbuf);
+               if (trace) {
+                       printf ("Scanning directory %s\n",fullname);
+                       (void) fflush (stdout);
+               }
+               listdir (fullname,always);
+               if (updir == 0 || link) {
+                       (void) chdir (basedir);
+                       if (prefix) (void) chdir (prefix);
+                       if (updir && *updir) (void) chdir (updir);
+               } else
+                       (void) chdir ("..");
+               return;
+       }
+       if (access(name,R_OK) < 0) return;
+#ifdef RCSSTAT
+        if (candorcs) {
+                char rcs_release[STRINGLENGTH];
+                int status;
+                if (rcs_branch != NULL)
+#ifdef CVS
+                        sprintf(rcs_release, "-r %s", rcs_branch);
+#else
+                        sprintf(rcs_release, "-r%s", rcs_branch);
+#endif
+                else
+                        rcs_release[0] = '\0';
+#ifdef CVS
+                sprintf(sys_com, "cvs -d %s -r -l -Q co -p %s %s > %s\n", cvs_root, rcs_release, name, rcs_file);
+#else
+                status = runp("rcsstat", "rcsstat", "-q", rcs_release, name, 0);
+#endif
+                if (status != 0) return;
+        }
+#endif
+       listname (fullname,&statbuf);
+}
+
+static
+listname (name,st)
+register char *name;
+register struct stat *st;
+{
+       register TREE *t,*ts;
+       register int new;
+       register TREELIST *tl;
+
+       new = st->st_ctime > lasttime;
+       if (newonly && !new) {
+               for (tl = listTL; tl != NULL; tl = tl->TLnext)
+                       if (ts = Tsearch (tl->TLtree,name))
+                               ts->Tflags &= ~FNEW;
+               return;
+       }
+       t = Tinsert (&listT,name,FALSE);
+       if (t == NULL)  return;
+       t->Tmode = st->st_mode;
+       t->Tctime = st->st_ctime;
+       t->Tmtime = st->st_mtime;
+       if (new)  t->Tflags |= FNEW;
+       if (ts = Tsearch (flagsT,name))
+               t->Tflags |= ts->Tflags;
+       if (ts = Tsearch (execT,name)) {
+               t->Texec = ts->Texec;
+               ts->Texec = NULL;
+       }
+}
+
+static
+listdir (name,always)          /* expand directory */
+char *name;
+int always;
+{
+#ifdef HAS_POSIX_DIR
+       struct dirent *dentry;
+#else
+       struct direct *dentry;
+#endif
+       register DIR *dirp;
+       char ename[STRINGLENGTH],newname[STRINGLENGTH],filename[STRINGLENGTH];
+       register char *p,*newp;
+       register int i;
+
+       dirp = opendir (".");
+       if (dirp == 0) return;  /* unreadable: probably protected */
+
+       p = name;               /* punt leading ./ and trailing / */
+       newp = newname;
+       if (p[0] == '.' && p[1] == '/') {
+               p += 2;
+               while (*p == '/') p++;
+       }
+       while (*newp++ = *p++) ;        /* copy string */
+       --newp;                         /* trailing null */
+       while (newp > newname && newp[-1] == '/') --newp; /* trailing / */
+       *newp = 0;
+       if (strcmp (newname,".") == 0) newname[0] = 0;  /* "." ==> "" */
+
+       while (dentry=readdir(dirp)) {
+               if (dentry->d_ino == 0) continue;
+               if (strcmp(dentry->d_name,".") == 0) continue;
+               if (strcmp(dentry->d_name,"..") == 0) continue;
+               for (i=0; i<=MAXNAMLEN && dentry->d_name[i]; i++)
+                       ename[i] = dentry->d_name[i];
+               ename[i] = 0;
+               if (*newname)
+                       (void) sprintf (filename,"%s/%s",newname,ename);
+               else
+                       (void) strcpy (filename,ename);
+               listentry(ename,filename,newname,always);
+       }
+       closedir (dirp);
+}
+
+static
+omitanyone (t,filename)
+TREE *t;
+char **filename;
+{
+       if (anyglob (t->Tname,*filename))
+               return (SCMERR);
+       return (SCMOK);
+}
+
+static
+anyglob (pattern,match)
+char *pattern,*match;
+{
+       register char *p,*m;
+       register char *pb,*pe;
+
+       p = pattern; 
+       m = match;
+       while (*m && *p == *m ) { 
+               p++; 
+               m++; 
+       }
+       if (*p == '\0' && *m == '\0')
+               return (TRUE);
+       switch (*p++) {
+       case '*':
+               for (;;) {
+                       if (*p == '\0')
+                               return (TRUE);
+                       if (*m == '\0')
+                               return (*p == '\0');
+                       if (anyglob (p,++m))
+                               return (TRUE);
+               }
+       case '?':
+               return (anyglob (p,++m));
+       case '[':
+               pb = p;
+               while (*(++p) != ']')
+                       if (*p == '\0')
+                               return (FALSE);
+               pe = p;
+               for (p = pb + 1; p != pe; p++) {
+                       switch (*p) {
+                       case '-':
+                               if (p == pb && *m == '-') {
+                                       p = pe + 1;
+                                       return (anyglob (p,++m));
+                               }
+                               if (p == pb)
+                                       continue;
+                               if ((p + 1) == pe)
+                                       return (FALSE);
+                               if (*m > *(p - 1) &&
+                                   *m <= *(p + 1)) {
+                                       p = pe + 1;
+                                       return (anyglob (p,++m));
+                               }
+                               continue;
+                       default:
+                               if (*m == *p) {
+                                       p = pe + 1;
+                                       return (anyglob (p,++m));
+                               }
+                       }
+               }
+               return (FALSE);
+       default:
+               return (FALSE);
+       }
+}
+
+/*****************************************
+ ***    R E A D   S C A N   F I L E    ***
+ *****************************************/
+
+static
+int getscanfile (scanfile)
+char *scanfile;
+{
+       char buf[STRINGLENGTH];
+       char fname[MAXPATHLEN];
+       struct stat sbuf;
+       register FILE *f;
+       TREE ts;
+       register char *p,*q;
+       register TREE *tmp, *t = NULL;
+       register notwanted;
+       register TREELIST *tl;
+        
+       if (scanfile == NULL)
+               scanfile = FILESCANDEF;
+       (void) sprintf (buf,FILESCAN,collname,scanfile);
+       if (stat(buf,&sbuf) < 0)
+               return (FALSE);
+       if ((f = fopen (buf,"r")) == NULL)
+               return (FALSE);
+       if ((p = fgets (buf,sizeof(buf),f)) == NULL) {
+               (void) fclose (f);
+               return (FALSE);
+       }
+       if (q = index (p,'\n'))  *q = '\0';
+       if (*p++ != 'V') {
+               (void) fclose (f);
+               return (FALSE);
+       }
+       if (atoi (p) != SCANVERSION) {
+               (void) fclose (f);
+               return (FALSE);
+       }
+       scantime = sbuf.st_mtime;       /* upgrade time is time of supscan,
+                                        * i.e. time of creation of scanfile */
+       if (newonly && scantime == lasttime) {
+               (void) fclose (f);
+               return (TRUE);
+       }
+       notwanted = FALSE;
+       while (p = fgets (buf,sizeof(buf),f)) {
+               q = index (p,'\n');
+               if (q)  *q = 0;
+               ts.Tflags = 0;
+               if (*p == 'X') {
+                       if (notwanted)  continue;
+                       if (t == NULL)
+                               goaway ("scanfile format inconsistant");
+                       (void) Tinsert (&t->Texec,++p,FALSE);
+                       continue;
+               }
+               notwanted = FALSE;
+               if (*p == 'B') {
+                       p++;
+                       ts.Tflags |= FBACKUP;
+               }
+               if (*p == 'N') {
+                       p++;
+                       ts.Tflags |= FNOACCT;
+               }
+               if ((q = index (p,' ')) == NULL)
+                       goaway ("scanfile format inconsistant");
+               *q++ = '\0';
+               ts.Tmode = atoo (p);
+               p = q;
+               if ((q = index (p,' ')) == NULL)
+                       goaway ("scanfile format inconsistant");
+               *q++ = '\0';
+               ts.Tctime = atoi (p);
+               p = q;
+               if ((q = index (p,' ')) == NULL)
+                       goaway ("scanfile format inconsistant");
+               *q++ = 0;
+               ts.Tmtime = atoi (p);
+               (void) strunvis(fname, q);
+               if (ts.Tctime > lasttime)
+                       ts.Tflags |= FNEW;
+               else if (newonly) {
+                       for (tl = listTL; tl != NULL; tl = tl->TLnext)
+                               if (tmp = Tsearch (tl->TLtree,fname))
+                                       tmp->Tflags &= ~FNEW;
+                       notwanted = TRUE;
+                       continue;
+               }
+               if (Tlookup (refuseT,fname)) {
+                       notwanted = TRUE;
+                       continue;
+               }
+               t = Tinsert (&listT,fname,TRUE);
+               t->Tmode = ts.Tmode;
+               t->Tflags = ts.Tflags;
+               t->Tctime = ts.Tctime;
+               t->Tmtime = ts.Tmtime;
+       }
+       (void) fclose (f);
+       return (TRUE);
+}
+
+/*******************************************
+ ***    W R I T E   S C A N   F I L E    ***
+ *******************************************/
+
+static chkscanfile (scanfile)
+char *scanfile;
+{
+       char tname[STRINGLENGTH], fname[STRINGLENGTH];
+       FILE *f;
+
+       if (scanfile == NULL)
+               scanfile = FILESCANDEF;
+       (void) sprintf (fname,FILESCAN,collname,scanfile);
+       (void) sprintf (tname,"%s.temp",fname);
+       if (NULL == (f = fopen (tname, "w")))
+               goaway ("Can't test scan file temp %s for %s",tname,collname);
+       else {
+               (void) unlink (tname);
+               (void) fclose (f);
+       }
+}
+
+static makescanfile (scanfile)
+char *scanfile;
+{
+       char tname[STRINGLENGTH],fname[STRINGLENGTH];
+       struct timeval tbuf[2];
+       FILE *scanF;                    /* output file for scanned file list */
+       int recordone ();
+
+       if (scanfile == NULL)
+               scanfile = FILESCANDEF;
+       (void) sprintf (fname,FILESCAN,collname,scanfile);
+       (void) sprintf (tname,"%s.temp",fname);
+       scanF = fopen (tname,"w");
+       if (scanF == NULL)
+               goaway ("Can't write scan file temp %s for %s",tname,collname);
+       fprintf (scanF,"V%d\n",SCANVERSION);
+       (void) Tprocess (listT,recordone,scanF);
+       (void) fclose (scanF);
+       if (rename (tname,fname) < 0)
+               goaway ("Can't change %s to %s",tname,fname);
+       (void) unlink (tname);
+       tbuf[0].tv_sec = time((long *)NULL);  tbuf[0].tv_usec = 0;
+       tbuf[1].tv_sec = scantime;  tbuf[1].tv_usec = 0;
+       (void) utimes (fname,tbuf);
+}
+
+static
+recordone (t,scanF)
+TREE *t;
+FILE **scanF;
+{
+       int recordexec ();
+       char fname[MAXPATHLEN*4+1];
+
+       if (t->Tflags&FBACKUP)  fprintf (*scanF,"B");
+       if (t->Tflags&FNOACCT)  fprintf (*scanF,"N");
+       strvis(fname, t->Tname, VIS_WHITE);
+       fprintf (*scanF,"%o %d %d %s\n",
+               t->Tmode,t->Tctime,t->Tmtime,fname);
+       (void) Tprocess (t->Texec,recordexec,*scanF);
+       return (SCMOK);
+}
+
+static
+recordexec (t,scanF)
+TREE *t;
+FILE **scanF;
+{
+       char fname[MAXPATHLEN*4+1];
+       strvis(fname, t->Tname, VIS_WHITE);
+       fprintf(*scanF,"X%s\n",fname);
+       return (SCMOK);
+}
+
+cdprefix (prefix)
+char *prefix;
+{
+       static char *curprefix = NULL;
+
+       if (curprefix == NULL) {
+               if (prefix == NULL)
+                       return;
+               (void) chdir (prefix);
+               curprefix = prefix;
+               return;
+       }
+       if (prefix == NULL) {
+               (void) chdir (basedir);
+               curprefix = NULL;
+               return;
+       }
+       if (prefix == curprefix)
+               return;
+       if (strcmp (prefix, curprefix) == 0) {
+               curprefix = prefix;
+               return;
+       }
+       (void) chdir (basedir);
+       (void) chdir (prefix);
+       curprefix = prefix;
+}
diff --git a/usr.bin/sup/src/scm.c b/usr.bin/sup/src/scm.c
new file mode 100644 (file)
index 0000000..59be450
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * SUP Communication Module for 4.3 BSD
+ *
+ * SUP COMMUNICATION MODULE SPECIFICATIONS:
+ *
+ * IN THIS MODULE:
+ *
+ * CONNECTION ROUTINES
+ *
+ *   FOR SERVER
+ *     servicesetup (port)     establish TCP port connection
+ *       char *port;                   name of service
+ *     service ()              accept TCP port connection
+ *     servicekill ()          close TCP port in use by another process
+ *     serviceprep ()          close temp ports used to make connection
+ *     serviceend ()           close TCP port
+ *
+ *   FOR CLIENT
+ *     request (port,hostname,retry) establish TCP port connection
+ *       char *port,*hostname;           name of service and host
+ *       int retry;                      true if retries should be used
+ *     requestend ()           close TCP port
+ *
+ * HOST NAME CHECKING
+ *     p = remotehost ()       remote host name (if known)
+ *       char *p;
+ *     i = samehost ()         whether remote host is also this host
+ *       int i;
+ *     i = matchhost (name)    whether remote host is same as name
+ *       int i;
+ *       char *name;
+ *
+ * RETURN CODES
+ *     All procedures return values as indicated above.  Other routines
+ *     normally return SCMOK on success, SCMERR on error.
+ *
+ * COMMUNICATION PROTOCOL
+ *
+ *     Described in scmio.c.
+ *
+ **********************************************************************
+ * HISTORY
+ *  2-Oct-92  Mary Thompson (mrt) at Carnegie-Mellon University
+ *     Added conditional declarations of INADDR_NONE and INADDR_LOOPBACK
+ *     since Tahoe version of <netinet/in.h> does not define them.
+ *
+ * $Log: scm.c,v $
+ * Revision 1.1  1995/12/16 11:46:51  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.2  1995/06/03 21:21:51  christos
+ * Changes to write ascii timestamps in the when files.
+ * Looked into making it 64 bit clean, but it is hopeless.
+ * Added little program to convert from the old timestamp files
+ * into the new ones.
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:17  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.13  92/08/11  12:05:35  mrt
+ *     Added changes from stump:
+ *       Allow for multiple interfaces, and for numeric addresses.
+ *       Changed to use builtin port for the "supfiledbg"
+ *         service when getservbyname() cannot find it.
+ *       Added forward static declatations, delinted.
+ *       Updated variable argument usage.
+ *     [92/08/08            mrt]
+ * 
+ * Revision 1.12  92/02/08  19:01:11  mja
+ *     Add (struct sockaddr *) casts for HC 2.1.
+ *     [92/02/08  18:59:09  mja]
+ * 
+ * Revision 1.11  89/08/03  19:49:03  mja
+ *     Updated to use v*printf() in place of _doprnt().
+ *     [89/04/19            mja]
+ * 
+ * 11-Feb-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Moved sleep into computeBackoff, renamed to dobackoff.
+ *
+ * 10-Feb-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added timeout to backoff.
+ *
+ * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Removed nameserver support.
+ *
+ * 09-Sep-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Fixed to depend less upon having name of remote host.
+ *
+ * 25-May-87  Doug Philips (dwp) at Carnegie-Mellon Universtiy
+ *     Extracted backoff/sleeptime computation from "request" and
+ *     created "computeBackoff" so that I could use it in sup.c when
+ *     trying to get to nameservers as a group.
+ *
+ * 21-May-87  Chriss Stephens (chriss) at Carnegie Mellon University
+ *     Merged divergent CS and EE versions.
+ *
+ * 02-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added some bullet-proofing code around hostname calls.
+ *
+ * 31-Mar-87  Dan Nydick (dan) at Carnegie-Mellon University
+ *     Fixed for 4.3.
+ *
+ * 30-May-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to use known values for well-known ports if they are
+ *     not found in the host table.
+ *
+ * 19-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changed setsockopt SO_REUSEADDR to be non-fatal.  Added fourth
+ *     parameter as described in 4.3 manual entry.
+ *
+ * 15-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added call of readflush() to requestend() routine.
+ *
+ * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Major rewrite for protocol version 4.  All read/write and crypt
+ *     routines are now in scmio.c.
+ *
+ * 14-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added setsockopt SO_REUSEADDR call.
+ *
+ * 01-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Removed code to "gracefully" handle unexpected messages.  This
+ *     seems reasonable since it didn't work anyway, and should be
+ *     handled at a higher level anyway by adhering to protocol version
+ *     number conventions.
+ *
+ * 26-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Fixed scm.c to free space for remote host name when connection
+ *     is closed.
+ *
+ * 07-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Fixed 4.2 retry code to reload sin values before retry.
+ *
+ * 22-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to retry initial connection open request.
+ *
+ * 22-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Merged 4.1 and 4.2 versions together.
+ *
+ * 21-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Add close() calls after pipe() call.
+ *
+ * 12-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Converted for 4.2 sockets; added serviceprep() routine.
+ *
+ * 04-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Created for 4.2 BSD.
+ *
+ **********************************************************************
+ */
+
+#include <libc.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netdb.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "sup.h"
+
+#ifndef INADDR_NONE
+#define        INADDR_NONE             0xffffffff              /* -1 return */
+#endif
+#ifndef INADDR_LOOPBACK
+#define        INADDR_LOOPBACK         (u_long)0x7f000001      /* 127.0.0.1 */
+#endif
+
+extern int errno;
+static char *myhost ();
+
+char scmversion[] = "4.3 BSD";
+
+/*************************
+ ***    M A C R O S    ***
+ *************************/
+
+/* networking parameters */
+#define NCONNECTS 5
+
+/*********************************************
+ ***    G L O B A L   V A R I A B L E S    ***
+ *********************************************/
+
+extern char program[];                 /* name of program we are running */
+extern int progpid;                    /* process id to display */
+
+int netfile = -1;                      /* network file descriptor */
+
+static int sock = -1;                  /* socket used to make connection */
+static struct in_addr remoteaddr;      /* remote host address */
+static char *remotename = NULL;                /* remote host name */
+static int swapmode;                   /* byte-swapping needed on server? */
+
+#if __STDC__
+int scmerr(int,char *,...);
+#endif
+
+/***************************************************
+ ***    C O N N E C T I O N   R O U T I N E S    ***
+ ***    F O R   S E R V E R                      ***
+ ***************************************************/
+
+servicesetup (server)          /* listen for clients */
+char *server;
+{
+       struct sockaddr_in sin;
+       struct servent *sp;
+       short port;
+       int one = 1;
+
+       if (myhost () == NULL)
+               return (scmerr (-1,"Local hostname not known"));
+       if ((sp = getservbyname(server,"tcp")) == 0) {
+               if (strcmp(server, FILEPORT) == 0)
+                       port = htons((u_short)FILEPORTNUM);
+               else if (strcmp(server, DEBUGFPORT) == 0)
+                       port = htons((u_short)DEBUGFPORTNUM);
+               else
+                       return (scmerr (-1,"Can't find %s server description",server));
+               (void) scmerr (-1,"%s/tcp: unknown service: using port %d",
+                                       server,port);
+       } else
+               port = sp->s_port;
+       endservent ();
+       sock = socket (AF_INET,SOCK_STREAM,0);
+       if (sock < 0)
+               return (scmerr (errno,"Can't create socket for connections"));
+       if (setsockopt (sock,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(int)) < 0)
+               (void) scmerr (errno,"Can't set SO_REUSEADDR socket option");
+       (void) bzero ((char *)&sin,sizeof(sin));
+       sin.sin_family = AF_INET;
+       sin.sin_port = port;
+       if (bind (sock,(struct sockaddr *)&sin,sizeof(sin)) < 0)
+               return (scmerr (errno,"Can't bind socket for connections"));
+       if (listen (sock,NCONNECTS) < 0)
+               return (scmerr (errno,"Can't listen on socket"));
+       return (SCMOK);
+}
+
+service ()
+{
+       struct sockaddr_in from;
+       int x,len;
+
+       remotename = NULL;
+       len = sizeof (from);
+       do {
+               netfile = accept (sock,(struct sockaddr *)&from,&len);
+       } while (netfile < 0 && errno == EINTR);
+       if (netfile < 0)
+               return (scmerr (errno,"Can't accept connections"));
+       remoteaddr = from.sin_addr;
+       if (read(netfile,(char *)&x,sizeof(int)) != sizeof(int))
+               return (scmerr (errno,"Can't transmit data on connection"));
+       if (x == 0x01020304)
+               swapmode = 0;
+       else if (x == 0x04030201)
+               swapmode = 1;
+       else
+               return (scmerr (-1,"Unexpected byteswap mode %x",x));
+       return (SCMOK);
+}
+
+serviceprep ()         /* kill temp socket in daemon */
+{
+       if (sock >= 0) {
+               (void) close (sock);
+               sock = -1;
+       }
+       return (SCMOK);
+}
+
+servicekill ()         /* kill net file in daemon's parent */
+{
+       if (netfile >= 0) {
+               (void) close (netfile);
+               netfile = -1;
+       }
+       if (remotename) {
+               free (remotename);
+               remotename = NULL;
+       }
+       return (SCMOK);
+}
+
+serviceend ()          /* kill net file after use in daemon */
+{
+       if (netfile >= 0) {
+               (void) close (netfile);
+               netfile = -1;
+       }
+       if (remotename) {
+               free (remotename);
+               remotename = NULL;
+       }
+       return (SCMOK);
+}
+
+/***************************************************
+ ***    C O N N E C T I O N   R O U T I N E S    ***
+ ***    F O R   C L I E N T                      ***
+ ***************************************************/
+
+dobackoff (t,b)
+int *t,*b;
+{
+       struct timeval tt;
+       unsigned s;
+
+       if (*t == 0)
+               return (0);
+       s = *b * 30;
+       if (gettimeofday (&tt,(struct timezone *)NULL) >= 0)
+               s += (tt.tv_usec >> 8) % s;
+       if (*b < 32) *b <<= 1;
+       if (*t != -1) {
+               if (s > *t)
+                       s = *t;
+               *t -= s;
+       }
+       (void) scmerr (-1,"Will retry in %d seconds",s);
+       sleep (s);
+       return (1);
+}
+
+request (server,hostname,retry)                /* connect to server */
+char *server;
+char *hostname;
+int *retry;
+{
+       int x, backoff;
+       struct hostent *h;
+       struct servent *sp;
+       struct sockaddr_in sin, tin;
+       short port;
+
+       if ((sp = getservbyname(server,"tcp")) == 0) {
+               if (strcmp(server, FILEPORT) == 0)
+                       port = htons((u_short)FILEPORTNUM);
+               else if (strcmp(server, DEBUGFPORT) == 0)
+                       port = htons((u_short)DEBUGFPORTNUM);
+               else
+                       return (scmerr (-1,"Can't find %s server description",
+                                       server));
+               (void) scmerr (-1,"%s/tcp: unknown service: using port %d",
+                                       server,port);
+       } else
+               port = sp->s_port;
+       (void) bzero ((char *)&sin,sizeof(sin));
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = inet_addr (hostname);
+       if (sin.sin_addr.s_addr == (u_long) INADDR_NONE) {
+               if ((h = gethostbyname (hostname)) == NULL)
+                       return (scmerr (-1,"Can't find host entry for %s",
+                                       hostname));
+               hostname = h->h_name;
+               (void) bcopy (h->h_addr,(char *)&sin.sin_addr,h->h_length);
+       }
+       sin.sin_port = port;
+       backoff = 1;
+       for (;;) {
+               netfile = socket (AF_INET,SOCK_STREAM,0);
+               if (netfile < 0)
+                       return (scmerr (errno,"Can't create socket"));
+               tin = sin;
+               if (connect(netfile,(struct sockaddr *)&tin,sizeof(tin)) >= 0)
+                       break;
+               (void) scmerr (errno,"Can't connect to server for %s",server);
+               (void) close(netfile);
+               if (!dobackoff (retry,&backoff))
+                       return (SCMERR);
+       }
+       remoteaddr = sin.sin_addr;
+       remotename = salloc(hostname);
+       x = 0x01020304;
+       (void) write (netfile,(char *)&x,sizeof(int));
+       swapmode = 0;           /* swap only on server, not client */
+       return (SCMOK);
+}
+
+requestend ()                  /* end connection to server */
+{
+       (void) readflush ();
+       if (netfile >= 0) {
+               (void) close (netfile);
+               netfile = -1;
+       }
+       if (remotename) {
+               free (remotename);
+               remotename = NULL;
+       }
+       return (SCMOK);
+}
+
+/*************************************************
+ ***    H O S T   N A M E   C H E C K I N G    ***
+ *************************************************/
+
+static
+char *myhost ()                /* find my host name */
+{
+       struct hostent *h;
+       static char name[MAXHOSTNAMELEN];
+
+
+       if (name[0] == '\0') {
+               if (gethostname (name,MAXHOSTNAMELEN) < 0)
+                       return (NULL);
+               if ((h = gethostbyname (name)) == NULL)
+                       return (NULL);
+               (void) strcpy (name,h->h_name);
+       }
+       return (name);
+}
+
+char *remotehost ()    /* remote host name (if known) */
+{
+       register struct hostent *h;
+
+       if (remotename == NULL) {
+               h = gethostbyaddr ((char *)&remoteaddr,sizeof(remoteaddr),
+                                   AF_INET);
+               remotename = salloc (h ? h->h_name : inet_ntoa(remoteaddr));
+               if (remotename == NULL)
+                       return("UNKNOWN");
+       }
+       return (remotename);
+}
+
+int thishost (host)
+register char *host;
+{
+       register struct hostent *h;
+       char *name;
+
+       if ((name = myhost ()) == NULL)
+               logquit (1,"Can't find my host entry");
+       h = gethostbyname (host);
+       if (h == NULL) return (0);
+       return (strcasecmp (name,h->h_name) == 0);
+}
+
+int samehost ()                /* is remote host same as local host? */
+{
+       static struct in_addr *intp;
+       static int nint = 0;
+       struct in_addr *ifp;
+       int n;
+
+       if (nint <= 0) {
+               int s;
+               char buf[BUFSIZ];
+               struct ifconf ifc;
+               struct ifreq *ifr;
+               struct sockaddr_in sin;
+
+               if ((s = socket (AF_INET,SOCK_DGRAM,0)) < 0)
+                       logquit (1,"Can't create socket for SIOCGIFCONF");
+               ifc.ifc_len = sizeof(buf);
+               ifc.ifc_buf = buf;
+               if (ioctl (s,SIOCGIFCONF,(char *)&ifc) < 0)
+                       logquit (1,"SIOCGIFCONF failed");
+               (void) close(s);
+               if ((nint = ifc.ifc_len/sizeof(struct ifreq)) <= 0)
+                       return (0);
+               intp = (struct in_addr *)
+                       malloc ((unsigned) nint*sizeof(struct in_addr));
+               if ((ifp = intp) == 0)
+                       logquit (1,"no space for interfaces");
+               for (ifr = ifc.ifc_req, n = nint; n > 0; --n, ifr++) {
+                       (void) bcopy ((char *)&ifr->ifr_addr,(char *)&sin,sizeof(sin));
+                       *ifp++ = sin.sin_addr;
+               }
+       }
+       if (remoteaddr.s_addr == htonl(INADDR_LOOPBACK))
+               return (1);
+       for (ifp = intp, n = nint; n > 0; --n, ifp++)
+               if (remoteaddr.s_addr == ifp->s_addr)
+                       return (1);
+       return (0);
+}
+
+int matchhost (name)   /* is this name of remote host? */
+char *name;
+{
+       struct hostent *h;
+       struct in_addr addr;
+       char **ap;
+       if ((addr.s_addr = inet_addr(name)) != (u_long) INADDR_NONE)
+               return (addr.s_addr == remoteaddr.s_addr);
+       if ((h = gethostbyname (name)) == 0)
+               return (0);
+       if (h->h_addrtype != AF_INET || h->h_length != sizeof(struct in_addr))
+               return (0);
+       for (ap = h->h_addr_list; *ap; ap++)
+               if (bcmp ((char *)&remoteaddr,*ap,h->h_length) == 0)
+                       return (1);
+       return (0);
+}
+
+#if __STDC__
+int scmerr (int errno,char *fmt,...)
+#else
+/*VARARGS*//*ARGSUSED*/
+int scmerr (va_alist)
+va_dcl
+#endif
+{
+#if !__STDC__
+       int errno;
+       char *fmt;
+#endif
+       va_list ap;
+
+       (void) fflush (stdout);
+       if (progpid > 0)
+               fprintf (stderr,"%s %d: ",program,progpid);
+       else
+               fprintf (stderr,"%s: ",program);
+#if __STDC__
+       va_start(ap,fmt);
+#else
+       va_start(ap);
+       errno = va_arg(ap,int);
+       fmt = va_arg(ap,char *);
+#endif
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       if (errno >= 0)
+               fprintf (stderr,": %s\n",errmsg(errno));
+       else
+               fprintf (stderr,"\n");
+       (void) fflush (stderr);
+       return (SCMERR);
+}
+
+/*******************************************************
+ ***    I N T E G E R   B Y T E - S W A P P I N G    ***
+ *******************************************************/
+
+union intchar {
+       int ui;
+       char uc[sizeof(int)];
+};
+
+int byteswap (in)
+int in;
+{
+       union intchar x,y;
+       register int ix,iy;
+
+       if (swapmode == 0)  return (in);
+       x.ui = in;
+       iy = sizeof(int);
+       for (ix=0; ix<sizeof(int); ix++) {
+               --iy;
+               y.uc[iy] = x.uc[ix];
+       }
+       return (y.ui);
+}
diff --git a/usr.bin/sup/src/scmio.c b/usr.bin/sup/src/scmio.c
new file mode 100644 (file)
index 0000000..b0852e2
--- /dev/null
@@ -0,0 +1,744 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * SUP Communication Module for 4.3 BSD
+ *
+ * SUP COMMUNICATION MODULE SPECIFICATIONS:
+ *
+ * IN THIS MODULE:
+ *
+ * OUTPUT TO NETWORK
+ *
+ *   MESSAGE START/END
+ *     writemsg (msg)          start message
+ *       int msg;                      message type
+ *     writemend ()            end message and flush data to network
+ *
+ *   MESSAGE DATA
+ *     writeint (i)            write int
+ *       int i;                        integer to write
+ *     writestring (p)         write string
+ *       char *p;                      string pointer
+ *     writefile (f)           write open file
+ *       int f;                        open file descriptor
+ *
+ *   COMPLETE MESSAGE (start, one data block, end)
+ *     writemnull (msg)        write message with no data
+ *       int msg;                      message type
+ *     writemint (msg,i)       write int message
+ *       int msg;                      message type
+ *       int i;                        integer to write
+ *     writemstr (msg,p)       write string message
+ *       int msg;                      message type
+ *       char *p;                      string pointer
+ *
+ * INPUT FROM NETWORK
+ *   MESSAGE START/END
+ *     readflush ()            flush any unread data (close)
+ *     readmsg (msg)           read specified message type
+ *       int msg;                      message type
+ *     readmend ()             read message end
+ *
+ *   MESSAGE DATA
+ *     readskip ()             skip over one input data block
+ *     readint (i)             read int
+ *       int *i;                       pointer to integer
+ *     readstring (p)          read string
+ *       char **p;                     pointer to string pointer
+ *     readfile (f)            read into open file
+ *       int f;                        open file descriptor
+ *
+ *   COMPLETE MESSAGE (start, one data block, end)
+ *     readmnull (msg)         read message with no data
+ *       int msg;                      message type
+ *     readmint (msg,i)        read int message
+ *       int msg;                      message type
+ *       int *i;                       pointer to integer
+ *     readmstr (msg,p)        read string message
+ *       int msg;                      message type
+ *       char **p;                     pointer to string pointer
+ *
+ * RETURN CODES
+ *     All routines normally return SCMOK.  SCMERR may be returned
+ *     by any routine on abnormal (usually fatal) errors.  An
+ *     unexpected MSGGOAWAY will result in SCMEOF being returned.
+ *
+ * COMMUNICATION PROTOCOL
+ *     Messages always alternate, with the first message after
+ *     connecting being sent by the client process.
+ *
+ *     At the end of the conversation, the client process will
+ *     send a message to the server telling it to go away.  Then,
+ *     both processes will close the network connection.
+ *
+ *     Any time a process receives a message it does not expect,
+ *     the "readmsg" routine will send a MSGGOAWAY message and
+ *     return SCMEOF.
+ *     
+ *     Each message has this format:
+ *         ----------    ------------    ------------         ----------
+ *         |msg type|    |count|data|    |count|data|   ...   |ENDCOUNT|
+ *         ----------    ------------    ------------         ----------
+ *     size:  int          int  var.       int  var.             int
+ *
+ *     All ints are assumed to be 32-bit quantities.  A message
+ *     with no data simply has a message type followed by ENDCOUNT.
+ *
+ **********************************************************************
+ * HISTORY
+ * $Log: scmio.c,v $
+ * Revision 1.1  1995/12/16 11:46:52  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.2  1993/05/24 17:57:26  brezak
+ * Remove netcrypt.c. Remove unneeded files. Cleanup make.
+ *
+ * Revision 1.1.1.1  1993/05/21  14:52:17  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.7  92/09/09  22:04:41  mrt
+ *     Removed the data encryption routines from here to netcrypt.c
+ *     [92/09/09            mrt]
+ * 
+ * Revision 1.6  92/08/11  12:05:57  mrt
+ *     Brad's changes: Delinted,Added forward declarations of 
+ *     static functions. Added copyright.
+ *     [92/07/24            mrt]
+ * 
+ * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added crosspatch support.
+ *
+ * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Found error in debuging code for readint().
+ *
+ * 01-Apr-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to readdata to "push" data back into the data buffer.
+ *     Added prereadcount() to return the message count size after
+ *     reading it and then pushing it back into the buffer.  Clear
+ *     any encryption when a GOAWAY message is detected before reading
+ *     the reason string. [V5.19]
+ *
+ * 02-Oct-86  Rudy Nedved (ern) at Carnegie-Mellon University
+ *     Put a timeout on reading from the network.
+ *
+ * 25-May-86  Jonathan J. Chew (jjc) at Carnegie-Mellon University
+ *     Renamed "howmany" parameter to routines "encode" and "decode" from
+ *     to "count" to avoid conflict with 4.3BSD macro.
+ *
+ * 15-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added readflush() to flush any unread data from the input
+ *     buffer.  Called by requestend() in scm.c module.
+ *
+ * 19-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added register variables to decode() for speedup.  Added I/O
+ *     buffering to reduce the number or read/write system calls.
+ *     Removed readmfil/writemfil routines which were not used and were
+ *     not compatable with the other similarly defined routines anyway.
+ *
+ * 19-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Created from scm.c I/O and crypt routines.
+ *
+ **********************************************************************
+ */
+
+#include <libc.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include "sup.h"
+#include "supmsg.h"
+
+extern int errno;
+
+/*************************
+ ***    M A C R O S    ***
+ *************************/
+
+/* end of message */
+#define ENDCOUNT (-1)                  /* end of message marker */
+#define NULLCOUNT (-2)                 /* used for sending NULL pointer */
+
+#define RETRIES 15                     /* # of times to retry io */
+#define FILEXFER 2048                  /* block transfer size */
+#define XFERSIZE(count) ((count > FILEXFER) ? FILEXFER : count)
+
+/*********************************************
+ ***    G L O B A L   V A R I A B L E S    ***
+ *********************************************/
+
+extern int scmerr ();                  /* error printing routine */
+extern int netfile;                    /* network file descriptor */
+
+int scmdebug;                          /* scm debug flag */
+
+int cryptflag;                         /* whether to encrypt/decrypt data */
+char *cryptbuf;                                /* buffer for data encryption/decryption */
+
+extern char *goawayreason;             /* reason for goaway message */
+
+struct buf {
+       char b_data[FILEXFER];          /* buffered data */
+       char *b_ptr;                    /* pointer to end of buffer */
+       int b_cnt;                      /* number of bytes in buffer */
+} buffers[2];
+struct buf *bufptr;                    /* buffer pointer */
+
+
+/***********************************************
+ ***    O U T P U T   T O   N E T W O R K    ***
+ ***********************************************/
+
+static
+writedata (count,data)         /* write raw data to network */
+int count;
+char *data;
+{
+       register int x,tries;
+       register struct buf *bp;
+
+       if (bufptr) {
+               if (bufptr->b_cnt + count <= FILEXFER) {
+                       bcopy (data,bufptr->b_ptr,count);
+                       bufptr->b_cnt += count;
+                       bufptr->b_ptr += count;
+                       return (SCMOK);
+               }
+               bp = (bufptr == buffers) ? &buffers[1] : buffers;
+               bcopy (data,bp->b_data,count);
+               bp->b_cnt = count;
+               bp->b_ptr = bp->b_data + count;
+               data = bufptr->b_data;
+               count = bufptr->b_cnt;
+               bufptr->b_cnt = 0;
+               bufptr->b_ptr = bufptr->b_data;
+               bufptr = bp;
+       }
+       tries = 0;
+       for (;;) {
+               errno = 0;
+               x = write (netfile,data,count);
+               if (x > 0)  break;
+               if (errno)  break;
+               if (++tries > RETRIES)  break;
+               if (scmdebug > 0)
+                       logerr ("SCM Retrying failed network write");
+       }
+       if (x <= 0) {
+               if (errno == EPIPE)
+                       return (scmerr (-1,"Network write timed out"));
+               if (errno)
+                       return (scmerr (errno,"Write error on network"));
+               return (scmerr (-1,"Write retries failed"));
+       }
+       if (x != count)
+               return (scmerr (-1,"Write error on network returned %d on write of %d",x,count));
+       return (SCMOK);
+}
+
+static
+writeblock (count,data)                /* write data block */
+int count;
+char *data;
+{
+       register int x;
+       int y = byteswap(count);
+
+       x = writedata (sizeof(int),(char *)&y);
+       if (x == SCMOK)  x = writedata (count,data);
+       return (x);
+}
+
+writemsg (msg)         /* write start of message */
+int msg;
+{
+       int x;
+
+       if (scmdebug > 1)
+               loginfo ("SCM Writing message %d",msg);
+       if (bufptr)
+               return (scmerr (-1,"Buffering already enabled"));
+       bufptr = buffers;
+       bufptr->b_ptr = bufptr->b_data;
+       bufptr->b_cnt = 0;
+       x = byteswap (msg);
+       return (writedata(sizeof(int),(char *)&x));
+}
+
+writemend ()           /* write end of message */
+{
+       register int count;
+       register char *data;
+       int x;
+
+       x = byteswap (ENDCOUNT);
+       x = writedata (sizeof(int),(char *)&x);
+       if (x != SCMOK)  return (x);
+       if (bufptr == NULL)
+               return (scmerr (-1,"Buffering already disabled"));
+       if (bufptr->b_cnt == 0) {
+               bufptr = NULL;
+               return (SCMOK);
+       }
+       data = bufptr->b_data;
+       count = bufptr->b_cnt;
+       bufptr = NULL;
+       return (writedata (count, data));
+}
+
+writeint (i)           /* write int as data block */
+int i;
+{
+       int x;
+       if (scmdebug > 2)
+               loginfo ("SCM Writing integer %d",i);
+       x = byteswap(i);
+       return (writeblock(sizeof(int),(char *)&x));
+}
+
+writestring (p)                /* write string as data block */
+char *p;
+{
+       register int len,x;
+       if (p == NULL) {
+               int y = byteswap(NULLCOUNT);
+               if (scmdebug > 2)
+                       loginfo ("SCM Writing string NULL");
+               return (writedata (sizeof(int),(char *)&y));
+       }
+       if (scmdebug > 2)
+               loginfo ("SCM Writing string %s",p);
+       len = strlen (p);
+       if (cryptflag) {
+               x = getcryptbuf (len+1);
+               if (x != SCMOK)
+                       return (x);
+               encode (p,cryptbuf,len);
+               p = cryptbuf;
+       }
+       return (writeblock(len,p));
+}
+
+writefile (f)          /* write open file as a data block */
+int f;
+{
+       char buf[FILEXFER];
+       register int number,sum,filesize,x;
+       int y;
+       struct stat statbuf;
+
+       if (fstat(f,&statbuf) < 0)
+               return (scmerr (errno,"Can't access open file for message"));
+       filesize = statbuf.st_size;
+       y = byteswap(filesize);
+       x = writedata (sizeof(int),(char *)&y);
+
+       if (cryptflag)  x = getcryptbuf (FILEXFER);
+
+       if (x == SCMOK) {
+               sum = 0;
+               do {
+                       number = read (f,buf,FILEXFER);
+                       if (number > 0) {
+                               if (cryptflag) {
+                                       encode (buf,cryptbuf,number);
+                                       x = writedata (number,cryptbuf);
+                               }
+                               else {
+                                       x = writedata (number,buf);
+                               }
+                               sum += number;
+                       }
+               } while (x == SCMOK && number > 0);
+       }
+       if (sum != filesize)
+               return (scmerr (-1,"File size error on output message"));
+       if (number < 0)
+               return (scmerr (errno,"Read error on file output message"));
+       return (x);
+}
+
+writemnull (msg)       /* write message with no data */
+int msg;
+{
+       register int x;
+       x = writemsg (msg);
+       if (x == SCMOK)  x = writemend ();
+       return (x);
+}
+
+writemint (msg,i)              /* write message of one int */
+int msg,i;
+{
+       register int x;
+       x = writemsg (msg);
+       if (x == SCMOK)  x = writeint (i);
+       if (x == SCMOK)  x = writemend ();
+       return (x);
+}
+
+writemstr (msg,p)              /* write message of one string */
+int msg;
+char *p;
+{
+       register int x;
+       x = writemsg (msg);
+       if (x == SCMOK)  x = writestring (p);
+       if (x == SCMOK)  x = writemend ();
+       return (x);
+}
+
+/*************************************************
+ ***    I N P U T   F R O M   N E T W O R K    ***
+ *************************************************/
+
+static
+readdata (count,data)          /* read raw data from network */
+int count;
+char *data;
+{
+       register char *p;
+       register int n,m,x;
+       int tries;
+       static int bufcnt = 0;
+       static char *bufptr;
+       static char buffer[FILEXFER];
+       static int imask;
+       static struct timeval timout;
+
+       if (count < 0) {
+               if (bufptr + count < buffer)
+                       return (scmerr (-1,"No space in buffer %d",count));
+               bufptr += count;
+               bufcnt -= count;
+               bcopy (data,bufptr,-count);
+               return (SCMOK);
+       }
+       if (count == 0 && data == NULL) {
+               bufcnt = 0;
+               return (SCMOK);
+       }
+       if (count <= bufcnt) {
+               bcopy (bufptr,data,count);
+               bufptr += count;
+               bufcnt -= count;
+               return (SCMOK);
+       }
+       if (bufcnt > 0) {
+               bcopy (bufptr,data,bufcnt);
+               data += bufcnt;
+               count -= bufcnt;
+       }
+       bufptr = buffer;
+       bufcnt = 0;
+       timout.tv_usec = 0;
+       timout.tv_sec = 2*60*60;
+       p = buffer;
+       n = FILEXFER;
+       m = count;
+       while (m > 0) {
+               tries = 0;
+               for (;;) {
+                       imask = 1 << netfile;
+                       if (select(32,(fd_set *)&imask,(fd_set *)0,(fd_set *)0,&timout) < 0)
+                               imask = 1;
+                       errno = 0;
+                       if (imask)
+                               x = read (netfile,p,n);
+                       else
+                               return (scmerr (-1,"Timeout on network input"));
+                       if (x > 0)  break;
+                       if (x == 0)
+                               return (scmerr (-1,"Premature EOF on network input"));
+                       if (errno)  break;
+                       if (++tries > RETRIES)  break;
+                       if (scmdebug > 0)
+                               loginfo ("SCM Retrying failed network read");
+               }
+               if (x < 0) {
+                       if (errno)
+                               return (scmerr (errno,"Read error on network"));
+                       return (scmerr (-1,"Read retries failed"));
+               }
+               p += x;
+               n -= x;
+               m -= x;
+               bufcnt += x;
+       }
+       bcopy (bufptr,data,count);
+       bufptr += count;
+       bufcnt -= count;
+       return (SCMOK);
+}
+
+static
+int readcount (count)                  /* read count of data block */
+int *count;
+{
+       register int x;
+       int y;
+       x = readdata (sizeof(int),(char *)&y);
+       if (x != SCMOK)  return (x);
+       *count = byteswap(y);
+       return (SCMOK);
+}
+
+int prereadcount (count)               /* preread count of data block */
+int *count;
+{
+       register int x;
+       int y;
+       x = readdata (sizeof(int),(char *)&y);
+       if (x != SCMOK)  return (x);
+       x = readdata (-sizeof(int),(char *)&y);
+       if (x != SCMOK)  return (x);
+       *count = byteswap(y);
+       return (SCMOK);
+}
+
+readflush ()
+{
+       return (readdata (0, (char *)NULL));
+}
+
+readmsg (msg)          /* read header for expected message */
+int msg;               /* if message is unexpected, send back SCMHUH */
+{
+       register int x;
+       int m;
+       if (scmdebug > 1)
+               loginfo ("SCM Reading message %d",msg);
+       x = readdata (sizeof(int),(char *)&m);  /* msg type */
+       if (x != SCMOK)  return (x);
+       m = byteswap(m);
+       if (m == msg)  return (x);
+
+       /* check for MSGGOAWAY in case he noticed problems first */
+       if (m != MSGGOAWAY)
+               return (scmerr (-1,"Received unexpected message %d",m));
+       (void) netcrypt ((char *)NULL);
+       (void) readstring (&goawayreason);
+       (void) readmend ();
+       if (goawayreason == NULL)
+               return (SCMEOF);
+       logerr ("SCM GOAWAY %s",goawayreason);
+       return (SCMEOF);
+}
+
+readmend ()
+{
+       register int x;
+       int y;
+       x = readdata (sizeof(int),(char *)&y);
+       y = byteswap(y);
+       if (x == SCMOK && y != ENDCOUNT)
+               return (scmerr (-1,"Error reading end of message"));
+       return (x);
+}
+
+readskip ()                    /* skip over one input block */
+{
+       register int x;
+       int n;
+       char buf[FILEXFER];
+       x = readcount (&n);
+       if (x != SCMOK)  return (x);
+       if (n < 0)
+               return (scmerr (-1,"Invalid message count %d",n));
+       while (x == SCMOK && n > 0) {
+               x = readdata (XFERSIZE(n),buf);
+               n -= XFERSIZE(n);
+       }
+       return (x);
+}
+
+int readint (buf)              /* read int data block */
+int *buf;
+{
+       register int x;
+       int y;
+       x = readcount (&y);
+       if (x != SCMOK)  return (x);
+       if (y < 0)
+               return (scmerr (-1,"Invalid message count %d",y));
+       if (y != sizeof(int))
+               return (scmerr (-1,"Size error for int message is %d",y));
+       x = readdata (sizeof(int),(char *)&y);
+       (*buf) = byteswap(y);
+       if (scmdebug > 2)
+               loginfo ("SCM Reading integer %d",*buf);
+       return (x);
+}
+
+int readstring (buf)   /* read string data block */
+register char **buf;
+{
+       register int x;
+       int count;
+       register char *p;
+
+       x = readcount (&count);
+       if (x != SCMOK)  return (x);
+       if (count == NULLCOUNT) {
+               if (scmdebug > 2)
+                       loginfo ("SCM Reading string NULL");
+               *buf = NULL;
+               return (SCMOK);
+       }
+       if (count < 0)
+               return (scmerr (-1,"Invalid message count %d",count));
+       if (scmdebug > 3)
+               loginfo ("SCM Reading string count %d",count);
+       if ((p = (char *)malloc ((unsigned)count+1)) == NULL)
+               return (scmerr (-1,"Can't malloc %d bytes for string",count));
+       if (cryptflag) {
+               x = getcryptbuf (count+1);
+               if (x == SCMOK)  x = readdata (count,cryptbuf);
+               if (x != SCMOK)  return (x);
+       if (scmdebug > 3)
+               printf ("SCM Reading encrypted string %s\n",cryptbuf);
+               decode (cryptbuf,p,count);
+       }
+       else {
+               x = readdata (count,p);
+               if (x != SCMOK)  return (x);
+       }
+       p[count] = 0;           /* NULL at end of string */
+       *buf = p;
+       if (scmdebug > 2)
+               loginfo ("SCM Reading string %s",*buf);
+       return (SCMOK);
+}
+
+readfile (f)           /* read data block into open file */
+int f;
+{
+       register int x;
+       int count;
+       char buf[FILEXFER];
+
+       if (cryptflag) {
+               x = getcryptbuf (FILEXFER);
+               if (x != SCMOK)  return (x);
+       }
+       x = readcount (&count);
+       if (x != SCMOK)  return (x);
+       if (count < 0)
+               return (scmerr (-1,"Invalid message count %d",count));
+       while (x == SCMOK && count > 0) {
+               if (cryptflag) {
+                       x = readdata (XFERSIZE(count),cryptbuf);
+                       if (x == SCMOK)  decode (cryptbuf,buf,XFERSIZE(count));
+               }
+               else
+                       x = readdata (XFERSIZE(count),buf);
+               if (x == SCMOK) {
+                       (void) write (f,buf,XFERSIZE(count));
+                       count -= XFERSIZE(count);
+               }
+       }
+       return (x);
+}
+
+readmnull (msg)                /* read null message */
+int msg;
+{
+       register int x;
+       x = readmsg (msg);
+       if (x == SCMOK)  x = readmend ();
+       return (x);
+}
+
+readmint (msg,buf)             /* read int message */
+int msg,*buf;
+{
+       register int x;
+       x = readmsg (msg);
+       if (x == SCMOK)  x = readint (buf);
+       if (x == SCMOK)  x = readmend ();
+       return (x);
+}
+
+int readmstr (msg,buf)         /* read string message */
+int msg;
+char **buf;
+{
+       register int x;
+       x = readmsg (msg);
+       if (x == SCMOK)  x = readstring (buf);
+       if (x == SCMOK)  x = readmend ();
+       return (x);
+}
+
+/**********************************
+ ***    C R O S S P A T C H     ***
+ **********************************/
+
+crosspatch ()
+{
+       fd_set ibits, obits, xbits;
+       register int c;
+       char buf[STRINGLENGTH];
+
+       for (;;) {
+               FD_ZERO (&ibits);
+               FD_ZERO (&obits);
+               FD_ZERO (&xbits);
+               FD_SET (0,&ibits);
+               FD_SET (netfile,&ibits);
+               if ((c = select(16, &ibits, &obits, &xbits,
+                               (struct timeval *)NULL)) < 1) {
+                       if (c == -1) {
+                               if (errno == EINTR) {
+                                       continue;
+                               }
+                       }
+                       sleep (5);
+                       continue;
+               }
+               if (FD_ISSET (netfile,&ibits)) {
+                       c = read (netfile,buf,sizeof (buf));
+                       if (c < 0 && errno == EWOULDBLOCK)
+                               c = 0;
+                       else {
+                               if (c <= 0) {
+                                       break;
+                               }
+                               (void) write (1,buf,c);
+                       }
+               }
+               if (FD_ISSET(0, &ibits)) {
+                       c = read (0,buf,sizeof (buf));
+                       if (c < 0 && errno == EWOULDBLOCK)
+                               c = 0;
+                       else {
+                               if (c <= 0)
+                                       break;
+                               (void) write (netfile,buf,c);
+                       }
+               }
+       }
+}
diff --git a/usr.bin/sup/src/skipto.c b/usr.bin/sup/src/skipto.c
new file mode 100644 (file)
index 0000000..2fa5a4f
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/************************************************************************
+ *  skipover and skipto -- skip over characters in string
+ *
+ *  Usage:     p = skipto (string,charset);
+ *             p = skipover (string,charset);
+ *
+ *  char *p,*charset,*string;
+ *
+ *  Skipto returns a pointer to the first character in string which
+ *  is in the string charset; it "skips until" a character in charset.
+ *  Skipover returns a pointer to the first character in string which
+ *  is not in the string charset; it "skips over" characters in charset.
+ ************************************************************************
+ * HISTORY
+ * 26-Jun-81  David Smith (drs) at Carnegie-Mellon University
+ *     Skipover, skipto rewritten to avoid inner loop at expense of space.
+ *
+ * 20-Nov-79  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Skipover, skipto adapted for VAX from skip() and skipx() on the PDP-11
+ *     (from Ken Greer).  The names are more mnemonic.
+ *
+ *     Sindex adapted for VAX from indexs() on the PDP-11 (thanx to Ralph
+ *     Guggenheim).  The name has changed to be more like the index()
+ *     and rindex() functions from Bell Labs; the return value (pointer
+ *     rather than integer) has changed partly for the same reason,
+ *     and partly due to popular usage of this function.
+ */
+
+static unsigned char tab[256] = {
+       0};
+
+char *skipto (string,charset)
+unsigned char *string, *charset;
+{
+       register unsigned char *setp,*strp;
+
+       tab[0] = 1;             /* Stop on a null, too. */
+       for (setp=charset;  *setp;  setp++) tab[*setp]=1;
+       for (strp=string;  tab[*strp]==0;  strp++)  ;
+       for (setp=charset;  *setp;  setp++) tab[*setp]=0;
+       return ((char *)strp);
+}
+
+char *skipover (string,charset)
+unsigned char *string, *charset;
+{
+       register unsigned char *setp,*strp;
+
+       tab[0] = 0;             /* Do not skip over nulls. */
+       for (setp=charset;  *setp;  setp++) tab[*setp]=1;
+       for (strp=string;  tab[*strp];  strp++)  ;
+       for (setp=charset;  *setp;  setp++) tab[*setp]=0;
+       return ((char *)strp);
+}
diff --git a/usr.bin/sup/src/stree.c b/usr.bin/sup/src/stree.c
new file mode 100644 (file)
index 0000000..125c37e
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * stree.c -- SUP Tree Routines
+ *
+ **********************************************************************
+ * HISTORY
+ * $Log: stree.c,v $
+ * Revision 1.1  1995/12/16 11:46:53  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:17  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.4  92/08/11  12:06:32  mrt
+ *     Added copyright. Delinted
+ *     [92/08/10            mrt]
+ * 
+ * 
+ * Revision 1.3  89/08/15  15:30:57  bww
+ *     Changed code in Tlookup to Tsearch for each subpart of path.
+ *     Added indent formatting code to Tprint.
+ *     From "[89/06/24            gm0w]" at CMU.
+ *     [89/08/15            bww]
+ * 
+ * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to please lint.
+ *
+ * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to initialize new fields.  Added Tfree routine.
+ *
+ * 27-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Created.
+ *
+ **********************************************************************
+ */
+
+#include <libc.h>
+#include <c.h>
+#include <sys/param.h>
+#include "sup.h"
+
+#define Static /* static               /* comment for debugging */
+
+/*************************************************************
+ ***    T R E E   P R O C E S S I N G   R O U T I N E S    ***
+ *************************************************************/
+
+Tfree (t)
+register TREE **t;
+{
+       if (*t == NULL)  return;
+       Tfree (&((*t)->Tlink));
+       Tfree (&((*t)->Texec));
+       Tfree (&((*t)->Tlo));
+       Tfree (&((*t)->Thi));
+       if ((*t)->Tname)  free ((*t)->Tname);
+       if ((*t)->Tuser)  free ((*t)->Tuser);
+       if ((*t)->Tgroup)  free ((*t)->Tgroup);
+       free (*(char **)t);
+       *t = NULL;
+}
+
+Static
+TREE *Tmake (p)
+char *p;
+{
+       register TREE *t;
+       t = (TREE *) malloc (sizeof (TREE));
+       t->Tname = (p == NULL) ? NULL : salloc (p);
+       t->Tflags = 0;
+       t->Tuid = 0;
+       t->Tgid = 0;
+       t->Tuser = NULL;
+       t->Tgroup = NULL;
+       t->Tmode = 0;
+       t->Tctime = 0;
+       t->Tmtime = 0;
+       t->Tlink = NULL;
+       t->Texec = NULL;
+       t->Tbf = 0;
+       t->Tlo = NULL;
+       t->Thi = NULL;
+       return (t);
+}
+
+Static
+TREE *Trotll (tp,tl)
+register TREE *tp,*tl;
+{
+    tp->Tlo = tl->Thi;
+    tl->Thi = tp;
+    tp->Tbf = tl->Tbf = 0;
+    return(tl);
+}
+
+Static
+TREE *Trotlh (tp,tl)
+register TREE *tp,*tl;
+{
+    register TREE *th;
+
+    th = tl->Thi;
+    tp->Tlo = th->Thi;
+    tl->Thi = th->Tlo;
+    th->Thi = tp;
+    th->Tlo = tl;
+    tp->Tbf = tl->Tbf = 0;
+    if (th->Tbf == 1)
+       tp->Tbf = -1;
+    else if (th->Tbf == -1)
+       tl->Tbf = 1;
+    th->Tbf = 0;
+    return(th);
+}
+
+Static
+TREE *Trothl (tp,th)
+register TREE *tp,*th;
+{
+    register TREE *tl;
+
+    tl = th->Tlo;
+    tp->Thi = tl->Tlo;
+    th->Tlo = tl->Thi;
+    tl->Tlo = tp;
+    tl->Thi = th;
+    tp->Tbf = th->Tbf = 0;
+    if (tl->Tbf == -1)
+       tp->Tbf = 1;
+    else if (tl->Tbf == 1)
+       th->Tbf = -1;
+    tl->Tbf = 0;
+    return(tl);
+}
+
+Static
+TREE *Trothh (tp,th)
+register TREE *tp,*th;
+{
+    tp->Thi = th->Tlo;
+    th->Tlo = tp;
+    tp->Tbf = th->Tbf = 0;
+    return(th);
+}
+
+Static
+Tbalance (t)
+TREE **t;
+{
+    if ((*t)->Tbf < 2 && (*t)->Tbf > -2)
+       return;
+    if ((*t)->Tbf > 0) {
+       if ((*t)->Tlo->Tbf > 0)
+           *t = Trotll(*t, (*t)->Tlo);
+       else
+           *t = Trotlh(*t, (*t)->Tlo);
+    } else {
+       if ((*t)->Thi->Tbf > 0)
+           *t = Trothl(*t, (*t)->Thi);
+       else
+           *t = Trothh(*t, (*t)->Thi);
+    }
+}
+
+Static
+TREE *Tinsertavl (t,p,find,dh)
+TREE **t;
+char *p;
+int find;
+int *dh;
+{
+       register TREE *newt;
+       register int cmp;
+       int deltah;
+
+       if (*t == NULL) {
+           *t = Tmake (p);
+           *dh = 1;
+           return (*t);
+       }
+       if ((cmp = strcmp(p, (*t)->Tname)) == 0) {
+           if (!find)  return (NULL);  /* node already exists */
+           *dh = 0;
+           return (*t);
+       } else if (cmp < 0) {
+           if ((newt = Tinsertavl (&((*t)->Tlo),p,find,&deltah)) == NULL)
+               return (NULL);
+           (*t)->Tbf += deltah;
+       } else {
+           if ((newt = Tinsertavl (&((*t)->Thi),p,find,&deltah)) == NULL)
+               return (NULL);
+           (*t)->Tbf -= deltah;
+       }
+       Tbalance(t);
+       if ((*t)->Tbf == 0) deltah = 0;
+       *dh = deltah;
+       return (newt);
+}
+
+TREE *Tinsert (t,p,find)
+TREE **t;
+register char *p;
+int find;
+{
+       int deltah;
+
+       if (p != NULL && p[0] == '.' && p[1] == '/') {
+               p += 2;
+               while (*p == '/') p++;
+               if (*p == 0) p = ".";
+       }
+       return (Tinsertavl (t,p,find,&deltah));
+}
+
+TREE *Tsearch (t,p)
+TREE *t;
+char *p;
+{
+       register TREE *x;
+       register int cmp;
+
+       x = t;
+       while (x) {
+               cmp = strcmp (p,x->Tname);
+               if (cmp == 0)  return (x);
+               if (cmp < 0)    x = x->Tlo;
+               else            x = x->Thi;
+       }
+       return (NULL);
+}
+
+TREE *Tlookup (t,p)
+TREE *t;
+char *p;
+{
+       register TREE *x;
+       char buf[MAXPATHLEN+1];
+
+       if (p == NULL)
+               return (NULL);
+       if (p[0] == '.' && p[1] == '/') {
+               p += 2;
+               while (*p == '/') p++;
+               if (*p == 0) p = ".";
+       }
+       if ((x = Tsearch (t,p)) != NULL)
+               return (x);
+       if (*p != '/' && (x = Tsearch (t,".")) != NULL)
+               return (x);
+       (void) strncpy(buf, p, sizeof(buf)-1);
+       buf[MAXPATHLEN] = '\0';
+       while ((p = rindex(buf, '/')) != NULL) {
+               while (p >= buf && *(p-1) == '/')
+                       p--;
+               if (p == buf)
+                       *(p+1) = '\0';
+               else
+                       *p = '\0';
+               if ((x = Tsearch (t,buf)) != NULL)
+                       return (x);
+               if (p == buf)
+                       break;
+       }
+       return (NULL);
+}
+
+Static int process_level;
+
+Static
+int Tsubprocess (t,reverse,f,argp)
+TREE *t;
+int reverse;
+int (*f)();
+int *argp;
+{
+       register int x = SCMOK;
+       process_level++;
+       if (reverse?t->Thi:t->Tlo)
+               x = Tsubprocess (reverse?t->Thi:t->Tlo,
+                                reverse,f,argp);
+       if (x == SCMOK) {
+               x = (*f) (t,argp);
+               if (x == SCMOK) {
+                       if (reverse?t->Tlo:t->Thi)
+                               x = Tsubprocess (reverse?t->Tlo:t->Thi,
+                                                reverse,f,argp);
+               }
+       }
+       process_level--;
+       return (x);
+}
+
+/* VARARGS2 */
+int Trprocess (t,f,args)
+TREE *t;
+int (*f)();
+int args;
+{
+       if (t == NULL)  return (SCMOK);
+       process_level = 0;
+       return (Tsubprocess (t,TRUE,f,&args));
+}
+
+/* VARARGS2 */
+int Tprocess (t,f,args)
+TREE *t;
+int (*f)();
+int args;
+{
+       if (t == NULL)  return (SCMOK);
+       process_level = 0;
+       return (Tsubprocess (t,FALSE,f,&args));
+}
+
+Static
+int Tprintone (t)
+TREE *t;
+{
+       int i;
+       for (i = 0; i < (process_level*2); i++)
+               (void) putchar(' ');
+       printf ("Node at %X name '%s' flags %o hi %X lo %X\n",t,t->Tname,t->Tflags,t->Thi,t->Tlo);
+       return (SCMOK);
+}
+
+Tprint (t,p)           /* print tree -- for debugging */
+TREE *t;
+char *p;
+{
+       printf ("%s\n",p);
+       (void) Tprocess (t,Tprintone);
+       printf ("End of tree\n");
+       (void) fflush (stdout);
+}
diff --git a/usr.bin/sup/src/sup.1 b/usr.bin/sup/src/sup.1
new file mode 100644 (file)
index 0000000..f3999e0
--- /dev/null
@@ -0,0 +1,862 @@
+.\" Copyright (c) 1992 Carnegie Mellon University
+.\" All Rights Reserved.
+.\"
+.\" Permission to use, copy, modify and distribute this software and its
+.\" documentation is hereby granted, provided that both the copyright
+.\" notice and this permission notice appear in all copies of the
+.\" software, derivative works or modified versions, and any portions
+.\" thereof, and that both notices appear in supporting documentation.
+.\" 
+.\" CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+.\" CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+.\" ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+.\"
+.\" Carnegie Mellon requests users of this software to return to
+.\"
+.\"  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+.\"  School of Computer Science
+.\"  Carnegie Mellon University
+.\"  Pittsburgh PA 15213-3890
+.\"
+.\" any improvements or extensions that they make and grant Carnegie Mellon
+.\" the rights to redistribute these changes.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\" HISTORY
+.\" $Log: sup.1,v $
+.\" Revision 1.1  1995/12/16 11:46:54  deraadt
+.\" add sup to the tree
+.\"
+.\" Revision 1.3  1995/06/03 21:21:53  christos
+.\" Changes to write ascii timestamps in the when files.
+.\" Looked into making it 64 bit clean, but it is hopeless.
+.\" Added little program to convert from the old timestamp files
+.\" into the new ones.
+.\"
+.\" Revision 1.2  1993/08/04 17:46:14  brezak
+.\" Changes from nate for gzip'ed sup
+.\"
+.\" Revision 1.1.1.1  1993/05/21  14:52:16  cgd
+.\" initial import of CMU's SUP to NetBSD
+.\"
+.\" Revision 1.4  92/08/11  12:08:40  mrt
+.\"    .TP
+.\"    Add description of releases and use-rel-suffix 
+.\"    [92/07/31            mrt]
+.\" 
+.\" Revision 1.3  92/02/08  18:24:31  mja
+.\"    Added description of -k and -K switches and "keep" option.
+.\"    [92/01/17            vdelvecc]
+.\" 
+.\" 10-May-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+.\"    Replaced reference to /usr/cmu with /usr/cs.
+.\" 
+.\" 29-Mar-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+.\"    Updated manual entry to version 5.14 of sup.
+.\" 
+.\" 14-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+.\"    Updated manual entry to version 5.7 of sup.
+.\" 
+.\" 04-Apr-85  Steven Shafer (sas) at Carnegie-Mellon University
+.\"    Created.
+.\" 
+.TH SUP 1 02/08/92
+.CM 4
+.SH "NAME"
+sup \- software upgrade protocol
+.SH "SYNOPSIS"
+\fBsup\fR [ \fIflags\fR ] [ \fIsupfile\fR ] [ \fIcollection\fR ...]
+.SH "DESCRIPTION"
+.I Sup
+is a program used for upgrading collections of files from other machines
+to your machine.  You execute
+.IR sup ,
+the
+.I client
+program, which talks over the network using IP/TCP to a
+.I file server
+process.
+The file server process cooperates with
+.I sup
+to determine which files of the collection need to be upgraded on
+your machine.
+
+Sup collections can have multiple releases. One use for such releases is
+to provide different versions of the same files. At CMU, for example,
+system binaries have alpha, beta and default release corresponding to
+different staging levels of the software. We also use release names
+default and minimal to provide complete releases or subset releases.
+In both of these cases, it only makes sense to sup one release of the
+collections. Releases have also been used in private or external sups to
+provide subsets of collections where it makes sense to pick up several
+of the releases. For example the Mach 3.0 kernel sources has a default
+release of machine independent sources and separate releases of 
+machine dependent sources for each supported platform.
+
+In performing an upgrade, the file server constructs a list of
+files included in the specified release of the collection.  The list is sent to your machine,
+which determines which files are needed.  Those files are then sent
+from the file server.
+It will be most useful to run
+.I sup
+as a daemon each night so you will continually have the latest version of the
+files in the needed collections.
+
+The only required argument to
+.I sup
+is the name of a supfile.  It must either be given explicitly on the command
+line, or the
+.B -s
+flag must be specified.  If the
+.B -s
+flag is given, the system supfile will be used and a supfile command argument
+should not be specified.  The list of collections is optional and if specified
+will be the only collections upgraded.  The following flags affect all
+collections specified:
+.TP
+.B -s
+As described above.
+.TP
+.B -t
+When this flag is given,
+.I sup
+will print the time
+that each collection was last upgraded, rather than
+performing actual upgrades.
+.TP
+.B -N
+.I Sup
+will trace network messages sent and received that implement the
+.I sup
+network protocol.
+.TP
+.B -P
+Sup will use a set of non-privileged network
+ports reserved for debugging purposes.
+.i0
+.DT
+.PP
+
+The remaining flags affect all collections unless an explicit list
+of collections are given with the flags.  Multiple flags may be
+specified together that affect the same collections.  For the sake
+of convience, any flags that always affect all collections can be
+specified with flags that affect only some collections.  For
+example,
+.B sup -sde=coll1,coll2
+would perform a system upgrade,
+and the first two collections would allow both file deletions and
+command executions.  Note that this is not the same command as
+.B sup -sde=coll1 coll2,
+which would perform a system upgrade of
+just the coll2 collection and would ignore the flags given for the
+coll1 collection.
+.TP
+.B -a
+All files in the collection will be copied from
+the repository, regardless of their status on the
+current machine.  Because of this, it is a very
+expensive operation and should only be done for
+small collections if data corruption is suspected
+and been confirmed.  In most cases, the
+.B -o
+flag should be sufficient.
+.TP
+.B -b
+If the
+.B -b
+flag if given, or the 
+.B backup
+supfile
+option is specified, the contents of regular files
+on the local system will be saved before they are
+overwritten with new data.  The file collection maintainer
+can designate specific files to be
+worthy of backing up whenever they are upgraded.
+However, such
+backup will only take place if you specify this flag or the
+.B backup
+option to allow
+backups for a file collection on your machine.
+The backup mechanism
+will create a copy of the current version of a file immediately
+before a new copy is received from the file server; the copy is
+given the same name as the original file but is put into a directory
+called
+.B 
+BACKUP
+within the directory containing the original file.
+For example,
+.B 
+/usr/sas/src/foo.c
+would have a backup copy called
+.B 
+/usr/sas/src/BACKUP/foo.c.
+There is no provision for automatically maintaining multiple old
+versions of files; you would have to do this yourself.
+.TP
+.B -B
+The
+.B -B
+flag overrides and disables the
+.B -b
+flag and the
+.B backup
+supfile option.
+.TP
+.B -d
+Files that are no longer in the collection on the
+repository will be deleted if present on the local
+machine and were put there by a previous sup.  
+This may also be specified in a supfile with the
+.B delete
+option.
+.TP
+.B -D
+The
+.B -D
+flag overrides and disables the
+.B -d
+flag and the
+.B delete
+supfile option.
+.TP
+.B -e
+Sup will execute commands sent from the repository
+that should be run when a file is upgraded.  If
+the
+.B -e
+flag is omitted, Sup will print a message
+that specifies the command to execute.  This may
+also be specified in a supfile with the
+.B execute
+option.
+.TP
+.B -E
+The
+.B -E
+flag overrides and disables the
+.B -e
+flag and the
+.B execute
+supfile option.
+.TP
+.B -f
+A
+.I list-only
+upgrade will be performed.  Messages
+will be printed that indicate what would happen if
+an actual upgrade were done.
+.TP
+.B -k
+.I Sup
+will check the modification times of
+files on the local disk before updating them.  Only files which are
+newer on the repository than on the local disk will be updated;
+files that are newer on the local disk will be kept as they are.
+This may also be specified in a supfile with the
+.B keep
+option.
+.TP
+.B -K
+The
+.B -K
+flag overrides and disables the
+.B -k
+flag and the
+.B keep
+supfile option.
+.TP
+.B -l
+Normally,
+.I sup
+will not upgrade a collection if the
+repository is on the same machine.  This allows
+users to run upgrades on all machines without
+having to make special checks for the repository
+machine.  If the
+.B -l
+flag is specified, collections
+will be upgraded even if the repository is local.
+.TP
+.B -m
+Normally,
+.I sup
+used standard output for messages.
+If the
+.B -m
+flag if given,
+.I sup
+will send mail to the user running
+.IR sup ,
+or a user specified with the
+.B notify
+supfile option, that contains messages
+printed by
+.IR sup .
+.TP
+.B -o
+.I Sup
+will normally only upgrade files that have
+changed on the repository since the last time an
+upgrade was performed. That is, if the file in the
+repository is newer than the date stored in the 
+.I when
+file on the client.  The
+.B -o
+flag, or the
+.B old
+supfile option, will cause
+.I sup
+to check all files
+in the collection for changes instead of just the
+new ones.
+.TP
+.B -O
+The
+.B -O
+flag overrides and disables the
+.B -o
+flag and the
+.B old
+supfile option.
+.TP
+.B -z
+Normally sup transfers files directly without any
+other processing, but with the 
+.B -z
+flag, or the
+.B compress
+supfile option, sup will compress the file 
+before sending it across the network and
+uncompress it and restore all the correct 
+file attributes at the recieving end.
+.TP
+.B -Z
+The
+.B -Z
+flag overrides and disables the
+.B -z
+flag and the
+.B compress
+supfile option.
+.TP
+.B -v
+Normally,
+.I sup
+will only print messages if there
+are problems.  This flag causes
+.I sup
+to also print
+messages during normal progress showing what
+.I sup
+is doing.
+.i0
+.DT
+.PP
+.SH "SETTING UP UPGRADES"
+Each file collection to be upgraded must have a
+.I base directory
+which contains a subdirectory called
+.B sup
+that will be used by the
+.I sup
+program; it will be created automatically if you do not create it.
+.I Sup
+will put subdirectories and files into this directory as needed.
+
+.I Sup
+will look for a subdirectory with the same name as the
+collection within the
+.B sup
+subdirectory of the
+.I base directory.
+If it exists it may contain any of the following files:
+.TP
+.B when.<rel-suffix>
+This file is automatically updated by
+.I sup
+when a collection is successfully upgraded and contains the
+time that the file server, or possibly
+.IR supscan ,
+created the list of files in the upgrade list.
+.I Sup
+will send this time to the file server for generating the list
+of files that have been changed on the repository machine.
+.TP
+.B refuse
+This file contains a list of files and directories, one per line, that
+the client is not interested in that should not be upgraded.
+.TP
+.B lock
+This file is used by
+.I sup
+to lock a collection while it is being upgraded.
+.I Sup
+will get exclusive access to the lock file using
+.IR flock (2),
+preventing more than one
+.I sup
+from upgrading the same collection at the same time.
+.TP
+.B last.<rel-suffix>
+This file contains a list of files and directories, one per line, that
+have been upgraded by
+.I sup
+in the past.  This information is used when the
+.B delete
+option, or the
+.B -d
+flag is used to locate files previously upgraded that are no longer
+in the collection that should be deleted.
+.i0
+.DT
+.PP
+
+Each file collection must also be described in one or more supfiles.
+When
+.I sup
+is executed, it reads the specified supfile to determine what file
+collections  and releases to upgrade.
+Each collection-release set is described by a single
+line of text in the supfile; this line must contain the name of the
+collection, and possibly one or more options separated by spaces.
+The options are:
+.TP
+.BI release= releasename
+If a collection contains multiple releases, you need to specify which
+release you want. You can only specify one release per line, so
+if you want multiple releases from the same collections, you will need
+to specify the collection more than once. In this case, you should use
+the 
+.I use-rel-suffix 
+ption in the supfile
+to keep the last and when files for the two releases separate.
+.TP
+.BI base= directory
+The usual default name of the base directory for a collection is
+described below (see FILES); if you want to specify another
+directory name, use this option specifying the desired
+directory.
+.TP
+.BI prefix= directory
+Each collection may also have an associated
+.I prefix directory
+which is used instead of the base directory to specify in what
+directory files within the collection will be placed. 
+.TP
+.BI host= hostname
+.br
+.ns
+.TP
+.BI hostbase= directory
+.br
+.I System
+collections are supported by the system maintainers, and
+.I sup
+will automatically find out the name of the host machine and
+base directory on that machine.
+However, you can also upgrade
+.I private
+collections; you simply specify with these options
+the
+.I hostname
+of the machine containing the files and the
+.I directory
+used as a base directory for the file server on that machine.
+Details of setting up a file collection are given in the section
+below.
+.TP
+.BI login= accountid
+.br
+.ns
+.TP
+.BI password= password
+.br
+.br
+.ns
+.TP
+.BI crypt= key
+.br
+Files on the file server may be protected, and network transmissions
+may be encrypted.
+This prevents unauthorized access to files via
+.IR sup .
+When files are not accessible to the default account (e.g.
+the
+.B anon
+anonymous account), you can specify an alternative
+.I accountid
+and
+.I password
+for the file server to use on the repository host.
+Network
+transmission of the password will be always be encrypted.
+You can
+also have the actual file data encrypted by specifying a
+.IR key ;
+the file collection on the repository must specify the same key
+or else
+.I sup
+will not be able to upgrade files from that collection.
+In this case, the default account used by the file server on the
+repository machine will be the owner of the encryption key
+file (see FILES) rather than the
+.B anon
+anonymous account.
+.TP
+.BI notify= address
+If you use the
+.B 
+-m
+option to receive log messages by mail, you can have the mail
+sent to different user, possibly on another host, than the user
+running the sup program.
+Messages will be sent to the specified
+.IR address ,
+which can be any legal netmail address.
+In particular, a
+project maintainer can be designated to receive mail for that
+project's file collection from all users running
+.I sup
+to upgrade that collection.
+.TP
+.B backup
+As described above under the
+.B -b
+flag.
+.TP
+.B delete
+As described above under the
+.B -d
+flag.
+.TP
+.B execute
+As described above under the
+.B -e
+flag.
+.TP
+.B keep
+As described above under the
+.B -k
+flag.
+.TP
+.B old
+As described above under the
+.B -o
+flag.
+.TP
+.B use-rel-suffix
+Causes the release name to be used as a suffix to the 
+.I last
+and
+.I when
+files. This is necessary whenever you are supping more than one
+release in the same collection.
+.i0
+.DT
+.PP
+.SH "PREPARING A FILE COLLECTION REPOSITORY"
+A set of files residing on a repository must be prepared before
+.I sup
+client processes can upgrade those files.
+The collection must
+be given a
+.I name
+and a
+.I base directory.
+If it is a private collection, client users
+must be told the name of the collection, repository host, and
+base directory;
+these will be specified in the supfile via the
+.B host
+and
+.B hostbase
+options.
+For a system-maintained file collection, entries must be
+placed into the host list file and directory list file as described
+in
+.IR supservers (8).
+
+Within the base directory, a subdirectory must be created called
+.B sup .
+Within this directory there must be a subdirectory for each
+collection using that base directory, whose name is the name of the
+collection; within each of these directories will be a
+list file and possibly a prefix file, a host file, an encryption key
+file, a log file and
+a scan file.
+The filenames are listed under FILES below.
+.TP
+.B prefix
+Normally, all files in the collection are relative to the base directory.
+This file contains a single line which is the name of a directory to be
+used in place of the base directory for file references.
+.TP
+.B host
+Normally,
+all remote host machines are allowed access to a file collection.
+If you wish to restrict access to specific remote hosts for this
+collection,
+put each allowed hostname on a
+separate line of text in this file.
+If a host has more than one name, only one of its names needs to be
+listed.
+The name
+.B LOCAL
+can be used to grant access to all hosts on the local
+network. The host name may be a  numeric network adddress
+or a network name. If a crypt appears on the same line as
+the host name, that crypt will be used for that host. Otherwise,
+the crypt appearing in the 
+.I crypt
+file, if any will be used. 
+.TP
+.B crypt
+If you wish to use the
+.I sup
+data encryption mechanism, create an encryption file containing,
+on a single line of text, the desired encryption key.
+Client
+processes must then specify the same key with the
+.B crypt
+option in the supfile or they will be denied access to the files.
+In addition, actual network transmission of file contents and
+filenames will be encrypted.
+.TP
+.B list
+This file describes the actual list of files to be included in this
+file collection, in a format described below.
+.TP
+.B releases
+This file describes any releases that the collection may have. Each
+line starts with the release name and then may specify any of the following
+files: 
+.I prefix=<dirname>
+to use a different parent directory for the files in this release.
+.I list=<listname>
+to specify the list of files in the release.
+.I scan=<scanfile>
+must be used in multi-release collections that are scanned to keep
+the scan files for the different releases separate.
+.I host=<hostfile>
+to allow different host restrictions for this release.
+.I next=<release>
+used to chain releases together. This has the effect of making one release
+be a combination of serveral other releases. If the same file appears in
+more than one chained release, the first one found will be used.
+If these files are not specified for a release the default names:
+prefix,list,scan and host will be used.
+.TP
+.B scan
+This file, created by
+.IR supscan ,
+is the list of filenames that correspond to the instructions in the
+list file.  The scan file is only used for frequently-updated file
+collections; it makes the file server run much faster.  See
+.IR supservers (8)
+for more information.
+.TP
+.B lock
+As previously mentioned, this file is used to indicate that the
+collection should be locked while upgrades are in progress.  All
+file servers will try to get shared access to the lock file with
+.IR flock (2).
+.TP
+.B logfile
+If a log file exists in the collection directory, the file server
+will append the last time an upgrade was successfully completed,
+the time the last upgrade started and finished, and the name of
+the host requesting the upgrade.
+.i0
+.DT
+.PP
+It should be noted that
+.I sup
+allows several different named collections to use the same base
+directory.  Separate encryption, remote host access, and file lists
+are used for each collection, since these files reside in subdirectorie
+.I <basedir>/sup/<coll.name>.
+
+The list file is a text file with one command on each line.
+Each command
+contains a keyword and a number of operands separated by spaces.
+All filenames in the list file are evaluated on the repository machine
+relative to the host's base directory, or prefix directory if one is
+specified, and on your machine with respect
+to the base, or prefix, directory for the client.
+The
+.I filenames
+below (except \fIexec-command\fR)
+may all include wild-cards and meta-characters as used by
+.IR csh (1)
+including *, ?, [...], and {...}.  The commands are:
+.TP
+\fBupgrade\fR \fIfilename\fR ...
+The specified file(s) (or directories) will be included in the list
+of files to be upgraded.
+If a directory name is given, it recursively
+includes all subdirectories and files within that directory.
+.TP
+\fBalways\fR \fIfilename\fR ...
+The always command is identical to upgrade, except that omit and
+omitany commands do not affect filenames specified with the always
+command.
+.TP
+\fBomit\fR \fIfilename\fR ...
+The specified file(s) (or directories) will be excluded from the
+list of files to be upgraded.
+For example, by specifying
+.B upgrade /usr/vision
+and
+.B omit /usr/vision/exp,
+the generated list
+of files would include all subdirectories and files of /usr/vision
+except /usr/vision/exp (and its subdirectories and files).
+.TP
+\fBomitany\fR \fIpattern\fR ...
+The specified patterns are compared against the files in the upgrade
+list.  If a pattern matches, the file is omitted.  The omitany command
+currently supports all wild-card patterns except {...}.  Also, the
+pattern must match the entire filename, so a leading */, or a trailing /*,
+may be necessary in the pattern.
+.TP
+\fBbackup\fR \fIfilename\fR ...
+The specified file(s) are marked for backup; if they are upgraded
+and the client has specified the
+.B backup
+option in the corresponding
+line of the supfile, then backup copies will be created as described
+above.
+Directories may not be specified, and no recursive filename
+construction is performed; you must specify the names of the specific
+files to be backed up before upgrading.
+.TP
+\fBnoaccount\fR \fIfilename\fR ...
+The accounting information of the specified file(s) will not be
+preserved by
+.IR sup .
+Accounting information consists of the owner,
+group, mode and modified time of a file.
+.TP
+\fBsymlink\fR \fIfilename\fR ...
+The specified file(s) are to be treated as symbolic links
+and will be transfered as such and not followed.  By default,
+.I sup
+will follow symbolic links.
+.TP
+\fBrsymlink\fR \fIdirname\fR ...
+All symbolic links in the specified directory and its
+subdirectories are to be treated as symbolic links. That
+is the links will be transferred and not the files to which
+they point.
+.TP
+\fBexecute\fR \fIexec-command\fR (\fIfilename\fR ...)
+The
+.I exec-command
+you specified will be executed on the client process
+whenever any of the files listed in parentheses are upgraded.
+A special token,
+.B %s,
+may be specified in the
+.I exec-command
+and will be replaced by the name of the file that was upgraded.
+For example, if you say
+\fBexecute ranlib %s (libc.a)\fR,
+then whenever libc.a is upgraded, the client machine will execute
+.B 
+ranlib libc.a.
+As described above, the client must invoke
+.I sup
+with the
+.B -e
+flag to allow the automatic execution of command files.
+.TP
+\fBinclude\fR \fIlistfile\fR ...
+The specified
+.I listfiles
+will be read at this point.  This is useful
+when one collection subsumes other collections; the larger collection
+can simply specify the listfiles for the smaller collections contained
+within it.
+.i0
+.DT
+.PP
+The order in which the command lines appear in the list file does not
+matter.  Blank lines may appear freely in the list file.
+.SH "FILES"
+Files on the client machine for
+.IR sup :
+.TP
+.B /usr/lib/supfiles/coll.list
+supfile used for -s flag
+.TP
+.B /usr/lib/supfiles/coll.what
+supfile used for -s flag when -t flag is also specified
+.TP
+.B /usr/lib/supfiles/coll.host
+host name list for system collections
+.TP
+<\fIbase-directory\fR>\fB/sup/\fR<\fIcollection\fR>\fB/last\fR<\fI.release\fR>
+recorded list of files in collection as of last upgrade
+.TP
+<\fIbase-directory\fR>\fB/sup/\fR<\fIcollection\fR>\fB/lock
+file used to lock collection
+.TP
+<\fIbase-directory\fR>\fB/sup/\fR<\fIcollection\fR>\fB/refuse
+list of files to refuse in collection
+.TP
+<\fIbase-directory\fR>\fB/sup/\fR<\fIcollection\fR>\fB/when\fR<\fI.release\fR>
+recorded time of last upgrade
+.TP
+\fB/usr/sup/\fR<\fIcollection\fR>
+default base directory for file collection
+.i0
+.DT
+.PP
+
+Files needed on each repository machine for the file server:
+.TP
+.B /usr/lib/supfiles/coll.dir
+base directory list for system
+collections
+.TP
+<\fIbase-directory\fR>\fB/sup/\fR<\fIcollection\fR>\fB/crypt
+data encryption key for a
+collection. the owner of this file is the
+default account used when data encryption is specified
+.TP
+<\fIbase-directory\fR>\fB/sup/\fR<\fIcollection\fR>\fB/host
+list of remote hosts allowed to
+upgrade a collection
+.TP
+<\fIbase-directory\fR>\fB/sup/\fR<\fIcollection\fR>\fB/list
+list file for a collection
+.TP
+<\fIbase-directory\fR>\fB/sup/\fR<\fIcollection\fR>\fB/lock
+lock file for a collection
+.TP
+<\fIbase-directory\fR>\fB/sup/\fR<\fIcollection\fR>\fB/logfile
+log file for a collection
+.TP
+<\fIbase-directory\fR>\fB/sup/\fR<\fIcollection\fR>\fB/prefix
+file containing the name of the prefix directory
+for a collection
+.TP
+<\fIbase-directory\fR>\fB/sup/\fR<\fIcollection\fR>\fB/scan
+scan file for a collection
+.TP
+\fB/usr/\fR<\fIcollection\fR>
+default base directory for a file collection
+.i0
+.DT
+.PP
+.SH "SEE ALSO"
+.IR supservers (8)
+.br
+\fIThe SUP Software Upgrade Protocol\fR, S. A. Shafer,
+CMU Computer Science Department, 1985.
+.SH "EXAMPLE"
+<example>
+.SH "BUGS"
+The encryption mechanism should be strengthened, although it's
+not trivial.
diff --git a/usr.bin/sup/src/sup.h b/usr.bin/sup/src/sup.h
new file mode 100644 (file)
index 0000000..eee3b86
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/* sup.h -- declarations for sup, supnamesrv, supfilesrv
+ *
+ * VERSION NUMBER for any program is given by:  a.b (c)
+ * where       a = PROTOVERSION        is the protocol version #
+ *             b = PGMVERSION          is program # within protocol
+ *             c = scmversion          is communication module version
+ *                     (i.e. operating system for which scm is configured)
+ **********************************************************************
+ * HISTORY
+ * 13-Sep-92  Mary Thompson (mrt) at Carnegie-Mellon University
+ *     Changed name of DEFDIR from /usr/cs to /usr.
+ *
+ * 7-July-93  Nate Williams at Montana State University
+ *     Modified SUP to use gzip based compression when sending files
+ *     across the network to save BandWidth
+ *
+ * $Log: sup.h,v $
+ * Revision 1.1  1995/12/16 11:46:55  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.3  1995/06/03 21:21:54  christos
+ * Changes to write ascii timestamps in the when files.
+ * Looked into making it 64 bit clean, but it is hopeless.
+ * Added little program to convert from the old timestamp files
+ * into the new ones.
+ *
+ * Revision 1.2  1993/08/04 17:46:15  brezak
+ * Changes from nate for gzip'ed sup
+ *
+ * Revision 1.1.1.1  1993/05/21  14:52:18  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.10  92/08/11  12:06:42  mrt
+ *     Added definition for DEBUGFPORTNUM, the debugging port number.
+ *     Changed so that last and when file names could include
+ *     the relase name if any.
+ *     [92/07/23            mrt]
+ * 
+ * Revision 1.9  91/04/29  14:39:03  mja
+ *     Reduce MAXCHILDREN from 8 to 3.
+ * 
+ * Revision 1.8  89/08/23  14:55:30  gm0w
+ *     Moved coll.dir from supservers to supfiles.
+ *     [89/08/23            gm0w]
+ * 
+ * 18-Mar-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added host=<hostfile> support to releases file.
+ *
+ * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added crosspatch support.  Removed nameserver support.
+ *
+ * 27-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added TREELIST and other changes for "release" support.
+ *
+ * 25-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Version 6 of the network protocol, better support to reflect errors
+ *     back to server logfile.
+ *
+ * 21-May-87  Chriss Stephens (chriss) at Carnegie Mellon University
+ *     Merged divergent CS and EE versions.
+ *
+ * 19-Sep-86  Mike Accetta (mja) at Carnegie-Mellon University
+ *     Added FILESUPTDEFAULT definition.
+ *
+ * 07-Jun-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Removed FILESRVBUSYWAIT.  Now uses exponential backoff.
+ *
+ * 30-May-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added numeric port numbers to use when port names are not in the
+ *     host table.
+ *
+ * 04-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Update protocol version to 5 for name server protocol change to
+ *     allow multiple repositories per collection.  Added FILESRVBUSYWAIT
+ *     of 5 minutes.  Added FILELOCK file to indicate collections that
+ *     should be exclusively locked when upgraded.
+ *
+ * 22-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Merged 4.1 and 4.2 versions together.
+ *
+ * 04-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Created for 4.2 BSD.
+ *
+ **********************************************************************
+ */
+
+/* PGMVERSION is defined separately in each program */
+extern char scmversion[];              /* string version of scm */
+#define PROTOVERSION 8                 /* version of network protocol */
+#define SCANVERSION  2                 /* version of scan file format */
+
+/* TCP servers for name server and file server */
+#define FILEPORT       "supfilesrv"
+#define FILEPORTNUM    871
+#define DEBUGFPORT     "supfiledbg"
+#define DEBUGFPORTNUM  1127
+
+/* Data files used in scan.c */
+#define FILELIST       "sup/%s/%s"
+#define FILESCAN       "sup/%s/%s"
+#define FILEHOST       "sup/%s/%s"
+#define FILELISTDEF    "list"
+#define FILESCANDEF    "scan"
+#define FILEHOSTDEF    "host"
+#define DEFRELEASE     "default"
+
+/* Data files used in sup.c */
+#define FILEBASEDEFAULT        "/usr/%s" /* also supfilesrv and supscan */
+#ifdef EE_XXX
+#define FILESUPDEFAULT "%s/supfiles/coll.list"
+#define FILESUPTDEFAULT        "%s/supfiles/coll.what"
+#define FILEHOSTS      "%s/supfiles/coll.host"
+#else  EE_XXX
+#define FILESUPDEFAULT "%s/lib/supfiles/coll.list"
+#define FILESUPTDEFAULT        "%s/lib/supfiles/coll.what"
+#define FILEHOSTS      "%s/lib/supfiles/coll.host"
+#endif EE_XXX
+#define FILEBKDIR      "%s/BACKUP"
+#define FILEBACKUP     "%s/BACKUP/%s"
+#define FILELAST       "sup/%s/last%s"
+#define FILELASTTEMP   "sup/%s/last.temp"
+#define FILELOCK       "sup/%s/lock"   /* also supfilesrv */
+#define FILEREFUSE     "sup/%s/refuse"
+#define FILEWHEN       "sup/%s/when%s"
+
+/* Data files used in supfilesrv.c */
+#define FILEXPATCH     "%s/sup/xpatch.host"
+#ifdef EE_XXX
+#define FILEDIRS       "%s/supfiles/coll.dir" /* also supscan */
+#else  EE_XXX
+#define FILEDIRS       "%s/lib/supfiles/coll.dir" /* also supscan */
+#endif EE_XXX
+#define FILECRYPT      "sup/%s/crypt"
+#define FILELOGFILE    "sup/%s/logfile"
+#define FILEPREFIX     "sup/%s/prefix" /* also supscan */
+#define FILERELEASES   "sup/%s/releases" /* also supscan */
+
+/* String length */
+#define STRINGLENGTH   2000
+
+/* Password transmission encryption key */
+#define PSWDCRYPT      "SuperMan"
+/* Test string for encryption */
+#define CRYPTTEST      "Hello there, Sailor Boy!"
+
+/* Default directory for system sup information */
+#ifndef        DEFDIR
+#ifdef EE_XXX
+#define DEFDIR         "/etc"
+#else  EE_XXX
+#define DEFDIR         "/usr"
+#endif EE_XXX
+#endif DEFDIR
+
+/* Default login account for file server */
+#ifndef        DEFUSER
+#define DEFUSER                "anon"
+#endif DEFUSER
+
+/* subroutine return codes */
+#define SCMOK          (1)             /* routine performed correctly */
+#define SCMEOF         (0)             /* read EOF on network connection */
+#define SCMERR         (-1)            /* error occurred during routine */
+
+/* data structure for describing a file being upgraded */
+
+struct treestruct {
+/* fields for file information */
+       char *Tname;                    /* path component name */
+       int Tflags;                     /* flags of file */
+       int Tmode;                      /* st_mode of file */
+       char *Tuser;                    /* owner of file */
+       int Tuid;                       /* owner id of file */
+       char *Tgroup;                   /* group of file */
+       int Tgid;                       /* group id of file */
+       int Tctime;                     /* inode modification time */
+       int Tmtime;                     /* data modification time */
+       struct treestruct *Tlink;       /* tree of link names */
+       struct treestruct *Texec;       /* tree of execute commands */
+/* fields for sibling AVL tree */
+       int Tbf;                        /* balance factor */
+       struct treestruct *Tlo,*Thi;    /* ordered sibling tree */
+};
+typedef struct treestruct TREE;
+
+/* data structure to represent a list of trees to upgrade */
+
+struct tliststruct {
+       struct tliststruct *TLnext;     /* next entry in tree list */
+/* fields for tree information */
+       char *TLname;                   /* release name for tree */
+       char *TLprefix;                 /* prefix of tree */
+       char *TLlist;                   /* name of list file */
+       char *TLscan;                   /* name of scan file */
+       char *TLhost;                   /* name of host file */
+       TREE *TLtree;                   /* tree of files to upgrade */
+};
+typedef struct tliststruct TREELIST;
+
+/* bitfield not defined in stat.h */
+#define S_IMODE                  07777         /* part of st_mode that chmod sets */
+
+/* flag bits for files */
+#define FNEW                01         /* ctime of file has changed */
+#define FBACKUP                     02         /* backup of file is allowed */
+#define FNOACCT                     04         /* don't set file information */
+#define FUPDATE                    010         /* only set file information */
+#define FNEEDED                0100000         /* file needed for upgrade */
+
+/* version 3 compatability */
+#define        FCOMPAT         0010000         /* Added to detect execute commands to send */
+
+/* message types now obsolete */
+#define MSGFEXECQ      (115)
+#define MSGFEXECNAMES  (116)
+
+/* flag bits for files in list of all files */
+#define ALLNEW               01
+#define ALLBACKUP            02
+#define ALLEND               04
+#define ALLDIR              010
+#define ALLNOACCT           020
+#define ALLSLINK           0100
+
+/* flag bits for file mode word */
+#define MODELINK         010000
+#define MODEDIR                  040000
+#define MODESYM                 0100000
+#define MODENOACCT      0200000
+#define MODEUPDATE     01000000
+
+/* blocking factor for filenames in list of all file names */
+#define BLOCKALL       32
+
+/* end version 3 compatability */
+
+#define MAXCHILDREN 3                  /* maximum number of children allowed
+                                          to sup at the same time */
+
+/* scm and stree external declarations */
+char *remotehost();
+TREE *Tinsert(),*Tsearch(),*Tlookup();
+long getwhen();
+int putwhen();
diff --git a/usr.bin/sup/src/supcdefs.h b/usr.bin/sup/src/supcdefs.h
new file mode 100644 (file)
index 0000000..1226140
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ *     supcdefs.h -- Declarations shared by the collection of files
+ *                     that build the sup client.
+ *
+ **********************************************************************
+ * HISTORY
+ * 7-July-93  Nate Williams at Montana State University
+ *     Modified SUP to use gzip based compression when sending files
+ *     across the network to save BandWidth
+ *
+ * $Log: supcdefs.h,v $
+ * Revision 1.1  1995/12/16 11:46:55  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.2  1993/08/04 17:46:16  brezak
+ * Changes from nate for gzip'ed sup
+ *
+ * Revision 1.1.1.1  1993/05/21  14:52:18  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.6  92/08/11  12:06:52  mrt
+ *     Added CFURELSUF  - use-release-suffix flag
+ *     Made rpause code conditional on MACH rather than CMUCS
+ *     [92/07/26            mrt]
+ * 
+ * Revision 1.5  92/02/08  18:23:57  mja
+ *     Added CFKEEP flag.
+ *     [92/01/17            vdelvecc]
+ * 
+ * 10-Feb-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added timeout for backoff.
+ *
+ * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added Crelease for "release" support.
+ *
+ * 25-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Created.
+ *
+ **********************************************************************
+ */
+
+#include <libc.h>
+#include <netdb.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#if    MACH                    /* used by resource pausing code only */
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#endif /* MACH */
+#include <c.h>
+#include "sup.h"
+#include "supmsg.h"
+
+extern int errno;
+extern uid_t getuid();
+extern gid_t getgid();
+extern long time();
+
+extern int PGMVERSION;
+
+/*******************************************
+ ***    D A T A   S T R U C T U R E S    ***
+ *******************************************/
+
+struct collstruct {                    /* one per collection to be upgraded */
+       char *Cname;                    /* collection name */
+       TREE *Chost;                    /* attempted host for collection */
+       TREE *Chtree;                   /* possible hosts for collection */
+       char *Cbase;                    /* local base directory */
+       char *Chbase;                   /* remote base directory */
+       char *Cprefix;                  /* local collection pathname prefix */
+       char *Crelease;                 /* release name */
+       char *Cnotify;                  /* user to notify of status */
+       char *Clogin;                   /* remote login name */
+       char *Cpswd;                    /* remote password */
+       char *Ccrypt;                   /* data encryption key */
+       int Ctimeout;                   /* timeout for backoff */
+       int Cflags;                     /* collection flags */
+       int Cnogood;                    /* upgrade no good, "when" unchanged */
+       int Clockfd;                    /* >= 0 if collection is locked */
+       struct collstruct *Cnext;       /* next collection */
+};
+typedef struct collstruct COLLECTION;
+
+#define CFALL          00001
+#define CFBACKUP       00002
+#define CFDELETE       00004
+#define CFEXECUTE      00010
+#define CFLIST         00020
+#define CFLOCAL                00040
+#define CFMAIL         00100
+#define CFOLD          00200
+#define CFVERBOSE      00400
+#define CFKEEP         01000
+#define CFURELSUF      02000
+#define CFCOMPRESS     04000
+
+/*************************
+ ***   M A C R O S    ***
+ *************************/
+
+#define vnotify        if (thisC->Cflags&CFVERBOSE)  notify
diff --git a/usr.bin/sup/src/supcmain.c b/usr.bin/sup/src/supcmain.c
new file mode 100644 (file)
index 0000000..5568acb
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ *     sup -- Software Upgrade Protocol client process
+ *
+ *     Usage:  sup [ flags ] [ supfile ] [ collection ... ]
+ *
+ *     The only required argument to sup is the name of a supfile.  It
+ *     must either be given explicitly on the command line, or the -s
+ *     flag must be specified.  If the -s flag is given, the system
+ *     supfile will be used and a supfile command argument should not be
+ *     specified.  The list of collections is optional and if specified
+ *     will be the only collections upgraded.  The following flags affect
+ *     all collections specified.
+ *
+ *     -s      "system upgrade" flag
+ *                     As described above.
+ *
+ *     -t      "upgrade time" flag
+ *                     When this flag is given, Sup will print the time
+ *                     that each collection was last upgraded, rather than
+ *                     performing actual upgrades.
+ *
+ *     -R      "resource pause" flag
+ *                     Sup will not disable resource pausing and will not
+ *                     make filesystem space checks.
+ *
+ *     -N      "debug network" flag
+ *                     Sup will trace messages sent and received that
+ *                     implement the Sup network protocol.
+ *
+ *     -P      "debug ports" flag
+ *                     Sup will use a set of non-privileged network
+ *                     ports reserved for debugging purposes.
+ *
+ *     -X      "crosspatch" flag
+ *                     Sup is being run remotely with a crosspatch.
+ *                     Need to be carefull as we may be running as root
+ *                     instead of collection owner.
+ *
+ *     The remaining flags affect all collections unless an explicit list
+ *     of collections are given with the flags.  Multiple flags may be
+ *     specified together that affect the same collections.  For the sake
+ *     of convience, any flags that always affect all collections can be
+ *     specified with flags that affect only some collections.  For
+ *     example, "sup -sde=coll1,coll2" would perform a system upgrade,
+ *     and the first two collections would allow both file deletions and
+ *     command executions.  Note that this is not the same command as
+ *     "sup -sde=coll1 coll2", which would perform a system upgrade of
+ *     just the coll2 collection and would ignore the flags given for the
+ *     coll1 collection.
+ *
+ *     -a      "all files" flag
+ *                     All files in the collection will be copied from
+ *                     the repository, regardless of their status on the
+ *                     current machine.  Because of this, it is a very
+ *                     expensive operation and should only be done for
+ *                     small collections if data corruption is suspected
+ *                     and been confirmed.  In most cases, the -o flag
+ *                     should be sufficient.
+ *
+ *     -b      "backup files" flag
+ *                     If the -b flag if given, or the "backup" supfile
+ *                     option is specified, the contents of regular files
+ *                     on the local system will be saved before they are
+ *                     overwritten with new data.  The data will be saved
+ *                     in a subdirectory called "BACKUP" in the directory
+ *                     containing the original version of the file, in a
+ *                     file with the same non-directory part of the file
+ *                     name.  The files to backup are specified by the
+ *                     list file on the repository.
+ *
+ *     -B      "don't backup files" flag
+ *                     The -B flag overrides and disables the -b flag and
+ *                     the "backup" supfile option.
+ *
+ *     -d      "delete files" flag
+ *                     Files that are no longer in the collection on the
+ *                     repository will be deleted if present on the local
+ *                     machine.  This may also be specified in a supfile
+ *                     with the "delete" option.
+ *
+ *     -D      "don't delete files" flag
+ *                     The -D flag overrides and disables the -d flag and
+ *                     the "delete" supfile option.
+ *
+ *     -e      "execute files" flag
+ *                     Sup will execute commands sent from the repository
+ *                     that should be run when a file is upgraded.  If
+ *                     the -e flag is omitted, Sup will print a message
+ *                     that specifies the command to execute.  This may
+ *                     also be specified in a supfile with the "execute"
+ *                     option.
+ *
+ *     -E      "don't execute files" flag
+ *                     The -E flag overrides and disables the -e flag and
+ *                     the "execute" supfile option.
+ *
+ *     -f      "file listing" flag
+ *                     A "list-only" upgrade will be performed.  Messages
+ *                     will be printed that indicate what would happen if
+ *                     an actual upgrade were done.
+ *
+ *     -k      "keep newer files" flag
+ *                     The -k flag, or "keep" supfile option, will cause
+ *                     Sup to check to see whether there is a newer file on
+ *                     the local disk before updating files.  Only files
+ *                     which are newer on the repository will be updated.
+ *
+ *     -K      "don't keep newer files" flag
+ *                     The -K flag overrides and disables the -k flag and
+ *                     the "keep" supfile option.
+ *
+ *     -l      "local upgrade" flag
+ *                     Normally, Sup will not upgrade a collection if the
+ *                     repository is on the same machine.  This allows
+ *                     users to run upgrades on all machines without
+ *                     having to make special checks for the repository
+ *                     machine.  If the -l flag is specified, collections
+ *                     will be upgraded even if the repository is local.
+ *
+ *     -m      "mail" flag
+ *                     Normally, Sup used standard output for messages.
+ *                     If the -m flag if given, Sup will send mail to the
+ *                     user running Sup, or a user specified with the
+ *                     "notify" supfile option, that contains messages
+ *                     printed by Sup.
+ *
+ *     -o      "old files" flag
+ *                     Sup will normally only upgrade files that have
+ *                     changed on the repository since the last time an
+ *                     upgrade was performed.  The -o flag, or the "old"
+ *                     supfile option, will cause Sup to check all files
+ *                     in the collection for changes instead of just the
+ *                     new ones.
+ *
+ *     -O      "not old files" flag
+ *                     The -O flag overrides and disables the -o flag and
+ *                     the "old" supfile option.
+ *
+ *     -v      "verbose" flag
+ *                     Normally, Sup will only print messages if there
+ *                     are problems.  This flag causes Sup to also print
+ *                     messages during normal progress showing what Sup
+ *                     is doing.
+ *
+ **********************************************************************
+ * HISTORY
+ *
+ * 7-July-93  Nate Williams at Montana State University
+ *     Modified SUP to use gzip based compression when sending files
+ *     across the network to save BandWidth
+ *
+ * $Log: supcmain.c,v $
+ * Revision 1.1  1995/12/16 11:46:56  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.4  1995/09/16 19:01:25  glass
+ * if the function returns nothing, declare it void
+ *
+ * Revision 1.3  1993/08/04 17:46:17  brezak
+ * Changes from nate for gzip'ed sup
+ *
+ * Revision 1.2  1993/05/24  17:57:28  brezak
+ * Remove netcrypt.c. Remove unneeded files. Cleanup make.
+ *
+ * Revision 1.1.1.1  1993/05/21  14:52:18  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.6  92/08/11  12:06:59  mrt
+ *     Merged in Brad's changes. Made resource pausing code conditional
+ *     on MACH, rather than CMUCS. Fixed some calls to sprintf to
+ *     return void.
+ *     [92/08/09            mrt]
+ * 
+ * Revision 1.5  92/02/08  19:01:18  mja
+ *     Correct oldsigsys type when ANSI C.
+ *     [92/02/08  18:59:47  mja]
+ * 
+ * Revision 1.4  92/02/08  18:24:01  mja
+ *     Added -k and -K switches.
+ *     [92/01/17            vdelvecc]
+ * 
+ * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added crosspatch support (is currently ignored).
+ *
+ * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code for "release" support.
+ *
+ * 25-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Split into several files.  This is the main program and
+ *     command line processing and old history log. [V5.21]
+ *
+ * 21-May-87  Chriss Stephens (chriss) at Carnegie Mellon University
+ *     Merged divergent CS and ECE versions. ifdeffed out the resource
+ *     pausing code - only compiled in if CMUCS defined. [V5.21a]
+ *
+ * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Removed support for version 3 of SUP protocol.  Added changes
+ *     to make lint happy.  Added calls to new logging routines. [V5.20]
+ *
+ * 01-Apr-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added -R switch to reenable resource pausing, which is currently
+ *     disabled by default.  Added code to check for free disk space
+ *     available on the target filesystem so that sup shouldn't run the
+ *     system out of disk space as frequently. [V5.19]
+ *
+ * 19-Sep-86  Mike Accetta (mja) at Carnegie-Mellon University
+ *     Changed default supfile name for system collections when -t
+ *     is specified to use FILESUPTDEFAULT; added missing new-line
+ *     in retry message. [V5.18]
+ *
+ * 21-Jun-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Missed a caller to a routine which had an extra argument added
+ *     to it last edit. [V5.17]
+ *
+ * 07-Jun-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changed getcoll() so that fatal errors are checked immediately
+ *     instead of after sleeping for a little while.  Changed all
+ *     rm -rf commands to rmdir since the Mach folks keep deleting
+ *     their root and /usr directory trees.  Reversed the order of
+ *     delete commands to that directories will possibly empty so
+ *     that the rmdir's work. [V5.16]
+ *
+ * 30-May-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changed temporary file names to #n.sup format. [V5.15]
+ *
+ * 19-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Moved PGMVERSION to supvers.c module. [V5.14]
+ *
+ * 06-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added check for file type before unlink when receiving a
+ *     symbolic link.  Now runs "rm -rf" if the file type is a
+ *     directory. [V5.13]
+ *
+ * 03-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Fixed small bug in signon that didn't retry connections if an
+ *     error occured on the first attempt to connect. [V5.12]
+ *
+ * 26-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     New command interface.  Added -bBDEO flags and "delete",
+ *     "execute" and "old" supfile options.  Changed -d to work
+ *     correctly without implying -o. [V5.11]
+ *
+ * 21-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Fix incorrect check for supfile changing.  Flush output buffers
+ *     before restart. [V5.10]
+ *
+ * 17-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Add call to requestend() after connection errors are retried to
+ *     free file descriptors. [V5.9]
+ *
+ * 15-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Fix SERIOUS merge error from previous edit.  Added notify
+ *     when execute command fails. [V5.8]
+ *
+ * 11-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changed ugconvert to clear setuid/setgid bits if it doesn't use
+ *     the user and group specified by the remote system.  Changed
+ *     execute code to invalidate collection if execute command returns
+ *     with a non-zero exit status.  Added support for execv() of
+ *     original arguments of supfile is upgraded sucessfully.  Changed
+ *     copyfile to always use a temp file if possible. [V5.7]
+ *
+ * 04-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added support for fileserver busy messages and new nameserver
+ *     protocol to support multiple repositories per collection.
+ *     Added code to lock collections with lock files. [V5.6]
+ *
+ * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Major rewrite for protocol version 4. [V4.5]
+ *
+ * 12-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changed to check for DIFFERENT mtime (again). [V3.4]
+ *
+ * 08-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Replaced [ug]convert routines with ugconvert routine so that an
+ *     appropriate group will be used if the default user is used.
+ *     Changed switch parsing to allow multiple switches to be specified
+ *     at the same time. [V3.3]
+ *
+ * 04-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added test to request a new copy of an old file that already
+ *     exists if the mtime is different. [V3.2]
+ *
+ * 24-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added -l switch to enable upgrades from local repositories.
+ *
+ * 03-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Minor change in order -t prints so that columns line up.
+ *
+ * 22-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to implement retry flag and pass this on to request().
+ *
+ * 22-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Merged 4.1 and 4.2 versions together.
+ *
+ * 04-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Created for 4.2 BSD.
+ *
+ **********************************************************************
+ */
+
+#define MSGFILE
+#include "supcdefs.h"
+#if    MACH
+#include <sys/syscall.h>
+#ifndef SYS_rpause
+#define SYS_rpause     (-5)
+#endif
+#endif
+
+/*********************************************
+ ***    G L O B A L   V A R I A B L E S    ***
+ *********************************************/
+
+char program[] = "SUP";                        /* program name for SCM messages */
+int progpid = -1;                      /* and process id */
+
+COLLECTION *firstC,*thisC;             /* collection list pointer */
+
+extern int dontjump;                   /* disable longjmp */
+extern int scmdebug;                   /* SCM debugging flag */
+
+int sysflag;                           /* system upgrade flag */
+int timeflag;                          /* print times flag */
+#if    MACH
+int rpauseflag;                                /* don't disable resource pausing */
+#endif /* MACH */
+int xpatchflag;                                /* crosspatched with remote system */
+int portdebug;                         /* network debugging ports */
+
+/*************************************
+ ***    M A I N   R O U T I N E    ***
+ *************************************/
+
+main (argc,argv)
+int argc;
+char **argv;
+{
+       char *init ();
+       char *progname,*supfname;
+       int restart,sfdev,sfino,sfmtime;
+       struct stat sbuf;
+       struct sigvec ignvec,oldvec;
+
+       /* initialize global variables */
+       pgmversion = PGMVERSION;        /* export version number */
+       server = FALSE;                 /* export that we're not a server */
+       collname = NULL;                /* no current collection yet */
+       dontjump = TRUE;                /* clear setjmp buffer */
+       progname = salloc (argv[0]);
+
+       supfname = init (argc,argv);
+       restart = -1;                   /* don't make restart checks */
+       if (*progname == '/' && *supfname == '/') {
+               if (stat (supfname,&sbuf) < 0)
+                       logerr ("Can't stat supfile %s",supfname);
+               else {
+                       sfdev = sbuf.st_dev;
+                       sfino = sbuf.st_ino;
+                       sfmtime = sbuf.st_mtime;
+                       restart = 0;
+               }
+       }
+       if (timeflag) {
+               for (thisC = firstC; thisC; thisC = thisC->Cnext)
+                       prtime ();
+       } else {
+               /* ignore network pipe signals */
+               ignvec.sv_handler = SIG_IGN;
+               ignvec.sv_onstack = 0;
+               ignvec.sv_mask = 0;
+               (void) sigvec (SIGPIPE,&ignvec,&oldvec);
+               getnams ();             /* find unknown repositories */
+               for (thisC = firstC; thisC; thisC = thisC->Cnext) {
+                       getcoll ();     /* upgrade each collection */
+                       if (restart == 0) {
+                               if (stat (supfname,&sbuf) < 0)
+                                       logerr ("Can't stat supfile %s",
+                                               supfname);
+                               else if (sfmtime != sbuf.st_mtime ||
+                                        sfino != sbuf.st_ino ||
+                                        sfdev != sbuf.st_dev) {
+                                       restart = 1;
+                                       break;
+                               }
+                       }
+               }
+               endpwent ();            /* close /etc/passwd */
+               (void) endgrent ();     /* close /etc/group */
+               if (restart == 1) {
+                       int fd;
+                       loginfo ("SUP Restarting %s with new supfile %s",
+                               progname,supfname);
+                       for (fd = getdtablesize (); fd > 3; fd--)
+                               (void) close (fd);
+                       execv (progname,argv);
+                       logquit (1,"Restart failed");
+               }
+       }
+       while (thisC = firstC) {
+               firstC = firstC->Cnext;
+               free (thisC->Cname);
+               Tfree (&thisC->Chtree);
+               free (thisC->Cbase);
+               if (thisC->Chbase)  free (thisC->Chbase);
+               if (thisC->Cprefix)  free (thisC->Cprefix);
+               if (thisC->Crelease)  free (thisC->Crelease);
+               if (thisC->Cnotify)  free (thisC->Cnotify);
+               if (thisC->Clogin)  free (thisC->Clogin);
+               if (thisC->Cpswd)  free (thisC->Cpswd);
+               if (thisC->Ccrypt)  free (thisC->Ccrypt);
+               free ((char *)thisC);
+       }
+       exit (0);
+}
+
+/*****************************************
+ ***    I N I T I A L I Z A T I O N    ***
+ *****************************************/
+/* Set up collection list from supfile.  Check all fields except
+ * hostname to be sure they make sense.
+ */
+
+#define Toflags        Tflags
+#define Taflags        Tmode
+#define Twant  Tuid
+#define Tcount Tgid
+
+void doswitch (argp,collTp,oflagsp,aflagsp)
+char *argp;
+register TREE **collTp;
+int *oflagsp,*aflagsp;
+{
+       register TREE *t;
+       register char *coll;
+       register int oflags,aflags;
+
+       oflags = aflags = 0;
+       for (;;) {
+               switch (*argp) {
+               default:
+                       logerr ("Invalid flag '%c' ignored",*argp);
+                       break;
+               case '\0':
+               case '=':
+                       if (*argp++ == '\0' || *argp == '\0') {
+                               *oflagsp |= oflags;
+                               *oflagsp &= ~aflags;
+                               *aflagsp |= aflags;
+                               *aflagsp &= ~oflags;
+                               return;
+                       }
+                       do {
+                               coll = nxtarg (&argp,", \t");
+                               t = Tinsert (collTp,coll,TRUE);
+                               t->Toflags |= oflags;
+                               t->Toflags &= ~aflags;
+                               t->Taflags |= aflags;
+                               t->Taflags &= ~oflags;
+                               argp = skipover (argp,", \t");
+                       } while (*argp);
+                       return;
+               case 'N':
+                       scmdebug++;
+                       break;
+               case 'P':
+                       portdebug = TRUE;
+                       break;
+               case 'R':
+#if    MACH
+                       rpauseflag = TRUE;
+#endif /* MACH */
+                       break;
+               case 'X':
+                       xpatchflag = TRUE;
+                       break;
+               case 's':
+                       sysflag = TRUE;
+                       break;
+               case 't':
+                       timeflag = TRUE;
+                       break;
+               case 'a':
+                       oflags |= CFALL;
+                       break;
+               case 'b':
+                       oflags |= CFBACKUP;
+                       aflags &= ~CFBACKUP;
+                       break;
+               case 'B':
+                       oflags &= ~CFBACKUP;
+                       aflags |= CFBACKUP;
+                       break;
+               case 'd':
+                       oflags |= CFDELETE;
+                       aflags &= ~CFDELETE;
+                       break;
+               case 'D':
+                       oflags &= ~CFDELETE;
+                       aflags |= CFDELETE;
+                       break;
+               case 'e':
+                       oflags |= CFEXECUTE;
+                       aflags &= ~CFEXECUTE;
+                       break;
+               case 'E':
+                       oflags &= ~CFEXECUTE;
+                       aflags |= CFEXECUTE;
+                       break;
+               case 'f':
+                       oflags |= CFLIST;
+                       break;
+               case 'k':
+                       oflags |= CFKEEP;
+                       aflags &= ~CFKEEP;
+                       break;
+               case 'K':
+                       oflags &= ~CFKEEP;
+                       aflags |= CFKEEP;
+                       break;
+               case 'l':
+                       oflags |= CFLOCAL;
+                       break;
+               case 'm':
+                       oflags |= CFMAIL;
+                       break;
+               case 'o':
+                       oflags |= CFOLD;
+                       aflags &= ~CFOLD;
+                       break;
+               case 'O':
+                       oflags &= ~CFOLD;
+                       aflags |= CFOLD;
+                       break;
+               case 'v':
+                       oflags |= CFVERBOSE;
+                       break;
+               case 'z':
+                       oflags |= CFCOMPRESS;
+                       break;
+               case 'Z':
+                       oflags &= ~CFCOMPRESS;
+                       break;
+               }
+               argp++;
+       }
+}
+
+char *init (argc,argv)
+int argc;
+char **argv;
+{
+       char buf[STRINGLENGTH],*p;
+       char username[STRINGLENGTH];
+       register char *supfname,*q,*arg;
+       register COLLECTION *c,*lastC;
+       register FILE *f;
+       register int bogus;
+       register struct passwd *pw;
+       register TREE *t;
+       TREE *collT;                    /* collections we are interested in */
+       long timenow;                   /* startup time */
+       int checkcoll ();
+       int oflags,aflags;
+       int cwant;
+#ifdef MACH
+#ifdef __STDC__
+       void (*oldsigsys)();
+#else
+       int (*oldsigsys)();
+#endif
+#endif /* MACH */
+       char *fmttime();
+
+       sysflag = FALSE;                /* not system upgrade */
+       timeflag = FALSE;               /* don't print times */
+#if    MACH
+       rpauseflag = FALSE;             /* don't disable resource pausing */
+#endif /* MACH */
+       xpatchflag = FALSE;             /* not normally crosspatched */
+       scmdebug = 0;                   /* level zero, no SCM debugging */
+       portdebug = FALSE;              /* no debugging ports */
+
+       collT = NULL;
+       oflags = aflags = 0;
+       while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') {
+               doswitch (&argv[1][1],&collT,&oflags,&aflags);
+               --argc;
+               argv++;
+       }
+       if (argc == 1 && !sysflag)
+               logquit (1,"Need either -s or supfile");
+#if    MACH
+       oldsigsys = signal (SIGSYS,SIG_IGN);
+       if (rpauseflag != TRUE)
+               if (syscall (SYS_rpause,ENOSPC,RPAUSE_ALL,RPAUSE_DISABLE) < 0)
+               rpauseflag = TRUE;
+       (void) signal (SIGSYS,oldsigsys);
+#endif /* MACH */
+       if (sysflag)
+               (void) sprintf (supfname = buf,
+                                   timeflag?FILESUPTDEFAULT:FILESUPDEFAULT,
+                                   DEFDIR);
+       else {
+               supfname = argv[1];
+               if (strcmp (supfname,"-") == 0)
+                       supfname = "";
+               --argc;
+               argv++;
+       }
+       cwant = argc > 1;
+       while (argc > 1) {
+               t = Tinsert (&collT,argv[1],TRUE);
+               t->Twant = TRUE;
+               --argc;
+               argv++;
+       }
+       if ((p = (char *)getlogin()) ||
+           ((pw = getpwuid ((int)getuid())) && (p = pw->pw_name)))
+               (void) strcpy (username,p);
+       else
+               *username = '\0';
+       if (*supfname) {
+               f = fopen (supfname,"r");
+               if (f == NULL)
+                       logquit (1,"Can't open supfile %s",supfname);
+       } else
+               f = stdin;
+       firstC = NULL;
+       lastC = NULL;
+       bogus = FALSE;
+       while (p = fgets (buf,STRINGLENGTH,f)) {
+               q = index (p,'\n');
+               if (q)  *q = '\0';
+               if (index ("#;:",*p))  continue;
+               arg = nxtarg (&p," \t");
+               if (*arg == '\0') {
+                       logerr ("Missing collection name in supfile");
+                       bogus = TRUE;
+                       continue;
+               }
+               if (cwant) {
+                       register TREE *t;
+                       if ((t = Tsearch (collT,arg)) == NULL)
+                               continue;
+                       t->Tcount++;
+               }
+               c = (COLLECTION *) malloc (sizeof(COLLECTION));
+               if (firstC == NULL)  firstC = c;
+               if (lastC != NULL) lastC->Cnext = c;
+               lastC = c;
+               if (parsecoll(c,arg,p) < 0) {
+                       bogus = TRUE;
+                       continue;
+               }
+               c->Cflags |= oflags;
+               c->Cflags &= ~aflags;
+               if (t = Tsearch (collT,c->Cname)) {
+                       c->Cflags |= t->Toflags;
+                       c->Cflags &= ~t->Taflags;
+               }
+               if ((c->Cflags&CFMAIL) && c->Cnotify == NULL) {
+                       if (*username == '\0')
+                               logerr ("User unknown, notification disabled");
+                       else
+                               c->Cnotify = salloc (username);
+               }
+               if (c->Cbase == NULL) {
+                       (void) sprintf (buf,FILEBASEDEFAULT,c->Cname);
+                       c->Cbase = salloc (buf);
+               }
+       }
+       if (bogus)  logquit (1,"Aborted due to supfile errors");
+       if (f != stdin)  (void) fclose (f);
+       if (cwant)  (void) Tprocess (collT,checkcoll);
+       Tfree (&collT);
+       if (firstC == NULL)  logquit (1,"No collections to upgrade");
+       timenow = time ((long *)NULL);
+       if (*supfname == '\0')
+               p = "standard input";
+       else if (sysflag)
+               p = "system software";
+       else
+               (void) sprintf (p = buf,"file %s",supfname);
+       loginfo ("SUP %d.%d (%s) for %s at %s",PROTOVERSION,PGMVERSION,
+               scmversion,p,fmttime (timenow));
+       return (salloc (supfname));
+}
+
+checkcoll (t)
+register TREE *t;
+{
+       if (!t->Twant)  return (SCMOK);
+       if (t->Tcount == 0)
+               logerr ("Collection %s not found",t->Tname);
+       if (t->Tcount > 1)
+               logerr ("Collection %s found more than once",t->Tname);
+       return (SCMOK);
+}
diff --git a/usr.bin/sup/src/supcmeat.c b/usr.bin/sup/src/supcmeat.c
new file mode 100644 (file)
index 0000000..daf07be
--- /dev/null
@@ -0,0 +1,1468 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * sup "meat" routines
+ **********************************************************************
+ * HISTORY
+ *
+ * 7-July-93  Nate Williams at Montana State University
+ *     Modified SUP to use gzip based compression when sending files
+ *     across the network to save BandWidth
+ *
+ * $Log: supcmeat.c,v $
+ * Revision 1.1  1995/12/16 11:46:56  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.6  1995/10/29 23:54:47  christos
+ * - runio fails when result != 0 not only < 0
+ * - print vis-encoded file in the scanner.
+ *
+ * Revision 1.5  1995/06/24 16:21:48  christos
+ * - Don't use system(3) to fork processes. It is a big security hole.
+ * - Encode the filenames in the scan files using strvis(3), so filenames
+ *   that contain newlines or other weird characters don't break the scanner.
+ *
+ * Revision 1.4  1995/06/03 21:21:56  christos
+ * Changes to write ascii timestamps in the when files.
+ * Looked into making it 64 bit clean, but it is hopeless.
+ * Added little program to convert from the old timestamp files
+ * into the new ones.
+ *
+ * Revision 1.3  1993/08/04 17:46:18  brezak
+ * Changes from nate for gzip'ed sup
+ *
+ * Revision 1.2  1993/05/24  18:57:50  brezak
+ * Use /var/tmp for NetBSD
+ *
+ * Revision 1.1.1.1  1993/05/21  14:52:18  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.16  92/09/09  22:04:51  mrt
+ *     Really added bww's recvone changes this time. 
+ *     Added code to support non-crypting version of sup.
+ *     [92/09/01            mrt]
+ * 
+ * Revision 1.15  92/08/11  12:07:09  mrt
+ *     Added support to add release to FILEWHEN name.
+ *     Updated variable arguemnt list usage - bww
+ *     Updated recvone() to take a va_list - bww
+ *     Changed conditional for rpausing code from CMUCS to MACH
+ *     [92/07/24            mrt]
+ * 
+ * Revision 1.14  92/02/08  18:24:12  mja
+ *     Only apply "keep" mode when local file is strictly newer
+ *     otherwise allow update as before if necessary.
+ *     [92/02/08  18:09:00  mja]
+ * 
+ *     Added support for -k (keep) option to needone().  Rewrote and
+ *     commented other parts of needone().
+ *     [92/01/17            vdelvecc]
+ * 
+ * Revision 1.13  91/05/16  14:49:41  ern
+ *     Add timestap to fileserver.
+ *     Drop day of the week from 5 messages.
+ *     [91/05/16  14:47:53  ern]
+ * 
+ * Revision 1.12  89/08/23  14:55:44  gm0w
+ *     Changed msgf routines to msg routines.
+ *     [89/08/23            gm0w]
+ * 
+ * Revision 1.11  89/08/03  19:49:10  mja
+ *     Updated to use v*printf() in place of _doprnt().
+ *     [89/04/19            mja]
+ * 
+ * Revision 1.10  89/06/18  14:41:27  gm0w
+ *     Fixed up some notify messages of errors to use "SUP:" prefix.
+ *     [89/06/18            gm0w]
+ * 
+ * Revision 1.9  89/06/10  15:12:17  gm0w
+ *     Changed to always use rename to install targets.  This breaks hard
+ *     links and recreates those known to sup, other links will be orphaned.
+ *     [89/06/10            gm0w]
+ * 
+ * Revision 1.8  89/05/24  15:04:23  gm0w
+ *     Added code to check for EINVAL from FSPARAM ioctl for disk
+ *     space check failures when the ioctl is not implemented.
+ *     [89/05/24            gm0w]
+ * 
+ * Revision 1.7  89/01/16  18:22:28  gm0w
+ *     Changed needone() to check that mode of files match before
+ *     setting update if times also match.
+ *     [89/01/16            gm0w]
+ * 
+ * 10-Feb-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added timeout to backoff.
+ *
+ * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added crosspatch support.
+ *
+ * 09-Sep-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to be less verbose when updating files that have
+ *     already been successfully upgraded.
+ *
+ * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code for "release" support.
+ *
+ * 26-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Converted to end connection with more information.
+ *     Added done routine.  Modified goaway routine to free old
+ *     goawayreason.
+ *
+ * 26-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Use computeBackoff from scm instead of doing it ourselves.
+ *
+ * 25-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Split off from sup.c and reindented goaway calls.
+ *
+ **********************************************************************
+ */
+
+#include "supcdefs.h"
+#include <sys/wait.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+TREE *lastT;                           /* last filenames in collection */
+jmp_buf sjbuf;                         /* jump location for network errors */
+int dontjump;                          /* flag to void sjbuf */
+int cancompress=FALSE;                 /* Can we do compression? */
+int docompress=FALSE;                  /* Do we do compression? */
+
+extern COLLECTION *thisC;              /* collection list pointer */
+extern int rpauseflag;                 /* don't disable resource pausing */
+extern int portdebug;                  /* network debugging ports */
+
+#if __STDC__
+int done(int,char *,...);
+int goaway(char *,...);
+#endif
+
+/*************************************************
+ ***    U P G R A D E   C O L L E C T I O N    ***
+ *************************************************/
+
+/* The next two routines define the fsm to support multiple fileservers
+ * per collection.
+ */
+getonehost (t,state)
+register TREE *t;
+int *state;
+{
+       if (t->Tflags != *state)
+               return (SCMOK);
+       if (*state != 0 && t->Tmode == SCMEOF) {
+               t->Tflags = 0;
+               return (SCMOK);
+       }
+       if (*state == 2)
+               t->Tflags--;
+       else
+               t->Tflags++;
+       thisC->Chost = t;
+       return (SCMEOF);
+}
+
+TREE *getcollhost (tout,backoff,state,nhostsp)
+int *tout,*backoff,*state,*nhostsp;
+{
+       static int laststate = 0;
+       static int nhosts = 0;
+
+       if (*state != laststate) {
+               *nhostsp = nhosts;
+               laststate = *state;
+               nhosts = 0;
+       }
+       if (Tprocess (thisC->Chtree,getonehost,*state) == SCMEOF) {
+               if (*state != 0 && nhosts == 0 && !dobackoff (tout,backoff))
+                       return (NULL);
+               nhosts++;
+               return (thisC->Chost);
+       }
+       if (nhosts == 0)
+               return (NULL);
+       if (*state == 2)
+               (*state)--;
+       else
+               (*state)++;
+       return (getcollhost (tout,backoff,state,nhostsp));
+}
+
+/*  Upgrade a collection from the file server on the appropriate
+ *  host machine.
+ */
+
+getcoll ()
+{
+       register TREE *t;
+       register int x;
+       int tout,backoff,state,nhosts;
+
+       collname = thisC->Cname;
+       tout = thisC->Ctimeout;
+       lastT = NULL;
+       backoff = 2;
+       state = 0;
+       nhosts = 0;
+       for (;;) {
+               t = getcollhost (&tout,&backoff,&state,&nhosts);
+               if (t == NULL) {
+                       finishup (SCMEOF);
+                       notify ((char *)NULL);
+                       return;
+               }
+               t->Tmode = SCMEOF;
+               dontjump = FALSE;
+               if (!setjmp (sjbuf) && !signon (t,nhosts,&tout) && !setup (t))
+                       break;
+               (void) requestend ();
+       }
+       dontjump = FALSE;
+       if (setjmp (sjbuf))
+               x = SCMERR;
+       else {
+               login ();
+               listfiles ();
+               recvfiles ();
+               x = SCMOK;
+       }
+       if (thisC->Clockfd >= 0) {
+               (void) close (thisC->Clockfd);
+               thisC->Clockfd = -1;
+       }
+       finishup (x);
+       notify ((char *)NULL);
+}
+
+/***  Sign on to file server ***/
+
+int signon (t,nhosts,tout)
+register TREE *t;
+int nhosts;
+int *tout;
+{
+       register int x;
+       int timeout;
+       long tloc;
+
+       if ((thisC->Cflags&CFLOCAL) == 0 && thishost (thisC->Chost->Tname)) {
+               vnotify ("SUP: Skipping local collection %s\n",collname);
+               t->Tmode = SCMEOF;
+               return (TRUE);
+       }
+       if (nhosts == 1)
+               timeout = *tout;
+       else
+               timeout = 0;
+       x = request (portdebug?DEBUGFPORT:FILEPORT,
+                       thisC->Chost->Tname,&timeout);
+       if (nhosts == 1)
+               *tout = timeout;
+       if (x != SCMOK) {
+               if (nhosts) {
+                       notify ("SUP: Can't connect to host %s\n",
+                               thisC->Chost->Tname);
+                       t->Tmode = SCMEOF;
+               } else
+                       t->Tmode = SCMOK;
+               return (TRUE);
+       }
+       xpatch = FALSE;
+       x = msgsignon ();       /* signon to fileserver */
+       if (x != SCMOK)
+               goaway ("Error sending signon request to fileserver");
+       x = msgsignonack ();    /* receive signon ack from fileserver */
+       if (x != SCMOK)
+               goaway ("Error reading signon reply from fileserver");
+       tloc = time ((long *)NULL);
+       vnotify ("SUP Fileserver %d.%d (%s) %d on %s at %.8s\n",
+               protver,pgmver,scmver,fspid,remotehost(),ctime (&tloc) + 11);
+       free (scmver);
+       scmver = NULL;
+       if (protver < 4) {
+               dontjump = TRUE;
+               goaway ("Fileserver sup protocol version is obsolete.");
+               notify ("SUP: This version of sup can only communicate with a fileserver using at least\n");
+               notify ("SUP: version 4 of the sup network protocol.  You should either run a newer\n");
+               notify ("SUP: version of the sup fileserver or find an older version of sup.\n");
+               t->Tmode = SCMEOF;
+               return (TRUE);
+       }
+       /* If protocol is > 7 then try compression */
+       if (protver > 7) {
+               cancompress = TRUE;
+       }
+       return (FALSE);
+}
+
+/***  Tell file server what to connect to ***/
+
+setup (t)
+register TREE *t;
+{
+       char relsufix[STRINGLENGTH];
+       register int f,x;
+       struct stat sbuf;
+
+       if (chdir (thisC->Cbase) < 0)
+               goaway ("Can't change to base directory %s",thisC->Cbase);
+       if (stat ("sup",&sbuf) < 0) {
+               (void) mkdir ("sup",0755);
+               if (stat("sup",&sbuf) < 0)
+                       goaway ("Can't create directory %s/sup",thisC->Cbase);
+               vnotify ("SUP Created directory %s/sup\n",thisC->Cbase);
+       }
+       if (thisC->Cprefix && chdir (thisC->Cprefix) < 0)
+               goaway ("Can't change to %s from base directory %s",
+                       thisC->Cprefix,thisC->Cbase);
+       if (stat (".",&sbuf) < 0)
+               goaway ("Can't stat %s directory %s",
+                       thisC->Cprefix?"prefix":"base",
+                       thisC->Cprefix?thisC->Cprefix:thisC->Cbase);
+       if (thisC->Cprefix)  (void) chdir (thisC->Cbase);
+       /* read time of last upgrade from when file */
+
+       if ((thisC->Cflags&CFURELSUF) && thisC->Crelease)
+               (void) sprintf (relsufix,".%s",thisC->Crelease);
+       else
+               relsufix[0] = '\0';
+       lasttime = getwhen(collname,relsufix);
+       /* setup for msgsetup */
+       basedir = thisC->Chbase;
+       basedev = sbuf.st_dev;
+       baseino = sbuf.st_ino;
+       listonly = (thisC->Cflags&CFLIST);
+       newonly = ((thisC->Cflags&(CFALL|CFDELETE|CFOLD)) == 0);
+       release = thisC->Crelease;
+       x = msgsetup ();
+       if (x != SCMOK)
+               goaway ("Error sending setup request to file server");
+       x = msgsetupack ();
+       if (x != SCMOK)
+               goaway ("Error reading setup reply from file server");
+       if (setupack == FSETUPOK) {
+               /* Test encryption */
+               if (netcrypt (thisC->Ccrypt) != SCMOK)
+                       goaway ("Running non-crypting sup");
+               crypttest = CRYPTTEST;
+               x = msgcrypt ();
+               if (x != SCMOK)
+                       goaway ("Error sending encryption test request");
+               x = msgcryptok ();
+               if (x == SCMEOF)
+                       goaway ("Data encryption test failed");
+               if (x != SCMOK)
+                       goaway ("Error reading encryption test reply");
+               return (FALSE);
+       }
+       switch (setupack) {
+       case FSETUPSAME:
+               notify ("SUP: Attempt to upgrade from same host to same directory\n");
+               done (FDONESRVERROR,"Overwrite error");
+       case FSETUPHOST:
+               notify ("SUP: This host has no permission to access %s\n",
+                       collname);
+               done (FDONESRVERROR,"Permission denied");
+       case FSETUPOLD:
+               notify ("SUP: This version of SUP is too old for the fileserver\n");
+               done (FDONESRVERROR,"Obsolete client");
+       case FSETUPRELEASE:
+               notify ("SUP: Invalid release %s for collection %s\n",
+                       release == NULL ? DEFRELEASE : release,collname);
+               done (FDONESRVERROR,"Invalid release");
+       case FSETUPBUSY:
+               vnotify ("SUP Fileserver is currently busy\n");
+               t->Tmode = SCMOK;
+               doneack = FDONESRVERROR;
+               donereason = "Fileserver is busy";
+               (void) netcrypt ((char *)NULL);
+               (void) msgdone ();
+               return (TRUE);
+       default:
+               goaway ("Unrecognized file server setup status %d",setupack);
+       }
+       /* NOTREACHED */
+}
+
+/***  Tell file server what account to use ***/
+
+int login ()
+{
+       char buf[STRINGLENGTH];
+       register int f,x;
+
+       /* lock collection if desired */
+       (void) sprintf (buf,FILELOCK,collname);
+       f = open (buf,O_RDONLY,0);
+       if (f >= 0) {
+               if (flock (f,(LOCK_EX|LOCK_NB)) < 0) {
+                       if (errno != EWOULDBLOCK)
+                               goaway ("Can't lock collection %s",collname);
+                       if (flock (f,(LOCK_SH|LOCK_NB)) < 0) {
+                               (void) close (f);
+                               if (errno == EWOULDBLOCK)
+                                       goaway ("Collection %s is locked by another sup",collname);
+                               goaway ("Can't lock collection %s",collname);
+                       }
+                       vnotify ("SUP Waiting for exclusive access lock\n");
+                       if (flock (f,LOCK_EX) < 0) {
+                               (void) close (f);
+                               goaway ("Can't lock collection %s",collname);
+                       }
+               }
+               thisC->Clockfd = f;
+               vnotify ("SUP Locked collection %s for exclusive access\n",collname);
+       }
+       logcrypt = (char *) NULL;
+       loguser = thisC->Clogin;
+       logpswd = thisC->Cpswd;
+
+#ifndef        CRYPTING  /* Define CRYPTING for backwards compatibility with old supfileservers */
+       if (thisC->Clogin != (char *) NULL) /* othewise we only encrypt if there is a login id */
+#endif /* CRYPTING */
+       {
+               logcrypt = CRYPTTEST;
+               (void) netcrypt (PSWDCRYPT);    /* encrypt password data */
+       }
+       x = msglogin ();
+#ifndef CRYPTING
+       if (thisC->Clogin != (char *) NULL) 
+#endif
+               (void) netcrypt ((char *)NULL); /* turn off encryption */
+       if (x != SCMOK)
+               goaway ("Error sending login request to file server");
+       x = msglogack ();
+       if (x != SCMOK)
+               goaway ("Error reading login reply from file server");
+       if (logack == FLOGNG) {
+               notify ("SUP: %s\n",logerror);
+               free (logerror);
+               logerror = NULL;
+               notify ("SUP: Improper login to %s account",
+                       thisC->Clogin ? thisC->Clogin : "default");
+               done (FDONESRVERROR,"Improper login");
+       }
+       if (netcrypt (thisC->Ccrypt) != SCMOK)  /* restore encryption */
+               goaway("Running non-crypting sup");
+}
+
+/*
+ *  send list of files that we are not interested in.  receive list of
+ *  files that are on the repository that could be upgraded.  Find the
+ *  ones that we need.  Receive the list of files that the server could
+ *  not access.  Delete any files that have been upgraded in the past
+ *  which are no longer on the repository.
+ */
+
+int listfiles ()
+{
+       int needone(), denyone(), deleteone();
+       char buf[STRINGLENGTH];
+       char relsufix[STRINGLENGTH];
+       register char *p,*q;
+       register FILE *f;
+       register int x;
+
+
+       if ((thisC->Cflags&CFURELSUF) && release)
+               (void) sprintf (relsufix,".%s",release);
+       else
+               relsufix[0] = '\0';
+       (void) sprintf (buf,FILELAST,collname,relsufix);
+       f = fopen (buf,"r");
+       if (f) {
+               while (p = fgets (buf,STRINGLENGTH,f)) {
+                       if (q = index (p,'\n'))  *q = '\0';
+                       if (index ("#;:",*p))  continue;
+                       (void) Tinsert (&lastT,p,FALSE);
+               }
+               (void) fclose (f);
+       }
+       refuseT = NULL;
+       (void) sprintf (buf,FILEREFUSE,collname);
+       f = fopen (buf,"r");
+       if (f) {
+               while (p = fgets (buf,STRINGLENGTH,f)) {
+                       if (q = index (p,'\n'))  *q = '\0';
+                       if (index ("#;:",*p))  continue;
+                       (void) Tinsert (&refuseT,p,FALSE);
+               }
+               (void) fclose (f);
+       }
+       vnotify ("SUP Requesting changes since %s",ctime (&lasttime) + 4);
+       x = msgrefuse ();
+       if (x != SCMOK)
+               goaway ("Error sending refuse list to file server");
+       listT = NULL;
+       x = msglist ();
+       if (x != SCMOK)
+               goaway ("Error reading file list from file server");
+       if (thisC->Cprefix)  (void) chdir (thisC->Cprefix);
+       needT = NULL;
+       (void) Tprocess (listT,needone);
+       Tfree (&listT);
+       x = msgneed ();
+       if (x != SCMOK)
+               goaway ("Error sending needed files list to file server");
+       Tfree (&needT);
+       denyT = NULL;
+       x = msgdeny ();
+       if (x != SCMOK)
+               goaway ("Error reading denied files list from file server");
+       if (thisC->Cflags&CFVERBOSE)
+               (void) Tprocess (denyT,denyone);
+       Tfree (&denyT);
+       if (thisC->Cflags&(CFALL|CFDELETE|CFOLD))
+               (void) Trprocess (lastT,deleteone);
+       Tfree (&refuseT);
+}
+
+needone (t)
+register TREE *t;
+{
+       register TREE *newt;
+       register int exists, fetch;
+       struct stat sbuf;
+
+       newt = Tinsert (&lastT,t->Tname,TRUE);
+       newt->Tflags |= FUPDATE;
+       fetch = TRUE;
+       if ((thisC->Cflags&CFALL) == 0) {
+               if ((t->Tflags&FNEW) == 0 && (thisC->Cflags&CFOLD) == 0)
+                       return (SCMOK);
+               if ((t->Tmode&S_IFMT) == S_IFLNK)
+                       exists = (lstat (t->Tname,&sbuf) == 0);
+               else
+                       exists = (stat (t->Tname,&sbuf) == 0);
+               /* This is moderately complicated:
+                  If the file is the wrong type or doesn't exist, we need to
+                  fetch the whole file.  If the file is a special file, we
+                  rely solely on the server:  if the file changed, we do an
+                  update; otherwise nothing. If the file is a normal file,
+                  we check timestamps.  If we are in "keep" mode, we fetch if
+                  the file on the server is newer, and do nothing otherwise.
+                  Otherwise, we fetch if the timestamp is wrong; if the file
+                  changed on the server but the timestamp is right, we do an
+                  update.  (Update refers to updating stat information, i.e.
+                  timestamp, owner, mode bits, etc.) */
+               if (exists && (sbuf.st_mode&S_IFMT) == (t->Tmode&S_IFMT))
+                       if ((t->Tmode&S_IFMT) != S_IFREG)
+                               if (t->Tflags&FNEW)
+                                       fetch = FALSE;
+                               else return (SCMOK);
+                       else if ((thisC->Cflags&CFKEEP) &&
+                                sbuf.st_mtime > t->Tmtime)
+                               return (SCMOK);
+                       else if (sbuf.st_mtime == t->Tmtime)
+                               if (t->Tflags&FNEW)
+                                       fetch = FALSE;
+                               else return (SCMOK);
+       }
+       /* If we get this far, we're either doing an update or a full fetch. */
+       newt = Tinsert (&needT,t->Tname,TRUE);
+       if (!fetch && (t->Tmode&S_IFMT) == S_IFREG)
+               newt->Tflags |= FUPDATE;
+       return (SCMOK);
+}
+
+denyone (t)
+register TREE *t;
+{
+       vnotify ("SUP: Access denied to %s\n",t->Tname);
+       return (SCMOK);
+}
+
+deleteone (t)
+TREE *t;
+{
+       struct stat sbuf;
+       register int x;
+       register char *name = t->Tname;
+
+       if (t->Tflags&FUPDATE)          /* in current upgrade list */
+               return (SCMOK);
+       if (lstat(name,&sbuf) < 0)      /* doesn't exist */
+               return (SCMOK);
+       /* is it a symbolic link ? */
+       if ((sbuf.st_mode & S_IFMT) == S_IFLNK) {
+               if (Tlookup (refuseT,name)) {
+                       vnotify ("SUP Would not delete symbolic link %s\n",
+                               name);
+                       return (SCMOK);
+               }
+               if (thisC->Cflags&CFLIST) {
+                       vnotify ("SUP Would delete symbolic link %s\n",name);
+                       return (SCMOK);
+               }
+               if ((thisC->Cflags&CFDELETE) == 0) {
+                       notify ("SUP Please delete symbolic link %s\n",name);
+                       t->Tflags |= FUPDATE;
+                       return (SCMOK);
+               }
+               x = unlink (name);
+               if (x < 0) {
+                       notify ("SUP: Unable to delete symbolic link %s\n",
+                               name);
+                       t->Tflags |= FUPDATE;
+                       return (SCMOK);
+               }
+               vnotify ("SUP Deleted symbolic link %s\n",name);
+               return (SCMOK);
+       }
+       /* is it a directory ? */
+       if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
+               if (Tlookup (refuseT,name)) {
+                       vnotify ("SUP Would not delete directory %s\n",name);
+                       return (SCMOK);
+               }
+               if (thisC->Cflags&CFLIST) {
+                       vnotify ("SUP Would delete directory %s\n",name);
+                       return (SCMOK);
+               }
+               if ((thisC->Cflags&CFDELETE) == 0) {
+                       notify ("SUP Please delete directory %s\n",name);
+                       t->Tflags |= FUPDATE;
+                       return (SCMOK);
+               }
+               (void) rmdir (name);
+               if (lstat(name,&sbuf) == 0) {
+                       notify ("SUP: Unable to delete directory %s\n",name);
+                       t->Tflags |= FUPDATE;
+                       return (SCMOK);
+               }
+               vnotify ("SUP Deleted directory %s\n",name);
+               return (SCMOK);
+       }
+       /* it is a file */
+       if (Tlookup (refuseT,name)) {
+               vnotify ("SUP Would not delete file %s\n",name);
+               return (SCMOK);
+       }
+       if (thisC->Cflags&CFLIST) {
+               vnotify ("SUP Would delete file %s\n",name);
+               return (SCMOK);
+       }
+       if ((thisC->Cflags&CFDELETE) == 0) {
+               notify ("SUP Please delete file %s\n",name);
+               t->Tflags |= FUPDATE;
+               return (SCMOK);
+       }
+       x = unlink (name);
+       if (x < 0) {
+               notify ("SUP: Unable to delete file %s\n",name);
+               t->Tflags |= FUPDATE;
+               return (SCMOK);
+       }
+       vnotify ("SUP Deleted file %s\n",name);
+       return (SCMOK);
+}
+
+/***************************************
+ ***    R E C E I V E   F I L E S    ***
+ ***************************************/
+
+/* Note for these routines, return code SCMOK generally means
+ * NETWORK communication is OK; it does not mean that the current
+ * file was correctly received and stored.  If a file gets messed
+ * up, too bad, just print a message and go on to the next one;
+ * but if the network gets messed up, the whole sup program loses
+ * badly and best just stop the program as soon as possible.
+ */
+
+recvfiles ()
+{
+       register int x;
+       int recvone ();
+       int recvmore;
+
+       /* Does the protocol support compression */
+       if (cancompress) {
+               /* Check for compression on sending files */
+               docompress = (thisC->Cflags&CFCOMPRESS);
+               x = msgcompress();
+               if ( x != SCMOK) 
+                       goaway ("Error sending compression check to server");
+               if (docompress)
+                       vnotify("SUP Using compressed file transfer\n");
+       }
+       recvmore = TRUE;
+       upgradeT = NULL;
+       do {
+               x = msgsend ();
+               if (x != SCMOK)
+                       goaway ("Error sending receive file request to file server");
+               (void) Tinsert (&upgradeT,(char *)NULL,FALSE);
+               x = msgrecv (recvone,&recvmore);
+               if (x != SCMOK)
+                       goaway ("Error receiving file from file server");
+               Tfree (&upgradeT);
+       } while (recvmore);
+}
+
+/* prepare the target, if necessary */
+prepare (name,mode,newp,statp)
+char *name;
+int mode,*newp;
+struct stat *statp;
+{
+       register char *type;
+
+       if (mode == S_IFLNK)
+               *newp = (lstat (name,statp) < 0);
+       else
+               *newp = (stat (name,statp) < 0);
+       if (*newp) {
+               if (thisC->Cflags&CFLIST)
+                       return (FALSE);
+               if (establishdir (name))
+                       return (TRUE);
+               return (FALSE);
+       }
+       if (mode == (statp->st_mode&S_IFMT))
+               return (FALSE);
+       *newp = TRUE;
+       switch (statp->st_mode&S_IFMT) {
+       case S_IFDIR:
+               type = "directory";
+               break;
+       case S_IFLNK:
+               type = "symbolic link";
+               break;
+       case S_IFREG:
+               type = "regular file";
+               break;
+       default:
+               type = "unknown file";
+               break;
+       }
+       if (thisC->Cflags&CFLIST) {
+               vnotify ("SUP Would remove %s %s\n",type,name);
+               return (FALSE);
+       }
+       if ((statp->st_mode&S_IFMT) == S_IFDIR) {
+               if (rmdir (name) < 0)
+                       runp ("rm","rm","-rf",name,0);
+       } else
+               (void) unlink (name);
+       if (stat (name,statp) < 0) {
+               vnotify ("SUP Removed %s %s\n",type,name);
+               return (FALSE);
+       }
+       notify ("SUP: Couldn't remove %s %s\n",type,name);
+       return (TRUE);
+}
+
+recvone (t,ap)
+register TREE *t;
+va_list ap;
+{
+       register int x;
+       int new;
+       struct stat sbuf;
+       int linkone (),execone ();
+       int *recvmore = va_arg(ap,int *);
+
+       /* check for end of file list */
+       if (t == NULL) {
+               *recvmore = FALSE;
+               return (SCMOK);
+       }
+       /* check for failed access at fileserver */
+       if (t->Tmode == 0) {
+               notify ("SUP: File server unable to transfer file %s\n",
+                       t->Tname);
+               thisC->Cnogood = TRUE;
+               return (SCMOK);
+       }
+       if (prepare (t->Tname,t->Tmode&S_IFMT,&new,&sbuf)) {
+               notify ("SUP: Can't prepare path for %s\n",t->Tname);
+               if ((t->Tmode&S_IFMT) == S_IFREG) {
+                       x = readskip ();        /* skip over file */
+                       if (x != SCMOK)
+                               goaway ("Can't skip file transfer");
+               }
+               thisC->Cnogood = TRUE;
+               return (SCMOK);
+       }
+       /* make file mode specific changes */
+       switch (t->Tmode&S_IFMT) {
+       case S_IFDIR:
+               x = recvdir (t,new,&sbuf);
+               break;
+       case S_IFLNK:
+               x = recvsym (t,new,&sbuf);
+               break;
+       case S_IFREG:
+               x = recvreg (t,new,&sbuf);
+               break;
+       default:
+               goaway ("Unknown file type %o\n",t->Tmode&S_IFMT);
+       }
+       if (x) {
+               thisC->Cnogood = TRUE;
+               return (SCMOK);
+       }
+       if ((t->Tmode&S_IFMT) == S_IFREG)
+               (void) Tprocess (t->Tlink,linkone,t->Tname);
+       (void) Tprocess (t->Texec,execone);
+       return (SCMOK);
+}
+
+int recvdir (t,new,statp)              /* receive directory from network */
+register TREE *t;
+register int new;
+register struct stat *statp;
+{
+       struct timeval tbuf[2];
+
+       if (new) {
+               if (thisC->Cflags&CFLIST) {
+                       vnotify ("SUP Would create directory %s\n",t->Tname);
+                       return (FALSE);
+               }
+               (void) mkdir (t->Tname,0755);
+               if (stat (t->Tname,statp) < 0) {
+                       notify ("SUP: Can't create directory %s\n",t->Tname);
+                       return (TRUE);
+               }
+       }
+       if ((t->Tflags&FNOACCT) == 0) {
+               /* convert user and group names to local ids */
+               ugconvert (t->Tuser,t->Tgroup,&t->Tuid,&t->Tgid,&t->Tmode);
+       }
+       if (!new && (t->Tflags&FNEW) == 0 && statp->st_mtime == t->Tmtime) {
+               if (t->Tflags&FNOACCT)
+                       return (FALSE);
+               if (statp->st_uid == t->Tuid && statp->st_gid == t->Tgid)
+                       return (FALSE);
+       }
+       if (thisC->Cflags&CFLIST) {
+               vnotify ("SUP Would update directory %s\n",t->Tname);
+               return (FALSE);
+       }
+       if ((t->Tflags&FNOACCT) == 0) {
+               (void) chown (t->Tname,t->Tuid,t->Tgid);
+               (void) chmod (t->Tname,t->Tmode&S_IMODE);
+       }
+       tbuf[0].tv_sec = time((long *)NULL);  tbuf[0].tv_usec = 0;
+       tbuf[1].tv_sec = t->Tmtime;  tbuf[1].tv_usec = 0;
+       (void) utimes (t->Tname,tbuf);
+       vnotify ("SUP %s directory %s\n",new?"Created":"Updated",t->Tname);
+       return (FALSE);
+}
+
+int recvsym (t,new,statp)                      /* receive symbolic link */
+register TREE *t;
+register int new;
+register struct stat *statp;
+{
+       char buf[STRINGLENGTH];
+       int n;
+       register char *linkname;
+
+       if (t->Tlink == NULL || t->Tlink->Tname == NULL) {
+               notify ("SUP: Missing linkname for symbolic link %s\n",
+                       t->Tname);
+               return (TRUE);
+       }
+       linkname = t->Tlink->Tname;
+       if (!new && (t->Tflags&FNEW) == 0 &&
+           (n = readlink (t->Tname,buf,sizeof(buf))) >= 0 &&
+           (n == strlen (linkname)) && (strncmp (linkname,buf,n) == 0))
+               return (FALSE);
+       if (thisC->Cflags&CFLIST) {
+               vnotify ("SUP Would %s symbolic link %s to %s\n",
+                       new?"create":"update",t->Tname,linkname);
+               return (FALSE);
+       }
+       if (!new)
+               (void) unlink (t->Tname);
+       if (symlink (linkname,t->Tname) < 0 || lstat(t->Tname,statp) < 0) {
+               notify ("SUP: Unable to create symbolic link %s\n",t->Tname);
+               return (TRUE);
+       }
+       vnotify ("SUP Created symbolic link %s to %s\n",t->Tname,linkname);
+       return (FALSE);
+}
+
+int recvreg (t,new,statp)                      /* receive file from network */
+register TREE *t;
+register int new;
+register struct stat *statp;
+{
+       register FILE *fin,*fout;
+       char dirpart[STRINGLENGTH],filepart[STRINGLENGTH];
+       char filename[STRINGLENGTH],buf[STRINGLENGTH];
+       struct timeval tbuf[2];
+       register int x;
+       register char *p;
+
+       if (t->Tflags&FUPDATE) {
+               if ((t->Tflags&FNOACCT) == 0) {
+                       /* convert user and group names to local ids */
+                       ugconvert (t->Tuser,t->Tgroup,&t->Tuid,&t->Tgid,
+                               &t->Tmode);
+               }
+               if (!new && (t->Tflags&FNEW) == 0 &&
+                   statp->st_mtime == t->Tmtime) {
+                       if (t->Tflags&FNOACCT)
+                               return (FALSE);
+                       if (statp->st_uid == t->Tuid &&
+                           statp->st_gid == t->Tgid)
+                               return (FALSE);
+               }
+               if (thisC->Cflags&CFLIST) {
+                       vnotify ("SUP Would update file %s\n",t->Tname);
+                       return (FALSE);
+               }
+               vnotify ("SUP Updating file %s\n",t->Tname);
+               if ((t->Tflags&FNOACCT) == 0) {
+                       (void) chown (t->Tname,t->Tuid,t->Tgid);
+                       (void) chmod (t->Tname,t->Tmode&S_IMODE);
+               }
+               tbuf[0].tv_sec = time((long *)NULL);  tbuf[0].tv_usec = 0;
+               tbuf[1].tv_sec = t->Tmtime;  tbuf[1].tv_usec = 0;
+               (void) utimes (t->Tname,tbuf);
+               return (FALSE);
+       }
+       if (thisC->Cflags&CFLIST) {
+               if (new)
+                       p = "create";
+               else if (statp->st_mtime < t->Tmtime)
+                       p = "receive new";
+               else if (statp->st_mtime > t->Tmtime)
+                       p = "receive old";
+               else
+                       p = "receive";
+               vnotify ("SUP Would %s file %s\n",p,t->Tname);
+               return (FALSE);
+       }
+       vnotify ("SUP Receiving file %s\n",t->Tname);
+       if (!new && (t->Tmode&S_IFMT) == S_IFREG &&
+           (t->Tflags&FBACKUP) && (thisC->Cflags&CFBACKUP)) {
+               fin = fopen (t->Tname,"r");     /* create backup */
+               if (fin == NULL) {
+                       x = readskip ();        /* skip over file */
+                       if (x != SCMOK)
+                               goaway ("Can't skip file transfer");
+                       notify ("SUP: Can't open %s to create backup\n",
+                               t->Tname);
+                       return (TRUE);          /* mark upgrade as nogood */
+               }
+               path (t->Tname,dirpart,filepart);
+               (void) sprintf (filename,FILEBACKUP,dirpart,filepart);
+               fout = fopen (filename,"w");
+               if (fout == NULL) {
+                       (void) sprintf (buf,FILEBKDIR,dirpart);
+                       (void) mkdir (buf,0755);
+                       fout = fopen (filename,"w");
+               }
+               if (fout == NULL) {
+                       x = readskip ();        /* skip over file */
+                       if (x != SCMOK)
+                               goaway ("Can't skip file transfer");
+                       notify ("SUP: Can't create %s for backup\n",filename);
+                       (void) fclose (fin);
+                       return (TRUE);
+               }
+               ffilecopy (fin,fout);
+               (void) fclose (fin);
+               (void) fclose (fout);
+               vnotify ("SUP Backup of %s created\n", t->Tname);
+       }
+       x = copyfile (t->Tname,(char *)NULL);
+       if (x)
+               return (TRUE);
+       if ((t->Tflags&FNOACCT) == 0) {
+               /* convert user and group names to local ids */
+               ugconvert (t->Tuser,t->Tgroup,&t->Tuid,&t->Tgid,&t->Tmode);
+               (void) chown (t->Tname,t->Tuid,t->Tgid);
+               (void) chmod (t->Tname,t->Tmode&S_IMODE);
+       }
+       tbuf[0].tv_sec = time((long *)NULL);  tbuf[0].tv_usec = 0;
+       tbuf[1].tv_sec = t->Tmtime;  tbuf[1].tv_usec = 0;
+       (void) utimes (t->Tname,tbuf);
+       return (FALSE);
+}
+
+linkone (t,fname)                      /* link to file already received */
+register TREE *t;
+register char **fname;
+{
+       struct stat fbuf,sbuf;
+       register char *name = t->Tname;
+       int new,x;
+       char *type;
+
+       if (stat(*fname,&fbuf) < 0) {   /* source file */
+               if (thisC->Cflags&CFLIST) {
+                       vnotify ("SUP Would link %s to %s\n",name,*fname);
+                       return (SCMOK);
+               }
+               notify ("SUP: Can't link %s to missing file %s\n",name,*fname);
+               thisC->Cnogood = TRUE;
+               return (SCMOK);
+       }
+       if (prepare (name,S_IFREG,&new,&sbuf)) {
+               notify ("SUP: Can't prepare path for link %s\n",name);
+               thisC->Cnogood = TRUE;
+               return (SCMOK);
+       }
+       if (!new && (t->Tflags&FNEW) == 0 &&
+           fbuf.st_dev == sbuf.st_dev && fbuf.st_ino == sbuf.st_ino)
+               return (SCMOK);
+       if (thisC->Cflags&CFLIST) {
+               vnotify ("SUP Would link %s to %s\n",name,*fname);
+               return (SCMOK);
+       }
+       (void) unlink (name);
+       type = "";
+       if ((x = link (*fname,name)) < 0) {
+               type = "symbolic ";
+               x = symlink (*fname,name);
+       }
+       if (x < 0 || lstat(name,&sbuf) < 0) {
+               notify ("SUP: Unable to create %slink %s\n",type,name);
+               return (TRUE);
+       }
+       vnotify ("SUP Created %slink %s to %s\n",type,name,*fname);
+       return (SCMOK);
+}
+
+execone (t)                    /* execute command for file */
+register TREE *t;
+{
+       union wait w;
+
+       if (thisC->Cflags&CFLIST) {
+               vnotify ("SUP Would execute %s\n",t->Tname);
+               return (SCMOK);
+       }
+       if ((thisC->Cflags&CFEXECUTE) == 0) {
+               notify ("SUP Please execute %s\n",t->Tname);
+               return (SCMOK);
+       }
+       vnotify ("SUP Executing %s\n",t->Tname);
+
+       w.w_status = system (t->Tname);
+       if (WIFEXITED(w) && w.w_retcode != 0) {
+               notify ("SUP: Execute command returned failure status %#o\n",
+                       w.w_retcode);
+               thisC->Cnogood = TRUE;
+       } else if (WIFSIGNALED(w)) {
+               notify ("SUP: Execute command killed by signal %d\n",
+                       w.w_termsig);
+               thisC->Cnogood = TRUE;
+       } else if (WIFSTOPPED(w)) {
+               notify ("SUP: Execute command stopped by signal %d\n",
+                       w.w_stopsig);
+               thisC->Cnogood = TRUE;
+       }
+       return (SCMOK);
+}
+
+int copyfile (to,from)
+char *to;
+char *from;            /* 0 if reading from network */
+{
+       register int fromf,tof,istemp,x;
+       char dpart[STRINGLENGTH],fpart[STRINGLENGTH];
+       char tname[STRINGLENGTH];
+       struct stat sbuf;
+
+       static int thispid = 0;         /* process id # */
+
+       if (from) {                     /* reading file */
+               fromf = open (from,O_RDONLY,0);
+               if (fromf < 0) {
+                       notify ("SUP: Can't open %s to copy to %s: %s\n",
+                               from,to,errmsg (-1));
+                       return (TRUE);
+               }
+       } else                          /* reading network */
+               fromf = -1;
+       istemp = TRUE;                  /* try to create temp file */
+       lockout (TRUE);                 /* block interrupts */
+       if (thispid == 0)  thispid = getpid ();
+       /* Now try hard to find a temp file name.  Try VERY hard. */
+       for (;;) {
+       /* try destination directory */
+               path (to,dpart,fpart);
+               (void) sprintf (tname,"%s/#%d.sup",dpart,thispid);
+               tof = open (tname,(O_WRONLY|O_CREAT|O_TRUNC),0600);
+               if (tof >= 0)  break;
+       /* try sup directory */
+               if (thisC->Cprefix)  (void) chdir (thisC->Cbase);
+               (void) sprintf (tname,"sup/#%d.sup",thispid);
+               tof = open (tname,(O_WRONLY|O_CREAT|O_TRUNC),0600);
+               if (tof >= 0) {
+                       if (thisC->Cprefix)  (void) chdir (thisC->Cprefix);
+                       break;
+               }
+       /* try base directory */
+               (void) sprintf (tname,"#%d.sup",thispid);
+               tof = open (tname,(O_WRONLY|O_CREAT|O_TRUNC),0600);
+               if (thisC->Cprefix)  (void) chdir (thisC->Cprefix);
+               if (tof >= 0)  break;
+#ifdef VAR_TMP
+       /* try /var/tmp */
+               (void) sprintf (tname,"/var/tmp/#%d.sup",thispid);
+               tof = open (tname,(O_WRONLY|O_CREAT|O_TRUNC),0600);
+               if (tof >= 0)  break;
+#else
+       /* try /usr/tmp */
+               (void) sprintf (tname,"/usr/tmp/#%d.sup",thispid);
+               tof = open (tname,(O_WRONLY|O_CREAT|O_TRUNC),0600);
+               if (tof >= 0)  break;
+#endif
+       /* try /tmp */
+               (void) sprintf (tname,"/tmp/#%d.sup",thispid);
+               tof = open (tname,(O_WRONLY|O_CREAT|O_TRUNC),0600);
+               if (tof >= 0)  break;
+               istemp = FALSE;
+       /* give up: try to create output file */
+               if (!docompress)
+                       tof = open (to,(O_WRONLY|O_CREAT|O_TRUNC),0600);
+               if (tof >= 0)  break;
+       /* no luck */
+               notify ("SUP: Can't create %s or temp file for it\n",to);
+               lockout (FALSE);
+               if (fromf >= 0)
+                       (void) close (fromf);
+               else {
+                       x = readskip ();
+                       if (x != SCMOK)
+                               goaway ("Can't skip file transfer");
+               }
+               return (TRUE);
+       }
+       if (fromf >= 0) {               /* read file */
+               x = filecopy (fromf,tof);
+               (void) close (fromf);
+               (void) close (tof);
+               if (x < 0) {
+                       notify ("SUP: Error in copying %s to %s\n",from,to);
+                       if (istemp)  (void) unlink (tname);
+                       lockout (FALSE);
+                       return (TRUE);
+               }
+       } else {                        /* read network */
+#if    MACH
+               if (!rpauseflag) {
+                       int fsize;
+                       struct fsparam fsp;
+
+                       x = prereadcount (&fsize);
+                       if (x != SCMOK) {
+                               if (istemp)  (void) unlink (tname);
+                               lockout (FALSE);
+                               x = readskip ();
+                               if (x != SCMOK)
+                                       goaway ("Can't skip file transfer");
+                               goaway ("Error in server space check");
+                               logquit (1,"Error in server space check");
+                       }
+                       errno = 0;
+                       if (ioctl (tof,FIOCFSPARAM,(char *)&fsp) < 0 &&
+                           errno != EINVAL) {
+                               if (istemp)  (void) unlink (tname);
+                               lockout (FALSE);
+                               x = readskip ();
+                               if (x != SCMOK)
+                                       goaway ("Can't skip file transfer");
+                               goaway ("Error in disk space check");
+                               logquit (1,"Error in disk space check");
+                       }
+                       if (errno == 0) {
+                               fsize = (fsize + 1023) / 1024;
+                               x = fsp.fsp_size * MAX (fsp.fsp_minfree,1) / 100;
+                               fsp.fsp_free -= x;
+                               if (fsize > MAX (fsp.fsp_free,0)) {
+                                       if (istemp)  (void) unlink (tname);
+                                       lockout (FALSE);
+                                       x = readskip ();
+                                       if (x != SCMOK)
+                                               goaway ("Can't skip file transfer");
+                                       goaway ("No disk space for file %s", to);
+                                       logquit (1,"No disk space for file %s",to);
+                               }
+                       }
+               }
+#endif /* MACH */
+               x = readfile (tof);
+               (void) close (tof);
+               if (x != SCMOK) {
+                       if (istemp)  (void) unlink (tname);
+                       lockout (FALSE);
+                       goaway ("Error in receiving %s\n",to);
+               }
+       }
+       if (!istemp) {                  /* no temp file used */
+               lockout (FALSE);
+               return (FALSE);
+       }
+       /* uncompress it first */
+       if (docompress) {
+               char *av[4];
+               int   ac = 0;
+               av[ac++] = "gzip";
+               av[ac++] = "-d";
+               av[ac++] = NULL;
+               if (runio(av, tname, to, NULL) != 0) {
+                       /* Uncompress it onto the destination */
+                       notify ("SUP: Error in uncompressing file %s\n",
+                               to);
+                       (void) unlink (tname);
+                       /* Just in case */
+                       (void) unlink (to);
+                       lockout (FALSE);
+                       return (TRUE);
+               }
+               (void) unlink (tname);
+               lockout (FALSE);
+               return (FALSE);
+       }
+       /* move to destination */
+       if (rename (tname,to) == 0) {
+               (void) unlink (tname);
+               lockout (FALSE);
+               return (FALSE);
+       }
+       fromf = open (tname,O_RDONLY,0);
+       if (fromf < 0) {
+               notify ("SUP: Error in moving temp file to %s: %s\n",
+                       to,errmsg (-1));
+               (void) unlink (tname);
+               lockout (FALSE);
+               return (TRUE);
+       }
+       tof = open (to,(O_WRONLY|O_CREAT|O_TRUNC),0600);
+       if (tof < 0) {
+               (void) close (fromf);
+               notify ("SUP: Can't create %s from temp file: %s\n",
+                       to,errmsg (-1));
+               (void) unlink (tname);
+               lockout (FALSE);
+               return (TRUE);
+       }
+       x = filecopy (fromf,tof);
+       (void) close (fromf);
+       (void) close (tof);
+       (void) unlink (tname);
+       lockout (FALSE);
+       if (x < 0) {
+               notify ("SUP: Error in storing data in %s\n",to);
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+/***  Finish connection with file server ***/
+
+finishup (x)
+int x;
+{
+       char tname[STRINGLENGTH],fname[STRINGLENGTH];
+       char relsufix[STRINGLENGTH];
+       char collrelname[STRINGLENGTH];
+       long tloc;
+       FILE *finishfile;               /* record of all filenames */
+       int f,finishone();
+
+       if ((thisC->Cflags&CFURELSUF) && release) {
+               (void) sprintf (relsufix,".%s",release);
+               (void) sprintf (collrelname,"%s-%s",collname,release);
+       } else {
+               relsufix[0] = '\0';
+               (void) strcpy (collrelname,collname);
+       }
+       dontjump = TRUE;                /* once here, no more longjmp */
+       (void) netcrypt ((char *)NULL);
+       if (protver < 6) {
+               /* done with server */
+               if (x == SCMOK)
+                       goaway ((char *)NULL);
+               (void) requestend ();
+       }
+       tloc = time ((long *)NULL);
+       if (x != SCMOK) {
+               notify ("SUP: Upgrade of %s aborted at %s",
+                       collrelname,ctime (&tloc) + 4);
+               Tfree (&lastT);
+               if (protver < 6)  return;
+               /* if we've not been blown off, make sure he is! */
+               if (x != SCMEOF)
+                       goaway ("Aborted");
+               (void) requestend ();
+               return;
+       }
+       if (thisC->Cnogood) {
+               notify ("SUP: Upgrade of %s completed with errors at %s",
+                       collrelname,ctime (&tloc) + 4);
+               notify ("SUP: Upgrade time will not be updated\n");
+               Tfree (&lastT);
+               if (protver < 6)  return;
+               done (FDONEUSRERROR,"Completed with errors");
+               (void) requestend ();
+               return;
+       }
+       if (thisC->Cprefix)  (void) chdir (thisC->Cbase);
+       vnotify ("SUP Upgrade of %s completed at %s",
+                collrelname,ctime (&tloc) + 4);
+       if (thisC->Cflags&CFLIST) {
+               Tfree (&lastT);
+               if (protver < 6)  return;
+               done (FDONEDONTLOG,"List only");
+               (void) requestend ();
+               return;
+       }
+       (void) sprintf (fname,FILEWHEN,collname,relsufix);
+       if (establishdir (fname)) {
+               notify ("SUP: Can't create directory for upgrade timestamp\n");
+               Tfree (&lastT);
+               if (protver < 6)  return;
+               done (FDONEUSRERROR,"Couldn't timestamp");
+               (void) requestend ();
+               return;
+       }
+       if (!putwhen(fname, scantime)) {
+               notify ("SUP: Can't record current time in %s: %s\n",
+                       fname,errmsg (-1));
+               Tfree (&lastT);
+               if (protver < 6)  return;
+               done (FDONEUSRERROR,"Couldn't timestamp");
+               (void) requestend ();
+               return;
+       }
+       if (protver >= 6) {
+               /* At this point we have let the server go */
+               /* "I'm sorry, we've had to let you go" */
+               done (FDONESUCCESS,"Success");
+               (void) requestend ();
+       }
+       (void) sprintf (tname,FILELASTTEMP,collname);
+       finishfile = fopen (tname,"w");
+       if (finishfile == NULL) {
+               notify ("SUP: Can't record list of all files in %s\n",tname);
+               Tfree (&lastT);
+               return;
+       }
+       (void) Tprocess (lastT,finishone,finishfile);
+       (void) fclose (finishfile);
+       (void) sprintf (fname,FILELAST,collname,relsufix);
+       if (rename (tname,fname) < 0)
+               notify ("SUP: Can't change %s to %s\n",tname,fname);
+       (void) unlink (tname);
+       Tfree (&lastT);
+}
+
+finishone (t,finishfile)
+TREE *t;
+FILE **finishfile;
+{
+       if ((thisC->Cflags&CFDELETE) == 0 || (t->Tflags&FUPDATE))
+               fprintf (*finishfile,"%s\n",t->Tname);
+       return (SCMOK);
+}
+
+#if __STDC__
+done (int value,char *fmt,...)
+#else
+/*VARARGS*//*ARGSUSED*/
+done (va_alist)
+va_dcl
+#endif
+{
+#if !__STDC__
+       int value;
+       char *fmt;
+#endif
+       char buf[STRINGLENGTH];
+       va_list ap;
+
+       (void) netcrypt ((char *)NULL);
+#if __STDC__
+       va_start(ap,fmt);
+#else
+       va_start(ap);
+       value = va_arg(ap,int);
+       fmt = va_arg(ap,char *);
+#endif
+       if (fmt) 
+               vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+       if (protver < 6) {
+               if (goawayreason)
+                       free (goawayreason);
+               goawayreason = (fmt) ? salloc (buf) : (char *)NULL;
+               (void) msggoaway ();
+       }
+       else {
+               doneack = value;
+               donereason = (fmt) ? buf : (char *)NULL;
+               (void) msgdone ();
+       }
+       if (!dontjump)
+               longjmp (sjbuf,TRUE);
+}
+#if __STDC__
+goaway (char *fmt,...)
+#else
+/*VARARGS*//*ARGSUSED*/
+goaway (va_alist)
+va_dcl
+#endif
+{
+#if !__STDC__
+       register char *fmt;
+#endif
+       char buf[STRINGLENGTH];
+       va_list ap;
+
+       (void) netcrypt ((char *)NULL);
+#if __STDC__
+       va_start(ap,fmt);
+#else
+       va_start(ap);
+       fmt = va_arg(ap,char *);
+#endif
+       if (fmt) {
+               vsnprintf(buf, sizeof(buf), fmt, ap);
+               goawayreason = buf;
+       } else
+               goawayreason = NULL;
+       va_end(ap);
+       (void) msggoaway ();
+       if (fmt)
+               if (thisC)
+                       notify ("SUP: %s\n",buf);
+               else
+                       printf ("SUP: %s\n",buf);
+       if (!dontjump)
+               longjmp (sjbuf,TRUE);
+}
diff --git a/usr.bin/sup/src/supcmisc.c b/usr.bin/sup/src/supcmisc.c
new file mode 100644 (file)
index 0000000..54bade3
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * sup misc. routines, include list processing.
+ **********************************************************************
+ * HISTORY
+ * $Log: supcmisc.c,v $
+ * Revision 1.1  1995/12/16 11:46:57  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.2  1995/06/03 21:21:57  christos
+ * Changes to write ascii timestamps in the when files.
+ * Looked into making it 64 bit clean, but it is hopeless.
+ * Added little program to convert from the old timestamp files
+ * into the new ones.
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:18  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.5  92/08/11  12:07:22  mrt
+ *     Added release to FILEWHEN name.
+ *     Brad's changes: delinted and updated variable arguement usage.
+ *     [92/07/26            mrt]
+ * 
+ * Revision 1.3  89/08/15  15:31:28  bww
+ *     Updated to use v*printf() in place of _doprnt().
+ *     From "[89/04/19            mja]" at CMU.
+ *     [89/08/15            bww]
+ * 
+ * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Fixed bug in ugconvert() which left pw uninitialized.
+ *
+ * 25-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Split off from sup.c and changed goaway to use printf
+ *     instead of notify if thisC is NULL.
+ *
+ **********************************************************************
+ */
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "supcdefs.h"
+
+struct liststruct {            /* uid and gid lists */
+       char *Lname;            /* name */
+       int Lnumber;            /* uid or gid */
+       struct liststruct *Lnext;
+};
+typedef struct liststruct LIST;
+
+#define HASHBITS       4
+#define HASHSIZE       (1<<HASHBITS)
+#define HASHMASK       (HASHSIZE-1)
+#define LISTSIZE       (HASHSIZE*HASHSIZE)
+
+static LIST *uidL[LISTSIZE];           /* uid and gid lists */
+static LIST *gidL[LISTSIZE];
+
+extern COLLECTION *thisC;              /* collection list pointer */
+#if __STDC__
+int notify (char *, ...);
+#endif
+
+/*************************************************
+ ***    P R I N T   U P D A T E   T I M E S    ***
+ *************************************************/
+
+prtime ()
+{
+       char buf[STRINGLENGTH];
+       char relsufix[STRINGLENGTH];
+       long twhen;
+       int f;
+
+       if ((thisC->Cflags&CFURELSUF) && thisC->Crelease)
+               (void) sprintf (relsufix,".%s",thisC->Crelease);
+       else
+               relsufix[0] = '\0';
+       if (chdir (thisC->Cbase) < 0)
+               logerr ("Can't change to base directory %s for collection %s",
+                       thisC->Cbase,thisC->Cname);
+       twhen = getwhen(thisC->Cname,relsufix);
+       (void) strcpy (buf,ctime (&twhen));
+       buf[strlen(buf)-1] = '\0';
+       loginfo ("Last update occurred at %s for collection %s",
+               buf,thisC->Cname);
+}
+
+int establishdir (fname)
+char *fname;
+{
+       char dpart[STRINGLENGTH],fpart[STRINGLENGTH];
+       path (fname,dpart,fpart);
+       return (estabd (fname,dpart));
+}
+
+int estabd (fname,dname)
+char *fname,*dname;
+{
+       char dpart[STRINGLENGTH],fpart[STRINGLENGTH];
+       struct stat sbuf;
+       register int x;
+
+       if (stat (dname,&sbuf) >= 0)  return (FALSE); /* exists */
+       path (dname,dpart,fpart);
+       if (strcmp (fpart,".") == 0) {          /* dname is / or . */
+               notify ("SUP: Can't create directory %s for %s\n",dname,fname);
+               return (TRUE);
+       }
+       x = estabd (fname,dpart);
+       if (x)  return (TRUE);
+       (void) mkdir (dname,0755);
+       if (stat (dname,&sbuf) < 0) {           /* didn't work */
+               notify ("SUP: Can't create directory %s for %s\n",dname,fname);
+               return (TRUE);
+       }
+       vnotify ("SUP Created directory %s for %s\n",dname,fname);
+       return (FALSE);
+}
+
+/***************************************
+ ***    L I S T   R O U T I N E S    ***
+ ***************************************/
+
+static
+int Lhash (name)
+char *name;
+{
+       /* Hash function is:  HASHSIZE * (strlen mod HASHSIZE)
+        *                    +          (char   mod HASHSIZE)
+        * where "char" is last character of name (if name is non-null).
+        */
+
+       register int len;
+       register char c;
+
+       len = strlen (name);
+       if (len > 0)    c = name[len-1];
+       else            c = 0;
+       return (((len&HASHMASK)<<HASHBITS)|(((int)c)&HASHMASK));
+}
+
+static
+Linsert (table,name,number)
+LIST **table;
+char *name;
+int number;
+{
+       register LIST *l;
+       register int lno;
+       lno = Lhash (name);
+       l = (LIST *) malloc (sizeof(LIST));
+       l->Lname = name;
+       l->Lnumber = number;
+       l->Lnext = table[lno];
+       table[lno] = l;
+}
+
+static
+LIST *Llookup (table,name)
+LIST **table;
+char *name;
+{
+       register int lno;
+       register LIST *l;
+       lno = Lhash (name);
+       for (l = table[lno]; l && strcmp(l->Lname,name) != 0; l = l->Lnext);
+       return (l);
+}
+
+ugconvert (uname,gname,uid,gid,mode)
+char *uname,*gname;
+int *uid,*gid,*mode;
+{
+       register LIST *u,*g;
+       register struct passwd *pw;
+       register struct group *gr;
+       struct stat sbuf;
+       static int defuid = -1;
+       static int defgid;
+       static int first = TRUE;
+
+       if (first) {
+               bzero ((char *)uidL, sizeof (uidL));
+               bzero ((char *)gidL, sizeof (gidL));
+               first = FALSE;
+       }
+       pw = NULL;
+       if (u = Llookup (uidL,uname))
+               *uid = u->Lnumber;
+       else if (pw = getpwnam (uname)) {
+               Linsert (uidL,salloc(uname),pw->pw_uid);
+               *uid = pw->pw_uid;
+       }
+       if (u || pw) {
+               if (g = Llookup (gidL,gname)) {
+                       *gid = g->Lnumber;
+                       return;
+               }
+               if (gr = getgrnam (gname)) {
+                       Linsert (gidL,salloc(gname),gr->gr_gid);
+                       *gid = gr->gr_gid;
+                       return;
+               }
+               if (pw == NULL)
+                       pw = getpwnam (uname);
+               *mode &= ~S_ISGID;
+               *gid = pw->pw_gid;
+               return;
+       }
+       *mode &= ~(S_ISUID|S_ISGID);
+       if (defuid >= 0) {
+               *uid = defuid;
+               *gid = defgid;
+               return;
+       }
+       if (stat (".",&sbuf) < 0) {
+               *uid = defuid = getuid ();
+               *gid = defgid = getgid ();
+               return;
+       }
+       *uid = defuid = sbuf.st_uid;
+       *gid = defgid = sbuf.st_gid;
+}
+
+
+/*********************************************
+ ***    U T I L I T Y   R O U T I N E S    ***
+ *********************************************/
+
+#if __STDC__
+notify (char *fmt,...)         /* record error message */
+#else
+/*VARARGS*//*ARGSUSED*/
+notify (va_alist)              /* record error message */
+va_dcl
+#endif
+{
+#if !__STDC__
+       char *fmt;
+#endif
+       char buf[STRINGLENGTH];
+       char collrelname[STRINGLENGTH];
+       long tloc;
+       static FILE *noteF = NULL;      /* mail program on pipe */
+       va_list ap;
+
+#if __STDC__
+       va_start(ap,fmt);
+#else
+       va_start(ap);
+       fmt = va_arg(ap,char *);
+#endif
+       if (fmt == NULL) {
+               if (noteF && noteF != stdout)
+                       (void) pclose (noteF);
+               noteF = NULL;
+               return;
+       }
+       if ((thisC->Cflags&CFURELSUF) && thisC->Crelease) 
+               (void) sprintf (collrelname,"%s-%s",collname,thisC->Crelease);
+       else
+               (void) strcpy (collrelname,collname);
+       
+       if (noteF == NULL) {
+               if ((thisC->Cflags&CFMAIL) && thisC->Cnotify) {
+                       (void) sprintf (buf,"mail -s \"SUP Upgrade of %s\" %s >/dev/null",
+                               collrelname,thisC->Cnotify);
+                       noteF = popen (buf,"w");
+                       if (noteF == NULL) {
+                               logerr ("Can't send mail to %s for %s",
+                                       thisC->Cnotify,collrelname);
+                               noteF = stdout;
+                       }
+               } else
+                       noteF = stdout;
+               tloc = time ((long *)NULL);
+               fprintf (noteF,"SUP Upgrade of %s at %s",
+                       collrelname,ctime (&tloc));
+               (void) fflush (noteF);
+       }
+       vfprintf(noteF,fmt,ap);
+       va_end(ap);
+       (void) fflush (noteF);
+}
+
+lockout (on)           /* lock out interrupts */
+int on;
+{
+       register int x;
+       static int lockmask;
+
+       if (on) {
+               x = sigmask (SIGHUP) | sigmask (SIGINT) |
+                   sigmask (SIGQUIT) | sigmask (SIGTERM);
+               lockmask = sigblock (x);
+       }
+       else {
+               (void) sigsetmask (lockmask);
+       }
+}
+
+char *fmttime (time)
+long time;
+{
+       static char buf[STRINGLENGTH];
+       int len;
+
+       (void) strcpy (buf,ctime (&time));
+       len = strlen(buf+4)-6;
+       (void) strncpy (buf,buf+4,len);
+       buf[len] = '\0';
+       return (buf);
+}
diff --git a/usr.bin/sup/src/supcname.c b/usr.bin/sup/src/supcname.c
new file mode 100644 (file)
index 0000000..fbad5e3
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * sup client name server interface
+ **********************************************************************
+ * HISTORY
+ * $Log: supcname.c,v $
+ * Revision 1.1  1995/12/16 11:46:58  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.2  1995/09/16 19:12:14  glass
+ * if the function returns nothing, declare it void
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:18  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.4  92/08/11  12:07:32  mrt
+ *     Added copyright.
+ *     [92/08/10            mrt]
+ * 
+ * 21-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changed to no longer use a name server.
+ *
+ * 26-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Changed getnams and added several new routines to change the
+ *     way that sup finds nameservers.  It now builds a tree of
+ *     servers to check.  It walks over the tree.  At each node, it
+ *     tries to contact the name server and get as many names
+ *     resolved as it can.  It stops after either all collections
+ *     have host names, or if some collections don't have host names
+ *     but either everyone doesn't know what they are, or after too
+ *     many tries, none could be reached.
+ *
+ * 25-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Split off from sup.c
+ *
+ **********************************************************************
+ */
+
+#include "supcdefs.h"
+
+extern COLLECTION *firstC;             /* collection list pointer */
+
+/*****************************************
+ ***    G E T   H O S T   N A M E S    ***
+ *****************************************/
+
+/*
+ * For each collection that doesn't have a host name specified, read
+ * the file server list for the name of the host for that collection.
+ * It's a fatal error if a collection has no file server.
+ */
+
+void getnams ()
+{
+       register COLLECTION *c;
+       char buf[STRINGLENGTH];
+       register FILE *f;
+       char *p,*q;
+
+       for (c = firstC; c && c->Chtree != NULL; c = c->Cnext);
+       if (c == NULL) return;
+       (void) sprintf (buf,FILEHOSTS,DEFDIR);
+       f = fopen (buf,"r");
+       if (f == NULL)  logquit (1,"Can't open %s",buf);
+       while ((p = fgets (buf,STRINGLENGTH,f)) != NULL) {
+               if (q = index (p,'\n'))  *q = '\0';
+               if (index ("#;:",*p))  continue;
+               q = nxtarg (&p,"= \t");
+               p = skipover (p," \t");
+               if (*p == '=')  p++;
+               p = skipover (p," \t");
+               if (*p == '\0')  goaway ("error in collection/host file");
+               do {
+                       if (strcmp (c->Cname, q) == 0) {
+                               do {
+                                       q = nxtarg (&p,", \t");
+                                       p = skipover (p," \t");
+                                       if (*p == ',')  p++;
+                                       p = skipover (p," \t");
+                                       (void) Tinsert (&c->Chtree,q,FALSE);
+                               } while (*p != '\0');
+                       }
+                       while ((c = c->Cnext) != NULL && c->Chtree != NULL);
+               } while (c != NULL);
+               for (c = firstC; c && c->Chtree != NULL; c = c->Cnext);
+               if (c == NULL) break;
+       }
+       (void) fclose (f);
+       if (c == NULL)  return;
+       do {
+               logerr ("Host for collection %s not found",c->Cname);
+               while ((c = c->Cnext) != NULL && c->Chtree != NULL);
+       } while (c);
+       logquit (1,"Hosts not found for all collections");
+}
diff --git a/usr.bin/sup/src/supcparse.c b/usr.bin/sup/src/supcparse.c
new file mode 100644 (file)
index 0000000..ea3eb6e
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * sup collection parsing routines
+ **********************************************************************
+ * HISTORY
+ *
+ * 7-July-93  Nate Williams at Montana State University
+ *     Modified SUP to use gzip based compression when sending files
+ *     across the network to save BandWidth
+ *
+ * $Log: supcparse.c,v $
+ * Revision 1.1  1995/12/16 11:46:58  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.4  1995/06/09 04:33:34  christos
+ * fixed bug related to the ascii `when' files previous fix, where the -t
+ * option would fail to read the timestamp files.
+ *
+ * Revision 1.2  1993/08/04  17:46:20  brezak
+ * Changes from nate for gzip'ed sup
+ *
+ * Revision 1.1.1.1  1993/05/21  14:52:18  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.6  92/08/11  12:07:38  mrt
+ *     Added use-rel-suffix option corresponding to -u switch.
+ *     [92/07/26            mrt]
+ * 
+ * Revision 1.5  92/02/08  18:24:19  mja
+ *     Added "keep" supfile option, corresponding to -k switch.
+ *     [92/01/17            vdelvecc]
+ * 
+ * Revision 1.4  91/05/16  14:49:50  ern
+ *     Change default timeout from none to 3 hours so we don't accumalute 
+ *     processes running sups to dead hosts especially for users.
+ *     [91/05/16  14:49:21  ern]
+ * 
+ *
+ * 10-Feb-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added timeout to backoff.
+ *
+ * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code for "release" support.  Removed obsolete options.
+ *
+ * 25-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Split off from sup.c
+ *
+ **********************************************************************
+ */
+
+#include "supcdefs.h"
+
+
+#ifdef lint
+static char _argbreak;
+#else
+extern char _argbreak;                 /* break character from nxtarg */
+#endif
+
+typedef enum {                         /* supfile options */
+       OHOST, OBASE, OHOSTBASE, OPREFIX, ORELEASE,
+       ONOTIFY, OLOGIN, OPASSWORD, OCRYPT,
+       OBACKUP, ODELETE, OEXECUTE, OOLD, OTIMEOUT, OKEEP, OURELSUF,
+       OCOMPRESS
+} OPTION;
+
+struct option {
+       char *op_name;
+       OPTION op_enum;
+} options[] = {
+       "host",         OHOST,
+       "base",         OBASE,
+       "hostbase",     OHOSTBASE,
+       "prefix",       OPREFIX,
+       "release",      ORELEASE,
+       "notify",       ONOTIFY,
+       "login",        OLOGIN,
+       "password",     OPASSWORD,
+       "crypt",        OCRYPT,
+       "backup",       OBACKUP,
+       "delete",       ODELETE,
+       "execute",      OEXECUTE,
+       "old",          OOLD,
+       "timeout",      OTIMEOUT,
+       "keep",         OKEEP,
+       "use-rel-suffix", OURELSUF,
+       "compress",     OCOMPRESS
+};
+
+passdelim (ptr,delim)          /* skip over delimiter */
+char **ptr,delim;
+{
+       *ptr = skipover (*ptr, " \t");
+       if (_argbreak != delim && **ptr == delim) {
+               (*ptr)++;
+               *ptr = skipover (*ptr, " \t");
+       }
+}
+
+parsecoll(c,collname,args)
+COLLECTION *c;
+char *collname,*args;
+{
+       register char *arg,*p;
+       register OPTION option;
+       int opno;
+
+       c->Cnext = NULL;
+       c->Cname = salloc (collname);
+       c->Chost = NULL;
+       c->Chtree = NULL;
+       c->Cbase = NULL;
+       c->Chbase = NULL;
+       c->Cprefix = NULL;
+       c->Crelease = NULL;
+       c->Cnotify = NULL;
+       c->Clogin = NULL;
+       c->Cpswd = NULL;
+       c->Ccrypt = NULL;
+       c->Ctimeout = 3*60*60;  /* default to 3 hours instead of no timeout */
+       c->Cflags = 0;
+       c->Cnogood = FALSE;
+       c->Clockfd = -1;
+       args = skipover (args," \t");
+       while (*(arg=nxtarg(&args," \t="))) {
+               for (opno = 0; opno < sizeofA(options); opno++)
+                       if (strcmp (arg,options[opno].op_name) == 0)
+                               break;
+               if (opno == sizeofA(options)) {
+                       logerr ("Invalid supfile option %s for collection %s",
+                               arg,c->Cname);
+                       return(-1);
+               }
+               option = options[opno].op_enum;
+               switch (option) {
+               case OHOST:
+                       passdelim (&args,'=');
+                       do {
+                               arg = nxtarg (&args,", \t");
+                               (void) Tinsert (&c->Chtree,arg,FALSE);
+                               arg = args;
+                               p = skipover (args," \t");
+                               if (*p++ == ',')  args = p;
+                       } while (arg != args);
+                       break;
+               case OBASE:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       c->Cbase = salloc (arg);
+                       break;
+               case OHOSTBASE:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       c->Chbase = salloc (arg);
+                       break;
+               case OPREFIX:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       c->Cprefix = salloc (arg);
+                       break;
+               case ORELEASE:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       c->Crelease = salloc (arg);
+                       break;
+               case ONOTIFY:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       c->Cnotify = salloc (arg);
+                       break;
+               case OLOGIN:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       c->Clogin = salloc (arg);
+                       break;
+               case OPASSWORD:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       c->Cpswd = salloc (arg);
+                       break;
+               case OCRYPT:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       c->Ccrypt = salloc (arg);
+                       break;
+               case OBACKUP:
+                       c->Cflags |= CFBACKUP;
+                       break;
+               case ODELETE:
+                       c->Cflags |= CFDELETE;
+                       break;
+               case OEXECUTE:
+                       c->Cflags |= CFEXECUTE;
+                       break;
+               case OOLD:
+                       c->Cflags |= CFOLD;
+                       break;
+               case OKEEP:
+                       c->Cflags |= CFKEEP;
+                       break;
+               case OURELSUF:
+                       c->Cflags |= CFURELSUF;
+                       break;
+               case OCOMPRESS:
+                       c->Cflags |= CFCOMPRESS;
+                       break;
+               case OTIMEOUT:
+                       passdelim (&args,'=');
+                       arg = nxtarg (&args," \t");
+                       c->Ctimeout = atoi (arg);
+                       break;
+               }
+       }
+       return(0);
+}
+
+
+long
+getwhen(collection, relsuffix)
+       char *collection, *relsuffix;
+{
+       char buf[STRINGLENGTH];
+       char *ep;
+       FILE *fp;
+       long tstamp;
+
+       (void) sprintf (buf,FILEWHEN,collection,relsuffix);
+
+       if ((fp = fopen(buf, "r")) == NULL)
+               return 0;
+
+       if (fgets(buf, sizeof(buf), fp) == NULL) {
+               (void) fclose(fp);
+               return 0;
+       }
+
+       (void) fclose(fp);
+
+       if ((tstamp = strtol(buf, &ep, 0)) == -1 || *ep != '\n')
+               return 0;
+
+       return tstamp;
+}
+
+int
+putwhen(fname, tstamp)
+       char *fname;
+       long tstamp;
+{
+       FILE *fp;
+       if ((fp = fopen(fname, "w")) == NULL)
+               return 0;
+       if (fprintf(fp, "%ld\n", tstamp) < 0)
+               return 0;
+       if (fclose(fp) != 0)
+               return 0;
+       return 1;
+}
diff --git a/usr.bin/sup/src/supcvers.c b/usr.bin/sup/src/supcvers.c
new file mode 100644 (file)
index 0000000..e325fe9
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ **********************************************************************
+ * HISTORY
+ * $Log: supcvers.c,v $
+ * Revision 1.1  1995/12/16 11:46:59  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:19  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.8  92/08/11  12:07:51  mrt
+ *     Added use-rel-suffix option. Picked up STUMP changes.
+ *     [V7.26]
+ * 
+ * Revision 1.7  92/02/08  18:24:23  mja
+ *     Support for -k/-K and "keep" option. [V7.25]
+ *     [92/01/17            vdelvecc]
+ * 
+ * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added crosspatch support.  Removed nameserver support. [V7.24]
+ *
+ * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code for "release" support. [V6.23]
+ *
+ * 26-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Changes for Version 6, better supoort to reflect errors to
+ *     logfile. [V6.22]
+ *
+ * 25-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Split sup.c into subparts. [V5.21]
+ *
+ * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changes to many files to make lint happy. [V5.20]
+ *
+ * 01-Apr-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changes to sup.c and scmio.c. [V5.19]
+ *
+ * 19-Sep-86  Mike Accetta (mja) at Carnegie-Mellon University
+ *     Changes to sup.c. [V5.18]
+ *
+ * 21-Jun-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Minor bug fix to previous edit in sup.c. [V5.17]
+ *
+ * 07-Jun-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changes to sup.c and sup.h. [V5.16]
+ *
+ * 30-May-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added changes to sup.c, sup.h, scm.c, scmio.h. [V5.15]
+ *
+ * 19-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Created. [V5.14]
+ *
+ **********************************************************************
+ */
+
+int PGMVERSION = 26;           /* program version of sup */
diff --git a/usr.bin/sup/src/supfilesrv.c b/usr.bin/sup/src/supfilesrv.c
new file mode 100644 (file)
index 0000000..12e2ce2
--- /dev/null
@@ -0,0 +1,1870 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+/*
+ * supfilesrv -- SUP File Server
+ *
+ * Usage:  supfilesrv [-l] [-P] [-N] [-R]
+ *     -l      "live" -- don't fork daemon
+ *     -P      "debug ports" -- use debugging network ports
+ *     -N      "debug network" -- print debugging messages for network i/o
+ *     -R      "RCS mode" -- if file is an rcs file, use co to get contents
+ *
+ **********************************************************************
+ * HISTORY
+ * 13-Sep-92  Mary Thompson (mrt) at Carnegie-Mellon University
+ *     Changed name of sup program in xpatch from /usr/cs/bin/sup to
+ *     /usr/bin/sup for exported version of sup.
+ *
+ * 7-July-93  Nate Williams at Montana State University
+ *     Modified SUP to use gzip based compression when sending files
+ *     across the network to save BandWidth
+ *
+ * $Log: supfilesrv.c,v $
+ * Revision 1.1  1995/12/16 11:46:59  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.8  1995/10/29 23:54:49  christos
+ * - runio fails when result != 0 not only < 0
+ * - print vis-encoded file in the scanner.
+ *
+ * Revision 1.7  1995/06/24 16:21:55  christos
+ * - Don't use system(3) to fork processes. It is a big security hole.
+ * - Encode the filenames in the scan files using strvis(3), so filenames
+ *   that contain newlines or other weird characters don't break the scanner.
+ *
+ * Revision 1.6  1995/06/03 21:22:00  christos
+ * Changes to write ascii timestamps in the when files.
+ * Looked into making it 64 bit clean, but it is hopeless.
+ * Added little program to convert from the old timestamp files
+ * into the new ones.
+ *
+ * Revision 1.5  1993/08/04 17:46:21  brezak
+ * Changes from nate for gzip'ed sup
+ *
+ * Revision 1.3  1993/06/05  21:32:17  cgd
+ * use daemon() to put supfilesrv into daemon mode...
+ *
+ * Revision 1.2  1993/05/24  17:57:31  brezak
+ * Remove netcrypt.c. Remove unneeded files. Cleanup make.
+ *
+ * Revision 1.20  92/09/09  22:05:00  mrt
+ *     Added Brad's change to make sendfile take a va_list.
+ *     Added support in login to accept an non-encrypted login
+ *     message if no user or password is being sent. This supports
+ *     a non-crypting version of sup. Also fixed to skip leading
+ *     white space from crypts in host files.
+ *     [92/09/01            mrt]
+ * 
+ * Revision 1.19  92/08/11  12:07:59  mrt
+ *             Made maxchildren a patchable variable, which can be set by the
+ *             command line switch -C or else defaults to the MAXCHILDREN
+ *             defined in sup.h. Added most of Brad's STUMP changes.
+ *     Increased PGMVERSION to 12 to reflect substantial changes.
+ *     [92/07/28            mrt]
+ * 
+ * Revision 1.18  90/12/25  15:15:39  ern
+ *     Yet another rewrite of the logging code. Make up the text we will write
+ *        and then get in, write it and get out.
+ *     Also set error on write-to-full-disk if the logging is for recording
+ *        server is busy.
+ *     [90/12/25  15:15:15  ern]
+ * 
+ * Revision 1.17  90/05/07  09:31:13  dlc
+ *     Sigh, some more fixes to the new "crypt" file handling code.  First,
+ *     just because the "crypt" file is in a local file system does not mean
+ *     it can be trusted.  We have to check for hard links to root owned
+ *     files whose contents could be interpretted as a crypt key.  For
+ *     checking this fact, the new routine stat_info_ok() was added.  This
+ *     routine also makes other sanity checks, such as owner only permission,
+ *     the file is a regular file, etc.  Also, even if the uid/gid of th
+ *     "crypt" file is not going to be used, still use its contents in order
+ *     to cause fewer surprises to people supping out of a shared file system
+ *     such as AFS.
+ *     [90/05/07            dlc]
+ * 
+ * Revision 1.16  90/04/29  04:21:08  dlc
+ *     Fixed logic bug in docrypt() which would not get the stat information
+ *     from the crypt file if the crypt key had already been set from a
+ *     "host" file.
+ *     [90/04/29            dlc]
+ * 
+ * Revision 1.15  90/04/18  19:51:27  dlc
+ *     Added the new routines local_file(), link_nofollow() for use in
+ *     dectecting whether a file is located in a local file system.  These
+ *     routines probably should have been in another module, but only
+ *     supfilesrv needs to do the check and none of its other modules seemed
+ *     appropriate.  Note, the implementation should be changed once we have
+ *     direct kernel support, for example the fstatfs(2) system call, for
+ *     detecting the type of file system a file resides.  Also, I changed
+ *     the routines which read the crosspatch crypt file or collection crypt
+ *     file to save the uid and gid from the stat information obtained via
+ *     the local_file() call (when the file is local) at the same time the
+ *     crypt key is read.  This change disallows non-local files for the
+ *     crypt key to plug a security hole involving the usage of the uid/gid
+ *     of the crypt file to define who the the file server should run as.  If
+ *     the saved uid/gid are both valid, then the server will set its uid/gid
+ *     to these values.
+ *     [90/04/18            dlc]
+ * 
+ * Revision 1.14  89/08/23  14:56:15  gm0w
+ *     Changed msgf routines to msg routines.
+ *     [89/08/23            gm0w]
+ * 
+ * Revision 1.13  89/08/03  19:57:33  mja
+ *     Remove setaid() call.
+ * 
+ * Revision 1.12  89/08/03  19:49:24  mja
+ *     Updated to use v*printf() in place of _doprnt().
+ *     [89/04/19            mja]
+ * 
+ * 11-Sep-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to record release name in logfile.
+ *
+ * 18-Mar-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added host=<hostfile> support to releases file. [V7.12]
+ *
+ * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added crosspatch support.  Created docrypt() routine for crypt
+ *     test message.
+ *
+ * 09-Sep-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Removed common information logging code, the quiet switch, and
+ *     moved samehost() check to after device/inode check.
+ *
+ * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code for "release" support. [V5.11]
+ *
+ * 26-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Added code to record final status of client in logfile. [V5.10]
+ *
+ * 22-May-87  Chriss Stephens (chriss) at Carnegie Mellon University
+ *     Mergered divergent CS and ECE versions. [V5.9a]
+ *
+ * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Removed support for version 3 of SUP protocol.  Added changes
+ *     to make lint happy.  Added calls to new logging routines. [V5.9]
+ *
+ * 31-Mar-87  Dan Nydick (dan) at Carnegie-Mellon University
+ *     Fixed so no password check is done when crypts are used.
+ *
+ * 25-Nov-86  Rudy Nedved (ern) at Carnegie-Mellon University
+ *     Set F_APPEND fcntl in logging to increase the chance
+ *     that the log entry from this incarnation of the file
+ *     server will not be lost by another incarnation. [V5.8]
+ *
+ * 20-Oct-86  Dan Nydick (dan) at Carnegie-Mellon University
+ *     Changed not to call okmumbles when not compiled with CMUCS.
+ *
+ * 04-Aug-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to increment scmdebug as more -N flags are
+ *     added. [V5.7]
+ *
+ * 25-May-86  Jonathan J. Chew (jjc) at Carnegie-Mellon University
+ *     Renamed local variable in main program from "sigmask" to
+ *     "signalmask" to avoid name conflict with 4.3BSD identifier.
+ *     Conditionally compile in calls to CMU routines, "setaid" and
+ *     "logaccess". [V5.6]
+ *
+ * 21-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changed supfilesrv to use the crypt file owner and group for
+ *     access purposes, rather than the directory containing the crypt
+ *     file. [V5.5]
+ *
+ * 07-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to keep logfiles in repository collection directory.
+ *     Added code for locking collections. [V5.4]
+ *
+ * 05-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to support new FSETUPBUSY return.  Now accepts all
+ *     connections and tells any clients after the 8th that the
+ *     fileserver is busy.  New clients will retry again later. [V5.3]
+ *
+ * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Major rewrite for protocol version 4. [V4.2]
+ *
+ * 12-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Fixed close of crypt file to use file pointer as argument
+ *     instead of string pointer.
+ *
+ * 24-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Allow "!hostname" lines and comments in collection "host" file.
+ *
+ * 13-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Don't use access() on symbolic links since they may not point to
+ *     an existing file.
+ *
+ * 22-Oct-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code to restrict file server availability to when it has
+ *     less than or equal to eight children.
+ *
+ * 22-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Merged 4.1 and 4.2 versions together.
+ *
+ * 04-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Created for 4.2 BSD.
+ *
+ **********************************************************************
+ */
+
+#include <libc.h>
+#ifdef AFS
+#include <afs/param.h>
+#undef MAXNAMLEN
+#endif
+#include <sys/param.h>
+#include <c.h>
+#include <signal.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <pwd.h>
+#include <grp.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/dir.h>
+#if    MACH
+#include <sys/ioctl.h>
+#endif
+#if    CMUCS
+#include <acc.h>
+#include <sys/ttyloc.h>
+#include <access.h>
+#include <sys/viceioctl.h>
+#else  CMUCS
+#define ACCESS_CODE_OK         0
+#define ACCESS_CODE_BADPASSWORD (-2)
+#endif  CMUCS
+#include "sup.h"
+#define MSGFILE
+#include "supmsg.h"
+
+#ifdef lint
+/*VARARGS1*//*ARGSUSED*/
+static void quit(status) {};
+#endif /* lint */
+
+extern int errno;
+long time ();
+uid_t getuid ();
+
+int maxchildren;
+
+/*
+ * These are used to save the stat information from the crosspatch crypt
+ * file or collection crypt file at the time it is opened for the crypt
+ * key and it is verified to be a local file.
+ */
+int runas_uid = -1;
+int runas_gid = -1;
+
+#define PGMVERSION 13
+
+/*************************
+ ***    M A C R O S    ***
+ *************************/
+
+#define HASHBITS 8
+#define HASHSIZE (1<<HASHBITS)
+#define HASHMASK (HASHSIZE-1)
+#define HASHFUNC(x,y) ((x)&HASHMASK)
+
+/*******************************************
+ ***    D A T A   S T R U C T U R E S    ***
+ *******************************************/
+
+struct hashstruct {                    /* hash table for number lists */
+       int Hnum1;                      /* numeric keys */
+       int Hnum2;
+       char *Hname;                    /* string value */
+       TREE *Htree;                    /* TREE value */
+       struct hashstruct *Hnext;
+};
+typedef struct hashstruct HASH;
+
+/*********************************************
+ ***    G L O B A L   V A R I A B L E S    ***
+ *********************************************/
+
+char program[] = "supfilesrv";         /* program name for SCM messages */
+int progpid = -1;                      /* and process id */
+
+jmp_buf sjbuf;                         /* jump location for network errors */
+TREELIST *listTL;                      /* list of trees to upgrade */
+
+int live;                              /* -l flag */
+int dbgportsq;                         /* -P flag */
+extern int scmdebug;                   /* -N flag */
+extern int netfile;
+#ifdef RCS
+int candorcs;                          /* -R flag */
+int dorcs = FALSE;
+#endif
+
+char *clienthost;                      /* host name of client */
+int nchildren;                         /* number of children that exist */
+char *prefix;                          /* collection pathname prefix */
+char *release;                         /* collection release name */
+char *cryptkey;                                /* encryption key if non-null */
+#ifdef CVS
+char *cvs_root;                                /* RCS root */
+#endif
+char *rcs_branch;                      /* RCS branch name */
+int lockfd;                            /* descriptor of lock file */
+
+/* global variables for scan functions */
+int trace = FALSE;                     /* directory scan trace */
+int cancompress = FALSE;               /* Can we compress files */
+int docompress = FALSE;                        /* Do we compress files */
+
+HASH *uidH[HASHSIZE];                  /* for uid and gid lookup */
+HASH *gidH[HASHSIZE];
+HASH *inodeH[HASHSIZE];                        /* for inode lookup for linked file check */
+
+char *fmttime ();                      /* time format routine */
+#if __STDC__
+int goaway(char *fmt,...);
+#endif
+
+/*************************************
+ ***    M A I N   R O U T I N E    ***
+ *************************************/
+
+main (argc,argv)
+int argc;
+char **argv;
+{
+       register int x,pid,signalmask;
+       struct sigvec chldvec,ignvec,oldvec;
+       void chldsig();
+       long tloc;
+
+       /* initialize global variables */
+       pgmversion = PGMVERSION;        /* export version number */
+       server = TRUE;                  /* export that we're not a server */
+       collname = NULL;                /* no current collection yet */
+       maxchildren = MAXCHILDREN;      /* defined in sup.h */
+
+       init (argc,argv);               /* process arguments */
+
+#ifdef HAS_DAEMON
+       if (!live)                      /* if not debugging, turn into daemon */
+               daemon(0, 0);
+#endif
+
+       logopen ("supfile");
+       tloc = time ((long *)NULL);
+       loginfo ("SUP File Server Version %d.%d (%s) starting at %s",
+               PROTOVERSION,PGMVERSION,scmversion,fmttime (tloc));
+       if (live) {
+               x = service ();
+               if (x != SCMOK)
+                       logquit (1,"Can't connect to network");
+               answer ();
+               (void) serviceend ();
+               exit (0);
+       }
+       ignvec.sv_handler = SIG_IGN;
+       ignvec.sv_onstack = 0;
+       ignvec.sv_mask = 0;
+       (void) sigvec (SIGHUP,&ignvec,&oldvec);
+       (void) sigvec (SIGINT,&ignvec,&oldvec);
+       (void) sigvec (SIGPIPE,&ignvec,&oldvec);
+       chldvec.sv_handler = chldsig;
+       chldvec.sv_mask = 0;
+       chldvec.sv_onstack = 0;
+       (void) sigvec (SIGCHLD,&chldvec,&oldvec);
+       nchildren = 0;
+       for (;;) {
+               x = service ();
+               if (x != SCMOK) {
+                       logerr ("Error in establishing network connection");
+                       (void) servicekill ();
+                       continue;
+               }
+               signalmask = sigblock(sigmask(SIGCHLD));
+               if ((pid = fork()) == 0) { /* server process */
+                       (void) serviceprep ();
+                       answer ();
+                       (void) serviceend ();
+                       exit (0);
+               }
+               (void) servicekill ();  /* parent */
+               if (pid > 0) nchildren++;
+               (void) sigsetmask(signalmask);
+       }
+}
+
+/*
+ * Child status signal handler
+ */
+
+void
+chldsig(snum)
+       int snum;
+{
+       union wait w;
+
+       while (wait3((int *) &w, WNOHANG, (struct rusage *)0) > 0) {
+               if (nchildren) nchildren--;
+       }
+}
+
+/*****************************************
+ ***    I N I T I A L I Z A T I O N    ***
+ *****************************************/
+
+usage ()
+{
+       quit (1,"Usage: supfilesrv [ -l | -P | -N | -C <max children> | -H <host> <user> <cryptfile> <supargs> ]\n");
+}
+
+init (argc,argv)
+int argc;
+char **argv;
+{
+       register int i;
+       register int x;
+       char *clienthost,*clientuser;
+       char *p,*q;
+       char buf[STRINGLENGTH];
+       int maxsleep;
+       register FILE *f;
+
+#ifdef RCS
+        candorcs = FALSE;
+#endif
+       live = FALSE;
+       dbgportsq = FALSE;
+       scmdebug = 0;
+       clienthost = NULL;
+       clientuser = NULL;
+       maxsleep = 5;
+       if (--argc < 0)
+               usage ();
+       argv++;
+       while (clienthost == NULL && argc > 0 && argv[0][0] == '-') {
+               switch (argv[0][1]) {
+               case 'l':
+                       live = TRUE;
+                       break;
+               case 'P':
+                       dbgportsq = TRUE;
+                       break;
+               case 'N':
+                       scmdebug++;
+                       break;
+               case 'C':
+                       if (--argc < 1)
+                               quit (1,"Missing arg to -C\n");
+                       argv++;
+                       maxchildren = atoi(argv[0]);
+                       break;
+               case 'H':
+                       if (--argc < 3)
+                               quit (1,"Missing args to -H\n");
+                       argv++;
+                       clienthost = argv[0];
+                       clientuser = argv[1];
+                       cryptkey = argv[2];
+                       argc -= 2;
+                       argv += 2;
+                       break;
+#ifdef RCS
+                case 'R':
+                        candorcs = TRUE;
+                        break;
+#endif
+               default:
+                       fprintf (stderr,"Unknown flag %s ignored\n",argv[0]);
+                       break;
+               }
+               --argc;
+               argv++;
+       }
+       if (clienthost == NULL) {
+               if (argc != 0)
+                       usage ();
+               x = servicesetup (dbgportsq ? DEBUGFPORT : FILEPORT);
+               if (x != SCMOK)
+                       quit (1,"Error in network setup");
+               for (i = 0; i < HASHSIZE; i++)
+                       uidH[i] = gidH[i] = inodeH[i] = NULL;
+               return;
+       }
+       server = FALSE;
+       if (argc < 1)
+               usage ();
+       f = fopen (cryptkey,"r");
+       if (f == NULL)
+               quit (1,"Unable to open cryptfile %s\n",cryptkey);
+       if (p = fgets (buf,STRINGLENGTH,f)) {
+               if (q = index (p,'\n'))  *q = '\0';
+               if (*p == '\0')
+                       quit (1,"No cryptkey found in %s\n",cryptkey);
+               cryptkey = salloc (buf);
+       }
+       (void) fclose (f);
+       x = request (dbgportsq ? DEBUGFPORT : FILEPORT,clienthost,&maxsleep);
+       if (x != SCMOK)
+               quit (1,"Unable to connect to host %s\n",clienthost);
+       x = msgsignon ();
+       if (x != SCMOK)
+               quit (1,"Error sending signon request to fileserver\n");
+       x = msgsignonack ();
+       if (x != SCMOK)
+               quit (1,"Error reading signon reply from fileserver\n");
+       printf ("SUP Fileserver %d.%d (%s) %d on %s\n",
+               protver,pgmver,scmver,fspid,remotehost());
+       free (scmver);
+       scmver = NULL;
+       if (protver < 7)
+               quit (1,"Remote fileserver does not implement reverse sup\n");
+       xpatch = TRUE;
+       xuser = clientuser;
+       x = msgsetup ();
+       if (x != SCMOK)
+               quit (1,"Error sending setup request to fileserver\n");
+       x = msgsetupack ();
+       if (x != SCMOK)
+               quit (1,"Error reading setup reply from fileserver\n");
+       switch (setupack) {
+       case FSETUPOK:
+               break;
+       case FSETUPSAME:
+               quit (1,"User %s not found on remote client\n",xuser);
+       case FSETUPHOST:
+               quit (1,"This host has no permission to reverse sup\n");
+       default:
+               quit (1,"Unrecognized file server setup status %d\n",setupack);
+       }
+       if (netcrypt (cryptkey) != SCMOK )
+               quit (1,"Running non-crypting fileserver\n");
+       crypttest = CRYPTTEST;
+       x = msgcrypt ();
+       if (x != SCMOK)
+               quit (1,"Error sending encryption test request\n");
+       x = msgcryptok ();
+       if (x == SCMEOF)
+               quit (1,"Data encryption test failed\n");
+       if (x != SCMOK)
+               quit (1,"Error reading encryption test reply\n");
+       logcrypt = CRYPTTEST;
+       loguser = NULL;
+       logpswd = NULL;
+       if (netcrypt (PSWDCRYPT) != SCMOK)      /* encrypt password data */
+               quit (1,"Running non-crypting fileserver\n");
+       x = msglogin ();
+       (void) netcrypt ((char *)NULL); /* turn off encryption */
+       if (x != SCMOK)
+               quit (1,"Error sending login request to file server\n");
+       x = msglogack ();
+       if (x != SCMOK)
+               quit (1,"Error reading login reply from file server\n");
+       if (logack == FLOGNG)
+               quit (1,"%s\nImproper login to %s account\n",logerror,xuser);
+       xargc = argc;
+       xargv = argv;
+       x = msgxpatch ();
+       if (x != SCMOK)
+               quit (1,"Error sending crosspatch request\n");
+       crosspatch ();
+       exit (0);
+}
+
+/*****************************************
+ ***    A N S W E R   R E Q U E S T    ***
+ *****************************************/
+
+answer ()
+{
+       long starttime;
+       register int x;
+
+       progpid = fspid = getpid ();
+       collname = NULL;
+       basedir = NULL;
+       prefix = NULL;
+       release = NULL;
+        rcs_branch = NULL;
+#ifdef CVS
+        cvs_root = NULL;
+#endif
+       goawayreason = NULL;
+       donereason = NULL;
+       lockfd = -1;
+       starttime = time ((long *)NULL);
+       if (!setjmp (sjbuf)) {
+               signon ();
+               setup ();
+               docrypt ();
+               login ();
+               if (xpatch) {
+                       int fd;
+
+                       x = msgxpatch ();
+                       if (x != SCMOK)
+                               exit (0);
+                       xargv[0] = "sup";
+                       xargv[1] = "-X";
+                       xargv[xargc] = (char *)NULL;
+                       (void) dup2 (netfile,0);
+                       (void) dup2 (netfile,1);
+                       (void) dup2 (netfile,2);
+                       fd = getdtablesize ();
+                       while (--fd > 2)
+                               (void) close (fd);
+                       execvp (xargv[0],xargv);
+                       exit (0);
+               }
+               listfiles ();
+               sendfiles ();
+       }
+       finishup (starttime);
+       if (collname)  free (collname);
+       if (basedir)  free (basedir);
+       if (prefix)  free (prefix);
+       if (release)  free (release);
+       if (rcs_branch)  free (rcs_branch);
+#ifdef CVS
+       if (cvs_root)  free (cvs_root);
+#endif
+       if (goawayreason) {
+               if (donereason == goawayreason)
+                       donereason = NULL;
+               free (goawayreason);
+       }
+       if (donereason)  free (donereason);
+       if (lockfd >= 0)  (void) close (lockfd);
+       endpwent ();
+       (void) endgrent ();
+#if    CMUCS
+       endacent ();
+#endif /* CMUCS */
+       Hfree (uidH);
+       Hfree (gidH);
+       Hfree (inodeH);
+}
+
+/*****************************************
+ ***    S I G N   O N   C L I E N T    ***
+ *****************************************/
+
+signon ()
+{
+       register int x;
+
+       xpatch = FALSE;
+       x = msgsignon ();
+       if (x != SCMOK)  goaway ("Error reading signon request from client");
+       x = msgsignonack ();
+       if (x != SCMOK)  goaway ("Error sending signon reply to client");
+       free (scmver);
+       scmver = NULL;
+}
+
+/*****************************************************************
+ ***    E X C H A N G E   S E T U P   I N F O R M A T I O N    ***
+ *****************************************************************/
+
+setup ()
+{
+       register int x;
+       char *p,*q;
+       char buf[STRINGLENGTH];
+       register FILE *f;
+       struct stat sbuf;
+       register TREELIST *tl;
+
+       if (protver > 7) {
+               cancompress = TRUE;
+       }
+       x = msgsetup ();
+       if (x != SCMOK)  goaway ("Error reading setup request from client");
+       if (protver < 4) {
+               setupack = FSETUPOLD;
+               (void) msgsetupack ();
+               if (protver >= 6)  longjmp (sjbuf,TRUE);
+               goaway ("Sup client using obsolete version of protocol");
+       }
+       if (xpatch) {
+               register struct passwd *pw;
+               extern int link_nofollow(), local_file();
+
+               if ((pw = getpwnam (xuser)) == NULL) {
+                       setupack = FSETUPSAME;
+                       (void) msgsetupack ();
+                       if (protver >= 6)  longjmp (sjbuf,TRUE);
+                       goaway ("User not found");
+               }
+               (void) free (xuser);
+               xuser = salloc (pw->pw_dir);
+
+               /* check crosspatch host access file */
+               cryptkey = NULL;
+               (void) sprintf (buf,FILEXPATCH,xuser);
+
+               /* Turn off link following */
+               if (link_nofollow(1) != -1) {
+                       int hostok = FALSE;
+                       /* get stat info before open */
+                       if (stat(buf, &sbuf) == -1)
+                               (void) bzero((char *)&sbuf, sizeof(sbuf));
+
+                       if ((f = fopen (buf,"r")) != NULL) {
+                               struct stat fsbuf;
+
+                               while (p = fgets (buf,STRINGLENGTH,f)) {
+                                       q = index (p,'\n');
+                                       if (q)  *q = 0;
+                                       if (index ("#;:",*p))  continue;
+                                       q = nxtarg (&p," \t");
+                                       if (*p == '\0')  continue;
+                                       if (!matchhost(q)) continue;
+
+                                       cryptkey = salloc (p);
+                                       hostok = TRUE;
+                                       if (local_file(fileno(f), &fsbuf) > 0
+                                           && stat_info_ok(&sbuf, &fsbuf)) {
+                                               runas_uid = sbuf.st_uid;
+                                               runas_gid = sbuf.st_gid;
+                                       }
+                                       break;
+                               }
+                               (void) fclose (f);
+                       }
+
+                       /* Restore link following */
+                       if (link_nofollow(0) == -1)
+                               goaway ("Restore link following");
+
+                       if (!hostok) {
+                               setupack = FSETUPHOST;
+                               (void) msgsetupack ();
+                               if (protver >= 6)  longjmp (sjbuf,TRUE);
+                               goaway ("Host not on access list");
+                       }
+               }
+               setupack = FSETUPOK;
+               x = msgsetupack ();
+               if (x != SCMOK)
+                       goaway ("Error sending setup reply to client");
+               return;
+       }
+#ifdef RCS
+        if (candorcs && release != NULL &&
+            (strncmp(release, "RCS.", 4) == 0)) {
+                rcs_branch = salloc(&release[4]);
+                free(release);
+                release = salloc("RCS");
+                dorcs = TRUE;
+        }
+#endif
+       if (release == NULL)
+               release = salloc (DEFRELEASE);
+       if (basedir == NULL || *basedir == '\0') {
+               basedir = NULL;
+               (void) sprintf (buf,FILEDIRS,DEFDIR);
+               f = fopen (buf,"r");
+               if (f) {
+                       while (p = fgets (buf,STRINGLENGTH,f)) {
+                               q = index (p,'\n');
+                               if (q)  *q = 0;
+                               if (index ("#;:",*p))  continue;
+                               q = nxtarg (&p," \t=");
+                               if (strcmp(q,collname) == 0) {
+                                       basedir = skipover(p," \t=");
+                                       basedir = salloc (basedir);
+                                       break;
+                               }
+                       }
+                       (void) fclose (f);
+               }
+               if (basedir == NULL) {
+                       (void) sprintf (buf,FILEBASEDEFAULT,collname);
+                       basedir = salloc(buf);
+               }
+       }
+       if (chdir (basedir) < 0)
+               goaway ("Can't chdir to base directory %s",basedir);
+       (void) sprintf (buf,FILEPREFIX,collname);
+       f = fopen (buf,"r");
+       if (f) {
+               while (p = fgets (buf,STRINGLENGTH,f)) {
+                       q = index (p,'\n');
+                       if (q)  *q = 0;
+                       if (index ("#;:",*p))  continue;
+                       prefix = salloc(p);
+                       if (chdir (prefix) < 0)
+                               goaway ("Can't chdir to %s from base directory %s",
+                                       prefix,basedir);
+                       break;
+               }
+               (void) fclose (f);
+       }
+       x = stat (".",&sbuf);
+       if (prefix)  (void) chdir (basedir);
+       if (x < 0)
+               goaway ("Can't stat base/prefix directory");
+       if (nchildren >= maxchildren) {
+               setupack = FSETUPBUSY;
+               (void) msgsetupack ();
+               if (protver >= 6)  longjmp (sjbuf,TRUE);
+               goaway ("Sup client told to try again later");
+       }
+       if (sbuf.st_dev == basedev && sbuf.st_ino == baseino && samehost()) {
+               setupack = FSETUPSAME;
+               (void) msgsetupack ();
+               if (protver >= 6)  longjmp (sjbuf,TRUE);
+               goaway ("Attempt to upgrade to same directory on same host");
+       }
+       /* obtain release information */
+       if (!getrelease (release)) {
+               setupack = FSETUPRELEASE;
+               (void) msgsetupack ();
+               if (protver >= 6)  longjmp (sjbuf,TRUE);
+               goaway ("Invalid release information");
+       }
+       /* check host access file */
+       cryptkey = NULL;
+       for (tl = listTL; tl != NULL; tl = tl->TLnext) {
+               char *h;
+               if ((h = tl->TLhost) == NULL)
+                       h = FILEHOSTDEF;
+               (void) sprintf (buf,FILEHOST,collname,h);
+               f = fopen (buf,"r");
+               if (f) {
+                       int hostok = FALSE;
+                       while (p = fgets (buf,STRINGLENGTH,f)) {
+                               int not;
+                               q = index (p,'\n');
+                               if (q)  *q = 0;
+                               if (index ("#;:",*p))  continue;
+                               q = nxtarg (&p," \t");
+                               if ((not = (*q == '!')) && *++q == '\0')
+                                       q = nxtarg (&p," \t");
+                               hostok = (not == (matchhost(q) == 0));
+                               if (hostok) {
+                                       while ((*p == ' ') || (*p == '\t')) p++;
+                                       if (*p)  cryptkey = salloc (p);
+                                       break;
+                               }
+                       }
+                       (void) fclose (f);
+                       if (!hostok) {
+                               setupack = FSETUPHOST;
+                               (void) msgsetupack ();
+                               if (protver >= 6)  longjmp (sjbuf,TRUE);
+                               goaway ("Host not on access list for %s",
+                                       collname);
+                       }
+               }
+       }
+       /* try to lock collection */
+       (void) sprintf (buf,FILELOCK,collname);
+       x = open (buf,O_RDONLY,0);
+       if (x >= 0) {
+               if (flock (x,(LOCK_SH|LOCK_NB)) < 0) {
+                       (void) close (x);
+                       if (errno != EWOULDBLOCK)
+                               goaway ("Can't lock collection %s",collname);
+                       setupack = FSETUPBUSY;
+                       (void) msgsetupack ();
+                       if (protver >= 6)  longjmp (sjbuf,TRUE);
+                       goaway ("Sup client told to wait for lock");
+               }
+               lockfd = x;
+       }
+       setupack = FSETUPOK;
+       x = msgsetupack ();
+       if (x != SCMOK)  goaway ("Error sending setup reply to client");
+}
+
+/** Test data encryption **/
+docrypt ()
+{
+       register int x;
+       char *p,*q;
+       char buf[STRINGLENGTH];
+       register FILE *f;
+       struct stat sbuf;
+       extern int  link_nofollow(), local_file();
+
+       if (!xpatch) {
+               (void) sprintf (buf,FILECRYPT,collname);
+
+               /* Turn off link following */
+               if (link_nofollow(1) != -1) {
+                       /* get stat info before open */
+                       if (stat(buf, &sbuf) == -1)
+                               (void) bzero((char *)&sbuf, sizeof(sbuf));
+
+                       if ((f = fopen (buf,"r")) != NULL) {
+                               struct stat fsbuf;
+
+                               if (cryptkey == NULL &&
+                                   (p = fgets (buf,STRINGLENGTH,f))) {
+                                       if (q = index (p,'\n'))  *q = '\0';
+                                       if (*p)  cryptkey = salloc (buf);
+                               }
+                               if (local_file(fileno(f), &fsbuf) > 0
+                                   && stat_info_ok(&sbuf, &fsbuf)) {
+                                       runas_uid = sbuf.st_uid;
+                                       runas_gid = sbuf.st_gid;
+                               }
+                               (void) fclose (f);
+                       }
+                       /* Restore link following */
+                       if (link_nofollow(0) == -1)
+                               goaway ("Restore link following");
+               }
+       }
+       if ( netcrypt (cryptkey) != SCMOK )
+               goaway ("Runing non-crypting supfilesrv");
+       x = msgcrypt ();
+       if (x != SCMOK)
+               goaway ("Error reading encryption test request from client");
+       (void) netcrypt ((char *)NULL);
+       if (strcmp(crypttest,CRYPTTEST) != 0)
+               goaway ("Client not encrypting data properly");
+       free (crypttest);
+       crypttest = NULL;
+       x = msgcryptok ();
+       if (x != SCMOK)
+               goaway ("Error sending encryption test reply to client");
+}
+
+/***************************************************************
+ ***    C O N N E C T   T O   P R O P E R   A C C O U N T    ***
+ ***************************************************************/
+
+login ()
+{
+       char *changeuid ();
+       register int x,fileuid,filegid;
+
+       (void) netcrypt (PSWDCRYPT);    /* encrypt acct name and password */
+       x = msglogin ();
+       (void) netcrypt ((char *)NULL); /* turn off encryption */
+       if (x != SCMOK)  goaway ("Error reading login request from client");
+       if ( logcrypt ) {
+           if (strcmp(logcrypt,CRYPTTEST) != 0) {
+               logack = FLOGNG;
+               logerror = "Improper login encryption";
+               (void) msglogack ();
+               goaway ("Client not encrypting login information properly");
+           }
+           free (logcrypt);
+           logcrypt = NULL;
+       }
+       if (loguser == NULL) {
+               if (cryptkey) {
+                       if (runas_uid >= 0 && runas_gid >= 0) {
+                               fileuid = runas_uid;
+                               filegid = runas_gid;
+                               loguser = NULL;
+                       } else
+                               loguser = salloc (DEFUSER);
+               } else
+                       loguser = salloc (DEFUSER);
+       }
+       if ((logerror = changeuid (loguser,logpswd,fileuid,filegid)) != NULL) {
+               logack = FLOGNG;
+               (void) msglogack ();
+               if (protver >= 6)  longjmp (sjbuf,TRUE);
+               goaway ("Client denied login access");
+       }
+       if (loguser)  free (loguser);
+       if (logpswd)  free (logpswd);
+       logack = FLOGOK;
+       x = msglogack ();
+       if (x != SCMOK)  goaway ("Error sending login reply to client");
+       if (!xpatch)  /* restore desired encryption */
+               if (netcrypt (cryptkey) != SCMOK)
+                       goaway("Running non-crypting supfilesrv");
+       free (cryptkey);
+       cryptkey = NULL;
+}
+
+/*****************************************
+ ***    M A K E   N A M E   L I S T    ***
+ *****************************************/
+
+listfiles ()
+{
+       int denyone();
+       register int x;
+
+       refuseT = NULL;
+       x = msgrefuse ();
+       if (x != SCMOK)  goaway ("Error reading refuse list from client");
+       getscanlists ();
+       Tfree (&refuseT);
+       x = msglist ();
+       if (x != SCMOK)  goaway ("Error sending file list to client");
+       Tfree (&listT);
+       listT = NULL;
+       needT = NULL;
+       x = msgneed ();
+       if (x != SCMOK)
+               goaway ("Error reading needed files list from client");
+       denyT = NULL;
+       (void) Tprocess (needT,denyone);
+       Tfree (&needT);
+       x = msgdeny ();
+       if (x != SCMOK)  goaway ("Error sending denied files list to client");
+       Tfree (&denyT);
+}
+
+denyone (t)
+register TREE *t;
+{
+       register TREELIST *tl;
+       register char *name = t->Tname;
+       register int update = (t->Tflags&FUPDATE) != 0;
+       struct stat sbuf;
+       register TREE *tlink;
+       TREE *linkcheck ();
+       char slinkname[STRINGLENGTH];
+       register int x;
+
+       for (tl = listTL; tl != NULL; tl = tl->TLnext)
+               if ((t = Tsearch (tl->TLtree,name)) != NULL)
+                       break;
+       if (t == NULL) {
+               (void) Tinsert (&denyT,name,FALSE);
+               return (SCMOK);
+       }
+       cdprefix (tl->TLprefix);
+       if ((t->Tmode&S_IFMT) == S_IFLNK)
+               x = lstat(name,&sbuf);
+       else
+               x = stat(name,&sbuf);
+       if (x < 0 || (sbuf.st_mode&S_IFMT) != (t->Tmode&S_IFMT)) {
+               (void) Tinsert (&denyT,name,FALSE);
+               return (SCMOK);
+       }
+       switch (t->Tmode&S_IFMT) {
+       case S_IFLNK:
+               if ((x = readlink (name,slinkname,STRINGLENGTH)) <= 0) {
+                       (void) Tinsert (&denyT,name,FALSE);
+                       return (SCMOK);
+               }
+               slinkname[x] = '\0';
+               (void) Tinsert (&t->Tlink,slinkname,FALSE);
+               break;
+       case S_IFREG:
+               if (sbuf.st_nlink > 1 &&
+                   (tlink = linkcheck (t,(int)sbuf.st_dev,(int)sbuf.st_ino)))
+               {
+                       (void) Tinsert (&tlink->Tlink,name,FALSE);
+                       return (SCMOK);
+               }
+               if (update)  t->Tflags |= FUPDATE;
+       case S_IFDIR:
+               t->Tuid = sbuf.st_uid;
+               t->Tgid = sbuf.st_gid;
+               break;
+       default:
+               (void) Tinsert (&denyT,name,FALSE);
+               return (SCMOK);
+       }
+       t->Tflags |= FNEEDED;
+       return (SCMOK);
+}
+
+/*********************************
+ ***    S E N D   F I L E S    ***
+ *********************************/
+
+sendfiles ()
+{
+       int sendone(),senddir(),sendfile();
+       register TREELIST *tl;
+       register int x;
+
+       /* Does the protocol support compression */
+       if (cancompress) {
+               /* Check for compression on sending files */
+               x = msgcompress();
+               if ( x != SCMOK)
+                       goaway ("Error sending compression check to server");
+       }
+       /* send all files */
+       for (tl = listTL; tl != NULL; tl = tl->TLnext) {
+               cdprefix (tl->TLprefix);
+#ifdef CVS
+                if (candorcs) {
+                        cvs_root = getcwd(NULL, 256);
+                        if (access("CVSROOT", F_OK) < 0)
+                                dorcs = FALSE;
+                        else {
+                                loginfo("is a CVSROOT \"%s\"\n", cvs_root);
+                                dorcs = TRUE;
+                        }
+                }
+#endif
+               (void) Tprocess (tl->TLtree,sendone);
+       }
+       /* send directories in reverse order */
+       for (tl = listTL; tl != NULL; tl = tl->TLnext) {
+               cdprefix (tl->TLprefix);
+               (void) Trprocess (tl->TLtree,senddir);
+       }
+       x = msgsend ();
+       if (x != SCMOK)
+               goaway ("Error reading receive file request from client");
+       upgradeT = NULL;
+       x = msgrecv (sendfile,0);
+       if (x != SCMOK)
+               goaway ("Error sending file to client");
+}
+
+sendone (t)
+TREE *t;
+{
+       register int x,fd;
+       register int fdtmp;
+       char temp_file[STRINGLENGTH], rcs_file[STRINGLENGTH];
+        union wait status;
+       char *uconvert(),*gconvert();
+       int sendfile ();
+       int ac;
+       char *av[50];   /* More than enough */
+
+       if ((t->Tflags&FNEEDED) == 0)   /* only send needed files */
+               return (SCMOK);
+       if ((t->Tmode&S_IFMT) == S_IFDIR) /* send no directories this pass */
+               return (SCMOK);
+       x = msgsend ();
+       if (x != SCMOK)  goaway ("Error reading receive file request from client");
+       upgradeT = t;                   /* upgrade file pointer */
+       fd = -1;                        /* no open file */
+       if ((t->Tmode&S_IFMT) == S_IFREG) {
+               if (!listonly && (t->Tflags&FUPDATE) == 0) {
+#ifdef RCS
+                        if (dorcs) {
+                                char rcs_release[STRINGLENGTH];
+
+                               tmpnam(rcs_file);
+                                if (strcmp(&t->Tname[strlen(t->Tname)-2], ",v") == 0) {
+                                        t->Tname[strlen(t->Tname)-2] = '\0';
+                                       ac = 0;
+#ifdef CVS
+                                       av[ac++] = "cvs";
+                                       av[ac++] = "-d";
+                                       av[ac++] = cvs_root;
+                                       av[ac++] = "-r";
+                                       av[ac++] = "-l";
+                                       av[ac++] = "-Q";
+                                       av[ac++] = "co";
+                                       av[ac++] = "-p";
+                                       if (rcs_branch != NULL) {
+                                               av[ac++] = "-r";
+                                               av[ac++] = rcs_branch;
+                                       }
+#else
+                                       av[ac++] = "co";
+                                       av[ac++] = "-q";
+                                       av[ac++] = "-p";
+                                       if (rcs_branch != NULL) {
+                                               sprintf(rcs_release, "-r%s",
+                                                       rcs_branch);
+                                               av[ac++] = rcs_release;
+                                       }
+#endif
+                                       av[ac++] = t->Tname;
+                                       av[ac++] = NULL;
+                                       status.w_status = runio(av,
+                                                               NULL,
+                                                               rcs_file,
+                                                               "/dev/null");
+                                        /*loginfo("using rcs mode \n");*/
+                                        if (status.w_status < 0 || status.w_retcode) {
+                                                /* Just in case */
+                                                unlink(rcs_file);
+                                                if (status.w_status < 0) {
+                                                        goaway ("We died trying to run cvs or rcs");
+                                                        t->Tmode = 0;
+                                                }
+                                                else {
+                                                        /*logerr("rcs command failed = %d\n",
+                                                               status.w_retcode);*/
+                                                        t->Tflags |= FUPDATE;
+                                                }
+                                        }
+                                        else if (docompress) {
+                                                tmpnam(temp_file);
+                                               av[0] = "gzip";
+                                               av[1] = "-c";
+                                               av[2] = NULL;
+                                               if (runio(av, rcs_file, temp_file, NULL) != 0) {
+                                                        /* Just in case */
+                                                        unlink(temp_file);
+                                                        unlink(rcs_file);
+                                                        goaway ("We died trying to gzip a file");
+                                                        t->Tmode = 0;
+                                                }
+                                                fd = open (temp_file,O_RDONLY,0);
+                                        }
+                                        else
+                                                fd = open (rcs_file,O_RDONLY,0);
+                                }
+                        }
+#endif
+                        if (fd == -1) {
+                                if (docompress) {
+                                        tmpnam(temp_file);
+                                       av[0] = "gzip";
+                                       av[1] = "-c";
+                                       av[2] = NULL;
+                                       if (runio(av, t->Tname, temp_file, NULL) != 0) {
+                                                /* Just in case */
+                                                unlink(temp_file);
+                                                goaway ("We died trying to run gzip");
+                                                t->Tmode = 0;
+                                        }
+                                        fd = open (temp_file,O_RDONLY,0);
+                                }
+                                else
+                                        fd = open (t->Tname,O_RDONLY,0);
+                        }
+                       if (fd < 0 && (t->Tflags&FUPDATE) == 0)  t->Tmode = 0;
+               }
+               if (t->Tmode) {
+                       t->Tuser = salloc (uconvert (t->Tuid));
+                       t->Tgroup = salloc (gconvert (t->Tgid));
+               }
+       }
+       x = msgrecv (sendfile,fd);
+       if (docompress)
+               unlink(temp_file);
+#ifdef RCS
+       if (dorcs)
+               unlink(rcs_file);
+#endif
+       if (x != SCMOK)  goaway ("Error sending file to client");
+       return (SCMOK);
+}
+
+senddir (t)
+TREE *t;
+{
+       register int x;
+       char *uconvert(),*gconvert();
+       int sendfile ();
+
+       if ((t->Tflags&FNEEDED) == 0)   /* only send needed files */
+               return (SCMOK);
+       if ((t->Tmode&S_IFMT) != S_IFDIR) /* send only directories this pass */
+               return (SCMOK);
+       x = msgsend ();
+       if (x != SCMOK)  goaway ("Error reading receive file request from client");
+       upgradeT = t;                   /* upgrade file pointer */
+       t->Tuser = salloc (uconvert (t->Tuid));
+       t->Tgroup = salloc (gconvert (t->Tgid));
+       x = msgrecv (sendfile,0);
+       if (x != SCMOK)  goaway ("Error sending file to client");
+       return (SCMOK);
+}
+
+sendfile (t,ap)
+register TREE *t;
+va_list ap;
+{
+       register int x;
+       int fd = va_arg(ap,int);
+       if ((t->Tmode&S_IFMT) != S_IFREG || listonly || (t->Tflags&FUPDATE))
+               return (SCMOK);
+       x = writefile (fd);
+       if (x != SCMOK)  goaway ("Error sending file to client");
+        (void) close (fd);
+       return (SCMOK);
+}
+
+/*****************************************
+ ***    E N D   C O N N E C T I O N    ***
+ *****************************************/
+
+finishup (starttime)
+long starttime;
+{
+       register int x = SCMOK;
+       char tmpbuf[BUFSIZ], *p, lognam[STRINGLENGTH];
+       int logfd;
+       struct stat sbuf;
+       long finishtime;
+       char *releasename;
+
+       (void) netcrypt ((char *)NULL);
+       if (protver < 6) {
+               if (goawayreason != NULL)
+                       free (goawayreason);
+               goawayreason = (char *)NULL;
+               x = msggoaway();
+               doneack = FDONESUCCESS;
+               donereason = salloc ("Unknown");
+       } else if (goawayreason == (char *)NULL)
+               x = msgdone ();
+       else {
+               doneack = FDONEGOAWAY;
+               donereason = goawayreason;
+       }
+       if (x == SCMEOF || x == SCMERR) {
+               doneack = FDONEUSRERROR;
+               donereason = salloc ("Premature EOF on network");
+       } else if (x != SCMOK) {
+               doneack = FDONESRVERROR;
+               donereason = salloc ("Unknown SCM code");
+       }
+       if (doneack == FDONEDONTLOG)
+               return;
+       if (donereason == NULL)
+               donereason = salloc ("No reason");
+       if (doneack == FDONESRVERROR || doneack == FDONEUSRERROR)
+               logerr ("%s", donereason);
+       else if (doneack == FDONEGOAWAY)
+               logerr ("GOAWAY: %s",donereason);
+       else if (doneack != FDONESUCCESS)
+               logerr ("Reason %d:  %s",doneack,donereason);
+       goawayreason = donereason;
+       cdprefix ((char *)NULL);
+       (void) sprintf (lognam,FILELOGFILE,collname);
+       if ((logfd = open(lognam,O_APPEND|O_WRONLY,0644)) < 0)
+               return; /* can not open file up...error */
+       finishtime = time ((long *)NULL);
+       p = tmpbuf;
+       (void) sprintf (p,"%s ",fmttime (lasttime));
+       p += strlen(p);
+       (void) sprintf (p,"%s ",fmttime (starttime));
+       p += strlen(p);
+       (void) sprintf (p,"%s ",fmttime (finishtime));
+       p += strlen(p);
+       if ((releasename = release) == NULL)
+               releasename = "UNKNOWN";
+       (void) sprintf (p,"%s %s %d %s\n",remotehost(),releasename,
+               FDONESUCCESS-doneack,donereason);
+       p += strlen(p);
+#if    MACH
+       /* if we are busy dont get stuck updating the disk if full */
+       if(setupack == FSETUPBUSY) {
+           long l = FIOCNOSPC_ERROR;
+           ioctl(logfd, FIOCNOSPC, &l);
+       }
+#endif /* MACH */
+       (void) write(logfd,tmpbuf,(p - tmpbuf));
+       (void) close(logfd);
+}
+
+/***************************************************
+ ***    H A S H   T A B L E   R O U T I N E S    ***
+ ***************************************************/
+
+Hfree (table)
+HASH **table;
+{
+       register HASH *h;
+       register int i;
+       for (i = 0; i < HASHSIZE; i++)
+               while (h = table[i]) {
+                       table[i] = h->Hnext;
+                       if (h->Hname)  free (h->Hname);
+                       free ((char *)h);
+               }
+}
+
+HASH *Hlookup (table,num1,num2)
+HASH **table;
+int num1,num2;
+{
+       register HASH *h;
+       register int hno;
+       hno = HASHFUNC(num1,num2);
+       for (h = table[hno]; h && (h->Hnum1 != num1 || h->Hnum2 != num2); h = h->Hnext);
+       return (h);
+}
+
+Hinsert (table,num1,num2,name,tree)
+HASH **table;
+int num1,num2;
+char *name;
+TREE *tree;
+{
+       register HASH *h;
+       register int hno;
+       hno = HASHFUNC(num1,num2);
+       h = (HASH *) malloc (sizeof(HASH));
+       h->Hnum1 = num1;
+       h->Hnum2 = num2;
+       h->Hname = name;
+       h->Htree = tree;
+       h->Hnext = table[hno];
+       table[hno] = h;
+}
+
+/*********************************************
+ ***    U T I L I T Y   R O U T I N E S    ***
+ *********************************************/
+
+TREE *linkcheck (t,d,i)
+TREE *t;
+int d,i;                       /* inode # and device # */
+{
+       register HASH *h;
+       h = Hlookup (inodeH,i,d);
+       if (h)  return (h->Htree);
+       Hinsert (inodeH,i,d,(char *)NULL,t);
+       return ((TREE *)NULL);
+}
+
+char *uconvert (uid)
+int uid;
+{
+       register struct passwd *pw;
+       register char *p;
+       register HASH *u;
+       u = Hlookup (uidH,uid,0);
+       if (u)  return (u->Hname);
+       pw = getpwuid (uid);
+       if (pw == NULL)  return ("");
+       p = salloc (pw->pw_name);
+       Hinsert (uidH,uid,0,p,(TREE*)NULL);
+       return (p);
+}
+
+char *gconvert (gid)
+int gid;
+{
+       register struct group *gr;
+       register char *p;
+       register HASH *g;
+       g = Hlookup (gidH,gid,0);
+       if (g)  return (g->Hname);
+       gr = getgrgid (gid);
+       if (gr == NULL)  return ("");
+       p = salloc (gr->gr_name);
+       Hinsert (gidH,gid,0,p,(TREE *)NULL);
+       return (p);
+}
+
+char *changeuid (namep,passwordp,fileuid,filegid)
+char *namep,*passwordp;
+int fileuid,filegid;
+{
+       char *okpassword ();
+       char *group,*account,*pswdp;
+       struct passwd *pwd;
+       struct group *grp;
+#if    CMUCS
+       struct account *acc;
+       struct ttyloc tlc;
+#endif /* CMUCS */
+       register int status = ACCESS_CODE_OK;
+       char nbuf[STRINGLENGTH];
+       static char errbuf[STRINGLENGTH];
+#if    CMUCS
+       int *grps;
+#endif /* CMUCS */
+       char *p;
+
+       if (namep == NULL) {
+               pwd = getpwuid (fileuid);
+               if (pwd == NULL) {
+                       (void) sprintf (errbuf,"Reason:  Unknown user id %d",
+                               fileuid);
+                       return (errbuf);
+               }
+               grp = getgrgid (filegid);
+               if (grp)  group = strcpy (nbuf,grp->gr_name);
+               else  group = NULL;
+               account = NULL;
+               pswdp = NULL;
+       } else {
+               (void) strcpy (nbuf,namep);
+               account = group = index (nbuf,',');
+               if (group != NULL) {
+                       *group++ = '\0';
+                       account = index (group,',');
+                       if (account != NULL) {
+                               *account++ = '\0';
+                               if (*account == '\0')  account = NULL;
+                       }
+                       if (*group == '\0')  group = NULL;
+               }
+               pwd = getpwnam (nbuf);
+               if (pwd == NULL) {
+                       (void) sprintf (errbuf,"Reason:  Unknown user %s",
+                               nbuf);
+                       return (errbuf);
+               }
+               if (strcmp (nbuf,DEFUSER) == 0)
+                       pswdp = NULL;
+               else
+                       pswdp = passwordp ? passwordp : "";
+#ifdef AFS
+                if (strcmp (nbuf,DEFUSER) != 0) {
+                        char *reason;
+                        setpag(); /* set a pag */
+                        if (ka_UserAuthenticate(pwd->pw_name, "", 0,
+                                                pswdp, 1, &reason)) {
+                                (void) sprintf (errbuf,"AFS authentication failed, %s",
+                                                reason);
+                                logerr ("Attempt by %s; %s",
+                                        nbuf, errbuf);
+                                return (errbuf);
+                        }
+                }
+#endif
+       }
+       if (getuid () != 0) {
+               if (getuid () == pwd->pw_uid)
+                       return (NULL);
+               if (strcmp (pwd->pw_name,DEFUSER) == 0)
+                       return (NULL);
+               logerr ("Fileserver not superuser");
+               return ("Reason:  fileserver is not running privileged");
+       }
+#if    CMUCS
+       tlc.tlc_hostid = TLC_UNKHOST;
+       tlc.tlc_ttyid = TLC_UNKTTY;
+       if (okaccess(pwd->pw_name,ACCESS_TYPE_SU,0,-1,tlc) != 1)
+               status = ACCESS_CODE_DENIED;
+       else {
+               grp = NULL;
+               acc = NULL;
+               status = oklogin(pwd->pw_name,group,&account,pswdp,&pwd,&grp,&acc,&grps);
+               if (status == ACCESS_CODE_OK) {
+                       if ((p = okpassword(pswdp,pwd->pw_name,pwd->pw_gecos)) != NULL)
+                               status = ACCESS_CODE_INSECUREPWD;
+               }
+       }
+#else  /* CMUCS */
+       status = ACCESS_CODE_OK;
+       if (namep && strcmp(pwd->pw_name, DEFUSER) != 0)
+               if (strcmp(pwd->pw_passwd,(char *)crypt(pswdp,pwd->pw_passwd)))
+                       status = ACCESS_CODE_BADPASSWORD;
+#endif /* CMUCS */
+       switch (status) {
+       case ACCESS_CODE_OK:
+               break;
+       case ACCESS_CODE_BADPASSWORD:
+               p = "Reason:  Invalid password";
+               break;
+#if    CMUCS
+       case ACCESS_CODE_INSECUREPWD:
+               (void) sprintf (errbuf,"Reason:  %s",p);
+               p = errbuf;
+               break;
+       case ACCESS_CODE_DENIED:
+               p = "Reason:  Access denied";
+               break;
+       case ACCESS_CODE_NOUSER:
+               p = errbuf;
+               break;
+       case ACCESS_CODE_ACCEXPIRED:
+               p = "Reason:  Account expired";
+               break;
+       case ACCESS_CODE_GRPEXPIRED:
+               p = "Reason:  Group expired";
+               break;
+       case ACCESS_CODE_ACCNOTVALID:
+               p = "Reason:  Invalid account";
+               break;
+       case ACCESS_CODE_MANYDEFACC:
+               p = "Reason:  User has more than one default account";
+               break;
+       case ACCESS_CODE_NOACCFORGRP:
+               p = "Reason:  No account for group";
+               break;
+       case ACCESS_CODE_NOGRPFORACC:
+               p = "Reason:  No group for account";
+               break;
+       case ACCESS_CODE_NOGRPDEFACC:
+               p = "Reason:  No group for default account";
+               break;
+       case ACCESS_CODE_NOTGRPMEMB:
+               p = "Reason:  Not member of group";
+               break;
+       case ACCESS_CODE_NOTDEFMEMB:
+               p = "Reason:  Not member of default group";
+               break;
+       case ACCESS_CODE_OOPS:
+               p = "Reason:  Internal error";
+               break;
+#endif /* CMUCS */
+       default:
+               (void) sprintf (p = errbuf,"Reason:  Status %d",status);
+               break;
+       }
+       if (pwd == NULL)
+               return (p);
+       if (status != ACCESS_CODE_OK) {
+               logerr ("Login failure for %s",pwd->pw_name);
+               logerr ("%s",p);
+#if    CMUCS
+               logaccess (pwd->pw_name,ACCESS_TYPE_SUP,status,0,-1,tlc);
+#endif /* CMUCS */
+               return (p);
+       }
+#if    CMUCS
+       if (setgroups (grps[0], &grps[1]) < 0)
+               logerr ("setgroups: %%m");
+       if (setgid ((gid_t)grp->gr_gid) < 0)
+               logerr ("setgid: %%m");
+       if (setuid ((uid_t)pwd->pw_uid) < 0)
+               logerr ("setuid: %%m");
+#else   /* CMUCS */
+       if (initgroups (pwd->pw_name,pwd->pw_gid) < 0)
+               return("Error setting group list");
+       if (setgid (pwd->pw_gid) < 0)
+               logerr ("setgid: %%m");
+       if (setuid (pwd->pw_uid) < 0)
+               logerr ("setuid: %%m");
+#endif /* CMUCS */
+       return (NULL);
+}
+
+#if __STDC__
+goaway (char *fmt,...)
+#else
+/*VARARGS*//*ARGSUSED*/
+goaway (va_alist)
+va_dcl
+#endif
+{
+#if !__STDC__
+       register char *fmt;
+#endif
+       char buf[STRINGLENGTH];
+       va_list ap;
+
+       (void) netcrypt ((char *)NULL);
+#if __STDC__
+       va_start(ap,fmt);
+#else
+       va_start(ap);
+       fmt = va_arg(ap,char *);
+#endif
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+       goawayreason = salloc (buf);
+       (void) msggoaway ();
+       logerr ("%s",buf);
+       longjmp (sjbuf,TRUE);
+}
+
+char *fmttime (time)
+long time;
+{
+       static char buf[STRINGLENGTH];
+       int len;
+
+       (void) strcpy (buf,ctime (&time));
+       len = strlen(buf+4)-6;
+       (void) strncpy (buf,buf+4,len);
+       buf[len] = '\0';
+       return (buf);
+}
+
+/*
+ * Determine whether the file referenced by the file descriptor 'handle' can
+ * be trusted, namely is it a file resident in the local file system.
+ *
+ * The main method of operation is to perform operations on the file
+ * descriptor so that an attempt to spoof the checks should fail, for
+ * example renamimg the file from underneath us and/or changing where the
+ * file lives from underneath us.
+ *
+ * returns: -1 for error, indicating that we can not tell
+ *          0 for file is definately not local, or it is an RFS link
+ *          1 for file is local and can be trusted
+ *
+ * Side effect: copies the stat information into the supplied buffer,
+ * regardless of the type of file system the file resides.
+ *
+ * Currently, the cases that we try to distinguish are RFS, AFS, NFS and
+ * UFS, where the latter is considered a trusted file.  We assume that the
+ * caller has disabled link following and will detect an attempt to access
+ * a file through an RFS link, except in the case the the last component is
+ * an RFS link.  With link following disabled, the last component itself is
+ * interpreted as a regular file if it is really an RFS link, so we
+ * disallow the RFS link identified by group "symlink" and mode "IEXEC by
+ * owner only". An AFS file is
+ * detected by trying the VIOCIGETCELL ioctl, which is one of the few AFS
+ * ioctls which operate on a file descriptor.  Note, this AFS ioctl is
+ * implemented in the cache manager, so the decision does not involve a
+ * query with the AFS file server.  An NFS file is detected by looking at
+ * the major device number and seeing if it matches the known values for
+ * MACH NSF/Sun OS 3.x or Sun OS 4.x.
+ *
+ * Having the fstatfs() system call would make this routine easier and
+ * more reliable.
+ *
+ * Note, in order to make the checks simpler, the file referenced by the
+ * file descriptor can not be a BSD style symlink.  Even with symlink
+ * following of the last path component disabled, the attempt to open a
+ * file which is a symlink will succeed, so we check for the BSD symlink
+ * file type here.  Also, the link following on/off and RFS file types
+ * are only relevant in a MACH environment. 
+ */
+#ifdef AFS
+#include <sys/viceioctl.h>
+#endif
+
+#define SYMLINK_GRP 64
+
+int local_file(handle, sinfo)
+int handle;
+struct stat *sinfo;
+{
+       struct stat sb;
+#ifdef VIOCIGETCELL
+       /*
+        * dummies for the AFS ioctl
+        */
+       struct ViceIoctl vdata;
+       char cellname[512];
+#endif /* VIOCIGETCELL */
+
+       if (fstat(handle, &sb) < 0)
+               return(-1);
+       if (sinfo != NULL)
+               *sinfo = sb;
+
+#if    CMUCS
+       /*
+        * If the following test succeeds, then the file referenced by
+        * 'handle' is actually an RFS link, so we will not trust it.
+        * See <sys/inode.h>.
+        */
+       if (sb.st_gid == SYMLINK_GRP
+               && (sb.st_mode & (S_IFMT|S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)))
+                       == (S_IFREG|S_IEXEC))
+               return(0);
+#endif /* CMUCS */
+
+       /*
+        * Do not trust BSD style symlinks either.
+        */
+       if ((sb.st_mode & S_IFMT) == S_IFLNK)
+               return(0);
+
+#ifdef VIOCIGETCELL
+       /*
+        * This is the VIOCIGETCELL ioctl, which takes an fd, not
+        * a path name.  If it succeeds, then the file is in AFS.
+        *
+        * On failure, ENOTTY indicates that the file was not in
+        * AFS; all other errors are pessimistically assumed to be
+        * a temporary AFS error.
+        */
+       vdata.in_size = 0;
+       vdata.out_size = sizeof(cellname);
+       vdata.out = cellname;
+       if (ioctl(handle, VIOCIGETCELL, (char *)&vdata) != -1)
+               return(0);
+       if (errno != ENOTTY)
+               return(-1);
+#endif /* VIOCIGETCELL */
+
+       /*
+        * Verify the file is not in NFS.
+        *
+        * Our current implementation and Sun OS 3.x use major device
+        * 255 for NFS files; Sun OS 4.x seems to use 130 (I have only
+        * determined this empirically -- DLC).  Without a fstatfs()
+        * system call, this will have to do for now.
+        */
+       if (major(sb.st_dev) == 255 || major(sb.st_dev) == 130)
+               return(0);
+
+       return(1);
+}
+
+/*
+ * Companion routine for ensuring that a local file can be trusted.  Compare
+ * various pieces of the stat information to make sure that the file can be
+ * trusted.  Returns true for stat information which meets the criteria
+ * for being trustworthy.  The main paranoia is to prevent a hard link to
+ * a root owned file.  Since the link could be removed after the file is
+ * opened, a simply fstat() can not be relied upon.  The two stat buffers
+ * for comparison should come from a stat() on the file name and a following
+ * fstat() on the open file.  Some of the following checks are also an
+ * additional level of paranoia.  Also, this test will fail (correctly) if
+ * either or both of the stat structures have all fields zeroed; typically
+ * due to a stat() failure.
+ */
+
+
+int stat_info_ok(sb1, sb2)
+struct stat *sb1, *sb2;
+{
+    return (sb1->st_ino == sb2->st_ino &&      /* Still the same file */
+           sb1->st_dev == sb2->st_dev &&       /* On the same device */
+           sb1->st_mode == sb2->st_mode &&     /* Perms (and type) same */
+           (sb1->st_mode & S_IFMT) == S_IFREG && /* Only allow reg files */
+           (sb1->st_mode & 077) == 0 &&        /* Owner only perms */
+           sb1->st_nlink == sb2->st_nlink &&   /* # hard links same... */
+           sb1->st_nlink == 1 &&               /* and only 1 */
+           sb1->st_uid == sb2->st_uid &&       /* owner and ... */
+           sb1->st_gid == sb2->st_gid &&       /* group unchanged */
+           sb1->st_mtime == sb2->st_mtime &&   /* Unmodified between stats */
+           sb1->st_ctime == sb2->st_ctime);    /* Inode unchanged.  Hopefully
+                                                  a catch-all paranoid test */
+}
+
+#if MACH
+/*
+ * Twiddle symbolic/RFS link following on/off.  This is a no-op in a non
+ * CMUCS/MACH environment.  Also, the setmodes/getmodes interface is used
+ * mainly because it is simpler than using table(2) directly.
+ */
+#include <sys/table.h>
+
+int link_nofollow(on)
+int on;
+{
+       static int modes = -1;
+
+       if (modes == -1 && (modes = getmodes()) == -1)
+               return(-1);
+       if (on)
+               return(setmodes(modes | UMODE_NOFOLLOW));
+       return(setmodes(modes));
+}
+#else  /* MACH */
+/*ARGSUSED*/
+int link_nofollow(on)
+int on;
+{
+       return(0);
+}
+#endif /* MACH */
diff --git a/usr.bin/sup/src/supmsg.c b/usr.bin/sup/src/supmsg.c
new file mode 100644 (file)
index 0000000..21b4991
--- /dev/null
@@ -0,0 +1,625 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ **********************************************************************
+ * HISTORY
+ *
+ * 7-July-93  Nate Williams at Montana State University
+ *     Modified SUP to use gzip based compression when sending files
+ *     across the network to save BandWidth
+ *
+ * $Log: supmsg.c,v $
+ * Revision 1.1  1995/12/16 11:47:00  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.2  1993/08/04 17:46:23  brezak
+ * Changes from nate for gzip'ed sup
+ *
+ * Revision 1.1.1.1  1993/05/21  14:52:19  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 2.4  92/09/09  22:05:17  mrt
+ *     Moved PFI definition under __STDC__ conditional since it
+ *     is already defined in libc.h in this case.
+ *     [92/09/01            mrt]
+ * 
+ * Revision 2.3  92/08/11  12:08:12  mrt
+ *     Added copyright
+ *     [92/08/10            mrt]
+ *     Brad's changes: Delinted, Incorporated updated variable 
+ *     argument list usage from old msgxfer.c
+ *     [92/07/24            mrt]
+ * 
+ * Revision 2.2  89/08/23  15:02:56  gm0w
+ *     Created from separate message modules.
+ *     [89/08/14            gm0w]
+ * 
+ **********************************************************************
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <libc.h>
+#include <c.h>
+#include "sup.h"
+#define MSGSUBR
+#define MSGFILE
+#include "supmsg.h"
+
+/*
+ * signon message
+ */
+extern int     pgmver;                 /* program version of partner */
+extern int     pgmversion;             /* my program version */
+extern char    *scmver;                /* scm version of partner */
+extern int     fspid;                  /* process id of fileserver */
+
+int msgsignon ()
+{
+       register int x;
+
+       if (server) {
+               x = readmsg (MSGSIGNON);
+               if (x == SCMOK)  x = readint (&protver);
+               if (x == SCMOK)  x = readint (&pgmver);
+               if (x == SCMOK)  x = readstring (&scmver);
+               if (x == SCMOK)  x = readmend ();
+       } else {
+               x = writemsg (MSGSIGNON);
+               if (x == SCMOK)  x = writeint (PROTOVERSION);
+               if (x == SCMOK)  x = writeint (pgmversion);
+               if (x == SCMOK)  x = writestring (scmversion);
+               if (x == SCMOK)  x = writemend ();
+       }
+       return (x);
+}
+
+int msgsignonack ()
+{
+       register int x;
+
+       if (server) {
+               x = writemsg (MSGSIGNONACK);
+               if (x == SCMOK)  x = writeint (PROTOVERSION);
+               if (x == SCMOK)  x = writeint (pgmversion);
+               if (x == SCMOK)  x = writestring (scmversion);
+               if (x == SCMOK)  x = writeint (fspid);
+               if (x == SCMOK)  x = writemend ();
+       } else {
+               x = readmsg (MSGSIGNONACK);
+               if (x == SCMOK)  x = readint (&protver);
+               if (x == SCMOK)  x = readint (&pgmver);
+               if (x == SCMOK)  x = readstring (&scmver);
+               if (x == SCMOK)  x = readint (&fspid);
+               if (x == SCMOK)  x = readmend ();
+       }
+       return (x);
+}
+
+/*
+ * setup message
+ */
+extern int     xpatch;                 /* setup crosspatch to a new client */
+extern char    *xuser;                 /* user,group,acct for crosspatch */
+extern char    *collname;              /* base directory */
+extern char    *basedir;               /* base directory */
+extern int     basedev;                /* base directory device */
+extern int     baseino;                /* base directory inode */
+extern long    lasttime;               /* time of last upgrade */
+extern int     listonly;               /* only listing files, no data xfer */
+extern int     newonly;                /* only send new files */
+extern char    *release;               /* release name */
+extern int     setupack;               /* ack return value for setup */
+
+int msgsetup ()
+{
+       register int x;
+
+       if (server) {
+               x = readmsg (MSGSETUP);
+               if (x != SCMOK)  return (x);
+               if (protver >= 7) {
+                       x = readint (&xpatch);
+                       if (x != SCMOK)  return (x);
+               } else
+                       xpatch = FALSE;
+               if (xpatch) {
+                       x = readstring (&xuser);
+                       if (x != SCMOK)  return (x);
+                       return (readmend ());
+               }
+               x = readstring (&collname);
+               if (x == SCMOK)  x = readint ((int *)&lasttime);
+               if (x == SCMOK)  x = readstring (&basedir);
+               if (x == SCMOK)  x = readint (&basedev);
+               if (x == SCMOK)  x = readint (&baseino);
+               if (x == SCMOK)  x = readint (&listonly);
+               if (x == SCMOK)  x = readint (&newonly);
+               if (x == SCMOK)
+                       if (protver < 6)
+                               release = (char *)NULL;
+                       else
+                               x = readstring (&release);
+               if (x == SCMOK)  x = readmend ();
+       } else {
+               x = writemsg (MSGSETUP);
+               if (x != SCMOK)  return (x);
+               if (protver >= 7) {
+                       x = writeint (xpatch);
+                       if (x != SCMOK)  return (x);
+               }
+               if (xpatch) {
+                       x = writestring (xuser);
+                       if (x != SCMOK)  return (x);
+                       return (writemend ());
+               }
+               if (x == SCMOK)  x = writestring (collname);
+               if (x == SCMOK)  x = writeint ((int)lasttime);
+               if (x == SCMOK)  x = writestring (basedir);
+               if (x == SCMOK)  x = writeint (basedev);
+               if (x == SCMOK)  x = writeint (baseino);
+               if (x == SCMOK)  x = writeint (listonly);
+               if (x == SCMOK)  x = writeint (newonly);
+               if (x == SCMOK && protver >= 6)  x = writestring (release);
+               if (x == SCMOK)  x = writemend ();
+       }
+       return (x);
+}
+
+int msgsetupack ()
+{
+       if (server)
+               return (writemint (MSGSETUPACK,setupack));
+       return (readmint (MSGSETUPACK,&setupack));
+}
+
+/*
+ * crypt test message
+ */
+extern char    *crypttest;             /* encryption test string */
+
+int msgcrypt ()
+{
+       if (server)
+               return (readmstr (MSGCRYPT,&crypttest));
+       return (writemstr (MSGCRYPT,crypttest));
+}
+
+int msgcryptok ()
+{
+       if (server)
+               return (writemnull (MSGCRYPTOK));
+       return (readmnull (MSGCRYPTOK));
+}
+
+/*
+ * login message
+ */
+extern char    *logcrypt;              /* login encryption test */
+extern char    *loguser;               /* login username */
+extern char    *logpswd;               /* password for login */
+extern int     logack;                 /* login ack status */
+extern char    *logerror;              /* error from login */
+
+int msglogin ()
+{
+       register int x;
+       if (server) {
+               x = readmsg (MSGLOGIN);
+               if (x == SCMOK)  x = readstring (&logcrypt);
+               if (x == SCMOK)  x = readstring (&loguser);
+               if (x == SCMOK)  x = readstring (&logpswd);
+               if (x == SCMOK)  x = readmend ();
+       } else {
+               x = writemsg (MSGLOGIN);
+               if (x == SCMOK)  x = writestring (logcrypt);
+               if (x == SCMOK)  x = writestring (loguser);
+               if (x == SCMOK)  x = writestring (logpswd);
+               if (x == SCMOK)  x = writemend ();
+       }
+       return (x);
+}
+
+int msglogack ()
+{
+       register int x;
+       if (server) {
+               x = writemsg (MSGLOGACK);
+               if (x == SCMOK)  x = writeint (logack);
+               if (x == SCMOK)  x = writestring (logerror);
+               if (x == SCMOK)  x = writemend ();
+       } else {
+               x = readmsg (MSGLOGACK);
+               if (x == SCMOK)  x = readint (&logack);
+               if (x == SCMOK)  x = readstring (&logerror);
+               if (x == SCMOK)  x = readmend ();
+       }
+       return (x);
+}
+
+/*
+ * refuse list message
+ */
+extern TREE    *refuseT;               /* tree of files to refuse */
+
+static int refuseone (t)
+register TREE *t;
+{
+       return (writestring (t->Tname));
+}
+
+int msgrefuse ()
+{
+       register int x;
+       if (server) {
+               char *name;
+               x = readmsg (MSGREFUSE);
+               if (x == SCMOK)  x = readstring (&name);
+               while (x == SCMOK) {
+                       if (name == NULL)  break;
+                       (void) Tinsert (&refuseT,name,FALSE);
+                       free (name);
+                       x = readstring (&name);
+               }
+               if (x == SCMOK)  x = readmend ();
+       } else {
+               x = writemsg (MSGREFUSE);
+               if (x == SCMOK)  x = Tprocess (refuseT,refuseone);
+               if (x == SCMOK)  x = writestring ((char *)NULL);
+               if (x == SCMOK)  x = writemend ();
+       }
+       return (x);
+}
+
+/*
+ * list files message
+ */
+extern TREE    *listT;                 /* tree of files to list */
+extern long    scantime;               /* time that collection was scanned */
+
+static int listone (t)
+register TREE *t;
+{
+       register int x;
+
+       x = writestring (t->Tname);
+       if (x == SCMOK)  x = writeint ((int)t->Tmode);
+       if (x == SCMOK)  x = writeint ((int)t->Tflags);
+       if (x == SCMOK)  x = writeint (t->Tmtime);
+       return (x);
+}
+
+int msglist ()
+{
+       register int x;
+       if (server) {
+               x = writemsg (MSGLIST);
+               if (x == SCMOK)  x = Tprocess (listT,listone);
+               if (x == SCMOK)  x = writestring ((char *)NULL);
+               if (x == SCMOK)  x = writeint ((int)scantime);
+               if (x == SCMOK)  x = writemend ();
+       } else {
+               char *name;
+               int mode,flags,mtime;
+               register TREE *t;
+               x = readmsg (MSGLIST);
+               if (x == SCMOK)  x = readstring (&name);
+               while (x == SCMOK) {
+                       if (name == NULL)  break;
+                       x = readint (&mode);
+                       if (x == SCMOK)  x = readint (&flags);
+                       if (x == SCMOK)  x = readint (&mtime);
+                       if (x != SCMOK)  break;
+                       t = Tinsert (&listT,name,TRUE);
+                       free (name);
+                       t->Tmode = mode;
+                       t->Tflags = flags;
+                       t->Tmtime = mtime;
+                       x = readstring (&name);
+               }
+               if (x == SCMOK)  x = readint ((int *)&scantime);
+               if (x == SCMOK)  x = readmend ();
+       }
+       return (x);
+}
+
+/*
+ * files needed message
+ */
+extern TREE    *needT;                 /* tree of files to need */
+
+static int needone (t)
+register TREE *t;
+{
+       register int x;
+       x = writestring (t->Tname);
+       if (x == SCMOK)  x = writeint ((t->Tflags&FUPDATE) != 0);
+       return (x);
+}
+
+int msgneed ()
+{
+       register int x;
+       if (server) {
+               char *name;
+               int update;
+               register TREE *t;
+               x = readmsg (MSGNEED);
+               if (x == SCMOK)  x = readstring (&name);
+               while (x == SCMOK) {
+                       if (name == NULL)  break;
+                       x = readint (&update);
+                       if (x != SCMOK)  break;
+                       t = Tinsert (&needT,name,TRUE);
+                       free (name);
+                       if (update)  t->Tflags |= FUPDATE;
+                       x = readstring (&name);
+               }
+               if (x == SCMOK)  x = readmend ();
+       } else {
+               x = writemsg (MSGNEED);
+               if (x == SCMOK)  x = Tprocess (needT,needone);
+               if (x == SCMOK)  x = writestring ((char *)NULL);
+               if (x == SCMOK)  x = writemend ();
+       }
+       return (x);
+}
+
+/*
+ * files denied message
+ */
+extern TREE    *denyT;                 /* tree of files to deny */
+
+static int denyone (t)
+register TREE *t;
+{
+       return (writestring (t->Tname));
+}
+
+int msgdeny ()
+{
+       register int x;
+       if (server) {
+               x = writemsg (MSGDENY);
+               if (x == SCMOK)  x = Tprocess (denyT,denyone);
+               if (x == SCMOK)  x = writestring ((char *)NULL);
+               if (x == SCMOK)  x = writemend ();
+       } else {
+               char *name;
+               x = readmsg (MSGDENY);
+               if (x == SCMOK)  x = readstring (&name);
+               while (x == SCMOK) {
+                       if (name == NULL)  break;
+                       (void) Tinsert (&denyT,name,FALSE);
+                       free (name);
+                       x = readstring (&name);
+               }
+               if (x == SCMOK)  x = readmend ();
+       }
+       return (x);
+}
+
+/*
+ * send file message
+ */
+int msgsend ()
+{
+       if (server)
+               return (readmnull (MSGSEND));
+       return (writemnull (MSGSEND));
+}
+
+/*
+ * receive file message
+ */
+extern TREE    *upgradeT;              /* pointer to file being upgraded */
+
+static int writeone (t)
+register TREE *t;
+{
+       return (writestring (t->Tname));
+}
+
+
+#if __STDC__
+int msgrecv (PFI xferfile,...)
+#else
+/*VARARGS*//*ARGSUSED*/
+int msgrecv (va_alist)
+va_dcl
+#endif
+{
+#if !__STDC__
+       typedef int (*PFI)();
+       PFI xferfile;
+#endif
+       va_list args;
+       register int x;
+       register TREE *t = upgradeT;
+#if __STDC__
+       va_start(args,xferfile);
+#else
+       va_start(args);
+       xferfile = va_arg(args, PFI);
+#endif
+       if (server) {
+               x = writemsg (MSGRECV);
+               if (t == NULL) {
+                       if (x == SCMOK)  x = writestring ((char *)NULL);
+                       if (x == SCMOK)  x = writemend ();
+                       return (x);
+               }
+               if (x == SCMOK)  x = writestring (t->Tname);
+               if (x == SCMOK)  x = writeint (t->Tmode);
+               if (t->Tmode == 0) {
+                       if (x == SCMOK)  x = writemend ();
+                       return (x);
+               }
+               if (x == SCMOK)  x = writeint (t->Tflags);
+               if (x == SCMOK)  x = writestring (t->Tuser);
+               if (x == SCMOK)  x = writestring (t->Tgroup);
+               if (x == SCMOK)  x = writeint (t->Tmtime);
+               if (x == SCMOK)  x = Tprocess (t->Tlink,writeone);
+               if (x == SCMOK)  x = writestring ((char *)NULL);
+               if (x == SCMOK)  x = Tprocess (t->Texec,writeone);
+               if (x == SCMOK)  x = writestring ((char *)NULL);
+               if (x == SCMOK)  x = (*xferfile) (t,args);
+               if (x == SCMOK)  x = writemend ();
+       } else {
+               char *linkname,*execcmd;
+               if (t == NULL)  return (SCMERR);
+               x = readmsg (MSGRECV);
+               if (x == SCMOK)  x = readstring (&t->Tname);
+               if (x == SCMOK && t->Tname == NULL) {
+                       x = readmend ();
+                       if (x == SCMOK)  x = (*xferfile) (NULL,args);
+                       return (x);
+               }
+               if (x == SCMOK)  x = readint (&t->Tmode);
+               if (t->Tmode == 0) {
+                       x = readmend ();
+                       if (x == SCMOK)  x = (*xferfile) (t,args);
+                       return (x);
+               }
+               if (x == SCMOK)  x = readint (&t->Tflags);
+               if (x == SCMOK)  x = readstring (&t->Tuser);
+               if (x == SCMOK)  x = readstring (&t->Tgroup);
+               if (x == SCMOK)  x = readint (&t->Tmtime);
+               t->Tlink = NULL;
+               if (x == SCMOK)  x = readstring (&linkname);
+               while (x == SCMOK) {
+                       if (linkname == NULL)  break;
+                       (void) Tinsert (&t->Tlink,linkname,FALSE);
+                       free (linkname);
+                       x = readstring (&linkname);
+               }
+               t->Texec = NULL;
+               if (x == SCMOK)  x = readstring (&execcmd);
+               while (x == SCMOK) {
+                       if (execcmd == NULL)  break;
+                       (void) Tinsert (&t->Texec,execcmd,FALSE);
+                       free (execcmd);
+                       x = readstring (&execcmd);
+               }
+               if (x == SCMOK)  x = (*xferfile) (t,args);
+               if (x == SCMOK)  x = readmend ();
+       }
+       va_end(args);
+       return (x);
+}
+
+/*
+ * protocol done message
+ */
+extern int     doneack;
+extern char    *donereason;
+
+int msgdone ()
+{
+       register int x;
+
+       if (protver < 6) {
+               printf ("Error, msgdone should not have been called.");
+               return (SCMERR);
+       }
+       if (server) {
+               x = readmsg (MSGDONE);
+               if (x == SCMOK)  x = readint (&doneack);
+               if (x == SCMOK)  x = readstring (&donereason);
+               if (x == SCMOK)  x = readmend ();
+       } else {
+               x = writemsg (MSGDONE);
+               if (x == SCMOK)  x = writeint (doneack);
+               if (x == SCMOK)  x = writestring (donereason);
+               if (x == SCMOK)  x = writemend ();
+       }
+       return (x);
+}
+
+/*
+ * go away message
+ */
+extern char    *goawayreason;          /* reason for goaway */
+
+int msggoaway ()
+{
+       return (writemstr (MSGGOAWAY,goawayreason));
+}
+
+/*
+ * cross-patch protocol message
+ */
+extern int     xargc;                  /* arg count for crosspatch */
+extern char    **xargv;                /* arg array for crosspatch */
+
+int msgxpatch ()
+{
+       register int x;
+       register int i;
+
+       if (server) {
+               x = readmsg (MSGXPATCH);
+               if (x != SCMOK)  return (x);
+               x = readint (&xargc);
+               if (x != SCMOK)  return (x);
+               xargc += 2;
+               xargv = (char **)calloc (sizeof (char *),(unsigned)xargc+1);
+               if (xargv == NULL)
+                       return (SCMERR);
+               for (i = 2; i < xargc; i++) {
+                       x = readstring (&xargv[i]);
+                       if (x != SCMOK)  return (x);
+               }
+               x = readmend ();
+       } else {
+               x = writemsg (MSGXPATCH);
+               if (x != SCMOK)  return (x);
+               x = writeint (xargc);
+               if (x != SCMOK)  return (x);
+               for (i = 0; i < xargc; i++) {
+                       x = writestring (xargv[i]);
+                       if (x != SCMOK)  return (x);
+               }
+               x = writemend ();
+       }
+       return (x);
+}
+
+/*
+ * Compression check protocol message
+ */
+extern int     docompress;             /* Compress file before sending? */
+
+int msgcompress ()
+{
+       if (server)
+               return (readmint (MSGCOMPRESS,&docompress));
+       return (writemint (MSGCOMPRESS, docompress));
+}
diff --git a/usr.bin/sup/src/supmsg.h b/usr.bin/sup/src/supmsg.h
new file mode 100644 (file)
index 0000000..d4da853
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * supmsg.h - global definitions/variables used in msg routines.
+ *
+ **********************************************************************
+ * HISTORY
+ *
+ * 7-July-93  Nate Williams at Montana State University
+ *     Modified SUP to use gzip based compression when sending files
+ *     across the network to save BandWidth
+ *
+ * $Log: supmsg.h,v $
+ * Revision 1.1  1995/12/16 11:47:01  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.2  1993/08/04 17:46:24  brezak
+ * Changes from nate for gzip'ed sup
+ *
+ * Revision 1.1.1.1  1993/05/21  14:52:19  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.7  92/08/11  12:08:20  mrt
+ *     Added copyright.
+ *     [92/08/10            mrt]
+ * 
+ * Revision 1.6  89/08/23  14:56:42  gm0w
+ *     Changed MSGF to MSG constants.
+ *     [89/08/23            gm0w]
+ * 
+ * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added crosspatch support.  Removed nameserver support.
+ *
+ * 29-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added "release" support.
+ *
+ * 27-May-87  Doug Philips (dwp) at Carnegie-Mellon University
+ *     Added MSGFDONE and subvalues, added doneack and donereason.
+ *
+ * 20-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added changes to make lint happy.
+ *
+ * 04-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changed hostname to hostT to support multiple repositories per
+ *     collection.  Added FSETUPBUSY to tell clients that server is
+ *     currently busy.
+ *
+ * 19-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Created.
+ *
+ **********************************************************************
+ */
+
+/* Special messages reserved for SCM */
+#define MSGGOAWAY      (-1)            /* see scm.c */
+
+/* Message types -- see supmsg.c */
+#define MSGSIGNON      (101)
+#define MSGSIGNONACK   (102)
+#define MSGSETUP       (103)
+#define MSGSETUPACK    (104)
+#define MSGLOGIN       (105)
+#define MSGLOGACK      (106)
+#define MSGCRYPT       (107)
+#define MSGCRYPTOK     (108)
+#define MSGREFUSE      (109)
+#define MSGLIST                (110)
+#define MSGNEED                (111)
+#define MSGDENY                (112)
+#define MSGSEND                (113)
+#define MSGRECV                (114)
+#define MSGDONE                (115)
+#define MSGXPATCH      (117)
+#define MSGCOMPRESS    (118)
+
+/* MSGSETUPACK data codes - setupack */
+#define FSETUPOK       (999)
+#define FSETUPHOST     (998)
+#define FSETUPSAME     (997)
+#define FSETUPOLD      (996)
+#define FSETUPBUSY     (995)
+#define FSETUPRELEASE  (994)
+
+/* MSGLOGACK data codes - loginack */
+#define FLOGOK         (989)
+#define FLOGNG         (988)
+
+/* MSGDONE data codes - doneack */
+#define FDONESUCCESS   (979)
+#define FDONEDONTLOG   (978)
+#define FDONESRVERROR  (977)
+#define FDONEUSRERROR  (976)
+#define FDONEGOAWAY    (975)
+
+#ifdef MSGSUBR
+
+/* used in all msg routines */
+extern int     server;                 /* true if we are the server */
+extern int     protver;                /* protocol version of partner */
+
+#else  MSGSUBR
+
+#ifdef MSGFILE
+#define        EXTERN
+#else  MSGFILE
+#define        EXTERN  extern
+#endif MSGFILE
+
+/* used in all msg routines */
+EXTERN int     server;                 /* true if we are the server */
+
+/* msggoaway */
+EXTERN char    *goawayreason;          /* reason for goaway */
+
+/* msgsignon */
+EXTERN int     pgmversion;             /* version of this program */
+EXTERN int     protver;                /* protocol version of partner */
+EXTERN int     pgmver;                 /* program version of partner */
+EXTERN char    *scmver;                /* scm version of partner */
+EXTERN int     fspid;                  /* process id of fileserver */
+
+/* msgsetup */
+EXTERN int     xpatch;                 /* setup crosspatch to a new client */
+EXTERN char    *xuser;                 /* user for crosspatch */
+EXTERN char    *collname;              /* collection name */
+EXTERN char    *basedir;               /* base directory */
+EXTERN int     basedev;                /* base directory device */
+EXTERN int     baseino;                /* base directory inode */
+EXTERN long    lasttime;               /* time of last upgrade */
+EXTERN int     listonly;               /* only listing files, no data xfer */
+EXTERN int     newonly;                /* only send new files */
+EXTERN char    *release;               /* release name */
+EXTERN int     setupack;               /* ack return value for setup */
+
+/* msgcrypt */
+EXTERN char    *crypttest;             /* encryption test string */
+
+/* msglogin */
+EXTERN char    *logcrypt;              /* login encryption test */
+EXTERN char    *loguser;               /* login username */
+EXTERN char    *logpswd;               /* password for login */
+EXTERN int     logack;                 /* login ack status */
+EXTERN char    *logerror;              /* error string from oklogin */
+
+/* msgxpatch */
+EXTERN int     xargc;                  /* arg count for crosspatch */
+EXTERN char    **xargv;                /* arg array for crosspatch */
+
+/* msgrefuse */
+EXTERN TREE    *refuseT;               /* tree of files to refuse */
+
+/* msglist */
+EXTERN TREE    *listT;                 /* tree of files to list */
+EXTERN long    scantime;               /* time that collection was scanned */
+
+/* msgneed */
+EXTERN TREE    *needT;                 /* tree of files to need */
+
+/* msgdeny */
+EXTERN TREE    *denyT;                 /* tree of files to deny */
+
+/* msgrecv */
+/* msgsend */
+EXTERN TREE    *upgradeT;              /* pointer to file being upgraded */
+
+/* msgdone */
+EXTERN int     doneack;                /* done ack status */
+EXTERN char    *donereason;            /* set if indicated by doneack */
+
+#undef EXTERN
+
+#endif MSGSUBR
diff --git a/usr.bin/sup/src/supscan.c b/usr.bin/sup/src/supscan.c
new file mode 100644 (file)
index 0000000..1e6e808
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * supscan -- SUP Scan File Builder
+ *
+ * Usage: supscan [ -v ] collection [ basedir ]
+ *       supscan [ -v ] -f dirfile
+ *       supscan [ -v ] -s
+ *     -f      "file" -- use dirfile instead of system coll.dir
+ *     -s      "system" -- perform scan for system supfile
+ *     -v      "verbose" -- print messages as you go
+ *     collection      -- name of the desired collection if not -s
+ *     basedir         -- name of the base directory, if not
+ *                        the default or recorded in coll.dir
+ *     dirfile         -- name of replacement for system coll.dir.
+ *
+ **********************************************************************
+ * HISTORY
+ * $Log: supscan.c,v $
+ * Revision 1.1  1995/12/16 11:47:01  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:19  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 1.14  92/08/11  12:08:30  mrt
+ *     Picked up Brad's deliniting and variable argument changes
+ *     [92/08/10            mrt]
+ * 
+ * Revision 1.13  92/02/08  18:04:44  dlc
+ *     Once again revised localhost().  Do not use gethostbyname() at
+ *     all, but assume that the host names in the coll.host file are at
+ *     least a prefix of the fully qualified name.  Modcoll (and related
+ *     scripts) will maintain this fact.
+ *     [92/02/08            dlc]
+ * 
+ * Revision 1.12  91/08/17  23:35:31  dlc
+ *     Changes to localhost() function:
+ *             - Use host name in kernel for local host name; assume it is
+ *               fully qualified.
+ *             - If gethostbyname() of host to see if we are the repository
+ *               fails, with TRY_AGAIN or NO_RECOVERY, then use the "host"
+ *               parameter.  Print a diagnostic in this case.
+ *     [91/08/17            dlc]
+ * 
+ * Revision 1.11  90/04/04  10:53:01  dlc
+ *     Changed localhost to retry getting the local host name 4 times with
+ *     30 second sleep intervals before aborting; after 4 tries, things are
+ *     probably too messed up for the supscan to do anything useful
+ *     [90/04/04            dlc]
+ * 
+ * Revision 1.10  89/08/03  19:49:33  mja
+ *     Updated to use v*printf() in place of _doprnt().
+ *     [89/04/19            mja]
+ * 
+ * Revision 1.9  89/06/18  14:41:37  gm0w
+ *     Fixed up some notify messages of errors to use "SUP:" prefix.
+ *     [89/06/18            gm0w]
+ * 
+ * 13-May-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changed goaway to longjmp back to top-level to scan next
+ *     collection. [V7.6]
+ *
+ * 19-Feb-88  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added -f <filename> switch to scan all (or part) of the
+ *     collections in a file of collection/base-directory pairs.
+ *     [V7.5]
+ *
+ * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Removed nameserver support (which means to use a new
+ *     datafile).
+ *
+ * 09-Sep-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Use case-insensitive hostname comparison.
+ *
+ * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added code for "release" support. [V6.4]
+ *
+ * 05-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Changed collection setup errors to be non-fatal. [V5.3]
+ *
+ * 29-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Moved most of the scanning code to scan.c. [V4.2]
+ *
+ * 02-Nov-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Added "-s" option.
+ *
+ * 22-Sep-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
+ *     Merged 4.1 and 4.2 versions together.
+ *
+ * 04-Jun-85  Steven Shafer (sas) at Carnegie-Mellon University
+ *     Created for 4.2 BSD.
+ *
+ **********************************************************************
+ */
+
+#include <libc.h>
+#include <c.h>
+#include <netdb.h>
+#include <setjmp.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <sys/time.h>
+#include <sys/types.h>
+#include "sup.h"
+
+#ifdef lint
+/*VARARGS1*//*ARGSUSED*/
+static void quit(status) {};
+#endif /* lint */
+
+#define PGMVERSION 6
+
+/*******************************************
+ ***    D A T A   S T R U C T U R E S    ***
+ *******************************************/
+
+struct collstruct {                    /* one per collection to be upgraded */
+       char *Cname;                    /* collection name */
+       char *Cbase;                    /* local base directory */
+       char *Cprefix;                  /* local collection pathname prefix */
+       struct collstruct *Cnext;       /* next collection */
+};
+typedef struct collstruct COLLECTION;
+
+/*********************************************
+ ***    G L O B A L   V A R I A B L E S    ***
+ *********************************************/
+
+int trace;                             /* -v flag */
+
+COLLECTION *firstC;                    /* collection list pointer */
+char *collname;                                /* collection name */
+char *basedir;                         /* base directory name */
+char *prefix;                          /* collection pathname prefix */
+long lasttime = 0;                     /* time of last upgrade */
+long scantime;                         /* time of this scan */
+int newonly = FALSE;                   /* new files only */
+jmp_buf sjbuf;                         /* jump location for errors */
+
+TREELIST *listTL;      /* list of all files specified by <coll>.list */
+TREE *listT;           /* final list of files in collection */
+TREE *refuseT = NULL;  /* list of all files specified by <coll>.list */
+
+long time ();
+
+/*************************************
+ ***    M A I N   R O U T I N E    ***
+ *************************************/
+
+main (argc,argv)
+int argc;
+char **argv;
+{
+       register COLLECTION *c;
+
+       init (argc,argv);               /* process arguments */
+       for (c = firstC; c; c = c->Cnext) {
+               collname = c->Cname;
+               basedir = c->Cbase;
+               prefix = c->Cprefix;
+               (void) chdir (basedir);
+               scantime = time ((long *)NULL);
+               printf ("SUP Scan for %s starting at %s",collname,
+                       ctime (&scantime));
+               (void) fflush (stdout);
+               if (!setjmp (sjbuf)) {
+                       makescanlists (); /* record names in scan files */
+                       scantime = time ((long *)NULL);
+                       printf ("SUP Scan for %s completed at %s",collname,
+                               ctime (&scantime));
+               } else
+                       printf ("SUP: Scan for %s aborted at %s",collname,
+                               ctime (&scantime));
+               (void) fflush (stdout);
+       }
+       while (c = firstC) {
+               firstC = firstC->Cnext;
+               free (c->Cname);
+               free (c->Cbase);
+               if (c->Cprefix)  free (c->Cprefix);
+               free ((char *)c);
+       }
+       exit (0);
+}
+
+/*****************************************
+ ***    I N I T I A L I Z A T I O N    ***
+ *****************************************/
+
+usage ()
+{
+       fprintf (stderr,"Usage: supscan [ -v ] collection [ basedir ]\n");
+       fprintf (stderr,"       supscan [ -v ] -f dirfile\n");
+       fprintf (stderr,"       supscan [ -v ] -s\n");
+       exit (1);
+}
+
+init (argc,argv)
+int argc;
+char **argv;
+{
+       char buf[STRINGLENGTH],fbuf[STRINGLENGTH],*p,*q;
+       FILE *f;
+       COLLECTION **c, *getcoll();
+       int fflag,sflag;
+       char *filename;
+
+       trace = FALSE;
+       fflag = FALSE;
+       sflag = FALSE;
+       while (argc > 1 && argv[1][0] == '-') {
+               switch (argv[1][1]) {
+               case 'f':
+                       fflag = TRUE;
+                       if (argc == 2)
+                               usage ();
+                       --argc;
+                       argv++;
+                       filename = argv[1];
+                       break;
+               case 'v':
+                       trace = TRUE;
+                       break;
+               case 's':
+                       sflag = TRUE;
+                       break;
+               default:
+                       fprintf (stderr,"supscan: Invalid flag %s ignored\n",argv[1]);
+                       (void) fflush (stderr);
+               }
+               --argc;
+               argv++;
+       }
+       if (!fflag) {
+               (void) sprintf (fbuf,FILEDIRS,DEFDIR);
+               filename = fbuf;
+       }
+       if (sflag) {
+               if (argc != 1)
+                       usage ();
+               firstC = NULL;
+               c = &firstC;
+               (void) sprintf (buf,FILEHOSTS,DEFDIR);
+               if ((f = fopen (buf,"r")) == NULL)
+                       quit (1,"supscan: Unable to open %s\n",buf);
+               while ((p = fgets (buf,STRINGLENGTH,f)) != NULL) {
+                       q = index (p,'\n');
+                       if (q)  *q = 0;
+                       if (index ("#;:",*p))  continue;
+                       collname = nxtarg (&p," \t=");
+                       p = skipover (p," \t=");
+                       if (!localhost (p))  continue;
+                       *c = getcoll(filename,salloc (collname),
+                                       (char *)NULL);
+                       if (*c)  c = &((*c)->Cnext);
+               }
+               (void) fclose (f);
+               return;
+       }
+       if (argc < 2 && fflag) {
+               firstC = NULL;
+               c = &firstC;
+               if ((f = fopen (filename,"r")) == NULL)
+                       quit (1,"supscan: Unable to open %s\n",filename);
+               while (p = fgets (buf,STRINGLENGTH,f)) {
+                       q = index (p,'\n');
+                       if (q)  *q = 0;
+                       if (index ("#;:",*p))  continue;
+                       q = nxtarg (&p," \t=");
+                       p = skipover (p," \t=");
+                       *c = getcoll(filename,salloc (q),salloc (p));
+                       if (*c)  c = &((*c)->Cnext);
+               }
+               (void) fclose (f);
+               return;
+       }
+       if (argc < 2 || argc > 3)
+               usage ();
+       firstC = getcoll(filename,salloc (argv[1]),
+                       argc > 2 ? salloc (argv[2]) : (char *)NULL);
+}
+
+COLLECTION *
+getcoll(filename, collname, basedir)
+register char *filename,*collname,*basedir;
+{
+       char buf[STRINGLENGTH],*p,*q;
+       FILE *f;
+       COLLECTION *c;
+
+       if (basedir == NULL) {
+               if (f = fopen (filename,"r")) {
+                       while (p = fgets (buf,STRINGLENGTH,f)) {
+                               q = index (p,'\n');
+                               if (q)  *q = 0;
+                               if (index ("#;:",*p))  continue;
+                               q = nxtarg (&p," \t=");
+                               if (strcmp (q,collname) == 0) {
+                                       p = skipover (p," \t=");
+                                       basedir = salloc (p);
+                                       break;
+                               }
+                       }
+                       (void) fclose (f);
+               }
+               if (basedir == NULL) {
+                       (void) sprintf (buf,FILEBASEDEFAULT,collname);
+                       basedir = salloc (buf);
+               }
+       }
+       if (chdir(basedir) < 0) {
+               fprintf (stderr,"supscan:  Can't chdir to base directory %s for %s\n",
+                       basedir,collname);
+               return (NULL);
+       }
+       prefix = NULL;
+       (void) sprintf (buf,FILEPREFIX,collname);
+       if (f = fopen (buf,"r")) {
+               while (p = fgets (buf,STRINGLENGTH,f)) {
+                       q = index (p,'\n');
+                       if (q) *q = 0;
+                       if (index ("#;:",*p))  continue;
+                       prefix = salloc (p);
+                       if (chdir(prefix) < 0) {
+                               fprintf (stderr,"supscan: can't chdir to %s from base directory %s for %s\n",
+                                       prefix,basedir,collname);
+                               return (NULL);
+                       }
+                       break;
+               }
+               (void) fclose (f);
+       }
+       if ((c = (COLLECTION *) malloc (sizeof(COLLECTION))) == NULL)
+               quit (1,"supscan: can't malloc collection structure\n");
+       c->Cname = collname;
+       c->Cbase = basedir;
+       c->Cprefix = prefix;
+       c->Cnext = NULL;
+       return (c);
+}
+#if __STDC__
+goaway (char *fmt,...)
+#else
+/*VARARGS*//*ARGSUSED*/
+goaway (va_alist)
+va_dcl
+#endif
+{
+#if !__STDC__
+       char *fmt;
+#endif
+       va_list ap;
+
+#if __STDC__
+       va_start(ap,fmt);
+#else
+       va_start(ap);
+       fmt = va_arg(ap,char *);
+#endif
+
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       (void) putc ('\n',stderr);
+       (void) fflush (stderr);
+       longjmp (sjbuf,TRUE);
+}
+
+int localhost (host)
+register char *host;
+{
+       static char myhost[STRINGLENGTH];
+       static int myhostlen;
+       register int hostlen;
+
+       if (*myhost == '\0') {
+               /*
+                * We assume that the host name in the kernel is the
+                * fully qualified form.
+                */
+               if (gethostname (myhost,sizeof (myhost)) < 0) {
+                   quit (1,"supscan: can't get kernel host name\n");
+               }
+               myhostlen = strlen(myhost);
+       }
+
+       /*
+        * Here, we assume that the 'host' parameter from the
+        * coll.host file is at least a prefix of the fully qualified
+        * host name of some machine.  This will be true when modcoll(8)
+        * (and related scripts) maintain the relevant files, but if
+        * a person makes a manual change, problems could result.  In
+        * particular, if a nicname, such as "Y" for "GANDALF.CS.CMU.EDU"
+        * is present in the coll.host file, things will not work as
+        * expected.
+        */
+
+       hostlen = strlen(host);
+
+       return(strncasecmp (myhost,
+                           host,
+                           hostlen < myhostlen ? hostlen : myhostlen) == 0);
+}
diff --git a/usr.bin/sup/src/supservers.8 b/usr.bin/sup/src/supservers.8
new file mode 100644 (file)
index 0000000..53d2e9f
--- /dev/null
@@ -0,0 +1,241 @@
+.\" Copyright (c) 1992 Carnegie Mellon University
+.\" All Rights Reserved.
+.\"
+.\" Permission to use, copy, modify and distribute this software and its
+.\" documentation is hereby granted, provided that both the copyright
+.\" notice and this permission notice appear in all copies of the
+.\" software, derivative works or modified versions, and any portions
+.\" thereof, and that both notices appear in supporting documentation.
+.\" 
+.\" CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+.\" CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+.\" ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+.\"
+.\" Carnegie Mellon requests users of this software to return to
+.\"
+.\"  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
+.\"  School of Computer Science
+.\"  Carnegie Mellon University
+.\"  Pittsburgh PA 15213-3890
+.\"
+.\" any improvements or extensions that they make and grant Carnegie Mellon
+.\" the rights to redistribute these changes.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\" HISTORY
+.\" $Log: supservers.8,v $
+.\" Revision 1.1  1995/12/16 11:47:02  deraadt
+.\" add sup to the tree
+.\"
+.\" Revision 1.1.1.1  1993/05/21 14:52:16  cgd
+.\" initial import of CMU's SUP to NetBSD
+.\"
+.\" Revision 1.3  92/08/11  12:08:50  mrt
+.\"    Documented -C switch
+.\"    [92/08/11            mrt]
+.\" 
+.TH SUPSERVERS 8 1/16/86
+.CM 1
+.SH "NAME"
+supfilesrv, supscan \- sup server processes
+.SH "SYNOPSIS"
+supfilesrv
+[
+.I 
+-l
+] [
+.I 
+-q
+] [
+.I 
+-N
+] [
+.I 
+-P
+] [
+.I -C MaxChildren
+]
+.br
+supscan [
+.I 
+-v
+] [
+.I 
+-s
+] [
+.I 
+collection
+] [
+.I 
+basedir
+]
+.SH "DESCRIPTION"
+.I 
+Supfilesrv
+is the server processes used to interact with
+.I 
+sup
+client processes via the IP/TCP network protocol.
+This server
+normally is expected to be running on server machines at all times.
+Each machine with files of interest to users on other machines is
+expected to be a file server and should run
+.I 
+supfilesrv.
+A file server machine will service requests for both "private" and
+"system" file collections.
+No special action is necessary to support
+private collections, as the client user is expected to supply all
+necessary information.
+For system collections, if the base directory
+is not the default (see FILES below), an entry must be put into
+the directory list file; this entry is a single text line containing
+the name of the collection, one or more spaces, and the name of the
+base directory for that collection.
+
+Each collection should have
+an entry in the host list file; this entry is a single text line
+containing the name of the collection, one or more spaces, and
+the name of the host machine acting as file server for that collection.
+
+Details of setting up a file collection for the file server are
+described in the manual entry for
+.I 
+sup(1).
+
+.I 
+Supfilesrv
+generally runs as a network server process that listens for connections,
+and for each connection (double-)forks a process to handle the interaction
+with the client.
+However, with the -l flag, no forking will take place:
+the server will listen for a network connection, handle it, and exit.
+This is useful for debugging the servers in "live" mode rather than as
+daemons.
+
+For debugging purposes, the -P "debugging ports" flag can be used.
+It will cause the selection of an alternate, non-privileged set of
+TCP ports instead of the usual ports, which are reserved for the
+active server processes.  The -N "network debugging" flag can be used
+to produce voluminous messages describing the network communication
+progress and status. The more -N switches that you use the more output
+you get. Use 3 (separated by spaces: -N -N -N) to get a complete record
+of all network messages. Log messages are printed by 
+.I syslog
+on 
+.I daemon.log .
+To suppress
+log messages, the -q "quiet" flag can be used.
+
+
+Normally the 
+.I supfilesrv
+will only respond to 3 requests simultaneously, forking a child
+process for each client. If it gets additional requests it will respond
+with the error FSSETUPBUSY. The -C MaxChildren switch can be used
+to increase (or decrease) this number.
+
+.SH "SUPSCAN"
+It is possible to pre-compile a list of the files in a collection
+to make
+.I 
+supfilesrv
+service that collection much faster.  This can be done by running
+.I 
+supscan
+on the desired collection on the repository machine.  This produces a
+list of all the files in the collection at the time of the
+.I 
+supscan;
+subsequent upgrades will be based on this list of files rather than
+actually scanning the disk at the time of the upgrade.  Of course,
+the upgrade will consequently bring the client machine up to the status
+of the repository machine as of the time of the
+.I 
+supscan
+rather than as of the time of the upgrade; hence, if
+.I 
+supscan
+is used, it should be run periodically on the
+collection.
+This facility is useful for extremely large file collections
+that are upgraded many times per day, such as the CMU UNIX system
+software.  The "verbose" flag
+.I 
+-v
+will cause
+.I 
+supscan
+to produce output messages as it scans the files in the collection.
+The "system" flag
+.I 
+-s
+will cause
+.I 
+supscan
+to scan all system collections residing on the current host.
+The
+.I 
+basedir
+parameter must be specified if the collection is a private
+collection whose base directory is not the default.
+.SH "FILES"
+.TP
+/usr
+default base directory for a collection
+.TP
+/usr/cs/lib/supfiles/coll.dir
+directory list file for file server
+.TP
+/usr/cs/lib/supfiles/coll.host
+host list file for system sups.
+.TP
+<base-directory>/sup/<collection>/*
+files used by file server (see
+.I 
+sup(1))
+.TP
+<base-directory>/sup/<collection>/list
+list file used by
+.I 
+supscan
+to create file list
+.TP
+<base-directory>/sup/<collection>/scan
+file list created by
+.I 
+supscan
+from list file
+.i0
+.DT
+.PP
+.SH "SEE ALSO"
+sup(1)
+.br
+.I 
+The SUP Software Upgrade Protocol,
+S.
+A.
+Shafer, CMU Computer Science Dept., 1985.
+.SH "DIAGNOSTICS"
+The file server places log messages on the
+standard and diagnostic output files.
+The process name and process
+id number generally accompany each message for diagnostic purposes.
+.SH "HISTORY"
+.TP
+31-July-92 Mary Thompson (mrt) at Carnegie Mellon University
+Removed references to supnameserver which has not existed for
+a long time. Update a few file names. Added -C switch.
+.TP
+21-May-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
+Updated documentation for 4.3; changed /usr/cmu to /usr/cs.
+.TP
+15-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
+Updated documentation; -s switch to supscan.
+.TP
+23-May-85  Steven Shafer (sas) at Carnegie-Mellon University
+Supscan created and documented; also -N flag.
+.TP
+04-Apr-85  Steven Shafer (sas) at Carnegie-Mellon University
+Created.
diff --git a/usr.bin/sup/src/sysent.h b/usr.bin/sup/src/sysent.h
new file mode 100644 (file)
index 0000000..d513ea6
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*
+ **********************************************************************
+ * HISTORY
+ * $Log: sysent.h,v $
+ * Revision 1.1  1995/12/16 11:47:02  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:19  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 2.4  89/12/05  16:02:00  mrt
+ *     Removed include of sys/features.h as it is no longer
+ *     exported or needed.
+ *     [89/12/05            mrt]
+ * 
+ * Revision 2.3  89/01/20  15:44:24  gm0w
+ *     Added externs to the non-STDC case for functions that do not
+ *     have int return values.
+ *     [88/12/17            gm0w]
+ * 
+ * Revision 2.2  88/12/14  23:35:52  mja
+ *     Created.
+ *     [88/01/06            jjk]
+ * 
+ **********************************************************************
+ */
+
+#ifndef _SYSENT_H_
+#define _SYSENT_H_ 1
+
+#if defined(__STDC__)
+#if 0
+#include <sys/types.h>
+#include <sys/time.h>
+extern int access(const char *, int);
+extern int acct(const char *);
+extern int brk(void *);
+extern int sbrk(int);
+extern int chdir(const char *);
+extern int chmod(const char *, int);
+extern int fchmod(int, int);
+extern int chown(const char *, int, int);
+extern int fchown(int, int, int);
+extern int chroot(const char *);
+extern int close(int);
+extern int creat(const char *, int);
+extern int dup(int);
+extern int dup2(int, int);
+extern int execve(const char *, const char **, const char **);
+extern void _exit(int);
+extern int fcntl(int, int, int);
+extern int flock(int, int);
+extern int fork(void);
+extern int fsync(int);
+extern int getdtablesize(void);
+extern gid_t getgid(void);
+extern gid_t getegid(void);
+extern int getgroups(int, int *);
+extern long gethostid(void);
+extern int sethostid(long);
+extern int gethostname(char *, int);
+extern int sethostname(const char *, int);
+extern int getpagesize(void);
+extern int getpgrp(int);
+extern int getpid(void);
+extern int getppid(void);
+extern uid_t getuid(void);
+extern uid_t geteuid(void);
+extern int ioctl(int, unsigned long, void *);
+extern int kill(int, int);
+extern int killpg(int, int);
+extern int link(const char *, const char *);
+extern off_t lseek(int, off_t, int);
+extern int mkdir(const char *, int);
+extern int mknod(const char *, int, int);
+extern int mount(const char *, const char *, int);
+extern int umount(const char *);
+extern int open(const char *, int, int);
+extern int pipe(int *);
+extern int profil(void *, int, int, int);
+extern int ptrace(int, int, int *, int);
+extern int quota(int, int, int, void *);
+extern int read(int, void *, int);
+extern int readlink(const char *, void *, int);
+extern int reboot(int);
+extern int rename(const char *, const char *);
+extern int rmdir(const char *);
+extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+extern int setgroups(int, int *);
+extern int setpgrp(int, int);
+extern int setquota(const char *, const char *);
+extern int setregid(gid_t, gid_t);
+extern int setreuid(uid_t, uid_t);
+extern int swapon(const char *);
+extern int symlink(const char *, const char *);
+extern void sync(void);
+extern int syscall(int, ...);
+extern int truncate(const char *, off_t);
+extern int ftruncate(int, off_t);
+extern int umask(int);
+extern int unlink(const char *);
+extern int vfork(void);
+extern void vhangup(void);
+extern int write(int, void *, int);
+
+#ifndef        _VICEIOCTL
+#include <sys/viceioctl.h>
+#endif /* not _VICEIOCTL */
+extern int icreate(int, int, int, int, int, int);
+extern int iinc(int, int, long);
+extern int idec(int, int, long);
+extern int iopen(int, int, int);
+extern int iread(int, int, int, int, void *, int);
+extern int iwrite(int, int, int, int, void *, int);
+extern int pioctl(const char *, unsigned long, struct ViceIoctl *, int);
+extern int setpag(void);
+#endif
+#else defined(__STDC__)
+extern gid_t getgid();
+extern gid_t getegid();
+extern long gethostid();
+extern uid_t getuid();
+extern uid_t geteuid();
+extern off_t lseek();
+#endif /* __STDC__ */
+#endif /* not _SYSENT_H_ */
diff --git a/usr.bin/sup/src/time.h b/usr.bin/sup/src/time.h
new file mode 100644 (file)
index 0000000..0b4ea54
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement:  ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)time.h      5.6 (Berkeley) 6/23/90
+ */
+/* 
+ * HISTORY
+ * 20-Sep-90  Mary Thompson (mrt) at Carnegie-Mellon University
+ *     Taken from 4.3-reno-source to get the new copyright, but
+ *     removed the features that Mach is not supporting yet.
+ *
+ */
+
+#ifndef _TIME_H_
+#define _TIME_H_ 1
+
+struct tm {
+       int     tm_sec;         /* seconds after the minute [0-60] */
+       int     tm_min;         /* minutes after the hour [0-59] */
+       int     tm_hour;        /* hours since midnight [0-23] */
+       int     tm_mday;        /* day of the month [1-31] */
+       int     tm_mon;         /* months since January [0-11] */
+       int     tm_year;        /* years since 1900 */
+       int     tm_wday;        /* days since Sunday [0-6] */
+       int     tm_yday;        /* days since January 1 [0-365] */
+       int     tm_isdst;       /* Daylight Savings Time flag */
+       long    tm_gmtoff;      /* offset from CUT in seconds */
+       char    *tm_zone;       /* timezone abbreviation */
+};
+
+#if __STDC__ || c_plusplus
+extern struct tm *gmtime(const time_t *);
+extern struct tm *localtime(const time_t *);
+extern time_t mktime(const struct tm *);
+extern time_t time(time_t *);
+extern double difftime(const time_t, const time_t);
+extern char *asctime(const struct tm *);
+extern char *ctime(const time_t *);
+extern char *timezone(int , int);
+extern void tzset(void);
+extern void tzsetwall(void);
+#else
+extern struct tm *gmtime();
+extern struct tm *localtime();
+extern time_t mktime();
+extern time_t time();
+extern double difftime();
+extern char *asctime();
+extern char *ctime();
+extern char *timezone();
+extern void tzset();
+extern void tzsetwall();
+#endif 
+
+#endif /* _TIME_H */
diff --git a/usr.bin/sup/src/vprintf.c b/usr.bin/sup/src/vprintf.c
new file mode 100644 (file)
index 0000000..01280c2
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator   or   Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the rights
+ * to redistribute these changes.
+ */
+/*
+ * varargs versions of printf routines
+ *
+ **********************************************************************
+ * HISTORY
+ * $Log: vprintf.c,v $
+ * Revision 1.1  1995/12/16 11:47:03  deraadt
+ * add sup to the tree
+ *
+ * Revision 1.1.1.1  1993/05/21 14:52:19  cgd
+ * initial import of CMU's SUP to NetBSD
+ *
+ * Revision 2.5  89/09/08  18:15:55  mbj
+ *     Use _doprnt() for the Multimax (an "old" architecture).
+ *     [89/09/08            mbj]
+ * 
+ * Revision 2.4  89/08/03  14:40:10  mja
+ *     Add vsnprintf() routine.
+ *     [89/07/12            mja]
+ * 
+ *     Terminate vsprintf() string with null byte.
+ *     [89/04/21            mja]
+ * 
+ *     Change to use new hidden name for _doprnt on MIPS.
+ *     [89/04/18            mja]
+ * 
+ * Revision 2.3  89/06/10  14:13:43  gm0w
+ *     Added putc of NULL byte to vsprintf.
+ *     [89/06/10            gm0w]
+ * 
+ * Revision 2.2  88/12/13  13:53:17  gm0w
+ *     From Brad White.
+ *     [88/12/13            gm0w]
+ ************************************************************
+ */
+
+#include <stdio.h>
+#include <varargs.h>
+
+#ifdef DOPRINT_VA
+/* 
+ *  system provides _doprnt_va routine
+ */
+#define        _doprnt _doprnt_va
+#else
+/*
+ * system provides _doprnt routine
+ */
+#define _doprnt_va _doprnt
+#endif
+
+
+#ifdef NEED_VPRINTF
+int
+vprintf(fmt, args)
+       char *fmt;
+       va_list args;
+{
+       _doprnt(fmt, args, stdout);
+       return (ferror(stdout) ? EOF : 0);
+}
+
+int
+vfprintf(f, fmt, args)
+       FILE *f;
+       char *fmt;
+       va_list args;
+{
+       _doprnt(fmt, args, f);
+       return (ferror(f) ? EOF : 0);
+}
+
+int
+vsprintf(s, fmt, args)
+       char *s, *fmt;
+       va_list args;
+{
+       FILE fakebuf;
+
+       fakebuf._flag = _IOSTRG+_IOWRT; /* no _IOWRT: avoid stdio bug */
+       fakebuf._ptr = s;
+       fakebuf._cnt = 32767;
+       _doprnt(fmt, args, &fakebuf);
+       putc('\0', &fakebuf);
+       return (strlen(s));
+}
+#endif /* NEED_VPRINTF */
+
+#if    defined(NEED_VSNPRINTF) || defined(NEED_VPRINTF)
+int
+vsnprintf(s, n, fmt, args)
+       char *s, *fmt;
+       va_list args;
+{
+       FILE fakebuf;
+
+       fakebuf._flag = _IOSTRG+_IOWRT; /* no _IOWRT: avoid stdio bug */
+       fakebuf._ptr = s;
+       fakebuf._cnt = n-1;
+       _doprnt(fmt, args, &fakebuf);
+       fakebuf._cnt++;
+       putc('\0', &fakebuf);
+       if (fakebuf._cnt<0)
+           fakebuf._cnt = 0;
+       return (n-fakebuf._cnt-1);
+}
+#endif /* NEED_VPRINTF || NEED_VSNPRINTF */
diff --git a/usr.bin/sup/sup/Makefile b/usr.bin/sup/sup/Makefile
new file mode 100644 (file)
index 0000000..e200b5b
--- /dev/null
@@ -0,0 +1,19 @@
+#      $Id: Makefile,v 1.1 1995/12/16 11:47:05 deraadt Exp $
+
+.PATH: ${.CURDIR}/../src
+
+PROG=  sup
+MAN=   sup.1
+SRCS=  supcmain.o supcvers.o supcparse.o supcname.o supcmisc.o supcmeat.o \
+       scm.o scmio.o stree.o log.o supmsg.o \
+       atoo.o errmsg.o expand.o ffilecopy.o filecopy.o nxtarg.o \
+       path.o quit.o run.o salloc.o skipto.o vprintf.o netcryptvoid.c
+LDADDR+=-lutil
+DPADD+=        ${LIBUTIL}
+BINOWN=        root
+BINGRP=        daemon
+BINMODE=555
+BINDIR=        /usr/bin
+CFLAGS+=-I${.CURDIR}/../src
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/sup/supfilesrv/Makefile b/usr.bin/sup/supfilesrv/Makefile
new file mode 100644 (file)
index 0000000..787b17d
--- /dev/null
@@ -0,0 +1,18 @@
+#      $Id: Makefile,v 1.1 1995/12/16 11:47:06 deraadt Exp $
+
+.PATH: ${.CURDIR}/../src
+
+PROG=  supfilesrv
+MAN=   supservers.8
+SRCS=  supfilesrv.o scan.o scm.o scmio.o stree.o log.o supmsg.o \
+       atoo.o errmsg.o expand.o ffilecopy.o filecopy.o nxtarg.o \
+       path.o quit.o run.o salloc.o skipto.o vprintf.o netcryptvoid.c
+LDADD+=        -lutil -lcrypt
+DPADD+=        ${LIBUTIL}
+BINOWN=        root
+BINGRP=        daemon
+BINMODE=555
+BINDIR=        /usr/bin
+CFLAGS+=-I${.CURDIR}/../src
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/sup/supscan/Makefile b/usr.bin/sup/supscan/Makefile
new file mode 100644 (file)
index 0000000..c4fcff1
--- /dev/null
@@ -0,0 +1,18 @@
+#      $Id: Makefile,v 1.1 1995/12/16 11:47:07 deraadt Exp $
+
+.PATH: ${.CURDIR}/../src
+
+PROG=  supscan
+NOMAN=
+SRCS=  supscan.o stree.o scan.o \
+       atoo.o errmsg.o expand.o ffilecopy.o filecopy.o nxtarg.o \
+       path.o quit.o run.o salloc.o skipto.o vprintf.o netcryptvoid.c
+LDADD+=        -lutil
+DPADD+=        ${LIBUTIL}
+BINOWN=        root
+BINGRP=        daemon
+BINMODE=555
+BINDIR=        /usr/bin
+CFLAGS+=-I${.CURDIR}/../src
+
+.include <bsd.prog.mk>