X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=usr%2Fgen_init_cpio.c;h=33dbcbf77c5b0d5713d4c6774e5c7f863d4750fb;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=bf2d1fdd53a27693b48b90f00e8357e29a6f20d4;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index bf2d1fdd5..33dbcbf77 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -6,10 +6,27 @@ #include #include #include +#include +#include +#include + +/* + * Original work by Jeff Garzik + * + * External file lists, symlink, pipe and fifo support by Thayne Harbaugh + */ + +#define xstr(s) #s +#define str(s) xstr(s) static unsigned int offset; static unsigned int ino = 721; +struct file_handler { + const char *type; + int (*handler)(const char *line); +}; + static void push_string(const char *name) { unsigned int name_len = strlen(name) + 1; @@ -69,7 +86,7 @@ static void cpio_trailer(void) 0, /* minor */ 0, /* rmajor */ 0, /* rminor */ - (unsigned)strlen(name) + 1, /* namesize */ + (unsigned)strlen(name)+1, /* namesize */ 0); /* chksum */ push_hdr(s); push_rest(name); @@ -80,7 +97,55 @@ static void cpio_trailer(void) } } -static void cpio_mkdir(const char *name, unsigned int mode, +static int cpio_mkslink(const char *name, const char *target, + unsigned int mode, uid_t uid, gid_t gid) +{ + char s[256]; + time_t mtime = time(NULL); + + sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" + "%08X%08X%08X%08X%08X%08X%08X", + "070701", /* magic */ + ino++, /* ino */ + S_IFLNK | mode, /* mode */ + (long) uid, /* uid */ + (long) gid, /* gid */ + 1, /* nlink */ + (long) mtime, /* mtime */ + (unsigned)strlen(target)+1, /* filesize */ + 3, /* major */ + 1, /* minor */ + 0, /* rmajor */ + 0, /* rminor */ + (unsigned)strlen(name) + 1,/* namesize */ + 0); /* chksum */ + push_hdr(s); + push_string(name); + push_pad(); + push_string(target); + push_pad(); + return 0; +} + +static int cpio_mkslink_line(const char *line) +{ + char name[PATH_MAX + 1]; + char target[PATH_MAX + 1]; + unsigned int mode; + int uid; + int gid; + int rc = -1; + + if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) { + fprintf(stderr, "Unrecognized dir format '%s'", line); + goto fail; + } + rc = cpio_mkslink(name, target, mode, uid, gid); + fail: + return rc; +} + +static int cpio_mkgeneric(const char *name, unsigned int mode, uid_t uid, gid_t gid) { char s[256]; @@ -90,7 +155,7 @@ static void cpio_mkdir(const char *name, unsigned int mode, "%08X%08X%08X%08X%08X%08X%08X", "070701", /* magic */ ino++, /* ino */ - S_IFDIR | mode, /* mode */ + mode, /* mode */ (long) uid, /* uid */ (long) gid, /* gid */ 2, /* nlink */ @@ -104,10 +169,71 @@ static void cpio_mkdir(const char *name, unsigned int mode, 0); /* chksum */ push_hdr(s); push_rest(name); + return 0; } -static void cpio_mknod(const char *name, unsigned int mode, - uid_t uid, gid_t gid, int dev_type, +enum generic_types { + GT_DIR, + GT_PIPE, + GT_SOCK +}; + +struct generic_type { + const char *type; + mode_t mode; +}; + +static struct generic_type generic_type_table[] = { + [GT_DIR] = { + .type = "dir", + .mode = S_IFDIR + }, + [GT_PIPE] = { + .type = "pipe", + .mode = S_IFIFO + }, + [GT_SOCK] = { + .type = "sock", + .mode = S_IFSOCK + } +}; + +static int cpio_mkgeneric_line(const char *line, enum generic_types gt) +{ + char name[PATH_MAX + 1]; + unsigned int mode; + int uid; + int gid; + int rc = -1; + + if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) { + fprintf(stderr, "Unrecognized %s format '%s'", + line, generic_type_table[gt].type); + goto fail; + } + mode |= generic_type_table[gt].mode; + rc = cpio_mkgeneric(name, mode, uid, gid); + fail: + return rc; +} + +static int cpio_mkdir_line(const char *line) +{ + return cpio_mkgeneric_line(line, GT_DIR); +} + +static int cpio_mkpipe_line(const char *line) +{ + return cpio_mkgeneric_line(line, GT_PIPE); +} + +static int cpio_mksock_line(const char *line) +{ + return cpio_mkgeneric_line(line, GT_SOCK); +} + +static int cpio_mknod(const char *name, unsigned int mode, + uid_t uid, gid_t gid, char dev_type, unsigned int maj, unsigned int min) { char s[256]; @@ -136,43 +262,65 @@ static void cpio_mknod(const char *name, unsigned int mode, 0); /* chksum */ push_hdr(s); push_rest(name); + return 0; +} + +static int cpio_mknod_line(const char *line) +{ + char name[PATH_MAX + 1]; + unsigned int mode; + int uid; + int gid; + char dev_type; + unsigned int maj; + unsigned int min; + int rc = -1; + + if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u", + name, &mode, &uid, &gid, &dev_type, &maj, &min)) { + fprintf(stderr, "Unrecognized nod format '%s'", line); + goto fail; + } + rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min); + fail: + return rc; } /* Not marked static to keep the compiler quiet, as no one uses this yet... */ -void cpio_mkfile(const char *filename, const char *location, +static int cpio_mkfile(const char *name, const char *location, unsigned int mode, uid_t uid, gid_t gid) { char s[256]; - char *filebuf; + char *filebuf = NULL; struct stat buf; - int file; + int file = -1; int retval; - int i; + int rc = -1; mode |= S_IFREG; - retval = stat (filename, &buf); + retval = stat (location, &buf); if (retval) { - fprintf (stderr, "Filename %s could not be located\n", filename); + fprintf (stderr, "File %s could not be located\n", location); goto error; } - file = open (filename, O_RDONLY); + file = open (location, O_RDONLY); if (file < 0) { - fprintf (stderr, "Filename %s could not be opened for reading\n", filename); + fprintf (stderr, "File %s could not be opened for reading\n", location); goto error; } filebuf = malloc(buf.st_size); if (!filebuf) { fprintf (stderr, "out of memory\n"); - goto error_close; + goto error; } retval = read (file, filebuf, buf.st_size); if (retval < 0) { - fprintf (stderr, "Can not read %s file\n", filename); - goto error_free; + fprintf (stderr, "Can not read %s file\n", location); + goto error; } sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" @@ -189,40 +337,176 @@ void cpio_mkfile(const char *filename, const char *location, 1, /* minor */ 0, /* rmajor */ 0, /* rminor */ - (unsigned)strlen(location) + 1,/* namesize */ + (unsigned)strlen(name) + 1,/* namesize */ 0); /* chksum */ push_hdr(s); - push_string(location); + push_string(name); push_pad(); - for (i = 0; i < buf.st_size; ++i) - fputc(filebuf[i], stdout); + fwrite(filebuf, buf.st_size, 1, stdout); offset += buf.st_size; - close(file); - free(filebuf); push_pad(); - return; + rc = 0; -error_free: - free(filebuf); -error_close: - close(file); error: - exit(-1); + if (filebuf) free(filebuf); + if (file >= 0) close(file); + return rc; } -int main (int argc, char *argv[]) +static int cpio_mkfile_line(const char *line) { - cpio_mkdir("/dev", 0755, 0, 0); - cpio_mknod("/dev/console", 0600, 0, 0, 'c', 5, 1); - cpio_mkdir("/root", 0700, 0, 0); - cpio_trailer(); + char name[PATH_MAX + 1]; + char location[PATH_MAX + 1]; + unsigned int mode; + int uid; + int gid; + int rc = -1; - exit(0); + if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, location, &mode, &uid, &gid)) { + fprintf(stderr, "Unrecognized file format '%s'", line); + goto fail; + } + rc = cpio_mkfile(name, location, mode, uid, gid); + fail: + return rc; +} - /* silence compiler warnings */ - return 0; - (void) argc; - (void) argv; +void usage(const char *prog) +{ + fprintf(stderr, "Usage:\n" + "\t%s \n" + "\n" + " is a file containing newline separated entries that\n" + "describe the files to be included in the initramfs archive:\n" + "\n" + "# a comment\n" + "file \n" + "dir \n" + "nod \n" + "slink \n" + "pipe \n" + "sock \n" + "\n" + " name of the file/dir/nod/etc in the archive\n" + " location of the file in the current filesystem\n" + " link target\n" + " mode/permissions of the file\n" + " user id (0=root)\n" + " group id (0=root)\n" + " device type (b=block, c=character)\n" + " major number of nod\n" + " minor number of nod\n" + "\n" + "example:\n" + "# A simple initramfs\n" + "dir /dev 0755 0 0\n" + "nod /dev/console 0600 0 0 c 5 1\n" + "dir /root 0700 0 0\n" + "dir /sbin 0755 0 0\n" + "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n", + prog); } +struct file_handler file_handler_table[] = { + { + .type = "file", + .handler = cpio_mkfile_line, + }, { + .type = "nod", + .handler = cpio_mknod_line, + }, { + .type = "dir", + .handler = cpio_mkdir_line, + }, { + .type = "slink", + .handler = cpio_mkslink_line, + }, { + .type = "pipe", + .handler = cpio_mkpipe_line, + }, { + .type = "sock", + .handler = cpio_mksock_line, + }, { + .type = NULL, + .handler = NULL, + } +}; + +#define LINE_SIZE (2 * PATH_MAX + 50) + +int main (int argc, char *argv[]) +{ + FILE *cpio_list; + char line[LINE_SIZE]; + char *args, *type; + int ec = 0; + int line_nr = 0; + + if (2 != argc) { + usage(argv[0]); + exit(1); + } + + if (! (cpio_list = fopen(argv[1], "r"))) { + fprintf(stderr, "ERROR: unable to open '%s': %s\n\n", + argv[1], strerror(errno)); + usage(argv[0]); + exit(1); + } + + while (fgets(line, LINE_SIZE, cpio_list)) { + int type_idx; + size_t slen = strlen(line); + + line_nr++; + + if ('#' == *line) { + /* comment - skip to next line */ + continue; + } + + if (! (type = strtok(line, " \t"))) { + fprintf(stderr, + "ERROR: incorrect format, could not locate file type line %d: '%s'\n", + line_nr, line); + ec = -1; + } + + if ('\n' == *type) { + /* a blank line */ + continue; + } + + if (slen == strlen(type)) { + /* must be an empty line */ + continue; + } + + if (! (args = strtok(NULL, "\n"))) { + fprintf(stderr, + "ERROR: incorrect format, newline required line %d: '%s'\n", + line_nr, line); + ec = -1; + } + + for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) { + int rc; + if (! strcmp(line, file_handler_table[type_idx].type)) { + if ((rc = file_handler_table[type_idx].handler(args))) { + ec = rc; + fprintf(stderr, " line %d\n", line_nr); + } + break; + } + } + + if (NULL == file_handler_table[type_idx].type) { + fprintf(stderr, "unknown file type line %d: '%s'\n", + line_nr, line); + } + } + cpio_trailer(); + + exit(ec); +}