Note: If you reply to this, please CC me (I'm not on the list).

A co-worker and I happened to be talking about different packaging
mechanisms, and what most people really need.  What always tends to be a
problem is tracking non-packaged installed tarballs (the old ./configure;
make; make install routine).  My co-worker is very technically adept, but
he concedes that he doesn't bother installing from tarballs because they
get lost on the system; removing them becomes a pain.

This got us thinking to how such installations could be tracked, and it
turns out to be a pretty simple idea that we thought of.  Since most
GNU-tool-based tarballs use install(1) to move files into the system, why
not setup a little catch inside of install(1) to record what it's putting
where?

So I created a little patch (attached) to install(1) so that each time it
copies a file, it writes a small log to the file named in $INSTALL_LOG, if
it's set.  The idea is that you set $INSTALL_LOG to a filename before you
run "make install", run "make install", and then you can stuff the logfile
away after running the install, needing only the logfile later to
deinstall the program.  Of course, program installs can be more complex
than simply copying files, but that sort of leads me to my next point...

What does this have over "make uninstall"?  Well, it's simpler to use, for
one.  You also don't need to keep the source tree around for the Makefiles
merely to remove a program, and execute code to deinstall.  The
deinstallation procedure is quite simple;  the log messages are merely
lines of "install: /foo/bar".  This is human-readable, and you can 'see'
what was installed, too, easily.  E.g., from just installing nilsimsa:

install: /usr/local/doc/nilsimsa/index.html
install: /usr/local/doc/nilsimsa/index-1.html
install: /usr/local/doc/nilsimsa/index-2.html
install: /usr/local/doc/nilsimsa/index-3.html
install: /usr/local/doc/nilsimsa/index-4.html
install: /usr/local/doc/nilsimsa/index-5.html
install: /usr/local/doc/nilsimsa/index-6.html
install: /usr/local/bin/nilsimsa

The goal: you manipulate this easily with text-processing utils.  Maybe
people are looking for this functionality, maybe not.  I think it's a
nice, clean solution that is much better than relying on "make uninstall".
"make uninstall" has the potential to be much more powerful, but takes a
huge complexity hit.

Note that install(1) doesn't record creating directories, only copying
files.  The make_path was external to install.c, and I wanted keep my
changes minimal.

Any comments/ideas on this subject are appreciated.  Have people thought
of this before and been shot down?

Disclaimer: I don't like writing C, so you're likely to find a problem in
the attached patches.  However, again, it's really a simple patch.

I didn't write any docs for it, because I don't know TeX or roff.

Oh, and I created a test too for this functionality (also attached).

-- 
Frank Tobin             http://www.neverending.org/~ftobin/
#! /bin/sh
# Test $INSTALL_LOG stuff
# Note that the tests below use `ginstall', not install, because
# that's the name of the binary in ../../src.

if test "$VERBOSE" = yes; then
  set -x
  ginstall --version
fi

. $srcdir/../envvar-check

pwd=`pwd`
to=to
INSTALL_LOG=log
export INSTALL_LOG
from=from
expected=expected

trap "cd $pwd; rm -rf $INSTALL_LOG $from $to $expected" 0 1 2 3 15

fail=0

echo foo > $from
echo "install: $to" > $expected

# Before 4.0q, this would mistakenly create $file, not `dest'
# in no-dir1/no-dir2/.
ginstall $from $to || fail=1
cmp $expected log || fail=1

exit $fail
diff -ur fileutils-4.1.orig/src/install.c fileutils-4.1/src/install.c
--- fileutils-4.1.orig/src/install.c    Mon Dec 25 06:07:36 2000
+++ fileutils-4.1/src/install.c Fri Mar 15 00:01:40 2002
@@ -94,6 +94,9 @@
 static int install_file_in_file PARAMS ((const char *from, const char *to,
                                         const struct cp_options *x));
 static void get_ids PARAMS ((void));
+static void log_add_install PARAMS ((const char *to));
+static void log_finalize PARAMS ((void));
+static void log_init PARAMS ((const char *path));
 static void strip PARAMS ((const char *path));
 void usage PARAMS ((int status));
 
@@ -124,6 +127,9 @@
 /* If nonzero, install a directory instead of a regular file. */
 static int dir_arg;
 
+/* The filehandle of the log (if any) */
+static FILE *log_file;
+
 static struct option const long_options[] =
 {
   {"backup", optional_argument, NULL, 'b'},
@@ -191,6 +197,7 @@
   struct cp_options x;
   int n_files;
   char **file;
+  char *log_fn = NULL;
 
   program_name = argv[0];
   setlocale (LC_ALL, "");
@@ -206,11 +213,16 @@
   strip_files = 0;
   dir_arg = 0;
   umask (0);
+  log_file = NULL;
 
   /* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
      we'll actually use backup_suffix_string.  */
   backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
 
+  log_fn = getenv("INSTALL_LOG");
+  if (log_fn)
+    log_init(log_fn);  
+
   while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pvV:S:", long_options,
                              NULL)) != -1)
     {
@@ -346,6 +358,8 @@
        }
     }
 
+  log_finalize();
+
   exit (errors);
 }
 
@@ -392,6 +406,7 @@
 {
   if (copy_file (from, to, x))
     return 1;
+  log_add_install(to);
   if (strip_files)
     strip (to);
   if (change_attributes (to))
@@ -588,6 +603,32 @@
   else
     group_id = (gid_t) -1;
 }
+
+
+static void
+log_add_install (const char *to)
+{
+  if (log_file)
+      fprintf(log_file, "install: %s\n", to);
+}
+
+
+static void
+log_finalize (void)
+{
+  if (log_file)
+    fclose(log_file);
+}
+
+
+static void
+log_init (const char *path)
+{
+  log_file = fopen (path, "a");
+  if (!log_file)
+      error (0, 1, "cannot open log %s", path);
+}
+
 
 void
 usage (int status)
diff -ur fileutils-4.1.orig/tests/install/Makefile.am 
fileutils-4.1/tests/install/Makefile.am
--- fileutils-4.1.orig/tests/install/Makefile.am        Sun Feb 27 09:10:57 2000
+++ fileutils-4.1/tests/install/Makefile.am     Thu Mar 14 23:48:59 2002
@@ -1,7 +1,7 @@
 ## Process this file with automake to produce Makefile.in -*-Makefile-*-.
 AUTOMAKE_OPTIONS = 1.3 gnits
 
-TESTS = basic-1 create-leading
+TESTS = basic-1 create-leading create-log
 EXTRA_DIST = $(TESTS)
 TESTS_ENVIRONMENT = \
   PATH=`pwd`/../../src:$$PATH

Reply via email to