/* gen_init_cpio.c: taken form the Linux kernel. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation */ #include #include #include #include #include #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) #ifdef O_BINARY #warning Using binary flags in open and fopen ... #define FOPEN_BINRAY_MODE "b" #else #define FOPEN_BINRAY_MODE #define O_BINARY 0 #endif static FILE *archive = 0; 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; fputs(name, archive); fputc(0, archive); offset += name_len; } static void push_pad (void) { while (offset & 3) { fputc(0, archive); offset++; } } static void push_rest(const char *name) { unsigned int name_len = strlen(name) + 1; unsigned int tmp_ofs; fputs(name, archive); fputc(0, archive); offset += name_len; tmp_ofs = name_len + 110; while (tmp_ofs & 3) { fputc(0, archive); offset++; tmp_ofs++; } } static void push_hdr(const char *s) { fputs(s, archive); offset += 110; } static void cpio_trailer(void) { char s[256]; const char name[] = "TRAILER!!!"; sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", "070701", /* magic */ 0, /* ino */ 0, /* mode */ (long) 0, /* uid */ (long) 0, /* gid */ 1, /* nlink */ (long) 0, /* mtime */ 0, /* filesize */ 0, /* major */ 0, /* minor */ 0, /* rmajor */ 0, /* rminor */ (unsigned)strlen(name)+1, /* namesize */ 0); /* chksum */ push_hdr(s); push_rest(name); while (offset % 512) { fputc(0, archive); offset++; } } 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]; 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 */ mode, /* mode */ (long) uid, /* uid */ (long) gid, /* gid */ 2, /* nlink */ (long) mtime, /* mtime */ 0, /* filesize */ 3, /* major */ 1, /* minor */ 0, /* rmajor */ 0, /* rminor */ (unsigned)strlen(name) + 1,/* namesize */ 0); /* chksum */ push_hdr(s); push_rest(name); return 0; } 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]; time_t mtime = time(NULL); if (dev_type == 'b') mode |= S_IFBLK; else mode |= S_IFCHR; sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", "070701", /* magic */ ino++, /* ino */ mode, /* mode */ (long) uid, /* uid */ (long) gid, /* gid */ 1, /* nlink */ (long) mtime, /* mtime */ 0, /* filesize */ 3, /* major */ 1, /* minor */ maj, /* rmajor */ min, /* rminor */ (unsigned)strlen(name) + 1,/* namesize */ 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... */ static int cpio_mkfile(const char *name, const char *location, unsigned int mode, uid_t uid, gid_t gid) { char s[256]; char *filebuf = NULL; struct stat buf; int file = -1; int retval; int rc = -1; 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 | O_BINARY); if (file < 0) { 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; } retval = read (file, filebuf, buf.st_size); if (retval < 0) { fprintf (stderr, "Can not read %s file\n", location); goto error; } sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", "070701", /* magic */ ino++, /* ino */ mode, /* mode */ (long) uid, /* uid */ (long) gid, /* gid */ 1, /* nlink */ (long) buf.st_mtime, /* mtime */ (int) buf.st_size, /* filesize */ 3, /* major */ 1, /* minor */ 0, /* rmajor */ 0, /* rminor */ (unsigned)strlen(name) + 1,/* namesize */ 0); /* chksum */ push_hdr(s); push_string(name); push_pad(); fwrite(filebuf, buf.st_size, 1, archive); offset += buf.st_size; push_pad(); rc = 0; error: if (filebuf) free(filebuf); if (file >= 0) close(file); return rc; } void prepare_append(FILE * f) { fprintf(stderr, "Append to cpio archive not supported at the moment\n"); exit(1); } #define MKFILE cpio_mkfile #include "cpio_conv.c" static int cpio_mkfile_line(const char *line) { char name[PATH_MAX + 1]; char location[PATH_MAX + 1]; unsigned int mode; int uid; int gid; int rc = -1; if (! parse_file_line (line, 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; } struct file_handler file_handler_table[] = { { .type = "file", .handler = cpio_mkfile_line, }, { .type = "ufile", .handler = cpio_unix_mkfile_line, }, { .type = "dfile", .handler = cpio_dos_mkfile_line, }, { .type = "sfile", .handler = cpio_shell_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 = 0; char line[LINE_SIZE]; char *args, *type; int ec = 0; int line_nr = 0; get_options(argc, argv); if (! (cpio_list = fopen(list_name, "r"))) { fprintf(stderr, "ERROR: unable to open '%s': %s\n\n", list_name, 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); }