gen_init_cpio: Avoid race between call to stat() and call to open()
[linux-3.10.git] / usr / gen_init_cpio.c
index 8365db6..f463caf 100644 (file)
@@ -104,6 +104,8 @@ static int cpio_mkslink(const char *name, const char *target,
        char s[256];
        time_t mtime = time(NULL);
 
+       if (name[0] == '/')
+               name++;
        sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
               "%08X%08X%08X%08X%08X%08X%08X",
                "070701",               /* magic */
@@ -152,6 +154,8 @@ static int cpio_mkgeneric(const char *name, unsigned int mode,
        char s[256];
        time_t mtime = time(NULL);
 
+       if (name[0] == '/')
+               name++;
        sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
               "%08X%08X%08X%08X%08X%08X%08X",
                "070701",               /* magic */
@@ -245,6 +249,8 @@ static int cpio_mknod(const char *name, unsigned int mode,
        else
                mode |= S_IFCHR;
 
+       if (name[0] == '/')
+               name++;
        sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
               "%08X%08X%08X%08X%08X%08X%08X",
                "070701",               /* magic */
@@ -303,18 +309,18 @@ static int cpio_mkfile(const char *name, const char *location,
 
        mode |= S_IFREG;
 
-       retval = stat (location, &buf);
-       if (retval) {
-               fprintf (stderr, "File %s could not be located\n", location);
-               goto error;
-       }
-
        file = open (location, O_RDONLY);
        if (file < 0) {
                fprintf (stderr, "File %s could not be opened for reading\n", location);
                goto error;
        }
 
+       retval = fstat (file, &buf);
+       if (retval) {
+               fprintf (stderr, "File %s could not be stat()'ed\n", location);
+               goto error;
+       }
+
        filebuf = malloc(buf.st_size);
        if (!filebuf) {
                fprintf (stderr, "out of memory\n");
@@ -332,6 +338,8 @@ static int cpio_mkfile(const char *name, const char *location,
                /* data goes on last link */
                if (i == nlinks) size = buf.st_size;
 
+               if (name[0] == '/')
+                       name++;
                namesize = strlen(name) + 1;
                sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
                       "%08lX%08X%08X%08X%08X%08X%08X",
@@ -354,7 +362,10 @@ static int cpio_mkfile(const char *name, const char *location,
                push_pad();
 
                if (size) {
-                       fwrite(filebuf, size, 1, stdout);
+                       if (fwrite(filebuf, size, 1, stdout) != 1) {
+                               fprintf(stderr, "writing filebuf failed\n");
+                               goto error;
+                       }
                        offset += size;
                        push_pad();
                }
@@ -370,6 +381,30 @@ error:
        return rc;
 }
 
+static char *cpio_replace_env(char *new_location)
+{
+       char expanded[PATH_MAX + 1];
+       char env_var[PATH_MAX + 1];
+       char *start;
+       char *end;
+
+       for (start = NULL; (start = strstr(new_location, "${")); ) {
+               end = strchr(start, '}');
+               if (start < end) {
+                       *env_var = *expanded = '\0';
+                       strncat(env_var, start + 2, end - start - 2);
+                       strncat(expanded, new_location, start - new_location);
+                       strncat(expanded, getenv(env_var), PATH_MAX);
+                       strncat(expanded, end + 1, PATH_MAX);
+                       strncpy(new_location, expanded, PATH_MAX);
+               } else
+                       break;
+       }
+
+       return new_location;
+}
+
+
 static int cpio_mkfile_line(const char *line)
 {
        char name[PATH_MAX + 1];
@@ -415,13 +450,14 @@ static int cpio_mkfile_line(const char *line)
        } else {
                dname = name;
        }
-       rc = cpio_mkfile(dname, location, mode, uid, gid, nlinks);
+       rc = cpio_mkfile(dname, cpio_replace_env(location),
+                        mode, uid, gid, nlinks);
  fail:
        if (dname_len) free(dname);
        return rc;
 }
 
-void usage(const char *prog)
+static void usage(const char *prog)
 {
        fprintf(stderr, "Usage:\n"
                "\t%s <cpio_list>\n"
@@ -439,6 +475,7 @@ void usage(const char *prog)
                "\n"
                "<name>       name of the file/dir/nod/etc in the archive\n"
                "<location>   location of the file in the current filesystem\n"
+               "             expands shell variables quoted with ${}\n"
                "<target>     link target\n"
                "<mode>       mode/permissions of the file\n"
                "<uid>        user id (0=root)\n"
@@ -498,7 +535,9 @@ int main (int argc, char *argv[])
                exit(1);
        }
 
-       if (! (cpio_list = fopen(argv[1], "r"))) {
+       if (!strcmp(argv[1], "-"))
+               cpio_list = stdin;
+       else if (! (cpio_list = fopen(argv[1], "r"))) {
                fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
                        argv[1], strerror(errno));
                usage(argv[0]);