diff -ru coreutils-4.5.12/doc/coreutils.texi coreutils-4.5.12-shh/doc/coreutils.texi --- coreutils-4.5.12/doc/coreutils.texi Thu Mar 27 16:54:46 2003 +++ coreutils-4.5.12-shh/doc/coreutils.texi Sat May 10 13:25:22 2003 @@ -6463,6 +6463,50 @@ @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 name +The directory and name of the installed file. + +@end table + @node mv invocation @section @command{mv}: Move (rename) files diff -ru coreutils-4.5.12/src/install.c coreutils-4.5.12-shh/src/install.c --- coreutils-4.5.12/src/install.c Sun Dec 15 15:35:48 2002 +++ coreutils-4.5.12-shh/src/install.c Sat May 10 13:25:30 2003 @@ -27,6 +27,7 @@ #include #include #include +#include #include "system.h" #include "backupfile.h" @@ -82,6 +83,9 @@ static int change_attributes (const char *path); static int copy_file (const char *from, const char *to, const struct cp_options *x); +/* SHH: logging */ +static void log_install (const char *to, + int mode, uid_t uid, gid_t gid, int is_dir); static int install_file_to_path (const char *from, const char *to, const struct cp_options *x); static int install_file_in_dir (const char *from, const char *to_dir, @@ -119,6 +123,15 @@ /* If nonzero, install a directory instead of a regular file. */ static int dir_arg; +/* SHH: If non-NULL, name of the file to which logging should be written. */ +static char *log_file; + +/* SHH: The current identification to include in loglines. No SPC allowed. */ +static char *log_id; + +/* SHH: Perform logging to a file? */ +static int log_enabled = 0; + static struct option const long_options[] = { {"backup", optional_argument, NULL, 'b'}, @@ -186,6 +199,8 @@ struct cp_options x; int n_files; char **file; + /* SHH: logging */ + char *log; program_name = argv[0]; setlocale (LC_ALL, ""); @@ -206,6 +221,21 @@ we'll actually use backup_suffix_string. */ backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); + /* SHH: log stuff */ + 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, "bcsDdg:m:o:pvV:S:", long_options, NULL)) != -1) { @@ -268,6 +298,20 @@ error (EXIT_FAILURE, 0, _("the strip option may not be used when installing a directory")); + /* SHH: 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 (backup_suffix_string) simple_backup_suffix = xstrdup (backup_suffix_string); @@ -302,9 +346,15 @@ int i; for (i = 0; i < n_files; i++) { - errors |= - make_path (file[i], mode, mode, owner_id, group_id, 0, - (x.verbose ? _("creating directory %s") : NULL)); + int result; + + result = + make_path (file[i], mode, mode, owner_id, group_id, 0, + (x.verbose ? _("creating directory %s") : NULL)); + /* SHH: log it */ + if (result == 0) + log_install (file[i], mode, owner_id, group_id, 1); + errors |= result; } } else @@ -346,6 +396,69 @@ exit (errors); } +/* SHH: 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) +{ + 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 (uid == (uid_t) -1) + uid = geteuid(); + if ((pw = getpwuid (uid)) == NULL) + { + sprintf (pws, "%u", (unsigned) uid); + pwp = pws; + } + else + pwp = pw->pw_name; + + /* Ditto for the group id. */ + if (gid == (uid_t) -1) + gid = getegid(); + if ((gr = getgrgid (gid)) == NULL) + { + sprintf (grs, "%u", (unsigned) gid); + grp = grs; + } + else + grp = gr->gr_name; + + if (fprintf (f, + "%04d-%02d-%02d %02d:%02d:%02d %s %o %s %s %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, to) < 0) + { + error (0, errno, "%s", log_file); + log_enabled = 0; + } +} + /* Copy file FROM onto file TO, creating any missing parent directories of TO. Return 0 if successful, 1 if an error occurs */ @@ -389,6 +502,7 @@ { if (copy_file (from, to, x)) return 1; + log_install (to, mode, owner_id, group_id, 0); if (strip_files) strip (to); if (change_attributes (to))