Merge crunchgen & crunchhide (using name checking), and move to usr.sbin
authorderaadt <deraadt@openbsd.org>
Fri, 22 Aug 2008 15:18:54 +0000 (15:18 +0000)
committerderaadt <deraadt@openbsd.org>
Fri, 22 Aug 2008 15:18:54 +0000 (15:18 +0000)
next step is to not install it as two programs, but be even more clever

24 files changed:
distrib/crunch/Makefile
distrib/crunch/Makefile.inc [deleted file]
distrib/crunch/README [deleted file]
distrib/crunch/crunchgen/Makefile [deleted file]
distrib/crunch/crunchgen/crunched_main.c [deleted file]
distrib/crunch/crunchgen/crunchgen.1 [deleted file]
distrib/crunch/crunchgen/crunchgen.c [deleted file]
distrib/crunch/crunchgen/mkskel.sh [deleted file]
distrib/crunch/crunchide/Makefile [deleted file]
distrib/crunch/crunchide/crunchide.1 [deleted file]
distrib/crunch/crunchide/crunchide.c [deleted file]
distrib/crunch/crunchide/ecoff_hide.c [deleted file]
distrib/crunch/crunchide/elf_hide.c [deleted file]
usr.sbin/Makefile
usr.sbin/crunchgen/Makefile [new file with mode: 0644]
usr.sbin/crunchgen/README [new file with mode: 0644]
usr.sbin/crunchgen/crunched_main.c [new file with mode: 0644]
usr.sbin/crunchgen/crunchgen.1 [new file with mode: 0644]
usr.sbin/crunchgen/crunchgen.c [new file with mode: 0644]
usr.sbin/crunchgen/crunchide.1 [new file with mode: 0644]
usr.sbin/crunchgen/crunchide.c [new file with mode: 0644]
usr.sbin/crunchgen/ecoff_hide.c [new file with mode: 0644]
usr.sbin/crunchgen/elf_hide.c [new file with mode: 0644]
usr.sbin/crunchgen/mkskel.sh [new file with mode: 0644]

index 587c9f1..d10d0e0 100644 (file)
@@ -1,5 +1,5 @@
-#      $OpenBSD: Makefile,v 1.3 2003/03/02 12:32:08 deraadt Exp $
+#      $OpenBSD: Makefile,v 1.4 2008/08/22 15:18:55 deraadt Exp $
 
-SUBDIR=crunchgen crunchide ../sparc64/mksuncd
+SUBDIR=        ../sparc64/mksuncd
 
 .include <bsd.subdir.mk>
diff --git a/distrib/crunch/Makefile.inc b/distrib/crunch/Makefile.inc
deleted file mode 100644 (file)
index aaa06e1..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#      $OpenBSD: Makefile.inc,v 1.3 2001/01/29 01:19:21 deraadt Exp $
-
-# modify to taste
-DESTDIR=
-BINDIR?= /usr/bin
diff --git a/distrib/crunch/README b/distrib/crunch/README
deleted file mode 100644 (file)
index 6b150b5..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-
-CRUNCH 0.3 README                              7/23/94
-
-Crunch is available via anonymous ftp to ftp.cs.umd.edu in
-               pub/bsd/crunch-0.3.tar.gz
-
-WHAT'S NEW IN 0.3
-
-* The prototype awk script has been replaced by a more capable and
-  hopefully more robust C program.
-* No fragile template makefiles or dependencies on the details of the
-  bsd build environment.
-* You can build crunched binaries even with no sources on-line, you
-  just need the .o files.  Crunchgen still will try to figure out as
-  much as possible on its own, but you can override its guessing by
-  specifying the list of .o files explicitly.
-* Crunch itself has been bmake'd and some man pages written, so it
-  should be ready to install.
-* Added patch for FreeBSD from Jordan Hubbard, plus the .conf files used
-  for the FreeBSD install floppies as examples.
-
-
-INTRODUCTION
-
-Crunch is a little package that helps create "crunched" binaries for use
-on boot, install, and fixit floppies.  A crunched binary in this case is
-one where many programs have been linked together into one a.out file.
-The different programs are run depending on the value of argv[0], so
-hard links to the crunched binary suffice to simulate a perfectly normal
-system.
-
-As an example, I have created an 980K crunched "fixit" binary containing
-the following programs in their entirety:
-
-       cat chmod cp date dd df echo ed expr hostname kill ln ls mkdir
-       mt mv pwd rcp rm rmdir sh sleep stty sync test [ badsect
-       clri disklabel dump rdump dmesg fdisk fsck halt ifconfig init
-       mknod mount newfs ping reboot restore rrestore swapon umount
-       ftp rsh sed telnet rlogin vi cpio gzip gunzip gzcat
-
-Note carefully: vi, cpio, gzip, ed, sed, dump/restore, some networking
-utilities, and the disk management utilities, all in a binary small
-enough to fit on a 1.2 MB root filesystem floppy (albeit with the kernel
-on its own boot floppy).  A more reasonable subset can be made to fit
-easily with a kernel for a decent one-disk fixit filesystem.
-
-The linking together of different programs by hand is an old
-space-saving technique.         Crunch automates the process by building the
-necessary stub files and makefile for you (via the crunchgen program),
-and by doctoring the symbol tables of the component .o files to allow
-them to link without "symbol multiply defined" conflicts (via the
-crunchide program).
-
-
-BUILDING CRUNCH
-
-Just type make, then make install.
-
-Crunch was written and tested under NetBSD/i386, but should work under
-other PC BSD systems that use GNU ld.
-
-The crunchgen(1) and crunchide(1) man pages have more details on using
-crunch, and the examples subdirectory contains some working .conf files
-and a sample Makefile.
-
-CREDITS
-
-Thanks to the NetBSD team for a consistently high quality effort in
-bringing together a solid, state of the art development environment.
-
-Thanks to the FreeBSD guys; Rod Grimes, Nate Williams and Jordan
-Hubbard; and to Bruce Evans, for immediate and detailed feedback on
-crunch 0.1, and for pressing me to make the prototype more useable.
-
-Crunch was written for the Maruti Hard Real-Time Operating System
-project at the University of Maryland, to help make for better install
-and recovery procedures for our NetBSD-based development environment. It
-is copyright (c) 1994 by the University of Maryland under a UCB-style
-freely- redistributable notice.         See the file COPYRIGHT for details.
-
-Please let me know of any problems or of enhancements you make to this
-package.  I'm particularly interested in the details of what you found
-was good to put on your fixit or install disks.         Thanks!
-
-Share and Enjoy,
-Jaime
-............................................................................
-: Stand on my shoulders, : jds@cs.umd.edu  :                 James da Silva
-: not on my toes.       : uunet!mimsy!jds : http://www.cs.umd.edu/users/jds
diff --git a/distrib/crunch/crunchgen/Makefile b/distrib/crunch/crunchgen/Makefile
deleted file mode 100644 (file)
index 23625f0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#      $OpenBSD: Makefile,v 1.2 1996/09/25 06:40:52 etheisen Exp $
-
-PROG=          crunchgen
-SRCS=          crunchgen.c crunched_skel.c
-CFLAGS+=       -g -Wall
-CPPFLAGS+=     -DMF_NAMES='"Makefile.bsd-wrapper","Makefile"'
-CLEANFILES+=   crunched_skel.c
-
-crunched_skel.c: crunched_main.c
-       sh ${.CURDIR}/mkskel.sh ${.CURDIR}/crunched_main.c > crunched_skel.c
-
-.include <bsd.prog.mk>
diff --git a/distrib/crunch/crunchgen/crunched_main.c b/distrib/crunch/crunchgen/crunched_main.c
deleted file mode 100644 (file)
index 315a44d..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* $OpenBSD: crunched_main.c,v 1.5 2003/01/27 19:41:30 deraadt Exp $    */
-
-/*
- * Copyright (c) 1994 University of Maryland
- * All Rights Reserved.
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of U.M. not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  U.M. makes no representations about the
- * suitability of this software for any purpose.  It is provided "as is"
- * without express or implied warranty.
- *
- * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
- * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: James da Silva, Systems Design and Analysis Group
- *                        Computer Science Department
- *                        University of Maryland at College Park
- */
-/*
- * crunched_main.c - main program for crunched binaries, it branches to a
- *     particular subprogram based on the value of argv[0].  Also included
- *     is a little program invoked when the crunched binary is called via
- *     its EXECNAME.  This one prints out the list of compiled-in binaries,
- *     or calls one of them based on argv[1].   This allows the testing of
- *     the crunched binary without creating all the links.
- */
-#include <stdio.h>
-#include <string.h>
-
-struct stub {
-       char    *name;
-       int     (*f)();
-};
-
-extern struct stub entry_points[];
-
-int 
-main(int argc, char *argv[], char **envp)
-{
-       char            *slash, *basename;
-       struct stub     *ep;
-
-       if (argv[0] == NULL || *argv[0] == '\0')
-               crunched_usage();
-
-       slash = strrchr(argv[0], '/');
-       basename = slash ? slash + 1 : argv[0];
-
-       for (ep = entry_points; ep->name != NULL; ep++)
-               if (!strcmp(basename, ep->name))
-                       break;
-
-       if (ep->name)
-               return ep->f(argc, argv, envp);
-       else {
-               fprintf(stderr, "%s: %s not compiled in\n", EXECNAME, basename);
-               crunched_usage();
-       }
-}
-
-int 
-crunched_main(int argc, char **argv, char **envp)
-{
-       struct stub     *ep;
-       int             columns, len;
-
-       if (argc <= 1)
-               crunched_usage();
-
-       return main(--argc, ++argv, envp);
-}
-
-int 
-crunched_usage()
-{
-       int             columns, len;
-       struct stub     *ep;
-
-       fprintf(stderr,
-           "Usage: %s <prog> <args> ..., where <prog> is one of:\n",
-           EXECNAME);
-       columns = 0;
-       for (ep = entry_points; ep->name != NULL; ep++) {
-               len = strlen(ep->name) + 1;
-               if (columns + len < 80)
-                       columns += len;
-               else {
-                       fprintf(stderr, "\n");
-                       columns = len;
-               }
-               fprintf(stderr, " %s", ep->name);
-       }
-       fprintf(stderr, "\n");
-       exit(1);
-}
diff --git a/distrib/crunch/crunchgen/crunchgen.1 b/distrib/crunch/crunchgen/crunchgen.1
deleted file mode 100644 (file)
index 8c23ee1..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-.\"    $OpenBSD: crunchgen.1,v 1.21 2007/05/31 19:19:15 jmc Exp $
-.\"
-.\"
-.\" Copyright (c) 1994 University of Maryland
-.\" All Rights Reserved.
-.\"
-.\" Permission to use, copy, modify, distribute, and sell this software and its
-.\" documentation for any purpose is hereby granted without fee, provided that
-.\" the above copyright notice appear in all copies and that both that
-.\" copyright notice and this permission notice appear in supporting
-.\" documentation, and that the name of U.M. not be used in advertising or
-.\" publicity pertaining to distribution of the software without specific,
-.\" written prior permission.  U.M. makes no representations about the
-.\" suitability of this software for any purpose.  It is provided "as is"
-.\" without express or implied warranty.
-.\"
-.\" U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
-.\" BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
-.\" IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-.\"
-.\" Author: James da Silva, Systems Design and Analysis Group
-.\"                       Computer Science Department
-.\"                       University of Maryland at College Park
-.\"
-.Dd $Mdocdate: May 31 2007 $
-.Dt CRUNCHGEN 1
-.Os
-.Sh NAME
-.Nm crunchgen
-.Nd generates build environment for a crunched binary
-.Sh SYNOPSIS
-.Nm crunchgen
-.Bk -words
-.Op Fl Efq
-.Op Fl c Ar c-file-name
-.Op Fl D Ar src-root
-.Op Fl e Ar exec-file-name
-.Op Fl L Ar lib-dir
-.Op Fl m Ar makefile-name
-.Op Fl O Ar objdir-name
-.Ar conf-file
-.Ek
-.Sh DESCRIPTION
-A crunched binary is a program made up of many other programs linked
-together into a single executable.
-The crunched binary main() function determines which component program
-to run by the contents of argv[0].
-The main reason to crunch programs together is for fitting as many programs
-as possible onto an installation or system recovery floppy.
-.Pp
-.Nm
-reads in the specifications in
-.Ar conf-file
-for a crunched binary, and generates a Makefile and accompanying
-top-level C source file that when built create the crunched executable
-file from the component programs.
-For each component program,
-.Nm
-can optionally attempt to determine the object (.o) files that make up
-the program from its source directory Makefile.
-This information is cached in a file named
-.Pa <conf-name>.cache
-between runs.
-.Nm
-uses the companion program
-.Xr crunchide 1
-to eliminate link-time conflicts between the component programs by
-hiding all unnecessary symbols.
-.Pp
-After
-.Nm
-is run, the crunched binary can be built by running
-.Dq make -f <conf-name>.mk .
-The component programs' object files must already be built.
-An
-.Dq objs
-target, included in the output makefile,
-will run make in each component program's source dir to build the object
-files for the user.
-This is not done automatically since in release engineering circumstances
-it is generally not desirable to be modifying objects in other directories.
-.Pp
-The options are as follows:
-.Bl -tag -width indent
-.It Fl c Ar c-file-name
-Set output C file name to
-.Ar c-file-name .
-The default name is
-.Dq Ao conf-name Ac Ns \&.c .
-.It Fl D Ar src-root
-Assume that relative source directory specifications begin with
-.Ar src-root .
-.It Fl E
-Don't prepend stub names with an underscore.
-Used for architectures that don't have underscore prepended to symbol names.
-Example mips ELF.
-.It Fl e Ar exec-file-name
-Set crunched binary executable file name to
-.Ar exec-file-name .
-The default name is
-.Dq Aq conf-name .
-.It Fl f
-Flush cache.
-Forces the recalculation of cached parameters.
-.It Fl L Ar lib-dir
-Try to obtain libraries from
-.Ar lib-dir .
-.It Fl m Ar makefile-name
-Set output Makefile name to
-.Ar makefile-name .
-The default name is
-.Dq Ao conf-name Ac Ns \&.mk .
-.It Fl O Ar objdir-name
-Specify an object directory to use.
-It defaults to
-.Dq obj ,
-though for cross building purposes it can be used to specify
-obj.${HOST}.${MACHINE}.
-Normally used with the make variable ${MAKEOBJDIR}.
-.It Fl q
-Quiet operation.
-Status messages are suppressed.
-.El
-.Sh CRUNCHGEN CONFIGURATION FILE COMMANDS
-.Nm
-reads specifications from the
-.Ar conf-file
-that describe the components of the crunched binary.
-In its simplest use, the component program names are merely listed
-along with the top-level source directories in which their sources
-can be found.
-.Nm
-then calculates (via the source makefiles) and caches the
-list of object files and their locations.
-For more specialized situations, the user can specify by hand
-all the parameters that
-.Nm
-needs.
-.Pp
-The
-.Ar conf-file
-commands are as follows:
-.Bl -tag -width indent
-.It srcdirs Ar dirname ...
-A list of source trees in which the source directories of the
-component programs can be found.
-These dirs are searched using the BSD
-.Dq <source-dir>/<progname>/
-convention.
-Multiple srcdirs lines can be specified.
-The directories are searched in the order they are given.
-.It libdirs Ar dirname
-A list of source trees in which the source directories for supplementary
-libraries can be found.
-.It progs Ar progname ...
-A list of programs that make up the crunched binary.
-Multiple progs lines can be specified.
-.It libs Ar libspec ...
-A list of library specifications to be included in the crunched binary link.
-Multiple libs lines can be specified.
-.It ln Ar progname linkname
-Causes the crunched binary to invoke
-.Ar progname
-whenever
-.Ar linkname
-appears in argv[0].
-This allows programs that change their behavior when
-run under different names to operate correctly.
-.El
-.Pp
-To handle specialized situations, such as when the source is not
-available or not built via a conventional Makefile, the following
-.Ic special
-commands can be used to set
-.Nm
-parameters for a component program.
-.Bl -tag -width indent
-.It special Ar progname No srcdir Ar pathname
-Set the source directory for
-.Ar progname .
-This is normally calculated by searching the specified srcdirs
-for a directory named
-.Ar progname .
-.It special Ar progname No objdir Ar pathname
-Set the obj directory for
-.Ar progname .
-This is normally calculated by looking for a directory named
-.Dq obj
-under the
-.Ar srcdir ,
-and if that is not found, the
-.Ar srcdir
-itself becomes the objdir.
-.It special Ar progname No objs Ar object-file-name ...
-Set the list of object files for program
-.Ar progname .
-This is normally calculated by constructing a temporary makefile that includes
-.Dq srcdir/Makefile
-and outputs the value of $(OBJS).
-.It special Ar progname No objpaths Ar full-pathname-to-object-file ...
-Sets the pathnames of the object files for program
-.Ar progname .
-This is normally calculated by prepending the objdir
-pathname to each file in the objs list.
-.El
-.Pp
-Only the objpaths parameter is actually needed by
-.Nm crunchgen ,
-but it is calculated from objdir and objs,
-which are in turn calculated from srcdir,
-so it is sometimes convenient to specify the earlier parameters and let
-.Nm
-calculate forward from there if it can.
-.Pp
-The makefile produced by
-.Nm
-contains an optional
-.Ar objs
-target that will build the object files for each component program by
-running make inside that program's source directory.
-For this to work the srcdir and objs parameters must also be valid.
-If they are not valid for a particular program, that program is skipped in the
-.Ar objs
-target.
-.Sh EXAMPLES
-Here is an example
-.Nm
-input conf file, named
-.Pa kcopy.conf :
-.Bd -literal -offset indent
-srcdirs /usr/src/bin /usr/src/sbin
-
-progs test cp echo sh fsck halt init mount umount myinstall
-ln test [       # test can be invoked via [
-ln sh -sh       # init invokes the shell with "-sh" in argv[0]
-
-special myprog objpaths /homes/leroy/src/myinstall.o # no sources
-
-libs -lutil -lcrypt
-.Ed
-.Pp
-This conf file specifies a small crunched binary consisting of some
-basic system utilities plus a home-grown install program
-.Dq myinstall ,
-for which no source directory is specified, but its object file is
-specified directly with the
-.Ic special
-line.
-.Pp
-The crunched binary
-.Dq kcopy
-can be built as follows:
-.Bd -literal -offset indent
-% crunchgen -m Makefile kcopy.conf    # gen Makefile and kcopy.c
-% make objs            # build the component programs' .o files
-% make                 # build the crunched binary kcopy
-% kcopy sh             # test that this invokes a sh shell
-$                      # it works!
-.Ed
-.Pp
-At this point the binary
-.Dq kcopy
-can be copied onto an install floppy
-and hard-linked to the names of the component programs.
-.Sh SEE ALSO
-.Xr crunchide 1
-.Sh AUTHORS
-.Nm
-was written by James da Silva
-.Aq jds@cs.umd.edu .
-.Pp
-Copyright (c) 1994 University of Maryland.  All Rights Reserved.
-.Sh CAVEATS
-While
-.Nm
-takes care to eliminate link conflicts between the component programs
-of a crunched binary, conflicts are still possible between the
-libraries that are linked in.
-Some shuffling in the order of libraries may be required,
-and in some rare cases two libraries may
-have an unresolvable conflict and thus cannot be crunched together.
-.Pp
-Some versions of the BSD build environment do not by default build the
-intermediate object file for single-source file programs.
-The
-.Dq make objs
-target must then be used to get those object files built,
-or some other arrangements made.
diff --git a/distrib/crunch/crunchgen/crunchgen.c b/distrib/crunch/crunchgen/crunchgen.c
deleted file mode 100644 (file)
index 7829fdd..0000000
+++ /dev/null
@@ -1,1020 +0,0 @@
-/* $OpenBSD: crunchgen.c,v 1.28 2006/12/26 10:20:11 deraadt Exp $       */
-
-/*
- * Copyright (c) 1994 University of Maryland
- * All Rights Reserved.
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of U.M. not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  U.M. makes no representations about the
- * suitability of this software for any purpose.  It is provided "as is"
- * without express or implied warranty.
- *
- * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
- * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: James da Silva, Systems Design and Analysis Group
- *                        Computer Science Department
- *                        University of Maryland at College Park
- */
-/*
- * ========================================================================
- * crunchgen.c
- *
- * Generates a Makefile and main C file for a crunched executable,
- * from specs given in a .conf file.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <string.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-
-#define CRUNCH_VERSION "0.3"
-
-#define MAXLINELEN     16384
-#define MAXFIELDS       2048
-
-/* XXX - This should be runtime configurable */
-/*
- * We might have more than one makefile
- * name on any given platform. Make sure
- * default name is last though.
- */
-char           *mf_name[] = {
-#if defined(MF_NAMES)
-       MF_NAMES,
-#else
-       "Makefile",
-#endif
-       NULL
-};
-
-/* internal representation of conf file: */
-
-/* simple lists of strings suffice for most parms */
-
-typedef struct strlst {
-       struct strlst  *next;
-       char           *str;
-} strlst_t;
-
-/* progs have structure, each field can be set with "special" or calculated */
-
-typedef struct prog {
-       struct prog    *next;
-       char           *name, *ident, *mf_name;
-       char           *srcdir, *objdir;
-       strlst_t       *objs, *objpaths;
-       strlst_t       *links;
-       int             goterror;
-} prog_t;
-
-strlst_t       *srcdirs = NULL;
-strlst_t       *libs = NULL;
-strlst_t       *libdirs = NULL;
-char           objdir[MAXPATHLEN] = "obj";
-prog_t         *progs = NULL;
-
-char            line[MAXLINELEN];
-
-char            confname[MAXPATHLEN], infilename[MAXPATHLEN];
-char            outmkname[MAXPATHLEN], outcfname[MAXPATHLEN];
-char            cachename[MAXPATHLEN], curfilename[MAXPATHLEN];
-char            topdir[MAXPATHLEN], execfname[MAXPATHLEN];
-int             linenum = -1;
-int             goterror = 0;
-
-char           *progname = "crunchgen";
-
-int             verbose, readcache, elf_names; /* options */
-int             reading_cache;
-
-void            status(char *str);
-void            out_of_memory(void);
-void            add_string(strlst_t ** listp, char *str);
-int             is_dir(char *pathname);
-int             is_nonempty_file(char *pathname);
-void            usage(void);
-void            parse_conf_file(void);
-void            gen_outputs(void);
-
-int 
-main(int argc, char *argv[])
-{
-       char           *p;
-       int             optc;
-       extern int      optind;
-       extern char    *optarg;
-
-       verbose = 1;
-       readcache = 1;
-       *outmkname = *outcfname = *execfname = '\0';
-
-       if (argc > 0)
-               progname = argv[0];
-
-       while ((optc = getopt(argc, argv, "m:c:e:fqD:EL:O:")) != -1) {
-               switch (optc) {
-               case 'f':
-                       readcache = 0;
-                       break;
-               case 'q':
-                       verbose = 0;
-                       break;
-
-               case 'm':
-                       if (strlcpy(outmkname, optarg, sizeof(outmkname)) >=
-                           sizeof(outmkname))
-                               usage();
-                       break;
-               case 'c':
-                       if (strlcpy(outcfname, optarg, sizeof(outcfname)) >=
-                           sizeof(outcfname))
-                               usage();
-                       break;
-               case 'e':
-                       if (strlcpy(execfname, optarg, sizeof(execfname)) >=
-                           sizeof(execfname))
-                               usage();
-                       break;
-
-               case 'D':
-                       if (strlcpy(topdir, optarg, sizeof(topdir)) >= sizeof(topdir))
-                               usage();
-                       break;
-               case 'E':
-                       elf_names = 1;
-                       break;
-               case 'L':
-                       if (strlen(optarg) >= MAXPATHLEN)
-                               usage();
-                       add_string(&libdirs, optarg);
-                       break;
-               case 'O':
-                       if (strlcpy(objdir, optarg, sizeof(objdir)) >=
-                           sizeof(objdir))
-                               usage();
-                       break;
-               default:
-                       usage();
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-
-       if (argc != 1)
-               usage();
-
-       if (libdirs == NULL)
-               add_string(&libdirs, "/usr/lib");
-       /*
-         * generate filenames
-         */
-
-       if (strlcpy(infilename, argv[0], sizeof(infilename)) >=
-           sizeof(infilename))
-               usage();
-
-       /* confname = `basename infilename .conf` */
-
-       if ((p = strrchr(infilename, '/')) != NULL)
-               strlcpy(confname, p + 1, sizeof confname);
-       else
-               strlcpy(confname, infilename, sizeof confname);
-       if ((p = strrchr(confname, '.')) != NULL && !strcmp(p, ".conf"))
-               *p = '\0';
-
-       if (!*outmkname)
-               snprintf(outmkname, sizeof(outmkname), "%s.mk", confname);
-       if (!*outcfname)
-               snprintf(outcfname, sizeof(outcfname), "%s.c", confname);
-       if (!*execfname)
-               snprintf(execfname, sizeof(execfname), "%s", confname);
-       snprintf(cachename, sizeof(cachename), "%s.cache", confname);
-
-       parse_conf_file();
-       gen_outputs();
-
-       exit(goterror);
-}
-
-void 
-usage(void)
-{
-       fprintf(stderr,
-           "usage: %s [-Efq] [-c c-file-name] [-D src-root] [-e exec-file-name]\n"
-           "\t[-L lib-dir] [-m makefile-name] [-O objdir-name] conf-file\n",
-           progname);
-       exit(1);
-}
-
-void            parse_one_file(char *filename);
-void            parse_line(char *line, int *fc, char **fv, int nf);
-void            add_srcdirs(int argc, char **argv);
-void            add_progs(int argc, char **argv);
-void            add_link(int argc, char **argv);
-void            add_libs(int argc, char **argv);
-void            add_libdirs(int argc, char **argv);
-void            add_special(int argc, char **argv);
-
-prog_t         *find_prog(char *str);
-void            add_prog(char *progname);
-
-void 
-parse_conf_file(void)
-{
-       if (!is_nonempty_file(infilename)) {
-               fprintf(stderr, "%s: fatal: input file \"%s\" not found.\n",
-                   progname, infilename);
-               exit(1);
-       }
-       parse_one_file(infilename);
-       if (readcache && is_nonempty_file(cachename)) {
-               reading_cache = 1;
-               parse_one_file(cachename);
-       }
-}
-
-void 
-parse_one_file(char *filename)
-{
-       char           *fieldv[MAXFIELDS];
-       int             fieldc;
-       void            (*f) (int c, char **v);
-       FILE           *cf;
-
-       snprintf(line, sizeof(line), "reading %s", filename);
-       status(line);
-       strlcpy(curfilename, filename, sizeof curfilename);
-
-       if ((cf = fopen(curfilename, "r")) == NULL) {
-               perror(curfilename);
-               goterror = 1;
-               return;
-       }
-       linenum = 0;
-       while (fgets(line, MAXLINELEN, cf) != NULL) {
-               linenum++;
-               parse_line(line, &fieldc, fieldv, MAXFIELDS);
-               if (fieldc < 1)
-                       continue;
-               if (!strcmp(fieldv[0], "srcdirs"))
-                       f = add_srcdirs;
-               else if (!strcmp(fieldv[0], "progs"))
-                       f = add_progs;
-               else if (!strcmp(fieldv[0], "ln"))
-                       f = add_link;
-               else if (!strcmp(fieldv[0], "libs"))
-                       f = add_libs;
-               else if (!strcmp(fieldv[0], "special"))
-                       f = add_special;
-               else if (!strcmp(fieldv[0], "libdirs"))
-                       f = add_libdirs;
-               else {
-                       fprintf(stderr, "%s:%d: skipping unknown command `%s'.\n",
-                           curfilename, linenum, fieldv[0]);
-                       goterror = 1;
-                       continue;
-               }
-               if (fieldc < 2) {
-                       fprintf(stderr,
-                           "%s:%d: %s command needs at least 1 "
-                           "argument, skipping.\n",
-                           curfilename, linenum, fieldv[0]);
-                       goterror = 1;
-                       continue;
-               }
-               f(fieldc, fieldv);
-       }
-
-       if (ferror(cf)) {
-               perror(curfilename);
-               goterror = 1;
-       }
-       fclose(cf);
-}
-
-void 
-parse_line(char *line, int *fc, char **fv, int nf)
-{
-       char           *p;
-
-       p = line;
-       *fc = 0;
-       while (1) {
-               while (isspace(*p))
-                       p++;
-               if (*p == '\0' || *p == '#')
-                       break;
-
-               if (*fc < nf)
-                       fv[(*fc)++] = p;
-               while (*p && !isspace(*p) && *p != '#')
-                       p++;
-               if (*p == '\0' || *p == '#')
-                       break;
-               *p++ = '\0';
-       }
-       if (*p)
-               *p = '\0';      /* needed for '#' case */
-}
-
-void 
-add_srcdirs(int argc, char **argv)
-{
-       int             i;
-       char            tmppath[MAXPATHLEN];
-       int             overflow;
-
-       for (i = 1; i < argc; i++) {
-               overflow = 0;
-               if (argv[i][0] == '/' || topdir[0] == '\0') {
-                       if (strlcpy(tmppath, argv[i], sizeof(tmppath)) >=
-                           sizeof(tmppath))
-                               overflow = 1;
-               } else {
-                       if (strlcpy(tmppath, topdir, sizeof(tmppath)) >=
-                           sizeof(tmppath) ||
-                           strlcat(tmppath, "/", sizeof(tmppath)) >=
-                           sizeof(tmppath) ||
-                           strlcat(tmppath, argv[i], sizeof(tmppath)) >=
-                           sizeof(tmppath))
-                               overflow = 1;
-               }
-               if (overflow) {
-                       goterror = 1;
-                       fprintf(stderr, "%s:%d: `%.40s...' is too long, skipping it.\n",
-                           curfilename, linenum, argv[i]);
-                       continue;
-               }
-               if (is_dir(tmppath))
-                       add_string(&srcdirs, tmppath);
-               else {
-                       fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n",
-                           curfilename, linenum, tmppath);
-                       goterror = 1;
-               }
-       }
-}
-
-void 
-add_libdirs(int argc, char **argv)
-{
-       int             i;
-       char            tmppath[MAXPATHLEN];
-       char            tmppath2[MAXPATHLEN];
-       int             overflow;
-
-       for (i = 1; i < argc; i++) {
-               overflow = 0;
-               if (argv[i][0] == '/' || topdir[0] == '\0') {
-                       if (strlcpy(tmppath, argv[i], sizeof(tmppath)) >=
-                           sizeof(tmppath))
-                               overflow = 1;
-               } else {
-                       if (strlcpy(tmppath, topdir, sizeof(tmppath)) >=
-                           sizeof(tmppath) ||
-                           strlcat(tmppath, "/", sizeof(tmppath)) >=
-                           sizeof(tmppath) ||
-                           strlcat(tmppath, argv[i], sizeof(tmppath)) >=
-                           sizeof(tmppath))
-                               overflow = 1;
-               }
-               if (overflow) {
-                       goterror = 1;
-                       fprintf(stderr, "%s:%d: `%.40s...' is too long, skipping it.\n",
-                           curfilename, linenum, argv[i]);
-                       continue;
-               }
-               if (is_dir(tmppath)) {
-                       snprintf(tmppath2, sizeof(tmppath2), "%s/%s", tmppath,
-                           objdir);
-                       if (is_dir(tmppath2))
-                               add_string(&libdirs, tmppath2);
-                       else {
-                               snprintf(tmppath2, sizeof(tmppath2), 
-                                   "%s/obj.%s", tmppath, MACHINE);
-                               if (is_dir(tmppath2))
-                                       add_string(&libdirs, tmppath2);
-                               else
-                                       add_string(&libdirs, tmppath);
-                       }
-               }
-               else {
-                       fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n",
-                           curfilename, linenum, tmppath);
-                       goterror = 1;
-               }
-       }
-}
-
-
-void 
-add_progs(int argc, char **argv)
-{
-       int             i;
-
-       for (i = 1; i < argc; i++)
-               add_prog(argv[i]);
-}
-
-void 
-add_prog(char *progname)
-{
-       prog_t         *p1, *p2;
-
-       /* add to end, but be smart about dups */
-
-       for (p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next)
-               if (!strcmp(p2->name, progname))
-                       return;
-
-       p2 = calloc(1, sizeof(prog_t));
-       if (p2)
-               p2->name = strdup(progname);
-       if (!p2 || !p2->name)
-               out_of_memory();
-
-       p2->next = NULL;
-       if (p1 == NULL)
-               progs = p2;
-       else
-               p1->next = p2;
-
-       p2->ident = p2->srcdir = p2->objdir = NULL;
-       p2->links = p2->objs = NULL;
-       p2->goterror = 0;
-}
-
-void 
-add_link(int argc, char **argv)
-{
-       int             i;
-       prog_t         *p = find_prog(argv[1]);
-
-       if (p == NULL) {
-               fprintf(stderr,
-                   "%s:%d: no prog %s previously declared, skipping link.\n",
-                   curfilename, linenum, argv[1]);
-               goterror = 1;
-               return;
-       }
-       for (i = 2; i < argc; i++)
-               add_string(&p->links, argv[i]);
-}
-
-void 
-add_libs(int argc, char **argv)
-{
-       int             i;
-
-       for (i = 1; i < argc; i++)
-               add_string(&libs, argv[i]);
-}
-
-void 
-add_special(int argc, char **argv)
-{
-       int             i;
-       prog_t         *p = find_prog(argv[1]);
-
-       if (p == NULL) {
-               if (reading_cache)
-                       return;
-               fprintf(stderr,
-                   "%s:%d: no prog %s previously declared, skipping special.\n",
-                   curfilename, linenum, argv[1]);
-               goterror = 1;
-               return;
-       }
-       if (!strcmp(argv[2], "ident")) {
-               if (argc != 4)
-                       goto argcount;
-               if ((p->ident = strdup(argv[3])) == NULL)
-                       out_of_memory();
-       } else if (!strcmp(argv[2], "srcdir")) {
-               if (argc != 4)
-                       goto argcount;
-               if ((p->srcdir = strdup(argv[3])) == NULL)
-                       out_of_memory();
-       } else if (!strcmp(argv[2], "mf_name")) {
-               if (argc != 4)
-                       goto argcount;
-               if ((p->mf_name = strdup(argv[3])) == NULL)
-                       out_of_memory();
-       } else if (!strcmp(argv[2], "objdir")) {
-               if (argc != 4)
-                       goto argcount;
-               if ((p->objdir = strdup(argv[3])) == NULL)
-                       out_of_memory();
-       } else if (!strcmp(argv[2], "objs")) {
-               p->objs = NULL;
-               for (i = 3; i < argc; i++)
-                       add_string(&p->objs, argv[i]);
-       } else if (!strcmp(argv[2], "objpaths")) {
-               p->objpaths = NULL;
-               for (i = 3; i < argc; i++)
-                       add_string(&p->objpaths, argv[i]);
-       } else {
-               fprintf(stderr, "%s:%d: bad parameter name `%s', skipping line.\n",
-                   curfilename, linenum, argv[2]);
-               goterror = 1;
-       }
-       return;
-
-argcount:
-       fprintf(stderr,
-           "%s:%d: too %s arguments, expected \"special %s %s <string>\".\n",
-           curfilename, linenum, argc < 4 ? "few" : "many", argv[1], argv[2]);
-       goterror = 1;
-}
-
-prog_t  *
-find_prog(char *str)
-{
-       prog_t         *p;
-
-       for (p = progs; p != NULL; p = p->next)
-               if (!strcmp(p->name, str))
-                       return p;
-       return NULL;
-}
-
-void            remove_error_progs(void);
-void            fillin_program(prog_t * p);
-void            gen_specials_cache(void);
-void            gen_output_makefile(void);
-void            gen_output_cfile(void);
-
-void            fillin_program_objs(prog_t * p, char *path);
-void            top_makefile_rules(FILE * outmk);
-void            prog_makefile_rules(FILE * outmk, prog_t * p);
-void            output_strlst(FILE * outf, strlst_t * lst);
-char           *genident(char *str);
-char           *dir_search(char *progname);
-
-void 
-gen_outputs(void)
-{
-       prog_t         *p;
-
-       for (p = progs; p != NULL; p = p->next)
-               fillin_program(p);
-
-       remove_error_progs();
-       gen_specials_cache();
-       gen_output_cfile();
-       gen_output_makefile();
-       status("");
-       fprintf(stderr,
-           "Run \"make -f %s objs exe\" to build crunched binary.\n",
-           outmkname);
-}
-
-void 
-fillin_program(prog_t * p)
-{
-       char            path[MAXPATHLEN];
-       char           *srcparent;
-       strlst_t       *s;
-       int             i;
-
-       snprintf(line, sizeof(line), "filling in parms for %s", p->name);
-       status(line);
-
-       if (!p->ident)
-               p->ident = genident(p->name);
-       if (!p->srcdir) {
-               srcparent = dir_search(p->name);
-               if (srcparent)
-                       snprintf(path, sizeof(path), "%s/%s", srcparent, p->name);
-               if (is_dir(path))
-                       p->srcdir = strdup(path);
-       }
-       if (!p->objdir && p->srcdir) {
-               snprintf(path, sizeof(path), "%s/%s", p->srcdir, objdir);
-               if (is_dir(path))
-                       p->objdir = strdup(path);
-               else {
-                       snprintf(path, sizeof(path), "%s/obj.%s", p->srcdir, MACHINE);
-                       if (is_dir(path))
-                               p->objdir = strdup(path);
-                       else
-                               p->objdir = p->srcdir;
-               }
-       }
-       /* We have a sourcedir and no explicit objs, try */
-       /* to find makefile and get objs from it. */
-       if (p->srcdir && !p->objs) {
-               for (i = 0; mf_name[i] != NULL; i++) {
-                       snprintf(path, sizeof(path), "%s/%s", p->srcdir, mf_name[i]);
-                       if (is_nonempty_file(path)) {
-                               p->mf_name = mf_name[i];
-                               fillin_program_objs(p, path);
-                               break;
-                       }
-               }
-       }
-       if (!p->objpaths && p->objdir && p->objs)
-               for (s = p->objs; s != NULL; s = s->next) {
-                       snprintf(line, sizeof(line), "%s/%s", p->objdir, s->str);
-                       add_string(&p->objpaths, line);
-               }
-
-       if (!p->srcdir && verbose)
-               fprintf(stderr, "%s: %s: warning: could not find source directory.\n",
-                   infilename, p->name);
-       if (!p->objs && verbose)
-               fprintf(stderr, "%s: %s: warning: could not find any .o files.\n",
-                   infilename, p->name);
-
-       if (!p->objpaths) {
-               fprintf(stderr,
-                   "%s: %s: error: no objpaths specified or calculated.\n",
-                   infilename, p->name);
-               p->goterror = goterror = 1;
-       }
-}
-
-void 
-fillin_program_objs(prog_t * p, char *path)
-{
-       char           *cp, *obj, tempfname[MAXPATHLEN];
-       int             fd, rc;
-       FILE           *f;
-
-       /* discover the objs from the srcdir Makefile */
-
-       snprintf(tempfname, sizeof(tempfname), ".tmp_%sXXXXXXXXXX", confname);
-       if ((fd = mkstemp(tempfname)) == -1 || (f = fdopen(fd, "w")) == NULL) {
-               if (fd != -1)
-                       close(fd);
-               perror(tempfname);
-               goterror = 1;
-               return;
-       }
-       fprintf(f, ".include \"%s\"\n", path);
-       fprintf(f, ".if defined(PROG) && !defined(OBJS)\n");
-       fprintf(f, "OBJS=${PROG}.o\n");
-       fprintf(f, ".endif\n");
-       fprintf(f, "crunchgen_objs:\n\t@echo 'OBJS= '${OBJS}\n");
-       fclose(f);
-
-       snprintf(line, sizeof(line), "make -f %s crunchgen_objs 2>&1", tempfname);
-       if ((f = popen(line, "r")) == NULL) {
-               perror("submake pipe");
-               goterror = 1;
-               return;
-       }
-       while (fgets(line, MAXLINELEN, f)) {
-               if (strncmp(line, "OBJS= ", 6)) {
-                       if (strcmp(line,
-                           "sh: warning: running as root with dot in PATH\n") == 0)
-                               continue;
-                       fprintf(stderr, "make error: %s", line);
-                       goterror = 1;
-                       continue;
-               }
-               cp = line + 6;
-               while (isspace(*cp))
-                       cp++;
-               while (*cp) {
-                       obj = cp;
-                       while (*cp && !isspace(*cp))
-                               cp++;
-                       if (*cp)
-                               *cp++ = '\0';
-                       add_string(&p->objs, obj);
-                       while (isspace(*cp))
-                               cp++;
-               }
-       }
-       if ((rc = pclose(f)) != 0) {
-               fprintf(stderr, "make error: make returned %d\n", rc);
-               goterror = 1;
-       }
-       unlink(tempfname);
-}
-
-void 
-remove_error_progs(void)
-{
-       prog_t         *p1, *p2;
-
-       p1 = NULL;
-       p2 = progs;
-       while (p2 != NULL) {
-               if (!p2->goterror)
-                       p1 = p2, p2 = p2->next;
-               else {
-                       /* delete it from linked list */
-                       fprintf(stderr, "%s: %s: ignoring program because of errors.\n",
-                           infilename, p2->name);
-                       if (p1)
-                               p1->next = p2->next;
-                       else
-                               progs = p2->next;
-                       p2 = p2->next;
-               }
-       }
-}
-
-void 
-gen_specials_cache(void)
-{
-       FILE           *cachef;
-       prog_t         *p;
-
-       snprintf(line, sizeof(line), "generating %s", cachename);
-       status(line);
-
-       if ((cachef = fopen(cachename, "w")) == NULL) {
-               perror(cachename);
-               goterror = 1;
-               return;
-       }
-       fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n",
-           cachename, infilename, CRUNCH_VERSION);
-
-       for (p = progs; p != NULL; p = p->next) {
-               fprintf(cachef, "\n");
-               if (p->srcdir)
-                       fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir);
-               if (p->mf_name)
-                       fprintf(cachef, "special %s mf_name %s\n", p->name, p->mf_name);
-               if (p->objdir)
-                       fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir);
-               if (p->objs) {
-                       fprintf(cachef, "special %s objs", p->name);
-                       output_strlst(cachef, p->objs);
-               }
-               fprintf(cachef, "special %s objpaths", p->name);
-               output_strlst(cachef, p->objpaths);
-       }
-       fclose(cachef);
-}
-
-void 
-gen_output_makefile(void)
-{
-       prog_t         *p;
-       FILE           *outmk;
-
-       snprintf(line, sizeof(line), "generating %s", outmkname);
-       status(line);
-
-       if ((outmk = fopen(outmkname, "w")) == NULL) {
-               perror(outmkname);
-               goterror = 1;
-               return;
-       }
-       fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n",
-           outmkname, infilename, CRUNCH_VERSION);
-
-       top_makefile_rules(outmk);
-
-       for (p = progs; p != NULL; p = p->next)
-               prog_makefile_rules(outmk, p);
-
-       fprintf(outmk, "\n# ========\n");
-       fclose(outmk);
-}
-
-void 
-gen_output_cfile(void)
-{
-       extern char    *crunched_skel[];
-       char          **cp;
-       FILE           *outcf;
-       prog_t         *p;
-       strlst_t       *s;
-
-       snprintf(line, sizeof(line), "generating %s", outcfname);
-       status(line);
-
-       if ((outcf = fopen(outcfname, "w")) == NULL) {
-               perror(outcfname);
-               goterror = 1;
-               return;
-       }
-       fprintf(outcf, "/* %s - generated from %s by crunchgen %s */\n",
-           outcfname, infilename, CRUNCH_VERSION);
-
-       fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname);
-       for (cp = crunched_skel; *cp != NULL; cp++)
-               fprintf(outcf, "%s\n", *cp);
-
-       for (p = progs; p != NULL; p = p->next)
-               fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident);
-
-       fprintf(outcf, "\nstruct stub entry_points[] = {\n");
-       for (p = progs; p != NULL; p = p->next) {
-               fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
-                       p->name, p->ident);
-               for (s = p->links; s != NULL; s = s->next)
-                       fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
-                               s->str, p->ident);
-       }
-
-       fprintf(outcf, "\t{ EXECNAME, crunched_main },\n");
-       fprintf(outcf, "\t{ NULL, NULL }\n};\n");
-       fclose(outcf);
-}
-
-char           *
-genident(char *str)
-{
-       char           *n, *s, *d;
-
-       /*
-         * generates a Makefile/C identifier from a program name, mapping '-' to
-         * '_' and ignoring all other non-identifier characters.  This leads to
-         * programs named "foo.bar" and "foobar" to map to the same identifier.
-         */
-
-       if ((n = strdup(str)) == NULL)
-               return NULL;
-       for (d = s = n; *s != '\0'; s++) {
-               if (*s == '-')
-                       *d++ = '_';
-               else if (*s == '_' || isalnum(*s))
-                       *d++ = *s;
-       }
-       *d = '\0';
-       return n;
-}
-
-char           *
-dir_search(char *progname)
-{
-       char            path[MAXPATHLEN];
-       strlst_t       *dir;
-
-       for (dir = srcdirs; dir != NULL; dir = dir->next) {
-               snprintf(path, sizeof(path), "%s/%s", dir->str, progname);
-               if (is_dir(path))
-                       return dir->str;
-       }
-       return NULL;
-}
-
-void 
-top_makefile_rules(FILE * outmk)
-{
-       prog_t         *p;
-       strlst_t       *l;
-
-
-       fprintf(outmk, "STRIP?=strip\n");
-       fprintf(outmk, "LINK=$(LD) -dc -r\n");
-       fprintf(outmk, "LIBS=");
-       for (l = libdirs; l != NULL; l = l->next)
-               fprintf(outmk, " -L%s", l->str);
-       output_strlst(outmk, libs);
-
-       fprintf(outmk, "CRUNCHED_OBJS=");
-       for (p = progs; p != NULL; p = p->next)
-               fprintf(outmk, " %s.lo", p->name);
-       fprintf(outmk, "\n");
-
-       fprintf(outmk, "SUBMAKE_TARGETS=");
-       for (p = progs; p != NULL; p = p->next)
-               fprintf(outmk, " %s_make", p->ident);
-       fprintf(outmk, "\n\n");
-
-       fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS)\n",
-           execfname, execfname);
-       fprintf(outmk, "\t$(CC) -static -o $@ %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
-           execfname);
-       fprintf(outmk, "\t$(STRIP) %s\n", execfname);
-       fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
-       fprintf(outmk, "exe: %s\n", execfname);
-       fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n",
-           execfname);
-       fprintf(outmk, ".PHONY: all objs exe clean $(SUBMAKE_TARGETS)\n\n");
-}
-
-void 
-prog_makefile_rules(FILE * outmk, prog_t * p)
-{
-       fprintf(outmk, "\n# -------- %s\n\n", p->name);
-
-       if (p->srcdir && p->objs) {
-               fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
-               fprintf(outmk, "%s_OBJS=", p->ident);
-               output_strlst(outmk, p->objs);
-               fprintf(outmk, "%s_make:\n", p->ident);
-               fprintf(outmk, "\tcd $(%s_SRCDIR) && exec $(MAKE) -f %s $(%s_OBJS)\n\n",
-                   p->ident, p->mf_name, p->ident);
-       } else
-               fprintf(outmk, "%s_make:\n\t@echo \"** cannot make objs for %s\"\n\n",
-                   p->ident, p->name);
-
-       fprintf(outmk, "%s_OBJPATHS=", p->ident);
-       output_strlst(outmk, p->objpaths);
-
-       fprintf(outmk, "%s_stub.c:\n", p->name);
-       fprintf(outmk, "\techo \""
-           "int _crunched_%s_stub(int argc, char **argv, char **envp)"
-           "{return main(argc,argv,envp);}\" >$@\n",
-           p->ident);
-       fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n",
-           p->name, p->name, p->ident);
-       fprintf(outmk, "\t$(LINK) -o $@ %s_stub.o $(%s_OBJPATHS)\n",
-           p->name, p->ident);
-       fprintf(outmk, "\tcrunchide -k %s_crunched_%s_stub $@\n",
-           elf_names ? "" : "_", p->ident);
-}
-
-void 
-output_strlst(FILE * outf, strlst_t * lst)
-{
-       for (; lst != NULL; lst = lst->next)
-               fprintf(outf, " %s", lst->str);
-       fprintf(outf, "\n");
-}
-
-void 
-status(char *str)
-{
-       static int      lastlen = 0;
-       int             len, spaces;
-
-       if (!verbose)
-               return;
-
-       len = strlen(str);
-       spaces = lastlen - len;
-       if (spaces < 1)
-               spaces = 1;
-
-       fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " ");
-       fflush(stderr);
-       lastlen = len;
-}
-
-void 
-out_of_memory(void)
-{
-       fprintf(stderr, "%s: %d: out of memory, stopping.\n", infilename, linenum);
-       exit(1);
-}
-
-void 
-add_string(strlst_t ** listp, char *str)
-{
-       strlst_t       *p1, *p2;
-
-       /* add to end, but be smart about dups */
-
-       for (p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next)
-               if (!strcmp(p2->str, str))
-                       return;
-
-       p2 = calloc(1, sizeof(strlst_t));
-       if (p2)
-               p2->str = strdup(str);
-       if (!p2 || !p2->str)
-               out_of_memory();
-
-       p2->next = NULL;
-       if (p1 == NULL)
-               *listp = p2;
-       else
-               p1->next = p2;
-}
-
-int 
-is_dir(char *pathname)
-{
-       struct stat     buf;
-
-       if (stat(pathname, &buf) == -1)
-               return 0;
-       return S_ISDIR(buf.st_mode);
-}
-
-int 
-is_nonempty_file(char *pathname)
-{
-       struct stat     buf;
-
-       if (stat(pathname, &buf) == -1)
-               return 0;
-
-       return S_ISREG(buf.st_mode) && buf.st_size > 0;
-}
diff --git a/distrib/crunch/crunchgen/mkskel.sh b/distrib/crunch/crunchgen/mkskel.sh
deleted file mode 100644 (file)
index 676705b..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#! /bin/sh
-#      $OpenBSD: mkskel.sh,v 1.2 2000/03/01 22:10:03 todd Exp $
-
-# idea and sed lines taken straight from flex
-
-cat <<!EOF
-/* File created via mkskel.sh */
-
-char *crunched_skel[] = {
-!EOF
-
-sed 's/\\/&&/g' $* | sed 's/"/\\"/g' | sed 's/.*/  "&",/'
-
-cat <<!EOF
-  0
-};
-!EOF
diff --git a/distrib/crunch/crunchide/Makefile b/distrib/crunch/crunchide/Makefile
deleted file mode 100644 (file)
index 430fee3..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#      $OpenBSD: Makefile,v 1.4 2000/03/01 22:10:03 todd Exp $
-
-PROG=   crunchide
-SRCS=  crunchide.c elf_hide.c ecoff_hide.c
-
-.include <bsd.prog.mk>
diff --git a/distrib/crunch/crunchide/crunchide.1 b/distrib/crunch/crunchide/crunchide.1
deleted file mode 100644 (file)
index 6d4af9b..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-.\"    $OpenBSD: crunchide.1,v 1.9 2007/05/31 19:19:16 jmc Exp $
-.\"
-.\"
-.\" Copyright (c) 1994 University of Maryland
-.\" All Rights Reserved.
-.\"
-.\" Permission to use, copy, modify, distribute, and sell this software and its
-.\" documentation for any purpose is hereby granted without fee, provided that
-.\" the above copyright notice appear in all copies and that both that
-.\" copyright notice and this permission notice appear in supporting
-.\" documentation, and that the name of U.M. not be used in advertising or
-.\" publicity pertaining to distribution of the software without specific,
-.\" written prior permission.  U.M. makes no representations about the
-.\" suitability of this software for any purpose.  It is provided "as is"
-.\" without express or implied warranty.
-.\"
-.\" U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
-.\" BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
-.\" IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-.\"
-.\" Author: James da Silva, Systems Design and Analysis Group
-.\"                       Computer Science Department
-.\"                       University of Maryland at College Park
-.\"
-.Dd $Mdocdate: May 31 2007 $
-.Dt CRUNCHIDE 1
-.Os
-.Sh NAME
-.Nm crunchide
-.Nd hides symbol names from ld, for crunching programs together
-.Sh SYNOPSIS
-.Nm crunchide
-.Op Fl f Ar keep-list-file
-.Op Fl k Ar keep-symbol
-.Ar object-file ...
-.Sh DESCRIPTION
-.Nm
-hides the global symbols of
-.Ar object-file
-such that they are ignored by subsequent runs of the linker,
-.Xr ld 1 .
-Some symbols may be left visible via the
-.Fl k Ar keep-symbol
-and
-.Fl f Ar keep-list-file
-options.
-The
-.Ar keep-list-file
-must contain a list of symbols to keep visible, one symbol per line.
-Note that the C compiler prepends an underscore in front of
-symbols, so to keep the C function ``foo'' visible, the option
-.Dq -k _foo
-must be used.
-.Pp
-.Nm
-is designed as a companion program for
-.Xr crunchgen 1 ,
-which automates the process of creating crunched binaries from
-multiple component programs.
-.Sh NOTES
-The ELF version of
-.Nm crunchide
-mangles the symbol table beyond recognition.
-It is therefore not advisable to try to run
-.Xr nm 1
-on a crunched object file.
-This is due to the nature of the ELF symbol table
-and how some arches uses the symbol attributes for their GOT build.
-.Sh SEE ALSO
-.Xr crunchgen 1 ,
-.Xr ld 1
-.Sh AUTHORS
-.Nm
-was written by James da Silva
-.Aq jds@cs.umd.edu .
-.Pp
-Copyright (c) 1994 University of Maryland.  All Rights Reserved.
diff --git a/distrib/crunch/crunchide/crunchide.c b/distrib/crunch/crunchide/crunchide.c
deleted file mode 100644 (file)
index a8fd55b..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-/* $OpenBSD: crunchide.c,v 1.22 2007/02/18 23:50:46 ray Exp $   */
-
-/*
- * Copyright (c) 1994 University of Maryland
- * All Rights Reserved.
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of U.M. not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  U.M. makes no representations about the
- * suitability of this software for any purpose.  It is provided "as is"
- * without express or implied warranty.
- *
- * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
- * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: James da Silva, Systems Design and Analysis Group
- *                        Computer Science Department
- *                        University of Maryland at College Park
- */
-/*
- * crunchide.c - tiptoes through an a.out symbol table, hiding all defined
- *     global symbols.  Allows the user to supply a "keep list" of symbols
- *     that are not to be hidden.  This program relies on the use of the
- *     linker's -dc flag to actually put global bss data into the file's
- *     bss segment (rather than leaving it as undefined "common" data).
- *
- *     The point of all this is to allow multiple programs to be linked
- *     together without getting multiple-defined errors.
- *
- *     For example, consider a program "foo.c".  It can be linked with a
- *     small stub routine, called "foostub.c", eg:
- *         int foo_main(int argc, char **argv){ return main(argc, argv); }
- *      like so:
- *         cc -c foo.c foostub.c
- *         ld -dc -r foo.o foostub.o -o foo.combined.o
- *         crunchide -k _foo_main foo.combined.o
- *     at this point, foo.combined.o can be linked with another program
- *     and invoked with "foo_main(argc, argv)".  foo's main() and any
- *     other globals are hidden and will not conflict with other symbols.
- *
- * TODO:
- *     - resolve the theoretical hanging reloc problem (see check_reloc()
- *       below). I have yet to see this problem actually occur in any real
- *       program. In what cases will gcc/gas generate code that needs a
- *       relative reloc from a global symbol, other than PIC?  The
- *       solution is to not hide the symbol from the linker in this case,
- *       but to generate some random name for it so that it doesn't link
- *       with anything but holds the place for the reloc.
- *      - arrange that all the BSS segments start at the same address, so
- *       that the final crunched binary BSS size is the max of all the
- *       component programs' BSS sizes, rather than their sum.
- */
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <a.out.h>
-#include <sys/types.h>
-#ifdef _NLIST_DO_ECOFF
-#include <sys/exec_ecoff.h>
-#endif
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-/*
- * if __ELF__ is defined, do not bother supporting AOUT.
- */
-#if defined(_NLIST_DO_AOUT) && !(defined(__ELF__))
-#define DO_AOUT
-#endif
-
-char           *pname = "crunchide";
-
-void            usage(void);
-
-void            add_to_keep_list(char *);
-void            add_file_to_keep_list(char *);
-
-void            hide_syms(char *);
-#ifdef _NLIST_DO_ECOFF
-void            ecoff_hide(int, char *);
-#endif
-#ifdef _NLIST_DO_ELF
-void            elf_hide(int, char *);
-#endif
-
-int 
-main(int argc, char *argv[])
-{
-       int             ch;
-
-       if (argc > 0)
-               pname = argv[0];
-
-       while ((ch = getopt(argc, argv, "k:f:")) != -1)
-               switch (ch) {
-               case 'k':
-                       add_to_keep_list(optarg);
-                       break;
-               case 'f':
-                       add_file_to_keep_list(optarg);
-                       break;
-               default:
-                       usage();
-               }
-
-       argc -= optind;
-       argv += optind;
-
-       if (argc == 0)
-               usage();
-
-       while (argc) {
-               hide_syms(*argv);
-               argc--;
-               argv++;
-       }
-
-       return 0;
-}
-
-void 
-usage(void)
-{
-       fprintf(stderr,
-           "usage: %s [-f keep-list-file] [-k keep-symbol] object-file ...\n",
-           pname);
-       exit(1);
-}
-
-struct keep {
-       struct keep    *next;
-       char           *sym;
-} *keep_list;
-
-void 
-add_to_keep_list(char *symbol)
-{
-       struct keep    *newp, *prevp, *curp;
-       int             cmp;
-
-       for (curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next)
-               if ((cmp = strcmp(symbol, curp->sym)) <= 0)
-                       break;
-
-       if (curp && cmp == 0)
-               return;         /* already in table */
-
-       newp = (struct keep *) calloc(1, sizeof(struct keep));
-       if (newp)
-               newp->sym = strdup(symbol);
-       if (newp == NULL || newp->sym == NULL) {
-               fprintf(stderr, "%s: out of memory for keep list\n", pname);
-               exit(1);
-       }
-       newp->next = curp;
-       if (prevp)
-               prevp->next = newp;
-       else
-               keep_list = newp;
-}
-
-int 
-in_keep_list(char *symbol)
-{
-       struct keep    *curp;
-       int             cmp;
-
-       for (curp = keep_list; curp; curp = curp->next)
-               if ((cmp = strcmp(symbol, curp->sym)) <= 0)
-                       break;
-
-       return curp && cmp == 0;
-}
-
-void 
-add_file_to_keep_list(char *filename)
-{
-       FILE           *keepf;
-       char            symbol[1024];
-       int             len;
-
-       if ((keepf = fopen(filename, "r")) == NULL) {
-               perror(filename);
-               usage();
-       }
-       while (fgets(symbol, sizeof(symbol), keepf)) {
-               len = strlen(symbol);
-               if (len && symbol[len - 1] == '\n')
-                       symbol[len - 1] = '\0';
-
-               add_to_keep_list(symbol);
-       }
-       fclose(keepf);
-}
-
-int             nsyms, ntextrel, ndatarel;
-struct exec    *hdrp;
-char           *aoutdata, *strbase;
-struct relocation_info *textrel, *datarel;
-struct nlist   *symbase;
-
-#define SYMSTR(sp)     &strbase[(sp)->n_un.n_strx]
-
-/* is the symbol a global symbol defined in the current file? */
-#define IS_GLOBAL_DEFINED(sp) \
-       (((sp)->n_type & N_EXT) && ((sp)->n_type & N_TYPE) != N_UNDF)
-
-#ifdef DO_AOUT
-#if defined(__sparc__)
-/* is the relocation entry dependent on a symbol? */
-#define IS_SYMBOL_RELOC(rp)   \
-       ((rp)->r_extern || \
-       ((rp)->r_type >= RELOC_BASE10 && (rp)->r_type <= RELOC_BASE22) || \
-       (rp)->r_type == RELOC_JMP_TBL)
-#else
-/* is the relocation entry dependent on a symbol? */
-#define IS_SYMBOL_RELOC(rp)   \
-                 ((rp)->r_extern||(rp)->r_baserel||(rp)->r_jmptable)
-#endif
-#endif
-
-void            check_reloc(char *filename, struct relocation_info * relp);
-
-void 
-hide_syms(char *filename)
-{
-       int             inf, outf, rc;
-       struct stat     infstat;
-       struct relocation_info *relp;
-       struct nlist   *symp;
-       char           *buf;
-       u_char          zero = 0;
-
-       /*
-         * Open the file and do some error checking.
-         */
-
-       if ((inf = open(filename, O_RDWR)) == -1) {
-               perror(filename);
-               return;
-       }
-       if (fstat(inf, &infstat) == -1) {
-               perror(filename);
-               close(inf);
-               return;
-       }
-       if (infstat.st_size < sizeof(struct exec)) {
-               fprintf(stderr, "%s: short file\n", filename);
-               close(inf);
-               return;
-       }
-       if ((buf = mmap(NULL, infstat.st_size, PROT_READ | PROT_WRITE,
-           MAP_FILE | MAP_SHARED, inf, 0)) == MAP_FAILED) {
-               fprintf(stderr, "%s: cannot map\n", filename);
-               close(inf);
-               return;
-       }
-
-#ifdef _NLIST_DO_ELF
-       if (buf[0] == 0x7f && (buf[1] == 'E' || buf[1] == 'O') &&
-           buf[2] == 'L' && buf[3] == 'F') {
-               elf_hide(inf, buf);
-               return;
-       }
-#endif                         /* _NLIST_DO_ELF */
-
-#ifdef _NLIST_DO_ECOFF
-       if (!ECOFF_BADMAG((struct ecoff_exechdr *) buf)) {
-               ecoff_hide(inf, buf);
-               return;
-       }
-#endif                         /* _NLIST_DO_ECOFF */
-
-#ifdef DO_AOUT
-       aoutdata = buf;
-
-       /*
-         * Check the header and calculate offsets and sizes from it.
-         */
-       hdrp = (struct exec *) aoutdata;
-
-       if (N_BADMAG(*hdrp)) {
-               fprintf(stderr, "%s: bad magic: not an a.out, ecoff or elf  file\n",
-                   filename);
-               close(inf);
-               return;
-       }
-       textrel = (struct relocation_info *) (aoutdata + N_TRELOFF(*hdrp));
-       datarel = (struct relocation_info *) (aoutdata + N_DRELOFF(*hdrp));
-       symbase = (struct nlist *) (aoutdata + N_SYMOFF(*hdrp));
-       strbase = (char *) (aoutdata + N_STROFF(*hdrp));
-
-       ntextrel = hdrp->a_trsize / sizeof(struct relocation_info);
-       ndatarel = hdrp->a_drsize / sizeof(struct relocation_info);
-       nsyms = hdrp->a_syms / sizeof(struct nlist);
-
-       /*
-         * Zap the type field of all globally-defined symbols.  The linker will
-         * subsequently ignore these entries.  Don't zap any symbols in the
-         * keep list.
-         */
-       for (symp = symbase; symp < symbase + nsyms; symp++)
-               if (IS_GLOBAL_DEFINED(symp) && !in_keep_list(SYMSTR(symp))) {
-                       /*
-                        * XXX Our VM system has some problems, so
-                        * avoid the VM system....
-                        */
-                       lseek(inf, (off_t) ((void *) &symp->n_type -
-                           (void *) buf), SEEK_SET);
-                       write(inf, &zero, sizeof zero);
-                       symp->n_type = 0;
-               }
-       /*
-         * Check whether the relocation entries reference any symbols that we
-         * just zapped.  I don't know whether ld can handle this case, but I
-         * haven't encountered it yet.  These checks are here so that the program
-         * doesn't fail silently should such symbols be encountered.
-         */
-       for (relp = textrel; relp < textrel + ntextrel; relp++)
-               check_reloc(filename, relp);
-       for (relp = datarel; relp < datarel + ndatarel; relp++)
-               check_reloc(filename, relp);
-
-       msync(buf, infstat.st_size, MS_SYNC);
-       munmap(buf, infstat.st_size);
-       close(inf);
-#endif                         /* DO_AOUT */
-}
-
-#ifdef DO_AOUT
-void 
-check_reloc(char *filename, struct relocation_info * relp)
-{
-       /* bail out if we zapped a symbol that is needed */
-       if (IS_SYMBOL_RELOC(relp) && symbase[relp->r_symbolnum].n_type == 0) {
-               fprintf(stderr,
-                   "%s: oops, have hanging relocation for %s: bailing out!\n",
-                   filename, SYMSTR(&symbase[relp->r_symbolnum]));
-               exit(1);
-       }
-}
-#endif                         /* DO_AOUT */
diff --git a/distrib/crunch/crunchide/ecoff_hide.c b/distrib/crunch/crunchide/ecoff_hide.c
deleted file mode 100644 (file)
index c3b7c1f..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* $OpenBSD: ecoff_hide.c,v 1.3 2003/06/03 21:08:59 deraadt Exp $       */
-
-/*-
- * Copyright (c) 1997 Niklas Hallqvist.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/exec.h>
-#ifdef _NLIST_DO_ECOFF
-#include <sys/exec_ecoff.h>
-#include <string.h>
-
-/* Do we have these symbols in any include file?  */
-#define scText         1
-#define scData         2
-#define scBss          3
-#define scSData                13
-#define scSBss         14
-#define scRData                15
-
-#define stNil          0
-
-extern int      in_keep_list(char *);
-
-void
-ecoff_hide(int fd, char *p)
-{
-       struct ecoff_exechdr *ehdr = (struct ecoff_exechdr *) p;
-       struct ecoff_symhdr *shdr = (struct ecoff_symhdr *) (p + ehdr->f.f_symptr);
-       u_int           ecnt = shdr->esymMax;
-       struct ecoff_extsym *esym = (struct ecoff_extsym *) (p + shdr->cbExtOffset);
-       char           *estr = p + shdr->cbSsExtOffset;
-       int             i;
-
-       for (i = 0; i < ecnt; i++, esym++)
-               if ((esym->es_class == scText || esym->es_class == scData ||
-                   esym->es_class == scBss || esym->es_class == scSData ||
-                   esym->es_class == scSBss || esym->es_class == scRData) &&
-                   !in_keep_list(estr + esym->es_strindex))
-                       esym->es_type = stNil;
-}
-#endif                         /* _NLIST_DO_ECOFF */
diff --git a/distrib/crunch/crunchide/elf_hide.c b/distrib/crunch/crunchide/elf_hide.c
deleted file mode 100644 (file)
index a63702b..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/* $OpenBSD: elf_hide.c,v 1.12 2007/08/14 20:43:10 miod Exp $ */
-
-/*
- * Copyright (c) 1997 Dale Rahn.
- * All rights reserved.
- *
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/exec.h>
-#ifdef _NLIST_DO_ELF
-#include <sys/exec_elf.h>
-
-void   load_strtab(Elf_Ehdr * pehdr, char *pexe);
-void   dump_strtab();
-char   *get_str(int indx);
-
-void   load_symtab(Elf_Ehdr * pehdr, char *pexe);
-void   dump_symtab();
-
-void   load_shstr_tab(Elf_Ehdr * pehdr, char *pexe);
-char   *get_shstr(int indx);
-void   fprint_shstr(FILE * channel, int indx);
-
-void   hide_sym();
-void   reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
-           Elf_Sym * symtab, int symtabsize, int symtabsecnum);
-typedef long    Symmap;
-void   renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap,
-           int symtabsecnum);
-
-
-char           *pexe;
-
-void
-elf_hide(int pfile, char *p)
-{
-       int             i;
-       Elf_Ehdr       *pehdr;
-       Elf_Shdr       *pshdr;
-       Elf_Phdr       *pphdr;
-       struct stat     sb;
-
-       pexe = p;
-       pehdr = (Elf_Ehdr *) pexe;
-
-#ifdef DEBUG
-       printf("elf header\n");
-       printf("e_type %x\n", pehdr->e_type);
-       printf("e_machine %x\n", pehdr->e_machine);
-       printf("e_version %x\n", pehdr->e_version);
-       printf("e_entry %x\n", pehdr->e_entry);
-       printf("e_phoff %x\n", pehdr->e_phoff);
-       printf("e_shoff %x\n", pehdr->e_shoff);
-       printf("e_flags %x\n", pehdr->e_flags);
-       printf("e_ehsize %x\n", pehdr->e_ehsize);
-       printf("e_phentsize %x\n", pehdr->e_phentsize);
-       printf("e_phnum %x\n", pehdr->e_phnum);
-       printf("e_shentsize %x\n", pehdr->e_shentsize);
-       printf("e_shnum %x\n", pehdr->e_shnum);
-       printf("e_shstrndx %x\n", pehdr->e_shstrndx);
-#endif
-
-       load_shstr_tab(pehdr, pexe);
-#ifdef DEBUG
-       for (i = 0; i < pehdr->e_shnum; i++) {
-               pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff +
-                   (i * pehdr->e_shentsize));
-
-               printf("section header %d\n", i);
-               printf("sh_name %x ", pshdr->sh_name);
-               fprint_shstr(stdout, pshdr->sh_name);
-               printf("\n");
-               printf("sh_type %x\n", pshdr->sh_type);
-               printf("sh_flags %x\n", pshdr->sh_flags);
-               printf("sh_addr %x\n", pshdr->sh_addr);
-               printf("sh_offset %x\n", pshdr->sh_offset);
-               printf("sh_size %x\n", pshdr->sh_size);
-               printf("sh_link %x\n", pshdr->sh_link);
-               printf("sh_info %x\n", pshdr->sh_info);
-               printf("sh_addralign %x\n", pshdr->sh_addralign);
-               printf("sh_entsize %x\n", pshdr->sh_entsize);
-       }
-#endif                         /* DEBUG */
-
-#ifdef DEBUG
-       for (i = 0; i < pehdr->e_phnum; i++) {
-               pshdr = (Elf_Phdr *) (pexe + pehdr->e_phoff +
-                   (i * pehdr->e_phentsize));
-
-               printf("program header %d\n", i);
-               printf("p_type %x\n", pphdr->p_type);
-               printf("p_offset %x\n", pphdr->p_offset);
-               printf("p_vaddr %x\n", pphdr->p_vaddr);
-               printf("p_paddr %x\n", pphdr->p_paddr);
-               printf("p_filesz %x\n", pphdr->p_filesz);
-               printf("p_memsz %x\n", pphdr->p_memsz);
-               printf("p_flags %x\n", pphdr->p_flags);
-               printf("p_align %x\n", pphdr->p_align);
-       }
-#endif                         /* DEBUG */
-#if 0
-       for (i = 0; i < pehdr->e_shnum; i++) {
-               pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff +
-                   (i * pehdr->e_shentsize));
-               if (strcmp(".strtab", get_shstr(pshdr->sh_name)) == 0)
-                       break;
-       }
-       fprint_shstr(stdout, pshdr->sh_name);
-       printf("\n");
-#endif
-
-       load_strtab(pehdr, pexe);
-       load_symtab(pehdr, pexe);
-
-       munmap(pexe, sb.st_size);
-       close(pfile);
-}
-char           *shstrtab;
-
-void
-load_shstr_tab(Elf_Ehdr * pehdr, char *pexe)
-{
-       Elf_Shdr       *pshdr;
-       shstrtab = NULL;
-       if (pehdr->e_shstrndx == 0)
-               return;
-       pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
-           (pehdr->e_shstrndx * pehdr->e_shentsize));
-
-       shstrtab = (char *) (pexe + pshdr->sh_offset);
-}
-
-void
-fprint_shstr(FILE * channel, int indx)
-{
-       if (shstrtab != NULL)
-               fprintf(channel, "\"%s\"", &(shstrtab[indx]));
-}
-
-char           *
-get_shstr(int indx)
-{
-       return &(shstrtab[indx]);
-}
-
-void
-load_symtab(Elf_Ehdr * pehdr, char *pexe)
-{
-       Elf_Sym        *symtab;
-       Elf_Shdr       *symsect;
-       int             symtabsize;
-       Elf_Shdr       *pshdr;
-       Elf_Shdr       *psymshdr;
-       char           *shname;
-       int             i;
-
-       symtab = NULL;
-       for (i = 0; i < pehdr->e_shnum; i++) {
-               pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
-                   (i * pehdr->e_shentsize));
-               if (SHT_REL != pshdr->sh_type && SHT_RELA != pshdr->sh_type)
-                       continue;
-               psymshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
-                   (pshdr->sh_link * pehdr->e_shentsize));
-#ifdef DEBUG
-               fprint_shstr(stdout, pshdr->sh_name);
-               printf("\n");
-#endif
-               symtab = (Elf_Sym *) (pexe + psymshdr->sh_offset);
-               symsect = psymshdr;
-               symtabsize = psymshdr->sh_size;
-
-#ifdef DEBUG
-               dump_symtab(symsect, symtab, symtabsize);
-#endif
-               hide_sym(pehdr, symsect, symtab, symtabsize, pshdr->sh_link);
-       }
-
-}
-
-void
-dump_symtab(Elf_Shdr * symsect, Elf_Sym * symtab, int symtabsize)
-{
-       int             i;
-       Elf_Sym        *psymtab;
-
-       for (i = 0; i < (symtabsize / sizeof(Elf_Sym)); i++) {
-               psymtab = &(symtab[i]);
-               if ((psymtab->st_info & 0xf0) == 0x10 &&
-                   (psymtab->st_shndx != SHN_UNDEF)) {
-                       printf("symbol %d:\n", i);
-                       printf("st_name %x \"%s\"\n", psymtab->st_name,
-                           get_str(psymtab->st_name));
-                       printf("st_value %x\n", psymtab->st_value);
-                       printf("st_size %x\n", psymtab->st_size);
-                       printf("st_info %x\n", psymtab->st_info);
-                       printf("st_other %x\n", psymtab->st_other);
-                       printf("st_shndx %x\n", psymtab->st_shndx);
-               }
-       }
-}
-
-char           *strtab;
-int             strtabsize;
-void
-load_strtab(Elf_Ehdr * pehdr, char *pexe)
-{
-       Elf_Shdr       *pshdr;
-       char           *shname;
-       int             i;
-       strtab = NULL;
-       for (i = 0; i < pehdr->e_shnum; i++) {
-               pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
-                   (i * pehdr->e_shentsize));
-
-               shname = get_shstr(pshdr->sh_name);
-               if (strcmp(".strtab", shname) == 0)
-                       break;
-       }
-#ifdef DEBUG
-       fprint_shstr(stdout, pshdr->sh_name);
-       printf("\n");
-#endif
-
-       strtab = (char *) (pexe + pshdr->sh_offset);
-
-       strtabsize = pshdr->sh_size;
-
-#ifdef DEBUG
-       dump_strtab();
-#endif
-}
-
-void
-dump_strtab()
-{
-       int             index;
-       char           *pstr;
-       char           *pnstr;
-       int             i = 0;
-       index = 0;
-       pstr = strtab;
-       while (index < strtabsize) {
-               printf("string %x: \"%s\"\n", i, pstr);
-               pnstr = pstr + strlen(pstr) + 1;
-               index = pnstr - strtab;
-               pstr = pnstr;
-               i++;
-       }
-
-}
-
-fprint_str(FILE * channel, int indx)
-{
-       if (strtab != NULL)
-               fprintf(channel, "\"%s\"", &(strtab[indx]));
-}
-
-char *
-get_str(int indx)
-{
-       return &(strtab[indx]);
-}
-
-int             in_keep_list(char *symbol);
-
-void
-hide_sym(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
-    Elf_Sym * symtab, int symtabsize, int symtabsecnum)
-{
-       int             i;
-       unsigned char   info;
-       Elf_Sym        *psymtab;
-
-#ifdef __mips__
-       u_int32_t f = arc4random();
-#endif
-
-       for (i = 0; i < (symtabsize / sizeof(Elf_Sym)); i++) {
-               psymtab = &(symtab[i]);
-               if ((psymtab->st_info & 0xf0) == 0x10 &&
-                   (psymtab->st_shndx != SHN_UNDEF)) {
-                       if (in_keep_list(get_str(psymtab->st_name)))
-                               continue;
-#ifdef DEBUG
-                       printf("symbol %d:\n", i);
-                       printf("st_name %x \"%s\"\n", psymtab->st_name,
-                           get_str(psymtab->st_name));
-                       printf("st_info %x\n", psymtab->st_info);
-#endif
-#ifndef __mips__
-                       info = psymtab->st_info;
-                       info = info & 0xf;
-                       psymtab->st_info = info;
-#else
-                       /*
-                        * XXX This is a small ugly hack to be able to use
-                        * XXX chrunchide with MIPS.
-                        * XXX Because MIPS needs global symbols to stay
-                        * XXX global (has to do with GOT), we mess around
-                        * XXX with the symbol names instead. For most uses
-                        * XXX this will be no problem, symbols are stripped
-                        * XXX anyway. However, if many one character
-                        * XXX symbols exist, names may clash.
-                        */
-                       {
-                               char *p;
-                               u_int32_t n, z;
-
-                               z = f++;
-                               p = get_str(psymtab->st_name);
-                               n = strlen(p);
-                               if (n > 4)
-                                       n = 4;
-                               while (n--) {
-                                       p[n] = z;
-                                       z >>= 8;
-                                       while (p[n] == 0)
-                                               p[n] += arc4random();
-                               }
-                       }
-
-#endif
-#ifdef DEBUG
-                       printf("st_info %x\n", psymtab->st_info);
-#endif
-               }
-       }
-       reorder_syms(ehdr, symsect, symtab, symtabsize, symtabsecnum);
-}
-
-void
-reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
-    Elf_Sym * symtab, int symtabsize, int symtabsecnum)
-{
-       int             i;
-       int             nsyms;
-       int             cursym;
-       Elf_Sym        *tmpsymtab;
-       Symmap         *symmap;
-
-
-       nsyms = symtabsize / sizeof(Elf_Sym);
-
-       tmpsymtab = (Elf_Sym *) calloc(1, symtabsize);
-       symmap = (Symmap *) calloc(nsyms, sizeof(Symmap));
-       if (!tmpsymtab || !symmap)
-               errx(5, "calloc: %s", strerror(ENOMEM));
-
-       bcopy(symtab, tmpsymtab, symtabsize);
-
-       cursym = 1;
-       for (i = 1; i < nsyms; i++) {
-               if ((tmpsymtab[i].st_info & 0xf0) == 0x00) {
-#ifdef DEBUG
-                       printf("copying  l o%d n%d <%s>\n", i, cursym,
-                           get_str(tmpsymtab[i].st_name));
-#endif
-                       bcopy(&(tmpsymtab[i]), &(symtab[cursym]),
-                           sizeof(Elf_Sym));
-                       symmap[i] = cursym;
-                       cursym++;
-               }
-       }
-       symsect->sh_info = cursym;
-       for (i = 1; i < nsyms; i++) {
-               if ((tmpsymtab[i].st_info & 0xf0) != 0x00) {
-#ifdef DEBUG
-                       printf("copying nl o%d n%d <%s>\n", i, cursym,
-                           get_str(tmpsymtab[i].st_name));
-#endif
-                       bcopy(&(tmpsymtab[i]), &(symtab[cursym]),
-                           sizeof(Elf_Sym));
-                       symmap[i] = cursym;
-                       cursym++;
-               }
-       }
-       if (cursym != nsyms) {
-               printf("miscounted symbols somewhere c %d n %d \n",
-                   cursym, nsyms);
-               exit(5);
-       }
-       renum_reloc_syms(ehdr, symmap, symtabsecnum);
-       free(tmpsymtab);
-       free(symmap);
-}
-
-void
-renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap, int symtabsecnum)
-{
-       Elf_Shdr       *pshdr;
-       int             i, j;
-       int             num_reloc;
-       Elf_Rel        *prel;
-       Elf_RelA       *prela;
-       int             symnum;
-
-       for (i = 0; i < ehdr->e_shnum; i++) {
-               pshdr = (Elf_Shdr *) (pexe + ehdr->e_shoff +
-                   (i * ehdr->e_shentsize));
-               if ((pshdr->sh_type == SHT_RELA) &&
-                   pshdr->sh_link == symtabsecnum) {
-
-#ifdef DEBUG
-                       printf("section %d has rela relocations in symtab\n", i);
-#endif
-                       prela = (Elf_RelA *) (pexe + pshdr->sh_offset);
-                       num_reloc = pshdr->sh_size / sizeof(Elf_RelA);
-                       for (j = 0; j < num_reloc; j++) {
-                               symnum = ELF_R_SYM(prela[j].r_info);
-#ifdef DEBUG
-                               printf("sym num o %d n %d\n", symnum,
-                                   symmap[symnum]);
-#endif
-                               prela[j].r_info = ELF_R_INFO(symmap[symnum],
-                                   ELF_R_TYPE(prela[j].r_info));
-                       }
-               }
-               if ((pshdr->sh_type == SHT_REL) &&
-                   pshdr->sh_link == symtabsecnum) {
-#ifdef DEBUG
-                       printf("section %d has rel relocations in symtab\n", i);
-#endif
-                       prel = (Elf_Rel *) (pexe + pshdr->sh_offset);
-                       num_reloc = pshdr->sh_size / sizeof(Elf_Rel);
-                       for (j = 0; j < num_reloc; j++) {
-                               symnum = ELF_R_SYM(prel[j].r_info);
-#ifdef DEBUG
-                               printf("sym num o %d n %d\n", symnum,
-                                   symmap[symnum]);
-#endif
-                               prel[j].r_info = ELF_R_INFO(symmap[symnum],
-                                   ELF_R_TYPE(prel[j].r_info));
-                       }
-               }
-       }
-
-}
-#endif                         /* _NLIST_DO_ELF */
index a111330..af9a155 100644 (file)
@@ -1,9 +1,9 @@
-#      $OpenBSD: Makefile,v 1.142 2008/06/15 04:44:30 sturm Exp $
+#      $OpenBSD: Makefile,v 1.143 2008/08/22 15:18:54 deraadt Exp $
 
 .include <bsd.own.mk>
 
 SUBDIR=        ac accton acpidump adduser amd apm apmd arp \
-       authpf bgpctl bgpd bind chroot config cron dev_mkdb \
+       authpf bgpctl bgpd bind chroot config cron crunchgen dev_mkdb \
        dhcpd dhcrelay dvmrpctl dvmrpd edquota eeprom faithd fdformat \
        ftp-proxy gpioctl hostapd hotplugd httpd ifstated inetd iostat \
        kgmon kvm_mkdb lpr mailwrapper map-mbone memconfig mopd mrinfo \
diff --git a/usr.sbin/crunchgen/Makefile b/usr.sbin/crunchgen/Makefile
new file mode 100644 (file)
index 0000000..314174f
--- /dev/null
@@ -0,0 +1,15 @@
+#      $OpenBSD: Makefile,v 1.1 2008/08/22 15:18:55 deraadt Exp $
+
+PROG=          crunchgen
+MAN=           crunchgen.1 crunchide.1
+SRCS=          crunchgen.c crunched_skel.c \
+               crunchide.c elf_hide.c ecoff_hide.c
+CFLAGS+=       -g -Wall
+CLEANFILES+=   crunched_skel.c
+
+crunched_skel.c: crunched_main.c
+       sh ${.CURDIR}/mkskel.sh ${.CURDIR}/crunched_main.c > crunched_skel.c
+
+LINKS=  ${BINDIR}/crunchgen ${BINDIR}/crunchide
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/crunchgen/README b/usr.sbin/crunchgen/README
new file mode 100644 (file)
index 0000000..6b150b5
--- /dev/null
@@ -0,0 +1,89 @@
+
+CRUNCH 0.3 README                              7/23/94
+
+Crunch is available via anonymous ftp to ftp.cs.umd.edu in
+               pub/bsd/crunch-0.3.tar.gz
+
+WHAT'S NEW IN 0.3
+
+* The prototype awk script has been replaced by a more capable and
+  hopefully more robust C program.
+* No fragile template makefiles or dependencies on the details of the
+  bsd build environment.
+* You can build crunched binaries even with no sources on-line, you
+  just need the .o files.  Crunchgen still will try to figure out as
+  much as possible on its own, but you can override its guessing by
+  specifying the list of .o files explicitly.
+* Crunch itself has been bmake'd and some man pages written, so it
+  should be ready to install.
+* Added patch for FreeBSD from Jordan Hubbard, plus the .conf files used
+  for the FreeBSD install floppies as examples.
+
+
+INTRODUCTION
+
+Crunch is a little package that helps create "crunched" binaries for use
+on boot, install, and fixit floppies.  A crunched binary in this case is
+one where many programs have been linked together into one a.out file.
+The different programs are run depending on the value of argv[0], so
+hard links to the crunched binary suffice to simulate a perfectly normal
+system.
+
+As an example, I have created an 980K crunched "fixit" binary containing
+the following programs in their entirety:
+
+       cat chmod cp date dd df echo ed expr hostname kill ln ls mkdir
+       mt mv pwd rcp rm rmdir sh sleep stty sync test [ badsect
+       clri disklabel dump rdump dmesg fdisk fsck halt ifconfig init
+       mknod mount newfs ping reboot restore rrestore swapon umount
+       ftp rsh sed telnet rlogin vi cpio gzip gunzip gzcat
+
+Note carefully: vi, cpio, gzip, ed, sed, dump/restore, some networking
+utilities, and the disk management utilities, all in a binary small
+enough to fit on a 1.2 MB root filesystem floppy (albeit with the kernel
+on its own boot floppy).  A more reasonable subset can be made to fit
+easily with a kernel for a decent one-disk fixit filesystem.
+
+The linking together of different programs by hand is an old
+space-saving technique.         Crunch automates the process by building the
+necessary stub files and makefile for you (via the crunchgen program),
+and by doctoring the symbol tables of the component .o files to allow
+them to link without "symbol multiply defined" conflicts (via the
+crunchide program).
+
+
+BUILDING CRUNCH
+
+Just type make, then make install.
+
+Crunch was written and tested under NetBSD/i386, but should work under
+other PC BSD systems that use GNU ld.
+
+The crunchgen(1) and crunchide(1) man pages have more details on using
+crunch, and the examples subdirectory contains some working .conf files
+and a sample Makefile.
+
+CREDITS
+
+Thanks to the NetBSD team for a consistently high quality effort in
+bringing together a solid, state of the art development environment.
+
+Thanks to the FreeBSD guys; Rod Grimes, Nate Williams and Jordan
+Hubbard; and to Bruce Evans, for immediate and detailed feedback on
+crunch 0.1, and for pressing me to make the prototype more useable.
+
+Crunch was written for the Maruti Hard Real-Time Operating System
+project at the University of Maryland, to help make for better install
+and recovery procedures for our NetBSD-based development environment. It
+is copyright (c) 1994 by the University of Maryland under a UCB-style
+freely- redistributable notice.         See the file COPYRIGHT for details.
+
+Please let me know of any problems or of enhancements you make to this
+package.  I'm particularly interested in the details of what you found
+was good to put on your fixit or install disks.         Thanks!
+
+Share and Enjoy,
+Jaime
+............................................................................
+: Stand on my shoulders, : jds@cs.umd.edu  :                 James da Silva
+: not on my toes.       : uunet!mimsy!jds : http://www.cs.umd.edu/users/jds
diff --git a/usr.sbin/crunchgen/crunched_main.c b/usr.sbin/crunchgen/crunched_main.c
new file mode 100644 (file)
index 0000000..c0a7827
--- /dev/null
@@ -0,0 +1,104 @@
+/* $OpenBSD: crunched_main.c,v 1.1 2008/08/22 15:18:55 deraadt Exp $    */
+
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ *                        Computer Science Department
+ *                        University of Maryland at College Park
+ */
+/*
+ * crunched_main.c - main program for crunched binaries, it branches to a
+ *     particular subprogram based on the value of argv[0].  Also included
+ *     is a little program invoked when the crunched binary is called via
+ *     its EXECNAME.  This one prints out the list of compiled-in binaries,
+ *     or calls one of them based on argv[1].   This allows the testing of
+ *     the crunched binary without creating all the links.
+ */
+#include <stdio.h>
+#include <string.h>
+
+struct stub {
+       char    *name;
+       int     (*f)();
+};
+
+extern struct stub entry_points[];
+
+int 
+main(int argc, char *argv[], char **envp)
+{
+       char            *slash, *basename;
+       struct stub     *ep;
+
+       if (argv[0] == NULL || *argv[0] == '\0')
+               crunched_usage();
+
+       slash = strrchr(argv[0], '/');
+       basename = slash ? slash + 1 : argv[0];
+
+       for (ep = entry_points; ep->name != NULL; ep++)
+               if (!strcmp(basename, ep->name))
+                       break;
+
+       if (ep->name)
+               return ep->f(argc, argv, envp);
+       else {
+               fprintf(stderr, "%s: %s not compiled in\n", EXECNAME, basename);
+               crunched_usage();
+       }
+}
+
+int 
+crunched_main(int argc, char **argv, char **envp)
+{
+       struct stub     *ep;
+       int             columns, len;
+
+       if (argc <= 1)
+               crunched_usage();
+
+       return main(--argc, ++argv, envp);
+}
+
+int 
+crunched_usage()
+{
+       int             columns, len;
+       struct stub     *ep;
+
+       fprintf(stderr,
+           "Usage: %s <prog> <args> ..., where <prog> is one of:\n",
+           EXECNAME);
+       columns = 0;
+       for (ep = entry_points; ep->name != NULL; ep++) {
+               len = strlen(ep->name) + 1;
+               if (columns + len < 80)
+                       columns += len;
+               else {
+                       fprintf(stderr, "\n");
+                       columns = len;
+               }
+               fprintf(stderr, " %s", ep->name);
+       }
+       fprintf(stderr, "\n");
+       exit(1);
+}
diff --git a/usr.sbin/crunchgen/crunchgen.1 b/usr.sbin/crunchgen/crunchgen.1
new file mode 100644 (file)
index 0000000..1123784
--- /dev/null
@@ -0,0 +1,291 @@
+.\"    $OpenBSD: crunchgen.1,v 1.1 2008/08/22 15:18:55 deraadt Exp $
+.\"
+.\"
+.\" Copyright (c) 1994 University of Maryland
+.\" All Rights Reserved.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation, and that the name of U.M. not be used in advertising or
+.\" publicity pertaining to distribution of the software without specific,
+.\" written prior permission.  U.M. makes no representations about the
+.\" suitability of this software for any purpose.  It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.\" U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+.\" BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+.\" IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Author: James da Silva, Systems Design and Analysis Group
+.\"                       Computer Science Department
+.\"                       University of Maryland at College Park
+.\"
+.Dd $Mdocdate: August 22 2008 $
+.Dt CRUNCHGEN 1
+.Os
+.Sh NAME
+.Nm crunchgen
+.Nd generates build environment for a crunched binary
+.Sh SYNOPSIS
+.Nm crunchgen
+.Bk -words
+.Op Fl Efq
+.Op Fl c Ar c-file-name
+.Op Fl D Ar src-root
+.Op Fl e Ar exec-file-name
+.Op Fl L Ar lib-dir
+.Op Fl m Ar makefile-name
+.Op Fl O Ar objdir-name
+.Ar conf-file
+.Ek
+.Sh DESCRIPTION
+A crunched binary is a program made up of many other programs linked
+together into a single executable.
+The crunched binary main() function determines which component program
+to run by the contents of argv[0].
+The main reason to crunch programs together is for fitting as many programs
+as possible onto an installation or system recovery floppy.
+.Pp
+.Nm
+reads in the specifications in
+.Ar conf-file
+for a crunched binary, and generates a Makefile and accompanying
+top-level C source file that when built create the crunched executable
+file from the component programs.
+For each component program,
+.Nm
+can optionally attempt to determine the object (.o) files that make up
+the program from its source directory Makefile.
+This information is cached in a file named
+.Pa <conf-name>.cache
+between runs.
+.Nm
+uses the companion program
+.Xr crunchide 1
+to eliminate link-time conflicts between the component programs by
+hiding all unnecessary symbols.
+.Pp
+After
+.Nm
+is run, the crunched binary can be built by running
+.Dq make -f <conf-name>.mk .
+The component programs' object files must already be built.
+An
+.Dq objs
+target, included in the output makefile,
+will run make in each component program's source dir to build the object
+files for the user.
+This is not done automatically since in release engineering circumstances
+it is generally not desirable to be modifying objects in other directories.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl c Ar c-file-name
+Set output C file name to
+.Ar c-file-name .
+The default name is
+.Dq Ao conf-name Ac Ns \&.c .
+.It Fl D Ar src-root
+Assume that relative source directory specifications begin with
+.Ar src-root .
+.It Fl E
+Don't prepend stub names with an underscore.
+Used for architectures that don't have underscore prepended to symbol names.
+Example mips ELF.
+.It Fl e Ar exec-file-name
+Set crunched binary executable file name to
+.Ar exec-file-name .
+The default name is
+.Dq Aq conf-name .
+.It Fl f
+Flush cache.
+Forces the recalculation of cached parameters.
+.It Fl L Ar lib-dir
+Try to obtain libraries from
+.Ar lib-dir .
+.It Fl m Ar makefile-name
+Set output Makefile name to
+.Ar makefile-name .
+The default name is
+.Dq Ao conf-name Ac Ns \&.mk .
+.It Fl O Ar objdir-name
+Specify an object directory to use.
+It defaults to
+.Dq obj ,
+though for cross building purposes it can be used to specify
+obj.${HOST}.${MACHINE}.
+Normally used with the make variable ${MAKEOBJDIR}.
+.It Fl q
+Quiet operation.
+Status messages are suppressed.
+.El
+.Sh CRUNCHGEN CONFIGURATION FILE COMMANDS
+.Nm
+reads specifications from the
+.Ar conf-file
+that describe the components of the crunched binary.
+In its simplest use, the component program names are merely listed
+along with the top-level source directories in which their sources
+can be found.
+.Nm
+then calculates (via the source makefiles) and caches the
+list of object files and their locations.
+For more specialized situations, the user can specify by hand
+all the parameters that
+.Nm
+needs.
+.Pp
+The
+.Ar conf-file
+commands are as follows:
+.Bl -tag -width indent
+.It srcdirs Ar dirname ...
+A list of source trees in which the source directories of the
+component programs can be found.
+These dirs are searched using the BSD
+.Dq <source-dir>/<progname>/
+convention.
+Multiple srcdirs lines can be specified.
+The directories are searched in the order they are given.
+.It libdirs Ar dirname
+A list of source trees in which the source directories for supplementary
+libraries can be found.
+.It progs Ar progname ...
+A list of programs that make up the crunched binary.
+Multiple progs lines can be specified.
+.It libs Ar libspec ...
+A list of library specifications to be included in the crunched binary link.
+Multiple libs lines can be specified.
+.It ln Ar progname linkname
+Causes the crunched binary to invoke
+.Ar progname
+whenever
+.Ar linkname
+appears in argv[0].
+This allows programs that change their behavior when
+run under different names to operate correctly.
+.El
+.Pp
+To handle specialized situations, such as when the source is not
+available or not built via a conventional Makefile, the following
+.Ic special
+commands can be used to set
+.Nm
+parameters for a component program.
+.Bl -tag -width indent
+.It special Ar progname No srcdir Ar pathname
+Set the source directory for
+.Ar progname .
+This is normally calculated by searching the specified srcdirs
+for a directory named
+.Ar progname .
+.It special Ar progname No objdir Ar pathname
+Set the obj directory for
+.Ar progname .
+This is normally calculated by looking for a directory named
+.Dq obj
+under the
+.Ar srcdir ,
+and if that is not found, the
+.Ar srcdir
+itself becomes the objdir.
+.It special Ar progname No objs Ar object-file-name ...
+Set the list of object files for program
+.Ar progname .
+This is normally calculated by constructing a temporary makefile that includes
+.Dq srcdir/Makefile
+and outputs the value of $(OBJS).
+.It special Ar progname No objpaths Ar full-pathname-to-object-file ...
+Sets the pathnames of the object files for program
+.Ar progname .
+This is normally calculated by prepending the objdir
+pathname to each file in the objs list.
+.El
+.Pp
+Only the objpaths parameter is actually needed by
+.Nm crunchgen ,
+but it is calculated from objdir and objs,
+which are in turn calculated from srcdir,
+so it is sometimes convenient to specify the earlier parameters and let
+.Nm
+calculate forward from there if it can.
+.Pp
+The makefile produced by
+.Nm
+contains an optional
+.Ar objs
+target that will build the object files for each component program by
+running make inside that program's source directory.
+For this to work the srcdir and objs parameters must also be valid.
+If they are not valid for a particular program, that program is skipped in the
+.Ar objs
+target.
+.Sh EXAMPLES
+Here is an example
+.Nm
+input conf file, named
+.Pa kcopy.conf :
+.Bd -literal -offset indent
+srcdirs /usr/src/bin /usr/src/sbin
+
+progs test cp echo sh fsck halt init mount umount myinstall
+ln test [       # test can be invoked via [
+ln sh -sh       # init invokes the shell with "-sh" in argv[0]
+
+special myprog objpaths /homes/leroy/src/myinstall.o # no sources
+
+libs -lutil -lcrypt
+.Ed
+.Pp
+This conf file specifies a small crunched binary consisting of some
+basic system utilities plus a home-grown install program
+.Dq myinstall ,
+for which no source directory is specified, but its object file is
+specified directly with the
+.Ic special
+line.
+.Pp
+The crunched binary
+.Dq kcopy
+can be built as follows:
+.Bd -literal -offset indent
+% crunchgen -m Makefile kcopy.conf    # gen Makefile and kcopy.c
+% make objs            # build the component programs' .o files
+% make                 # build the crunched binary kcopy
+% kcopy sh             # test that this invokes a sh shell
+$                      # it works!
+.Ed
+.Pp
+At this point the binary
+.Dq kcopy
+can be copied onto an install floppy
+and hard-linked to the names of the component programs.
+.Sh SEE ALSO
+.Xr crunchide 1
+.Sh AUTHORS
+.Nm
+was written by James da Silva
+.Aq jds@cs.umd.edu .
+.Pp
+Copyright (c) 1994 University of Maryland.  All Rights Reserved.
+.Sh CAVEATS
+While
+.Nm
+takes care to eliminate link conflicts between the component programs
+of a crunched binary, conflicts are still possible between the
+libraries that are linked in.
+Some shuffling in the order of libraries may be required,
+and in some rare cases two libraries may
+have an unresolvable conflict and thus cannot be crunched together.
+.Pp
+Some versions of the BSD build environment do not by default build the
+intermediate object file for single-source file programs.
+The
+.Dq make objs
+target must then be used to get those object files built,
+or some other arrangements made.
diff --git a/usr.sbin/crunchgen/crunchgen.c b/usr.sbin/crunchgen/crunchgen.c
new file mode 100644 (file)
index 0000000..7a4c698
--- /dev/null
@@ -0,0 +1,1022 @@
+/* $OpenBSD: crunchgen.c,v 1.1 2008/08/22 15:18:55 deraadt Exp $        */
+
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ *                        Computer Science Department
+ *                        University of Maryland at College Park
+ */
+/*
+ * ========================================================================
+ * crunchgen.c
+ *
+ * Generates a Makefile and main C file for a crunched executable,
+ * from specs given in a .conf file.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#define CRUNCH_VERSION "0.3"
+
+#define MAXLINELEN     16384
+#define MAXFIELDS       2048
+
+/* XXX - This should be runtime configurable */
+/*
+ * We might have more than one makefile
+ * name on any given platform. Make sure
+ * default name is last though.
+ */
+char   *mf_name[] = {
+       "Makefile.bsd-wrapper",
+       "Makefile",
+       NULL
+};
+
+/* internal representation of conf file: */
+
+/* simple lists of strings suffice for most parms */
+
+typedef struct strlst {
+       struct strlst  *next;
+       char           *str;
+} strlst_t;
+
+/* progs have structure, each field can be set with "special" or calculated */
+
+typedef struct prog {
+       struct prog    *next;
+       char           *name, *ident, *mf_name;
+       char           *srcdir, *objdir;
+       strlst_t       *objs, *objpaths;
+       strlst_t       *links;
+       int             goterror;
+} prog_t;
+
+strlst_t       *srcdirs = NULL;
+strlst_t       *libs = NULL;
+strlst_t       *libdirs = NULL;
+char           objdir[MAXPATHLEN] = "obj";
+prog_t         *progs = NULL;
+
+char            line[MAXLINELEN];
+
+char            confname[MAXPATHLEN], infilename[MAXPATHLEN];
+char            outmkname[MAXPATHLEN], outcfname[MAXPATHLEN];
+char            cachename[MAXPATHLEN], curfilename[MAXPATHLEN];
+char            topdir[MAXPATHLEN], execfname[MAXPATHLEN];
+int             linenum = -1;
+int             goterror = 0;
+
+char           *progname = "crunchgen";
+
+int             verbose, readcache, elf_names; /* options */
+int             reading_cache;
+
+void            status(char *str);
+void            out_of_memory(void);
+void            add_string(strlst_t ** listp, char *str);
+int             is_dir(char *pathname);
+int             is_nonempty_file(char *pathname);
+void            usage(void);
+void            parse_conf_file(void);
+void            gen_outputs(void);
+
+extern int     crunchide_main(int, char *[]);
+
+int 
+main(int argc, char *argv[])
+{
+       char           *p;
+       int             optc;
+       extern int      optind;
+       extern char    *optarg, *__progname;
+
+       verbose = 1;
+       readcache = 1;
+       *outmkname = *outcfname = *execfname = '\0';
+
+       if (argc > 0)
+               progname = argv[0];
+
+       if (strcmp(__progname, "crunchide") == 0)
+               return (crunchide_main(argc, argv));
+
+       while ((optc = getopt(argc, argv, "m:c:e:fqD:EL:O:")) != -1) {
+               switch (optc) {
+               case 'f':
+                       readcache = 0;
+                       break;
+               case 'q':
+                       verbose = 0;
+                       break;
+
+               case 'm':
+                       if (strlcpy(outmkname, optarg, sizeof(outmkname)) >=
+                           sizeof(outmkname))
+                               usage();
+                       break;
+               case 'c':
+                       if (strlcpy(outcfname, optarg, sizeof(outcfname)) >=
+                           sizeof(outcfname))
+                               usage();
+                       break;
+               case 'e':
+                       if (strlcpy(execfname, optarg, sizeof(execfname)) >=
+                           sizeof(execfname))
+                               usage();
+                       break;
+
+               case 'D':
+                       if (strlcpy(topdir, optarg, sizeof(topdir)) >= sizeof(topdir))
+                               usage();
+                       break;
+               case 'E':
+                       elf_names = 1;
+                       break;
+               case 'L':
+                       if (strlen(optarg) >= MAXPATHLEN)
+                               usage();
+                       add_string(&libdirs, optarg);
+                       break;
+               case 'O':
+                       if (strlcpy(objdir, optarg, sizeof(objdir)) >=
+                           sizeof(objdir))
+                               usage();
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc != 1)
+               usage();
+
+       if (libdirs == NULL)
+               add_string(&libdirs, "/usr/lib");
+       /*
+         * generate filenames
+         */
+
+       if (strlcpy(infilename, argv[0], sizeof(infilename)) >=
+           sizeof(infilename))
+               usage();
+
+       /* confname = `basename infilename .conf` */
+
+       if ((p = strrchr(infilename, '/')) != NULL)
+               strlcpy(confname, p + 1, sizeof confname);
+       else
+               strlcpy(confname, infilename, sizeof confname);
+       if ((p = strrchr(confname, '.')) != NULL && !strcmp(p, ".conf"))
+               *p = '\0';
+
+       if (!*outmkname)
+               snprintf(outmkname, sizeof(outmkname), "%s.mk", confname);
+       if (!*outcfname)
+               snprintf(outcfname, sizeof(outcfname), "%s.c", confname);
+       if (!*execfname)
+               snprintf(execfname, sizeof(execfname), "%s", confname);
+       snprintf(cachename, sizeof(cachename), "%s.cache", confname);
+
+       parse_conf_file();
+       gen_outputs();
+
+       exit(goterror);
+}
+
+void 
+usage(void)
+{
+       fprintf(stderr,
+           "usage: %s [-Efq] [-c c-file-name] [-D src-root] [-e exec-file-name]\n"
+           "\t[-L lib-dir] [-m makefile-name] [-O objdir-name] conf-file\n",
+           progname);
+       exit(1);
+}
+
+void            parse_one_file(char *filename);
+void            parse_line(char *line, int *fc, char **fv, int nf);
+void            add_srcdirs(int argc, char **argv);
+void            add_progs(int argc, char **argv);
+void            add_link(int argc, char **argv);
+void            add_libs(int argc, char **argv);
+void            add_libdirs(int argc, char **argv);
+void            add_special(int argc, char **argv);
+
+prog_t         *find_prog(char *str);
+void            add_prog(char *progname);
+
+void 
+parse_conf_file(void)
+{
+       if (!is_nonempty_file(infilename)) {
+               fprintf(stderr, "%s: fatal: input file \"%s\" not found.\n",
+                   progname, infilename);
+               exit(1);
+       }
+       parse_one_file(infilename);
+       if (readcache && is_nonempty_file(cachename)) {
+               reading_cache = 1;
+               parse_one_file(cachename);
+       }
+}
+
+void 
+parse_one_file(char *filename)
+{
+       char           *fieldv[MAXFIELDS];
+       int             fieldc;
+       void            (*f) (int c, char **v);
+       FILE           *cf;
+
+       snprintf(line, sizeof(line), "reading %s", filename);
+       status(line);
+       strlcpy(curfilename, filename, sizeof curfilename);
+
+       if ((cf = fopen(curfilename, "r")) == NULL) {
+               perror(curfilename);
+               goterror = 1;
+               return;
+       }
+       linenum = 0;
+       while (fgets(line, MAXLINELEN, cf) != NULL) {
+               linenum++;
+               parse_line(line, &fieldc, fieldv, MAXFIELDS);
+               if (fieldc < 1)
+                       continue;
+               if (!strcmp(fieldv[0], "srcdirs"))
+                       f = add_srcdirs;
+               else if (!strcmp(fieldv[0], "progs"))
+                       f = add_progs;
+               else if (!strcmp(fieldv[0], "ln"))
+                       f = add_link;
+               else if (!strcmp(fieldv[0], "libs"))
+                       f = add_libs;
+               else if (!strcmp(fieldv[0], "special"))
+                       f = add_special;
+               else if (!strcmp(fieldv[0], "libdirs"))
+                       f = add_libdirs;
+               else {
+                       fprintf(stderr, "%s:%d: skipping unknown command `%s'.\n",
+                           curfilename, linenum, fieldv[0]);
+                       goterror = 1;
+                       continue;
+               }
+               if (fieldc < 2) {
+                       fprintf(stderr,
+                           "%s:%d: %s command needs at least 1 "
+                           "argument, skipping.\n",
+                           curfilename, linenum, fieldv[0]);
+                       goterror = 1;
+                       continue;
+               }
+               f(fieldc, fieldv);
+       }
+
+       if (ferror(cf)) {
+               perror(curfilename);
+               goterror = 1;
+       }
+       fclose(cf);
+}
+
+void 
+parse_line(char *line, int *fc, char **fv, int nf)
+{
+       char           *p;
+
+       p = line;
+       *fc = 0;
+       while (1) {
+               while (isspace(*p))
+                       p++;
+               if (*p == '\0' || *p == '#')
+                       break;
+
+               if (*fc < nf)
+                       fv[(*fc)++] = p;
+               while (*p && !isspace(*p) && *p != '#')
+                       p++;
+               if (*p == '\0' || *p == '#')
+                       break;
+               *p++ = '\0';
+       }
+       if (*p)
+               *p = '\0';      /* needed for '#' case */
+}
+
+void 
+add_srcdirs(int argc, char **argv)
+{
+       int             i;
+       char            tmppath[MAXPATHLEN];
+       int             overflow;
+
+       for (i = 1; i < argc; i++) {
+               overflow = 0;
+               if (argv[i][0] == '/' || topdir[0] == '\0') {
+                       if (strlcpy(tmppath, argv[i], sizeof(tmppath)) >=
+                           sizeof(tmppath))
+                               overflow = 1;
+               } else {
+                       if (strlcpy(tmppath, topdir, sizeof(tmppath)) >=
+                           sizeof(tmppath) ||
+                           strlcat(tmppath, "/", sizeof(tmppath)) >=
+                           sizeof(tmppath) ||
+                           strlcat(tmppath, argv[i], sizeof(tmppath)) >=
+                           sizeof(tmppath))
+                               overflow = 1;
+               }
+               if (overflow) {
+                       goterror = 1;
+                       fprintf(stderr, "%s:%d: `%.40s...' is too long, skipping it.\n",
+                           curfilename, linenum, argv[i]);
+                       continue;
+               }
+               if (is_dir(tmppath))
+                       add_string(&srcdirs, tmppath);
+               else {
+                       fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n",
+                           curfilename, linenum, tmppath);
+                       goterror = 1;
+               }
+       }
+}
+
+void 
+add_libdirs(int argc, char **argv)
+{
+       int             i;
+       char            tmppath[MAXPATHLEN];
+       char            tmppath2[MAXPATHLEN];
+       int             overflow;
+
+       for (i = 1; i < argc; i++) {
+               overflow = 0;
+               if (argv[i][0] == '/' || topdir[0] == '\0') {
+                       if (strlcpy(tmppath, argv[i], sizeof(tmppath)) >=
+                           sizeof(tmppath))
+                               overflow = 1;
+               } else {
+                       if (strlcpy(tmppath, topdir, sizeof(tmppath)) >=
+                           sizeof(tmppath) ||
+                           strlcat(tmppath, "/", sizeof(tmppath)) >=
+                           sizeof(tmppath) ||
+                           strlcat(tmppath, argv[i], sizeof(tmppath)) >=
+                           sizeof(tmppath))
+                               overflow = 1;
+               }
+               if (overflow) {
+                       goterror = 1;
+                       fprintf(stderr, "%s:%d: `%.40s...' is too long, skipping it.\n",
+                           curfilename, linenum, argv[i]);
+                       continue;
+               }
+               if (is_dir(tmppath)) {
+                       snprintf(tmppath2, sizeof(tmppath2), "%s/%s", tmppath,
+                           objdir);
+                       if (is_dir(tmppath2))
+                               add_string(&libdirs, tmppath2);
+                       else {
+                               snprintf(tmppath2, sizeof(tmppath2), 
+                                   "%s/obj.%s", tmppath, MACHINE);
+                               if (is_dir(tmppath2))
+                                       add_string(&libdirs, tmppath2);
+                               else
+                                       add_string(&libdirs, tmppath);
+                       }
+               }
+               else {
+                       fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n",
+                           curfilename, linenum, tmppath);
+                       goterror = 1;
+               }
+       }
+}
+
+
+void 
+add_progs(int argc, char **argv)
+{
+       int             i;
+
+       for (i = 1; i < argc; i++)
+               add_prog(argv[i]);
+}
+
+void 
+add_prog(char *progname)
+{
+       prog_t         *p1, *p2;
+
+       /* add to end, but be smart about dups */
+
+       for (p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next)
+               if (!strcmp(p2->name, progname))
+                       return;
+
+       p2 = calloc(1, sizeof(prog_t));
+       if (p2)
+               p2->name = strdup(progname);
+       if (!p2 || !p2->name)
+               out_of_memory();
+
+       p2->next = NULL;
+       if (p1 == NULL)
+               progs = p2;
+       else
+               p1->next = p2;
+
+       p2->ident = p2->srcdir = p2->objdir = NULL;
+       p2->links = p2->objs = NULL;
+       p2->goterror = 0;
+}
+
+void 
+add_link(int argc, char **argv)
+{
+       int             i;
+       prog_t         *p = find_prog(argv[1]);
+
+       if (p == NULL) {
+               fprintf(stderr,
+                   "%s:%d: no prog %s previously declared, skipping link.\n",
+                   curfilename, linenum, argv[1]);
+               goterror = 1;
+               return;
+       }
+       for (i = 2; i < argc; i++)
+               add_string(&p->links, argv[i]);
+}
+
+void 
+add_libs(int argc, char **argv)
+{
+       int             i;
+
+       for (i = 1; i < argc; i++)
+               add_string(&libs, argv[i]);
+}
+
+void 
+add_special(int argc, char **argv)
+{
+       int             i;
+       prog_t         *p = find_prog(argv[1]);
+
+       if (p == NULL) {
+               if (reading_cache)
+                       return;
+               fprintf(stderr,
+                   "%s:%d: no prog %s previously declared, skipping special.\n",
+                   curfilename, linenum, argv[1]);
+               goterror = 1;
+               return;
+       }
+       if (!strcmp(argv[2], "ident")) {
+               if (argc != 4)
+                       goto argcount;
+               if ((p->ident = strdup(argv[3])) == NULL)
+                       out_of_memory();
+       } else if (!strcmp(argv[2], "srcdir")) {
+               if (argc != 4)
+                       goto argcount;
+               if ((p->srcdir = strdup(argv[3])) == NULL)
+                       out_of_memory();
+       } else if (!strcmp(argv[2], "mf_name")) {
+               if (argc != 4)
+                       goto argcount;
+               if ((p->mf_name = strdup(argv[3])) == NULL)
+                       out_of_memory();
+       } else if (!strcmp(argv[2], "objdir")) {
+               if (argc != 4)
+                       goto argcount;
+               if ((p->objdir = strdup(argv[3])) == NULL)
+                       out_of_memory();
+       } else if (!strcmp(argv[2], "objs")) {
+               p->objs = NULL;
+               for (i = 3; i < argc; i++)
+                       add_string(&p->objs, argv[i]);
+       } else if (!strcmp(argv[2], "objpaths")) {
+               p->objpaths = NULL;
+               for (i = 3; i < argc; i++)
+                       add_string(&p->objpaths, argv[i]);
+       } else {
+               fprintf(stderr, "%s:%d: bad parameter name `%s', skipping line.\n",
+                   curfilename, linenum, argv[2]);
+               goterror = 1;
+       }
+       return;
+
+argcount:
+       fprintf(stderr,
+           "%s:%d: too %s arguments, expected \"special %s %s <string>\".\n",
+           curfilename, linenum, argc < 4 ? "few" : "many", argv[1], argv[2]);
+       goterror = 1;
+}
+
+prog_t  *
+find_prog(char *str)
+{
+       prog_t         *p;
+
+       for (p = progs; p != NULL; p = p->next)
+               if (!strcmp(p->name, str))
+                       return p;
+       return NULL;
+}
+
+void            remove_error_progs(void);
+void            fillin_program(prog_t * p);
+void            gen_specials_cache(void);
+void            gen_output_makefile(void);
+void            gen_output_cfile(void);
+
+void            fillin_program_objs(prog_t * p, char *path);
+void            top_makefile_rules(FILE * outmk);
+void            prog_makefile_rules(FILE * outmk, prog_t * p);
+void            output_strlst(FILE * outf, strlst_t * lst);
+char           *genident(char *str);
+char           *dir_search(char *progname);
+
+void 
+gen_outputs(void)
+{
+       prog_t         *p;
+
+       for (p = progs; p != NULL; p = p->next)
+               fillin_program(p);
+
+       remove_error_progs();
+       gen_specials_cache();
+       gen_output_cfile();
+       gen_output_makefile();
+       status("");
+       fprintf(stderr,
+           "Run \"make -f %s objs exe\" to build crunched binary.\n",
+           outmkname);
+}
+
+void 
+fillin_program(prog_t * p)
+{
+       char            path[MAXPATHLEN];
+       char           *srcparent;
+       strlst_t       *s;
+       int             i;
+
+       snprintf(line, sizeof(line), "filling in parms for %s", p->name);
+       status(line);
+
+       if (!p->ident)
+               p->ident = genident(p->name);
+       if (!p->srcdir) {
+               srcparent = dir_search(p->name);
+               if (srcparent)
+                       snprintf(path, sizeof(path), "%s/%s", srcparent, p->name);
+               if (is_dir(path))
+                       p->srcdir = strdup(path);
+       }
+       if (!p->objdir && p->srcdir) {
+               snprintf(path, sizeof(path), "%s/%s", p->srcdir, objdir);
+               if (is_dir(path))
+                       p->objdir = strdup(path);
+               else {
+                       snprintf(path, sizeof(path), "%s/obj.%s", p->srcdir, MACHINE);
+                       if (is_dir(path))
+                               p->objdir = strdup(path);
+                       else
+                               p->objdir = p->srcdir;
+               }
+       }
+       /* We have a sourcedir and no explicit objs, try */
+       /* to find makefile and get objs from it. */
+       if (p->srcdir && !p->objs) {
+               for (i = 0; mf_name[i] != NULL; i++) {
+                       snprintf(path, sizeof(path), "%s/%s", p->srcdir, mf_name[i]);
+                       if (is_nonempty_file(path)) {
+                               p->mf_name = mf_name[i];
+                               fillin_program_objs(p, path);
+                               break;
+                       }
+               }
+       }
+       if (!p->objpaths && p->objdir && p->objs)
+               for (s = p->objs; s != NULL; s = s->next) {
+                       snprintf(line, sizeof(line), "%s/%s", p->objdir, s->str);
+                       add_string(&p->objpaths, line);
+               }
+
+       if (!p->srcdir && verbose)
+               fprintf(stderr, "%s: %s: warning: could not find source directory.\n",
+                   infilename, p->name);
+       if (!p->objs && verbose)
+               fprintf(stderr, "%s: %s: warning: could not find any .o files.\n",
+                   infilename, p->name);
+
+       if (!p->objpaths) {
+               fprintf(stderr,
+                   "%s: %s: error: no objpaths specified or calculated.\n",
+                   infilename, p->name);
+               p->goterror = goterror = 1;
+       }
+}
+
+void 
+fillin_program_objs(prog_t * p, char *path)
+{
+       char           *cp, *obj, tempfname[MAXPATHLEN];
+       int             fd, rc;
+       FILE           *f;
+
+       /* discover the objs from the srcdir Makefile */
+
+       snprintf(tempfname, sizeof(tempfname), ".tmp_%sXXXXXXXXXX", confname);
+       if ((fd = mkstemp(tempfname)) == -1 || (f = fdopen(fd, "w")) == NULL) {
+               if (fd != -1)
+                       close(fd);
+               perror(tempfname);
+               goterror = 1;
+               return;
+       }
+       fprintf(f, ".include \"%s\"\n", path);
+       fprintf(f, ".if defined(PROG) && !defined(OBJS)\n");
+       fprintf(f, "OBJS=${PROG}.o\n");
+       fprintf(f, ".endif\n");
+       fprintf(f, "crunchgen_objs:\n\t@echo 'OBJS= '${OBJS}\n");
+       fclose(f);
+
+       snprintf(line, sizeof(line), "make -f %s crunchgen_objs 2>&1", tempfname);
+       if ((f = popen(line, "r")) == NULL) {
+               perror("submake pipe");
+               goterror = 1;
+               return;
+       }
+       while (fgets(line, MAXLINELEN, f)) {
+               if (strncmp(line, "OBJS= ", 6)) {
+                       if (strcmp(line,
+                           "sh: warning: running as root with dot in PATH\n") == 0)
+                               continue;
+                       fprintf(stderr, "make error: %s", line);
+                       goterror = 1;
+                       continue;
+               }
+               cp = line + 6;
+               while (isspace(*cp))
+                       cp++;
+               while (*cp) {
+                       obj = cp;
+                       while (*cp && !isspace(*cp))
+                               cp++;
+                       if (*cp)
+                               *cp++ = '\0';
+                       add_string(&p->objs, obj);
+                       while (isspace(*cp))
+                               cp++;
+               }
+       }
+       if ((rc = pclose(f)) != 0) {
+               fprintf(stderr, "make error: make returned %d\n", rc);
+               goterror = 1;
+       }
+       unlink(tempfname);
+}
+
+void 
+remove_error_progs(void)
+{
+       prog_t         *p1, *p2;
+
+       p1 = NULL;
+       p2 = progs;
+       while (p2 != NULL) {
+               if (!p2->goterror)
+                       p1 = p2, p2 = p2->next;
+               else {
+                       /* delete it from linked list */
+                       fprintf(stderr, "%s: %s: ignoring program because of errors.\n",
+                           infilename, p2->name);
+                       if (p1)
+                               p1->next = p2->next;
+                       else
+                               progs = p2->next;
+                       p2 = p2->next;
+               }
+       }
+}
+
+void 
+gen_specials_cache(void)
+{
+       FILE           *cachef;
+       prog_t         *p;
+
+       snprintf(line, sizeof(line), "generating %s", cachename);
+       status(line);
+
+       if ((cachef = fopen(cachename, "w")) == NULL) {
+               perror(cachename);
+               goterror = 1;
+               return;
+       }
+       fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n",
+           cachename, infilename, CRUNCH_VERSION);
+
+       for (p = progs; p != NULL; p = p->next) {
+               fprintf(cachef, "\n");
+               if (p->srcdir)
+                       fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir);
+               if (p->mf_name)
+                       fprintf(cachef, "special %s mf_name %s\n", p->name, p->mf_name);
+               if (p->objdir)
+                       fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir);
+               if (p->objs) {
+                       fprintf(cachef, "special %s objs", p->name);
+                       output_strlst(cachef, p->objs);
+               }
+               fprintf(cachef, "special %s objpaths", p->name);
+               output_strlst(cachef, p->objpaths);
+       }
+       fclose(cachef);
+}
+
+void 
+gen_output_makefile(void)
+{
+       prog_t         *p;
+       FILE           *outmk;
+
+       snprintf(line, sizeof(line), "generating %s", outmkname);
+       status(line);
+
+       if ((outmk = fopen(outmkname, "w")) == NULL) {
+               perror(outmkname);
+               goterror = 1;
+               return;
+       }
+       fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n",
+           outmkname, infilename, CRUNCH_VERSION);
+
+       top_makefile_rules(outmk);
+
+       for (p = progs; p != NULL; p = p->next)
+               prog_makefile_rules(outmk, p);
+
+       fprintf(outmk, "\n# ========\n");
+       fclose(outmk);
+}
+
+void 
+gen_output_cfile(void)
+{
+       extern char    *crunched_skel[];
+       char          **cp;
+       FILE           *outcf;
+       prog_t         *p;
+       strlst_t       *s;
+
+       snprintf(line, sizeof(line), "generating %s", outcfname);
+       status(line);
+
+       if ((outcf = fopen(outcfname, "w")) == NULL) {
+               perror(outcfname);
+               goterror = 1;
+               return;
+       }
+       fprintf(outcf, "/* %s - generated from %s by crunchgen %s */\n",
+           outcfname, infilename, CRUNCH_VERSION);
+
+       fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname);
+       for (cp = crunched_skel; *cp != NULL; cp++)
+               fprintf(outcf, "%s\n", *cp);
+
+       for (p = progs; p != NULL; p = p->next)
+               fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident);
+
+       fprintf(outcf, "\nstruct stub entry_points[] = {\n");
+       for (p = progs; p != NULL; p = p->next) {
+               fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
+                       p->name, p->ident);
+               for (s = p->links; s != NULL; s = s->next)
+                       fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
+                               s->str, p->ident);
+       }
+
+       fprintf(outcf, "\t{ EXECNAME, crunched_main },\n");
+       fprintf(outcf, "\t{ NULL, NULL }\n};\n");
+       fclose(outcf);
+}
+
+char           *
+genident(char *str)
+{
+       char           *n, *s, *d;
+
+       /*
+         * generates a Makefile/C identifier from a program name, mapping '-' to
+         * '_' and ignoring all other non-identifier characters.  This leads to
+         * programs named "foo.bar" and "foobar" to map to the same identifier.
+         */
+
+       if ((n = strdup(str)) == NULL)
+               return NULL;
+       for (d = s = n; *s != '\0'; s++) {
+               if (*s == '-')
+                       *d++ = '_';
+               else if (*s == '_' || isalnum(*s))
+                       *d++ = *s;
+       }
+       *d = '\0';
+       return n;
+}
+
+char           *
+dir_search(char *progname)
+{
+       char            path[MAXPATHLEN];
+       strlst_t       *dir;
+
+       for (dir = srcdirs; dir != NULL; dir = dir->next) {
+               snprintf(path, sizeof(path), "%s/%s", dir->str, progname);
+               if (is_dir(path))
+                       return dir->str;
+       }
+       return NULL;
+}
+
+void 
+top_makefile_rules(FILE * outmk)
+{
+       prog_t         *p;
+       strlst_t       *l;
+
+
+       fprintf(outmk, "STRIP?=strip\n");
+       fprintf(outmk, "LINK=$(LD) -dc -r\n");
+       fprintf(outmk, "LIBS=");
+       for (l = libdirs; l != NULL; l = l->next)
+               fprintf(outmk, " -L%s", l->str);
+       output_strlst(outmk, libs);
+
+       fprintf(outmk, "CRUNCHED_OBJS=");
+       for (p = progs; p != NULL; p = p->next)
+               fprintf(outmk, " %s.lo", p->name);
+       fprintf(outmk, "\n");
+
+       fprintf(outmk, "SUBMAKE_TARGETS=");
+       for (p = progs; p != NULL; p = p->next)
+               fprintf(outmk, " %s_make", p->ident);
+       fprintf(outmk, "\n\n");
+
+       fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS)\n",
+           execfname, execfname);
+       fprintf(outmk, "\t$(CC) -static -o $@ %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
+           execfname);
+       fprintf(outmk, "\t$(STRIP) %s\n", execfname);
+       fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
+       fprintf(outmk, "exe: %s\n", execfname);
+       fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n",
+           execfname);
+       fprintf(outmk, ".PHONY: all objs exe clean $(SUBMAKE_TARGETS)\n\n");
+}
+
+void 
+prog_makefile_rules(FILE * outmk, prog_t * p)
+{
+       fprintf(outmk, "\n# -------- %s\n\n", p->name);
+
+       if (p->srcdir && p->objs) {
+               fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
+               fprintf(outmk, "%s_OBJS=", p->ident);
+               output_strlst(outmk, p->objs);
+               fprintf(outmk, "%s_make:\n", p->ident);
+               fprintf(outmk, "\tcd $(%s_SRCDIR) && exec $(MAKE) -f %s $(%s_OBJS)\n\n",
+                   p->ident, p->mf_name, p->ident);
+       } else
+               fprintf(outmk, "%s_make:\n\t@echo \"** cannot make objs for %s\"\n\n",
+                   p->ident, p->name);
+
+       fprintf(outmk, "%s_OBJPATHS=", p->ident);
+       output_strlst(outmk, p->objpaths);
+
+       fprintf(outmk, "%s_stub.c:\n", p->name);
+       fprintf(outmk, "\techo \""
+           "int _crunched_%s_stub(int argc, char **argv, char **envp)"
+           "{return main(argc,argv,envp);}\" >$@\n",
+           p->ident);
+       fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n",
+           p->name, p->name, p->ident);
+       fprintf(outmk, "\t$(LINK) -o $@ %s_stub.o $(%s_OBJPATHS)\n",
+           p->name, p->ident);
+       fprintf(outmk, "\tcrunchide -k %s_crunched_%s_stub $@\n",
+           elf_names ? "" : "_", p->ident);
+}
+
+void 
+output_strlst(FILE * outf, strlst_t * lst)
+{
+       for (; lst != NULL; lst = lst->next)
+               fprintf(outf, " %s", lst->str);
+       fprintf(outf, "\n");
+}
+
+void 
+status(char *str)
+{
+       static int      lastlen = 0;
+       int             len, spaces;
+
+       if (!verbose)
+               return;
+
+       len = strlen(str);
+       spaces = lastlen - len;
+       if (spaces < 1)
+               spaces = 1;
+
+       fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " ");
+       fflush(stderr);
+       lastlen = len;
+}
+
+void 
+out_of_memory(void)
+{
+       fprintf(stderr, "%s: %d: out of memory, stopping.\n", infilename, linenum);
+       exit(1);
+}
+
+void 
+add_string(strlst_t ** listp, char *str)
+{
+       strlst_t       *p1, *p2;
+
+       /* add to end, but be smart about dups */
+
+       for (p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next)
+               if (!strcmp(p2->str, str))
+                       return;
+
+       p2 = calloc(1, sizeof(strlst_t));
+       if (p2)
+               p2->str = strdup(str);
+       if (!p2 || !p2->str)
+               out_of_memory();
+
+       p2->next = NULL;
+       if (p1 == NULL)
+               *listp = p2;
+       else
+               p1->next = p2;
+}
+
+int 
+is_dir(char *pathname)
+{
+       struct stat     buf;
+
+       if (stat(pathname, &buf) == -1)
+               return 0;
+       return S_ISDIR(buf.st_mode);
+}
+
+int 
+is_nonempty_file(char *pathname)
+{
+       struct stat     buf;
+
+       if (stat(pathname, &buf) == -1)
+               return 0;
+
+       return S_ISREG(buf.st_mode) && buf.st_size > 0;
+}
diff --git a/usr.sbin/crunchgen/crunchide.1 b/usr.sbin/crunchgen/crunchide.1
new file mode 100644 (file)
index 0000000..2f9b408
--- /dev/null
@@ -0,0 +1,80 @@
+.\"    $OpenBSD: crunchide.1,v 1.1 2008/08/22 15:18:55 deraadt Exp $
+.\"
+.\"
+.\" Copyright (c) 1994 University of Maryland
+.\" All Rights Reserved.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation, and that the name of U.M. not be used in advertising or
+.\" publicity pertaining to distribution of the software without specific,
+.\" written prior permission.  U.M. makes no representations about the
+.\" suitability of this software for any purpose.  It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.\" U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+.\" BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+.\" IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Author: James da Silva, Systems Design and Analysis Group
+.\"                       Computer Science Department
+.\"                       University of Maryland at College Park
+.\"
+.Dd $Mdocdate: August 22 2008 $
+.Dt CRUNCHIDE 1
+.Os
+.Sh NAME
+.Nm crunchide
+.Nd hides symbol names from ld, for crunching programs together
+.Sh SYNOPSIS
+.Nm crunchide
+.Op Fl f Ar keep-list-file
+.Op Fl k Ar keep-symbol
+.Ar object-file ...
+.Sh DESCRIPTION
+.Nm
+hides the global symbols of
+.Ar object-file
+such that they are ignored by subsequent runs of the linker,
+.Xr ld 1 .
+Some symbols may be left visible via the
+.Fl k Ar keep-symbol
+and
+.Fl f Ar keep-list-file
+options.
+The
+.Ar keep-list-file
+must contain a list of symbols to keep visible, one symbol per line.
+Note that the C compiler prepends an underscore in front of
+symbols, so to keep the C function ``foo'' visible, the option
+.Dq -k _foo
+must be used.
+.Pp
+.Nm
+is designed as a companion program for
+.Xr crunchgen 1 ,
+which automates the process of creating crunched binaries from
+multiple component programs.
+.Sh NOTES
+The ELF version of
+.Nm crunchide
+mangles the symbol table beyond recognition.
+It is therefore not advisable to try to run
+.Xr nm 1
+on a crunched object file.
+This is due to the nature of the ELF symbol table
+and how some arches uses the symbol attributes for their GOT build.
+.Sh SEE ALSO
+.Xr crunchgen 1 ,
+.Xr ld 1
+.Sh AUTHORS
+.Nm
+was written by James da Silva
+.Aq jds@cs.umd.edu .
+.Pp
+Copyright (c) 1994 University of Maryland.  All Rights Reserved.
diff --git a/usr.sbin/crunchgen/crunchide.c b/usr.sbin/crunchgen/crunchide.c
new file mode 100644 (file)
index 0000000..3c74a0d
--- /dev/null
@@ -0,0 +1,351 @@
+/* $OpenBSD: crunchide.c,v 1.1 2008/08/22 15:18:55 deraadt Exp $        */
+
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  U.M. makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ *                        Computer Science Department
+ *                        University of Maryland at College Park
+ */
+/*
+ * crunchide.c - tiptoes through an a.out symbol table, hiding all defined
+ *     global symbols.  Allows the user to supply a "keep list" of symbols
+ *     that are not to be hidden.  This program relies on the use of the
+ *     linker's -dc flag to actually put global bss data into the file's
+ *     bss segment (rather than leaving it as undefined "common" data).
+ *
+ *     The point of all this is to allow multiple programs to be linked
+ *     together without getting multiple-defined errors.
+ *
+ *     For example, consider a program "foo.c".  It can be linked with a
+ *     small stub routine, called "foostub.c", eg:
+ *         int foo_main(int argc, char **argv){ return main(argc, argv); }
+ *      like so:
+ *         cc -c foo.c foostub.c
+ *         ld -dc -r foo.o foostub.o -o foo.combined.o
+ *         crunchide -k _foo_main foo.combined.o
+ *     at this point, foo.combined.o can be linked with another program
+ *     and invoked with "foo_main(argc, argv)".  foo's main() and any
+ *     other globals are hidden and will not conflict with other symbols.
+ *
+ * TODO:
+ *     - resolve the theoretical hanging reloc problem (see check_reloc()
+ *       below). I have yet to see this problem actually occur in any real
+ *       program. In what cases will gcc/gas generate code that needs a
+ *       relative reloc from a global symbol, other than PIC?  The
+ *       solution is to not hide the symbol from the linker in this case,
+ *       but to generate some random name for it so that it doesn't link
+ *       with anything but holds the place for the reloc.
+ *      - arrange that all the BSS segments start at the same address, so
+ *       that the final crunched binary BSS size is the max of all the
+ *       component programs' BSS sizes, rather than their sum.
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <sys/types.h>
+#ifdef _NLIST_DO_ECOFF
+#include <sys/exec_ecoff.h>
+#endif
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+/*
+ * if __ELF__ is defined, do not bother supporting AOUT.
+ */
+#if defined(_NLIST_DO_AOUT) && !(defined(__ELF__))
+#define DO_AOUT
+#endif
+
+void            crunchide_usage(void);
+
+void            add_to_keep_list(char *);
+void            add_file_to_keep_list(char *);
+
+void            hide_syms(char *);
+#ifdef _NLIST_DO_ECOFF
+void            ecoff_hide(int, char *);
+#endif
+#ifdef _NLIST_DO_ELF
+void            elf_hide(int, char *);
+#endif
+
+extern char    *__progname;
+
+int 
+crunchide_main(int argc, char *argv[])
+{
+       int             ch;
+
+       while ((ch = getopt(argc, argv, "k:f:")) != -1)
+               switch (ch) {
+               case 'k':
+                       add_to_keep_list(optarg);
+                       break;
+               case 'f':
+                       add_file_to_keep_list(optarg);
+                       break;
+               default:
+                       crunchide_usage();
+               }
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc == 0)
+               crunchide_usage();
+
+       while (argc) {
+               hide_syms(*argv);
+               argc--;
+               argv++;
+       }
+
+       return 0;
+}
+
+void 
+crunchide_usage(void)
+{
+       fprintf(stderr,
+           "usage: crunchide [-f keep-list-file] [-k keep-symbol] object-file ...\n");
+       exit(1);
+}
+
+struct keep {
+       struct keep    *next;
+       char           *sym;
+} *keep_list;
+
+void 
+add_to_keep_list(char *symbol)
+{
+       struct keep    *newp, *prevp, *curp;
+       int             cmp;
+
+       for (curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next)
+               if ((cmp = strcmp(symbol, curp->sym)) <= 0)
+                       break;
+
+       if (curp && cmp == 0)
+               return;         /* already in table */
+
+       newp = (struct keep *) calloc(1, sizeof(struct keep));
+       if (newp)
+               newp->sym = strdup(symbol);
+       if (newp == NULL || newp->sym == NULL) {
+               fprintf(stderr, "%s: out of memory for keep list\n", __progname);
+               exit(1);
+       }
+       newp->next = curp;
+       if (prevp)
+               prevp->next = newp;
+       else
+               keep_list = newp;
+}
+
+int 
+in_keep_list(char *symbol)
+{
+       struct keep    *curp;
+       int             cmp = 0;
+
+       for (curp = keep_list; curp; curp = curp->next)
+               if ((cmp = strcmp(symbol, curp->sym)) <= 0)
+                       break;
+
+       return curp && cmp == 0;
+}
+
+void 
+add_file_to_keep_list(char *filename)
+{
+       FILE           *keepf;
+       char            symbol[1024];
+       int             len;
+
+       if ((keepf = fopen(filename, "r")) == NULL) {
+               perror(filename);
+               crunchide_usage();
+       }
+       while (fgets(symbol, sizeof(symbol), keepf)) {
+               len = strlen(symbol);
+               if (len && symbol[len - 1] == '\n')
+                       symbol[len - 1] = '\0';
+
+               add_to_keep_list(symbol);
+       }
+       fclose(keepf);
+}
+
+int             nsyms, ntextrel, ndatarel;
+struct exec    *hdrp;
+char           *aoutdata, *strbase;
+struct relocation_info *textrel, *datarel;
+struct nlist   *symbase;
+
+#define SYMSTR(sp)     &strbase[(sp)->n_un.n_strx]
+
+/* is the symbol a global symbol defined in the current file? */
+#define IS_GLOBAL_DEFINED(sp) \
+       (((sp)->n_type & N_EXT) && ((sp)->n_type & N_TYPE) != N_UNDF)
+
+#ifdef DO_AOUT
+#if defined(__sparc__)
+/* is the relocation entry dependent on a symbol? */
+#define IS_SYMBOL_RELOC(rp)   \
+       ((rp)->r_extern || \
+       ((rp)->r_type >= RELOC_BASE10 && (rp)->r_type <= RELOC_BASE22) || \
+       (rp)->r_type == RELOC_JMP_TBL)
+#else
+/* is the relocation entry dependent on a symbol? */
+#define IS_SYMBOL_RELOC(rp)   \
+                 ((rp)->r_extern||(rp)->r_baserel||(rp)->r_jmptable)
+#endif
+#endif
+
+void            check_reloc(char *filename, struct relocation_info * relp);
+
+void 
+hide_syms(char *filename)
+{
+       int             inf;
+       struct stat     infstat;
+#ifdef DO_AOUT
+       struct relocation_info *relp;
+       struct nlist   *symp;
+       u_char          zero = 0;
+#endif
+       char           *buf;
+
+       /*
+         * Open the file and do some error checking.
+         */
+
+       if ((inf = open(filename, O_RDWR)) == -1) {
+               perror(filename);
+               return;
+       }
+       if (fstat(inf, &infstat) == -1) {
+               perror(filename);
+               close(inf);
+               return;
+       }
+       if (infstat.st_size < sizeof(struct exec)) {
+               fprintf(stderr, "%s: short file\n", filename);
+               close(inf);
+               return;
+       }
+       if ((buf = mmap(NULL, infstat.st_size, PROT_READ | PROT_WRITE,
+           MAP_FILE | MAP_SHARED, inf, 0)) == MAP_FAILED) {
+               fprintf(stderr, "%s: cannot map\n", filename);
+               close(inf);
+               return;
+       }
+
+#ifdef _NLIST_DO_ELF
+       if (buf[0] == 0x7f && (buf[1] == 'E' || buf[1] == 'O') &&
+           buf[2] == 'L' && buf[3] == 'F') {
+               elf_hide(inf, buf);
+               return;
+       }
+#endif                         /* _NLIST_DO_ELF */
+
+#ifdef _NLIST_DO_ECOFF
+       if (!ECOFF_BADMAG((struct ecoff_exechdr *) buf)) {
+               ecoff_hide(inf, buf);
+               return;
+       }
+#endif                         /* _NLIST_DO_ECOFF */
+
+#ifdef DO_AOUT
+       aoutdata = buf;
+
+       /*
+         * Check the header and calculate offsets and sizes from it.
+         */
+       hdrp = (struct exec *) aoutdata;
+
+       if (N_BADMAG(*hdrp)) {
+               fprintf(stderr, "%s: bad magic: not an a.out, ecoff or elf  file\n",
+                   filename);
+               close(inf);
+               return;
+       }
+       textrel = (struct relocation_info *) (aoutdata + N_TRELOFF(*hdrp));
+       datarel = (struct relocation_info *) (aoutdata + N_DRELOFF(*hdrp));
+       symbase = (struct nlist *) (aoutdata + N_SYMOFF(*hdrp));
+       strbase = (char *) (aoutdata + N_STROFF(*hdrp));
+
+       ntextrel = hdrp->a_trsize / sizeof(struct relocation_info);
+       ndatarel = hdrp->a_drsize / sizeof(struct relocation_info);
+       nsyms = hdrp->a_syms / sizeof(struct nlist);
+
+       /*
+         * Zap the type field of all globally-defined symbols.  The linker will
+         * subsequently ignore these entries.  Don't zap any symbols in the
+         * keep list.
+         */
+       for (symp = symbase; symp < symbase + nsyms; symp++)
+               if (IS_GLOBAL_DEFINED(symp) && !in_keep_list(SYMSTR(symp))) {
+                       /*
+                        * XXX Our VM system has some problems, so
+                        * avoid the VM system....
+                        */
+                       lseek(inf, (off_t) ((void *) &symp->n_type -
+                           (void *) buf), SEEK_SET);
+                       write(inf, &zero, sizeof zero);
+                       symp->n_type = 0;
+               }
+       /*
+         * Check whether the relocation entries reference any symbols that we
+         * just zapped.  I don't know whether ld can handle this case, but I
+         * haven't encountered it yet.  These checks are here so that the program
+         * doesn't fail silently should such symbols be encountered.
+         */
+       for (relp = textrel; relp < textrel + ntextrel; relp++)
+               check_reloc(filename, relp);
+       for (relp = datarel; relp < datarel + ndatarel; relp++)
+               check_reloc(filename, relp);
+
+       msync(buf, infstat.st_size, MS_SYNC);
+       munmap(buf, infstat.st_size);
+       close(inf);
+#endif                         /* DO_AOUT */
+}
+
+#ifdef DO_AOUT
+void 
+check_reloc(char *filename, struct relocation_info * relp)
+{
+       /* bail out if we zapped a symbol that is needed */
+       if (IS_SYMBOL_RELOC(relp) && symbase[relp->r_symbolnum].n_type == 0) {
+               fprintf(stderr,
+                   "%s: oops, have hanging relocation for %s: bailing out!\n",
+                   filename, SYMSTR(&symbase[relp->r_symbolnum]));
+               exit(1);
+       }
+}
+#endif                         /* DO_AOUT */
diff --git a/usr.sbin/crunchgen/ecoff_hide.c b/usr.sbin/crunchgen/ecoff_hide.c
new file mode 100644 (file)
index 0000000..e21383c
--- /dev/null
@@ -0,0 +1,62 @@
+/* $OpenBSD: ecoff_hide.c,v 1.1 2008/08/22 15:18:55 deraadt Exp $       */
+
+/*-
+ * Copyright (c) 1997 Niklas Hallqvist.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/exec.h>
+#ifdef _NLIST_DO_ECOFF
+#include <sys/exec_ecoff.h>
+#include <string.h>
+
+/* Do we have these symbols in any include file?  */
+#define scText         1
+#define scData         2
+#define scBss          3
+#define scSData                13
+#define scSBss         14
+#define scRData                15
+
+#define stNil          0
+
+extern int      in_keep_list(char *);
+
+void
+ecoff_hide(int fd, char *p)
+{
+       struct ecoff_exechdr *ehdr = (struct ecoff_exechdr *) p;
+       struct ecoff_symhdr *shdr = (struct ecoff_symhdr *) (p + ehdr->f.f_symptr);
+       u_int           ecnt = shdr->esymMax;
+       struct ecoff_extsym *esym = (struct ecoff_extsym *) (p + shdr->cbExtOffset);
+       char           *estr = p + shdr->cbSsExtOffset;
+       int             i;
+
+       for (i = 0; i < ecnt; i++, esym++)
+               if ((esym->es_class == scText || esym->es_class == scData ||
+                   esym->es_class == scBss || esym->es_class == scSData ||
+                   esym->es_class == scSBss || esym->es_class == scRData) &&
+                   !in_keep_list(estr + esym->es_strindex))
+                       esym->es_type = stNil;
+}
+#endif                         /* _NLIST_DO_ECOFF */
diff --git a/usr.sbin/crunchgen/elf_hide.c b/usr.sbin/crunchgen/elf_hide.c
new file mode 100644 (file)
index 0000000..b52a775
--- /dev/null
@@ -0,0 +1,474 @@
+/* $OpenBSD: elf_hide.c,v 1.1 2008/08/22 15:18:55 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1997 Dale Rahn.
+ * All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/exec.h>
+#ifdef _NLIST_DO_ELF
+#include <sys/exec_elf.h>
+
+void   load_strtab(Elf_Ehdr * pehdr, char *pexe);
+void   dump_strtab();
+char   *get_str(int indx);
+
+void   load_symtab(Elf_Ehdr * pehdr, char *pexe);
+void   dump_symtab();
+
+void   load_shstr_tab(Elf_Ehdr * pehdr, char *pexe);
+char   *get_shstr(int indx);
+void   fprint_shstr(FILE * channel, int indx);
+
+void   hide_sym();
+void   reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
+           Elf_Sym * symtab, int symtabsize, int symtabsecnum);
+typedef long    Symmap;
+void   renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap,
+           int symtabsecnum);
+
+
+char           *pexe;
+
+void
+elf_hide(int pfile, char *p)
+{
+       Elf_Ehdr       *pehdr;
+#ifdef DEBUG
+       Elf_Shdr       *pshdr;
+       Elf_Phdr       *pphdr;
+       int             i;
+#endif
+       struct stat     sb;
+
+       pexe = p;
+       pehdr = (Elf_Ehdr *) pexe;
+
+#ifdef DEBUG
+       printf("elf header\n");
+       printf("e_type %x\n", pehdr->e_type);
+       printf("e_machine %x\n", pehdr->e_machine);
+       printf("e_version %x\n", pehdr->e_version);
+       printf("e_entry %x\n", pehdr->e_entry);
+       printf("e_phoff %x\n", pehdr->e_phoff);
+       printf("e_shoff %x\n", pehdr->e_shoff);
+       printf("e_flags %x\n", pehdr->e_flags);
+       printf("e_ehsize %x\n", pehdr->e_ehsize);
+       printf("e_phentsize %x\n", pehdr->e_phentsize);
+       printf("e_phnum %x\n", pehdr->e_phnum);
+       printf("e_shentsize %x\n", pehdr->e_shentsize);
+       printf("e_shnum %x\n", pehdr->e_shnum);
+       printf("e_shstrndx %x\n", pehdr->e_shstrndx);
+#endif
+
+       load_shstr_tab(pehdr, pexe);
+#ifdef DEBUG
+       for (i = 0; i < pehdr->e_shnum; i++) {
+               pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff +
+                   (i * pehdr->e_shentsize));
+
+               printf("section header %d\n", i);
+               printf("sh_name %x ", pshdr->sh_name);
+               fprint_shstr(stdout, pshdr->sh_name);
+               printf("\n");
+               printf("sh_type %x\n", pshdr->sh_type);
+               printf("sh_flags %x\n", pshdr->sh_flags);
+               printf("sh_addr %x\n", pshdr->sh_addr);
+               printf("sh_offset %x\n", pshdr->sh_offset);
+               printf("sh_size %x\n", pshdr->sh_size);
+               printf("sh_link %x\n", pshdr->sh_link);
+               printf("sh_info %x\n", pshdr->sh_info);
+               printf("sh_addralign %x\n", pshdr->sh_addralign);
+               printf("sh_entsize %x\n", pshdr->sh_entsize);
+       }
+#endif                         /* DEBUG */
+
+#ifdef DEBUG
+       for (i = 0; i < pehdr->e_phnum; i++) {
+               pshdr = (Elf_Phdr *) (pexe + pehdr->e_phoff +
+                   (i * pehdr->e_phentsize));
+
+               printf("program header %d\n", i);
+               printf("p_type %x\n", pphdr->p_type);
+               printf("p_offset %x\n", pphdr->p_offset);
+               printf("p_vaddr %x\n", pphdr->p_vaddr);
+               printf("p_paddr %x\n", pphdr->p_paddr);
+               printf("p_filesz %x\n", pphdr->p_filesz);
+               printf("p_memsz %x\n", pphdr->p_memsz);
+               printf("p_flags %x\n", pphdr->p_flags);
+               printf("p_align %x\n", pphdr->p_align);
+       }
+#endif                         /* DEBUG */
+#if 0
+       for (i = 0; i < pehdr->e_shnum; i++) {
+               pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff +
+                   (i * pehdr->e_shentsize));
+               if (strcmp(".strtab", get_shstr(pshdr->sh_name)) == 0)
+                       break;
+       }
+       fprint_shstr(stdout, pshdr->sh_name);
+       printf("\n");
+#endif
+
+       load_strtab(pehdr, pexe);
+       load_symtab(pehdr, pexe);
+
+       munmap(pexe, sb.st_size);
+       close(pfile);
+}
+char           *shstrtab;
+
+void
+load_shstr_tab(Elf_Ehdr * pehdr, char *pexe)
+{
+       Elf_Shdr       *pshdr;
+       shstrtab = NULL;
+       if (pehdr->e_shstrndx == 0)
+               return;
+       pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
+           (pehdr->e_shstrndx * pehdr->e_shentsize));
+
+       shstrtab = (char *) (pexe + pshdr->sh_offset);
+}
+
+void
+fprint_shstr(FILE * channel, int indx)
+{
+       if (shstrtab != NULL)
+               fprintf(channel, "\"%s\"", &(shstrtab[indx]));
+}
+
+char           *
+get_shstr(int indx)
+{
+       return &(shstrtab[indx]);
+}
+
+void
+load_symtab(Elf_Ehdr * pehdr, char *pexe)
+{
+       Elf_Sym        *symtab;
+       Elf_Shdr       *symsect;
+       int             symtabsize;
+       Elf_Shdr       *psymshdr;
+       Elf_Shdr       *pshdr;
+#ifdef DEBUG
+       char           *shname;
+#endif
+       int             i;
+
+       symtab = NULL;
+       for (i = 0; i < pehdr->e_shnum; i++) {
+               pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
+                   (i * pehdr->e_shentsize));
+               if (SHT_REL != pshdr->sh_type && SHT_RELA != pshdr->sh_type)
+                       continue;
+               psymshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
+                   (pshdr->sh_link * pehdr->e_shentsize));
+#ifdef DEBUG
+               fprint_shstr(stdout, pshdr->sh_name);
+               printf("\n");
+#endif
+               symtab = (Elf_Sym *) (pexe + psymshdr->sh_offset);
+               symsect = psymshdr;
+               symtabsize = psymshdr->sh_size;
+
+#ifdef DEBUG
+               dump_symtab(symsect, symtab, symtabsize);
+#endif
+               hide_sym(pehdr, symsect, symtab, symtabsize, pshdr->sh_link);
+       }
+
+}
+
+void
+dump_symtab(Elf_Shdr * symsect, Elf_Sym * symtab, int symtabsize)
+{
+       int             i;
+       Elf_Sym        *psymtab;
+
+       for (i = 0; i < (symtabsize / sizeof(Elf_Sym)); i++) {
+               psymtab = &(symtab[i]);
+               if ((psymtab->st_info & 0xf0) == 0x10 &&
+                   (psymtab->st_shndx != SHN_UNDEF)) {
+                       printf("symbol %d:\n", i);
+                       printf("st_name %x \"%s\"\n", psymtab->st_name,
+                           get_str(psymtab->st_name));
+                       printf("st_value %x\n", psymtab->st_value);
+                       printf("st_size %x\n", psymtab->st_size);
+                       printf("st_info %x\n", psymtab->st_info);
+                       printf("st_other %x\n", psymtab->st_other);
+                       printf("st_shndx %x\n", psymtab->st_shndx);
+               }
+       }
+}
+
+char           *strtab;
+int             strtabsize;
+void
+load_strtab(Elf_Ehdr * pehdr, char *pexe)
+{
+       Elf_Shdr       *pshdr = NULL;
+       char           *shname;
+       int             i;
+       strtab = NULL;
+       for (i = 0; i < pehdr->e_shnum; i++) {
+               pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
+                   (i * pehdr->e_shentsize));
+
+               shname = get_shstr(pshdr->sh_name);
+               if (strcmp(".strtab", shname) == 0)
+                       break;
+       }
+#ifdef DEBUG
+       fprint_shstr(stdout, pshdr->sh_name);
+       printf("\n");
+#endif
+
+       strtab = (char *) (pexe + pshdr->sh_offset);
+
+       strtabsize = pshdr->sh_size;
+
+#ifdef DEBUG
+       dump_strtab();
+#endif
+}
+
+void
+dump_strtab()
+{
+       int             index;
+       char           *pstr;
+       char           *pnstr;
+       int             i = 0;
+       index = 0;
+       pstr = strtab;
+       while (index < strtabsize) {
+               printf("string %x: \"%s\"\n", i, pstr);
+               pnstr = pstr + strlen(pstr) + 1;
+               index = pnstr - strtab;
+               pstr = pnstr;
+               i++;
+       }
+
+}
+
+void
+fprint_str(FILE * channel, int indx)
+{
+       if (strtab != NULL)
+               fprintf(channel, "\"%s\"", &(strtab[indx]));
+}
+
+char *
+get_str(int indx)
+{
+       return &(strtab[indx]);
+}
+
+int             in_keep_list(char *symbol);
+
+void
+hide_sym(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
+    Elf_Sym * symtab, int symtabsize, int symtabsecnum)
+{
+       int             i;
+       unsigned char   info;
+       Elf_Sym        *psymtab;
+
+#ifdef __mips__
+       u_int32_t f = arc4random();
+#endif
+
+       for (i = 0; i < (symtabsize / sizeof(Elf_Sym)); i++) {
+               psymtab = &(symtab[i]);
+               if ((psymtab->st_info & 0xf0) == 0x10 &&
+                   (psymtab->st_shndx != SHN_UNDEF)) {
+                       if (in_keep_list(get_str(psymtab->st_name)))
+                               continue;
+#ifdef DEBUG
+                       printf("symbol %d:\n", i);
+                       printf("st_name %x \"%s\"\n", psymtab->st_name,
+                           get_str(psymtab->st_name));
+                       printf("st_info %x\n", psymtab->st_info);
+#endif
+#ifndef __mips__
+                       info = psymtab->st_info;
+                       info = info & 0xf;
+                       psymtab->st_info = info;
+#else
+                       /*
+                        * XXX This is a small ugly hack to be able to use
+                        * XXX chrunchide with MIPS.
+                        * XXX Because MIPS needs global symbols to stay
+                        * XXX global (has to do with GOT), we mess around
+                        * XXX with the symbol names instead. For most uses
+                        * XXX this will be no problem, symbols are stripped
+                        * XXX anyway. However, if many one character
+                        * XXX symbols exist, names may clash.
+                        */
+                       {
+                               char *p;
+                               u_int32_t n, z;
+
+                               z = f++;
+                               p = get_str(psymtab->st_name);
+                               n = strlen(p);
+                               if (n > 4)
+                                       n = 4;
+                               while (n--) {
+                                       p[n] = z;
+                                       z >>= 8;
+                                       while (p[n] == 0)
+                                               p[n] += arc4random();
+                               }
+                       }
+
+#endif
+#ifdef DEBUG
+                       printf("st_info %x\n", psymtab->st_info);
+#endif
+               }
+       }
+       reorder_syms(ehdr, symsect, symtab, symtabsize, symtabsecnum);
+}
+
+void
+reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect,
+    Elf_Sym * symtab, int symtabsize, int symtabsecnum)
+{
+       int             i;
+       int             nsyms;
+       int             cursym;
+       Elf_Sym        *tmpsymtab;
+       Symmap         *symmap;
+
+
+       nsyms = symtabsize / sizeof(Elf_Sym);
+
+       tmpsymtab = (Elf_Sym *) calloc(1, symtabsize);
+       symmap = (Symmap *) calloc(nsyms, sizeof(Symmap));
+       if (!tmpsymtab || !symmap)
+               errx(5, "calloc: %s", strerror(ENOMEM));
+
+       bcopy(symtab, tmpsymtab, symtabsize);
+
+       cursym = 1;
+       for (i = 1; i < nsyms; i++) {
+               if ((tmpsymtab[i].st_info & 0xf0) == 0x00) {
+#ifdef DEBUG
+                       printf("copying  l o%d n%d <%s>\n", i, cursym,
+                           get_str(tmpsymtab[i].st_name));
+#endif
+                       bcopy(&(tmpsymtab[i]), &(symtab[cursym]),
+                           sizeof(Elf_Sym));
+                       symmap[i] = cursym;
+                       cursym++;
+               }
+       }
+       symsect->sh_info = cursym;
+       for (i = 1; i < nsyms; i++) {
+               if ((tmpsymtab[i].st_info & 0xf0) != 0x00) {
+#ifdef DEBUG
+                       printf("copying nl o%d n%d <%s>\n", i, cursym,
+                           get_str(tmpsymtab[i].st_name));
+#endif
+                       bcopy(&(tmpsymtab[i]), &(symtab[cursym]),
+                           sizeof(Elf_Sym));
+                       symmap[i] = cursym;
+                       cursym++;
+               }
+       }
+       if (cursym != nsyms) {
+               printf("miscounted symbols somewhere c %d n %d \n",
+                   cursym, nsyms);
+               exit(5);
+       }
+       renum_reloc_syms(ehdr, symmap, symtabsecnum);
+       free(tmpsymtab);
+       free(symmap);
+}
+
+void
+renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap, int symtabsecnum)
+{
+       Elf_Shdr       *pshdr;
+       int             i, j;
+       int             num_reloc;
+       Elf_Rel        *prel;
+       Elf_RelA       *prela;
+       int             symnum;
+
+       for (i = 0; i < ehdr->e_shnum; i++) {
+               pshdr = (Elf_Shdr *) (pexe + ehdr->e_shoff +
+                   (i * ehdr->e_shentsize));
+               if ((pshdr->sh_type == SHT_RELA) &&
+                   pshdr->sh_link == symtabsecnum) {
+
+#ifdef DEBUG
+                       printf("section %d has rela relocations in symtab\n", i);
+#endif
+                       prela = (Elf_RelA *) (pexe + pshdr->sh_offset);
+                       num_reloc = pshdr->sh_size / sizeof(Elf_RelA);
+                       for (j = 0; j < num_reloc; j++) {
+                               symnum = ELF_R_SYM(prela[j].r_info);
+#ifdef DEBUG
+                               printf("sym num o %d n %d\n", symnum,
+                                   symmap[symnum]);
+#endif
+                               prela[j].r_info = ELF_R_INFO(symmap[symnum],
+                                   ELF_R_TYPE(prela[j].r_info));
+                       }
+               }
+               if ((pshdr->sh_type == SHT_REL) &&
+                   pshdr->sh_link == symtabsecnum) {
+#ifdef DEBUG
+                       printf("section %d has rel relocations in symtab\n", i);
+#endif
+                       prel = (Elf_Rel *) (pexe + pshdr->sh_offset);
+                       num_reloc = pshdr->sh_size / sizeof(Elf_Rel);
+                       for (j = 0; j < num_reloc; j++) {
+                               symnum = ELF_R_SYM(prel[j].r_info);
+#ifdef DEBUG
+                               printf("sym num o %d n %d\n", symnum,
+                                   symmap[symnum]);
+#endif
+                               prel[j].r_info = ELF_R_INFO(symmap[symnum],
+                                   ELF_R_TYPE(prel[j].r_info));
+                       }
+               }
+       }
+
+}
+#endif                         /* _NLIST_DO_ELF */
diff --git a/usr.sbin/crunchgen/mkskel.sh b/usr.sbin/crunchgen/mkskel.sh
new file mode 100644 (file)
index 0000000..9faa6e9
--- /dev/null
@@ -0,0 +1,17 @@
+#! /bin/sh
+#      $OpenBSD: mkskel.sh,v 1.1 2008/08/22 15:18:55 deraadt Exp $
+
+# idea and sed lines taken straight from flex
+
+cat <<!EOF
+/* File created via mkskel.sh */
+
+char *crunched_skel[] = {
+!EOF
+
+sed 's/\\/&&/g' $* | sed 's/"/\\"/g' | sed 's/.*/  "&",/'
+
+cat <<!EOF
+  0
+};
+!EOF