Whamcloud - gitweb
debian: mark logsave as Multi-Arch: foreign
[tools/e2fsprogs.git] / util / subst.c
index 0015a9c..66d7d9a 100644 (file)
@@ -1,20 +1,37 @@
 /*
  * subst.c --- substitution program
  *
- * Subst is used as a quicky program to do @ substitutions
+ * Subst is used as a quickie program to do @ substitutions
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#else
+#define HAVE_SYS_STAT_H
+#define HAVE_SYS_TIME_H
+#endif
 #include <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <ctype.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif
+#include <fcntl.h>
 #include <time.h>
 #include <utime.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
 
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
@@ -30,14 +47,12 @@ struct subst_entry {
        struct subst_entry *next;
 };
 
-struct subst_entry *subst_table = 0;
+static struct subst_entry *subst_table = 0;
 
 static int add_subst(char *name, char *value)
 {
        struct subst_entry      *ent = 0;
-       int     retval;
 
-       retval = ENOMEM;
        ent = (struct subst_entry *) malloc(sizeof(struct subst_entry));
        if (!ent)
                goto fail;
@@ -54,13 +69,10 @@ static int add_subst(char *name, char *value)
        return 0;
 fail:
        if (ent) {
-               if (ent->name)
-                       free(ent->name);
-               if (ent->value)
-                       free(ent->value);
+               free(ent->name);
                free(ent);
        }
-       return retval;
+       return ENOMEM;
 }
 
 static struct subst_entry *fetch_subst_entry(char *name)
@@ -269,21 +281,11 @@ static void parse_config_file(FILE *f)
 /*
  * Return 0 if the files are different, 1 if the files are the same.
  */
-static int compare_file(const char *outfn, const char *newfn)
+static int compare_file(FILE *old_f, FILE *new_f)
 {
-       FILE    *old_f, *new_f;
        char    oldbuf[2048], newbuf[2048], *oldcp, *newcp;
        int     retval;
 
-       old_f = fopen(outfn, "r");
-       if (!old_f)
-               return 0;
-       new_f = fopen(newfn, "r");
-       if (!new_f) {
-               fclose(old_f);
-               return 0;
-       }
-
        while (1) {
                oldcp = fgets(oldbuf, sizeof(oldbuf), old_f);
                newcp = fgets(newbuf, sizeof(newbuf), new_f);
@@ -296,23 +298,40 @@ static int compare_file(const char *outfn, const char *newfn)
                        break;
                }
        }
-       fclose(old_f);
-       fclose(new_f);
        return retval;
 }
 
+void set_utimes(const char *filename, int fd, const struct timeval times[2])
+{
+#ifdef HAVE_FUTIMES
+       if (futimes(fd, times) < 0)
+               perror("futimes");
+#elif HAVE_UTIMES
+       if (utimes(filename, times) < 0)
+               perror("utimes");
+#else
+       struct utimbuf ut;
+
+       ut.actime = times[0].tv_sec;
+       ut.modtime = times[1].tv_sec;
+       if (utime(filename, &ut) < 0)
+               perror("utime");
+#endif
+}
 
 
 int main(int argc, char **argv)
 {
        char    line[2048];
        int     c;
-       FILE    *in, *out;
+       int     fd, ofd = -1;
+       FILE    *in, *out, *old = NULL;
        char    *outfn = NULL, *newfn = NULL;
        int     verbose = 0;
        int     adjust_timestamp = 0;
+       int     got_atime = 0;
        struct stat stbuf;
-       struct utimbuf ut;
+       struct timeval tv[2];
 
        while ((c = getopt (argc, argv, "f:tv")) != EOF) {
                switch (c) {
@@ -356,11 +375,34 @@ int main(int argc, char **argv)
                }
                strcpy(newfn, outfn);
                strcat(newfn, ".new");
-               out = fopen(newfn, "w");
-               if (!out) {
+               ofd = open(newfn, O_CREAT|O_TRUNC|O_RDWR, 0644);
+               if (ofd < 0) {
                        perror(newfn);
                        exit(1);
                }
+               out = fdopen(ofd, "w+");
+               if (!out) {
+                       perror("fdopen");
+                       exit(1);
+               }
+
+               fd = open(outfn, O_RDONLY);
+               if (fd > 0) {
+                       /* save the original atime, if possible */
+                       if (fstat(fd, &stbuf) == 0) {
+#if HAVE_STRUCT_STAT_ST_ATIM
+                               tv[0].tv_sec = stbuf.st_atim.tv_sec;
+                               tv[0].tv_usec = stbuf.st_atim.tv_nsec / 1000;
+#else
+                               tv[0].tv_sec = stbuf.st_atime;
+                               tv[0].tv_usec = 0;
+#endif
+                               got_atime = 1;
+                       }
+                       old = fdopen(fd, "r");
+                       if (!old)
+                               close(fd);
+               }
        } else {
                out = stdout;
                outfn = 0;
@@ -373,32 +415,49 @@ int main(int argc, char **argv)
                fputs(line, out);
        }
        fclose(in);
-       fclose(out);
        if (outfn) {
-               struct stat st;
-               if (compare_file(outfn, newfn)) {
+               fflush(out);
+               rewind(out);
+               if (old && compare_file(old, out)) {
                        if (verbose)
                                printf("No change, keeping %s.\n", outfn);
                        if (adjust_timestamp) {
-                               if (stat(outfn, &stbuf) == 0) {
-                                       if (verbose)
-                                               printf("Updating modtime for %s\n", outfn);
-                                       ut.actime = stbuf.st_atime;
-                                       ut.modtime = time(0);
-                                       if (utime(outfn, &ut) < 0)
-                                               perror("utime");
+                               if (verbose)
+                                       printf("Updating modtime for %s\n", outfn);
+                               if (gettimeofday(&tv[1], NULL) < 0) {
+                                       perror("gettimeofday");
+                                       exit(1);
                                }
+                               if (got_atime == 0)
+                                       tv[0] = tv[1];
+                               else if (verbose)
+                                       printf("Using original atime\n");
+                               set_utimes(outfn, fileno(old), tv);
                        }
-                       unlink(newfn);
+                       if (ofd >= 0)
+                               (void) fchmod(ofd, 0444);
+                       fclose(out);
+                       if (unlink(newfn) < 0)
+                               perror("unlink");
                } else {
                        if (verbose)
                                printf("Creating or replacing %s.\n", outfn);
-                       rename(newfn, outfn);
+                       if (ofd >= 0)
+                               (void) fchmod(ofd, 0444);
+                       fclose(out);
+                       if (old)
+                               fclose(old);
+                       old = NULL;
+                       if (rename(newfn, outfn) < 0) {
+                               perror("rename");
+                               exit(1);
+                       }
                }
-               /* set read-only to alert user it is a generated file */
-               if (stat(outfn, &st) == 0)
-                       chmod(outfn, st.st_mode & ~0222);
        }
+       if (old)
+               fclose(old);
+       if (newfn)
+               free(newfn);
        return (0);
 }