14 * Original work by Jeff Garzik
16 * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
17 * Hard link support by Luciano Rocha
21 #define str(s) xstr(s)
23 static unsigned int offset;
24 static unsigned int ino = 721;
28 int (*handler)(const char *line);
31 static void push_string(const char *name)
33 unsigned int name_len = strlen(name) + 1;
40 static void push_pad (void)
48 static void push_rest(const char *name)
50 unsigned int name_len = strlen(name) + 1;
57 tmp_ofs = name_len + 110;
65 static void push_hdr(const char *s)
71 static void cpio_trailer(void)
74 const char name[] = "TRAILER!!!";
76 sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
77 "%08X%08X%08X%08X%08X%08X%08X",
90 (unsigned)strlen(name)+1, /* namesize */
95 while (offset % 512) {
101 static int cpio_mkslink(const char *name, const char *target,
102 unsigned int mode, uid_t uid, gid_t gid)
105 time_t mtime = time(NULL);
109 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
110 "%08X%08X%08X%08X%08X%08X%08X",
111 "070701", /* magic */
113 S_IFLNK | mode, /* mode */
114 (long) uid, /* uid */
115 (long) gid, /* gid */
117 (long) mtime, /* mtime */
118 (unsigned)strlen(target)+1, /* filesize */
123 (unsigned)strlen(name) + 1,/* namesize */
133 static int cpio_mkslink_line(const char *line)
135 char name[PATH_MAX + 1];
136 char target[PATH_MAX + 1];
142 if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
143 fprintf(stderr, "Unrecognized dir format '%s'", line);
146 rc = cpio_mkslink(name, target, mode, uid, gid);
151 static int cpio_mkgeneric(const char *name, unsigned int mode,
152 uid_t uid, gid_t gid)
155 time_t mtime = time(NULL);
159 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
160 "%08X%08X%08X%08X%08X%08X%08X",
161 "070701", /* magic */
164 (long) uid, /* uid */
165 (long) gid, /* gid */
167 (long) mtime, /* mtime */
173 (unsigned)strlen(name) + 1,/* namesize */
186 struct generic_type {
191 static struct generic_type generic_type_table[] = {
206 static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
208 char name[PATH_MAX + 1];
214 if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
215 fprintf(stderr, "Unrecognized %s format '%s'",
216 line, generic_type_table[gt].type);
219 mode |= generic_type_table[gt].mode;
220 rc = cpio_mkgeneric(name, mode, uid, gid);
225 static int cpio_mkdir_line(const char *line)
227 return cpio_mkgeneric_line(line, GT_DIR);
230 static int cpio_mkpipe_line(const char *line)
232 return cpio_mkgeneric_line(line, GT_PIPE);
235 static int cpio_mksock_line(const char *line)
237 return cpio_mkgeneric_line(line, GT_SOCK);
240 static int cpio_mknod(const char *name, unsigned int mode,
241 uid_t uid, gid_t gid, char dev_type,
242 unsigned int maj, unsigned int min)
245 time_t mtime = time(NULL);
254 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
255 "%08X%08X%08X%08X%08X%08X%08X",
256 "070701", /* magic */
259 (long) uid, /* uid */
260 (long) gid, /* gid */
262 (long) mtime, /* mtime */
268 (unsigned)strlen(name) + 1,/* namesize */
275 static int cpio_mknod_line(const char *line)
277 char name[PATH_MAX + 1];
286 if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
287 name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
288 fprintf(stderr, "Unrecognized nod format '%s'", line);
291 rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
296 static int cpio_mkfile(const char *name, const char *location,
297 unsigned int mode, uid_t uid, gid_t gid,
301 char *filebuf = NULL;
312 file = open (location, O_RDONLY);
314 fprintf (stderr, "File %s could not be opened for reading\n", location);
318 retval = fstat(file, &buf);
320 fprintf(stderr, "File %s could not be stat()'ed\n", location);
324 filebuf = malloc(buf.st_size);
326 fprintf (stderr, "out of memory\n");
330 retval = read (file, filebuf, buf.st_size);
332 fprintf (stderr, "Can not read %s file\n", location);
337 for (i = 1; i <= nlinks; i++) {
338 /* data goes on last link */
339 if (i == nlinks) size = buf.st_size;
343 namesize = strlen(name) + 1;
344 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
345 "%08lX%08X%08X%08X%08X%08X%08X",
346 "070701", /* magic */
349 (long) uid, /* uid */
350 (long) gid, /* gid */
352 (long) buf.st_mtime, /* mtime */
358 namesize, /* namesize */
365 if (fwrite(filebuf, size, 1, stdout) != 1) {
366 fprintf(stderr, "writing filebuf failed\n");
379 if (filebuf) free(filebuf);
380 if (file >= 0) close(file);
384 static char *cpio_replace_env(char *new_location)
386 char expanded[PATH_MAX + 1];
387 char env_var[PATH_MAX + 1];
391 for (start = NULL; (start = strstr(new_location, "${")); ) {
392 end = strchr(start, '}');
394 *env_var = *expanded = '\0';
395 strncat(env_var, start + 2, end - start - 2);
396 strncat(expanded, new_location, start - new_location);
397 strncat(expanded, getenv(env_var), PATH_MAX);
398 strncat(expanded, end + 1, PATH_MAX);
399 strncpy(new_location, expanded, PATH_MAX);
408 static int cpio_mkfile_line(const char *line)
410 char name[PATH_MAX + 1];
411 char *dname = NULL; /* malloc'ed buffer for hard links */
412 char location[PATH_MAX + 1];
417 int end = 0, dname_len = 0;
420 if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
422 name, location, &mode, &uid, &gid, &end)) {
423 fprintf(stderr, "Unrecognized file format '%s'", line);
426 if (end && isgraph(line[end])) {
430 dname = malloc(strlen(line));
432 fprintf (stderr, "out of memory (%d)\n", dname_len);
436 dname_len = strlen(name) + 1;
437 memcpy(dname, name, dname_len);
441 if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
444 len = strlen(name) + 1;
445 memcpy(dname + dname_len, name, len);
449 } while (isgraph(line[end]));
453 rc = cpio_mkfile(dname, cpio_replace_env(location),
454 mode, uid, gid, nlinks);
456 if (dname_len) free(dname);
460 static void usage(const char *prog)
462 fprintf(stderr, "Usage:\n"
465 "<cpio_list> is a file containing newline separated entries that\n"
466 "describe the files to be included in the initramfs archive:\n"
469 "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
470 "dir <name> <mode> <uid> <gid>\n"
471 "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
472 "slink <name> <target> <mode> <uid> <gid>\n"
473 "pipe <name> <mode> <uid> <gid>\n"
474 "sock <name> <mode> <uid> <gid>\n"
476 "<name> name of the file/dir/nod/etc in the archive\n"
477 "<location> location of the file in the current filesystem\n"
478 " expands shell variables quoted with ${}\n"
479 "<target> link target\n"
480 "<mode> mode/permissions of the file\n"
481 "<uid> user id (0=root)\n"
482 "<gid> group id (0=root)\n"
483 "<dev_type> device type (b=block, c=character)\n"
484 "<maj> major number of nod\n"
485 "<min> minor number of nod\n"
486 "<hard links> space separated list of other links to file\n"
489 "# A simple initramfs\n"
490 "dir /dev 0755 0 0\n"
491 "nod /dev/console 0600 0 0 c 5 1\n"
492 "dir /root 0700 0 0\n"
493 "dir /sbin 0755 0 0\n"
494 "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n",
498 struct file_handler file_handler_table[] = {
501 .handler = cpio_mkfile_line,
504 .handler = cpio_mknod_line,
507 .handler = cpio_mkdir_line,
510 .handler = cpio_mkslink_line,
513 .handler = cpio_mkpipe_line,
516 .handler = cpio_mksock_line,
523 #define LINE_SIZE (2 * PATH_MAX + 50)
525 int main (int argc, char *argv[])
528 char line[LINE_SIZE];
538 if (!strcmp(argv[1], "-"))
540 else if (! (cpio_list = fopen(argv[1], "r"))) {
541 fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
542 argv[1], strerror(errno));
547 while (fgets(line, LINE_SIZE, cpio_list)) {
549 size_t slen = strlen(line);
554 /* comment - skip to next line */
558 if (! (type = strtok(line, " \t"))) {
560 "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
571 if (slen == strlen(type)) {
572 /* must be an empty line */
576 if (! (args = strtok(NULL, "\n"))) {
578 "ERROR: incorrect format, newline required line %d: '%s'\n",
583 for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
585 if (! strcmp(line, file_handler_table[type_idx].type)) {
586 if ((rc = file_handler_table[type_idx].handler(args))) {
588 fprintf(stderr, " line %d\n", line_nr);
594 if (NULL == file_handler_table[type_idx].type) {
595 fprintf(stderr, "unknown file type line %d: '%s'\n",