Hi! I was missing a logging feature of the install program, so I modified the source to include simple logging. If you think a logging install program may be useful, feel free to check this patch and do whatever you want with it (including throwing it away, of course). I hope the logging feature will simplify the task of moving and removing program packages, and also to copy an installed package from one computer to another. The version in the included patch, will log to the file given by the environment variable INSTALL_LOG_FILE. This way, logging may be done even if no logging is specified in Makefiles using the install program. Lines written to the log file may be tagged with an identifier, taken from the environment variable INSTALL_LOG_ID. One would typically set this environment variable to the name of the package of which one intends to do a "make install", to easily spot the files installed from this package. The patch should be performed on the fileutils-3.16 distribution: cd /directory/of/fileutils-3.16 patch -p1 < the-file-containing-this-patch The following files are affected: src/install.c man/install.1 doc/install.texi doc/install.info I have never written .texi-files before, so I may well have done something wrong. Please check it, and feel free to correct spelling errors and bad language as well. :) My coding style differs a bit from yours. I have tried to mimic the style found in the rest of install.c, but I may have missed something. Please tell me what you do with this patch! And while I have your attention, I would like to thank you for all the work and effort you have put into the GNU project. I run GNU/Linux at home, so I rely heavily on your great work. Thanks! Sverre - s.h.huseby@usit.uio.no. diff -Naur fileutils-3.16/doc/fileutils.info fileutils-3.16-shh/doc/fileutils.info --- fileutils-3.16/doc/fileutils.info Sun Jan 26 20:57:04 1997 +++ fileutils-3.16-shh/doc/fileutils.info Wed Sep 10 13:03:25 1997 @@ -1780,6 +1780,50 @@ can be `numbered' (or `t'), `existing' (or `nil'), or `never' (or `simple'). *Note Backup options::. + By setting the environment variable `INSTALL_LOG_FILE' to the name +of a file, `install' will log changes by appending lines to the end of +the given file. An identifier for the installation process may be given +in the environment variable `INSTALL_LOG_ID'. This identifier is +usefull if you want to separate files that come from different source +packages. + + Lines in the log file contains the following fields, separated by a +single space character: + +`date' + The date of the installation, in ISO date format. + +`time' + The time of the installation, in local time. + +`ID' + Identifier as given by the `INSTALL_LOG_ID' environment variable. + Defaults to "no-id" if the environment variable is unset. Note + that any occurences of space characters in the ID is replaced by + an underscore character. This simplifies automatic extraction of + fields from the log file. + +`mode' + The octal file permission mode of the file. + +`owner' + The owner of the installed file. + +`group' + The group of the file. + +`directory' + Indicates whether the file name refers to a directory or not. A 1 + in this field means the file is a directory. A 0 indicates a + regular file. + +`replaced' + Did the installed file replace an existing file? 1 indicates that + it did, 0 that it did not. + +`name' + The directory and name of the installed file. +  File: fileutils.info, Node: mv invocation, Next: rm invocation, Prev: install invocation, Up: Basic operations @@ -3357,23 +3401,23 @@ Node: cp invocation50979 Node: dd invocation56193 Node: install invocation58675 -Node: mv invocation61462 -Node: rm invocation63475 -Node: Special file types65328 -Node: ln invocation66612 -Node: mkdir invocation70342 -Node: mkfifo invocation71465 -Node: mknod invocation72359 -Node: rmdir invocation73915 -Node: Changing file attributes74541 -Node: chown invocation75352 -Node: chgrp invocation77261 -Node: chmod invocation78269 -Node: touch invocation79586 -Node: Disk usage81213 -Node: df invocation81826 -Node: du invocation86174 -Node: sync invocation88663 -Node: Index89484 +Node: mv invocation62838 +Node: rm invocation64851 +Node: Special file types66704 +Node: ln invocation67988 +Node: mkdir invocation71718 +Node: mkfifo invocation72841 +Node: mknod invocation73735 +Node: rmdir invocation75291 +Node: Changing file attributes75917 +Node: chown invocation76728 +Node: chgrp invocation78637 +Node: chmod invocation79645 +Node: touch invocation80962 +Node: Disk usage82589 +Node: df invocation83202 +Node: du invocation87550 +Node: sync invocation90039 +Node: Index90860  End Tag Table diff -Naur fileutils-3.16/doc/fileutils.texi fileutils-3.16-shh/doc/fileutils.texi --- fileutils-3.16/doc/fileutils.texi Mon Nov 25 15:29:30 1996 +++ fileutils-3.16-shh/doc/fileutils.texi Wed Sep 10 13:02:50 1997 @@ -1315,6 +1315,54 @@ @end table +By setting the environment variable @code{INSTALL_LOG_FILE} to the +name of a file, @code{install} will log changes by appending lines to +the end of the given file. An identifier for the installation process +may be given in the environment variable @code{INSTALL_LOG_ID}. This +identifier is usefull if you want to separate files that come from +different source packages. + +Lines in the log file contains the following fields, separated by +a single space character: + +@table @samp + +@item date +The date of the installation, in ISO date format. + +@item time +The time of the installation, in local time. + +@item ID +Identifier as given by the @code{INSTALL_LOG_ID} environment +variable. Defaults to "no-id" if the environment variable is +unset. Note that any occurences of space characters in the ID is +replaced by an underscore character. This simplifies automatic +extraction of fields from the log file. + +@item mode +The octal file permission mode of the file. + +@item owner +The owner of the installed file. + +@item group +The group of the file. + +@item directory +Indicates whether the file name refers to a directory or not. A 1 in +this field means the file is a directory. A 0 indicates a regular +file. + +@item replaced +Did the installed file replace an existing file? 1 indicates that it +did, 0 that it did not. + +@item name +The directory and name of the installed file. + +@end table + @node mv invocation @section @code{mv}: Move (rename) files diff -Naur fileutils-3.16/man/install.1 fileutils-3.16-shh/man/install.1 --- fileutils-3.16/man/install.1 Fri Jul 12 04:33:53 1996 +++ fileutils-3.16-shh/man/install.1 Wed Sep 10 12:52:39 1997 @@ -76,3 +76,48 @@ .TP .I "\-\-version" Print version information on standard output then exit successfully. +.SS LOGGING +By setting the environment variable INSTALL_LOG_FILE to the name of a +file, +.B install +will log changes by appending lines to the end of the given file. An +identifier for the installation process may be given in the +environment variable INSTALL_LOG_ID. This identifier is usefull if you +want to separate files that come from different source packages. +.PP +Lines in the log file contains the following fields, separated by +a single space character: +.TP +.I date +The date of the installation, in ISO date format. +.TP +.I time +The time of the installation, in local time. +.TP +.I ID +Identifier as given by the INSTALL_LOG_ID environment +variable. Defaults to "no-id" if the environment variable is +unset. Note that any occurences of space characters in the ID is +replaced by an underscore character. This simplifies automatic +extraction of fields from the log file. +.TP +.I mode +The octal file permission mode of the file. +.TP +.I owner +The owner of the installed file. +.TP +.I group +The group of the file. +.TP +.I directory +Indicates whether the file name refers to a directory or not. A 1 in +this field means the file is a directory. A 0 indicates a regular +file. +.TP +.I replaced +Did the installed file replace an existing file? 1 indicates that it +did, 0 that it did not. +.TP +.I name +The directory and name of the installed file. diff -Naur fileutils-3.16/src/install.c fileutils-3.16-shh/src/install.c --- fileutils-3.16/src/install.c Wed Dec 11 05:24:44 1996 +++ fileutils-3.16-shh/src/install.c Wed Sep 10 12:36:37 1997 @@ -58,6 +58,7 @@ #include #include +#include #include #include #include @@ -122,6 +123,7 @@ int isdir (); enum backup_type get_version (); +static void log_install __P ((const char *to, int mode, uid_t uid, gid_t gid, int is_dir, int replaced)); static int change_attributes __P ((char *path, int no_need_to_chown)); static int copy_file __P ((char *from, char *to, int *to_created)); static int install_file_in_dir __P ((char *from, char *to_dir)); @@ -163,6 +165,18 @@ /* If nonzero, print the version on standard output and exit. */ static int show_version; +/* If non-NULL, the name of the file to which logging should be written. */ +static char *log_file; + +/* The current identification to include in loglines. No SPC allowed. */ +static char *log_id; + +/* Perform logging to a file? */ +static int log_enabled = 0; + +/* Did the last file installed replace another file? Set in copy_file */ +static int file_replaced; + static struct option const long_options[] = { {"strip", no_argument, NULL, 's'}, @@ -185,6 +199,7 @@ char *symbolic_mode = NULL; int make_backups = 0; char *version; + char *log; program_name = argv[0]; setlocale (LC_ALL, ""); @@ -203,6 +218,18 @@ simple_backup_suffix = version; version = getenv ("VERSION_CONTROL"); + log = getenv ("INSTALL_LOG_FILE"); + if (log) { + log_file = log; + log_enabled = 1; + } + log = getenv ("INSTALL_LOG_ID"); + if (log) { + /* make a copy, since this one may be changed later. */ + log_id = xmalloc (strlen (log) + 1); + strcpy (log_id, log); + } + while ((optc = getopt_long (argc, argv, "bcsdg:m:o:V:S:", long_options, (int *) 0)) != EOF) { @@ -255,6 +282,18 @@ error (1, 0, _("the strip option may not be used when installing a directory")); + /* Remove any spaces from the log_id to simplify interpretation of + the log file. */ + if (log_id) { + char *s = log_id; + + while (*s) { + if (*s == ' ') + *s = '_'; + ++s; + } + } + if (make_backups) backup_type = get_version (version); @@ -280,8 +319,13 @@ { for (; optind < argc; ++optind) { - errors |= - make_path (argv[optind], mode, mode, owner_id, group_id, 0, NULL); + int result; + + result = make_path (argv[optind], mode, mode, + owner_id, group_id, 0, NULL); + if (result == 0) + log_install(argv[optind], mode, owner_id, group_id, 1, 0); + errors |= result; } } else @@ -307,6 +351,60 @@ exit (errors); } +/* Write logging information to a log file, if specified on the + command line or in environment variables. */ + +static void +log_install (const char *to, int mode, + uid_t uid, gid_t gid, + int is_dir, int replaced) +{ + static FILE *f; /* Log file. Closed on program termination. */ + time_t t; + struct tm *tm; + struct passwd *pw; + char pws[20], *pwp; + struct group *gr; + char grs[20], *grp; + + if (!log_enabled) + return; + + if (!f && (f = fopen (log_file, "a")) == NULL) { + error (0, errno, "%s", log_file); + log_enabled = 0; + return; + } + + time (&t); + tm = localtime (&t); + + /* Attempt mapping the user id to something more human. */ + if ((pw = getpwuid (uid)) == NULL) { + sprintf (pws, "%u", uid); + pwp = pws; + } else + pwp = pw->pw_name; + + /* Ditto for the group id. */ + if ((gr = getgrgid (gid)) == NULL) { + sprintf (grs, "%u", gid); + grp = grs; + } else + grp = gr->gr_name; + + if (fprintf (f, + "%04d-%02d-%02d %02d:%02d:%02d %s %o %s %s %d %d %s\n", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, + log_id ? log_id : "no-id", + mode, pwp, grp, + is_dir, replaced, to) < 0) { + error (0, errno, "%s", log_file); + log_enabled = 0; + } +} + /* Copy file FROM onto file TO and give TO the appropriate attributes. Return 0 if successful, 1 if an error occurs. */ @@ -319,6 +417,7 @@ if (copy_file (from, to, &to_created)) return 1; + log_install(to, mode, owner_id, group_id, 0, file_replaced); if (strip_files) strip (to); no_need_to_chown = (to_created @@ -378,6 +477,10 @@ error (0, 0, _("`%s' is a directory"), from); return 1; } + + /* For logging purposes: We want to know if destination existed. */ + file_replaced = 0; + if (stat (to, &to_stats) == 0) { if (!S_ISREG (to_stats.st_mode)) @@ -391,6 +494,8 @@ error (0, 0, _("`%s' and `%s' are the same file"), from, to); return 1; } + + file_replaced = 1; /* The destination file exists. Try to back it up if required. */ if (backup_type != none)