1 // SPDX-License-Identifier: GPL-2.0
15 * Original work by Jeff Garzik
17 * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
18 * Hard link support by Luciano Rocha
22 #define str(s) xstr(s)
24 static unsigned int offset;
25 static unsigned int ino = 721;
26 static time_t default_mtime;
30 int (*handler)(const char *line);
33 static void push_string(const char *name)
35 unsigned int name_len = strlen(name) + 1;
42 static void push_pad (void)
50 static void push_rest(const char *name)
52 unsigned int name_len = strlen(name) + 1;
59 tmp_ofs = name_len + 110;
67 static void push_hdr(const char *s)
73 static void cpio_trailer(void)
76 const char name[] = "TRAILER!!!";
78 sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
79 "%08X%08X%08X%08X%08X%08X%08X",
92 (unsigned)strlen(name)+1, /* namesize */
97 while (offset % 512) {
103 static int cpio_mkslink(const char *name, const char *target,
104 unsigned int mode, uid_t uid, gid_t gid)
110 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
111 "%08X%08X%08X%08X%08X%08X%08X",
112 "070701", /* magic */
114 S_IFLNK | mode, /* mode */
115 (long) uid, /* uid */
116 (long) gid, /* gid */
118 (long) default_mtime, /* mtime */
119 (unsigned)strlen(target)+1, /* filesize */
124 (unsigned)strlen(name) + 1,/* namesize */
134 static int cpio_mkslink_line(const char *line)
136 char name[PATH_MAX + 1];
137 char target[PATH_MAX + 1];
143 if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
144 fprintf(stderr, "Unrecognized dir format '%s'", line);
147 rc = cpio_mkslink(name, target, mode, uid, gid);
152 static int cpio_mkgeneric(const char *name, unsigned int mode,
153 uid_t uid, gid_t gid)
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) default_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)
253 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
254 "%08X%08X%08X%08X%08X%08X%08X",
255 "070701", /* magic */
258 (long) uid, /* uid */
259 (long) gid, /* gid */
261 (long) default_mtime, /* mtime */
267 (unsigned)strlen(name) + 1,/* namesize */
274 static int cpio_mknod_line(const char *line)
276 char name[PATH_MAX + 1];
285 if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
286 name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
287 fprintf(stderr, "Unrecognized nod format '%s'", line);
290 rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
295 static int cpio_mkfile(const char *name, const char *location,
296 unsigned int mode, uid_t uid, gid_t gid,
300 char *filebuf = NULL;
311 file = open (location, O_RDONLY);
313 fprintf (stderr, "File %s could not be opened for reading\n", location);
317 retval = fstat(file, &buf);
319 fprintf(stderr, "File %s could not be stat()'ed\n", location);
323 filebuf = malloc(buf.st_size);
325 fprintf (stderr, "out of memory\n");
329 retval = read (file, filebuf, buf.st_size);
331 fprintf (stderr, "Can not read %s file\n", location);
336 for (i = 1; i <= nlinks; i++) {
337 /* data goes on last link */
338 if (i == nlinks) size = buf.st_size;
342 namesize = strlen(name) + 1;
343 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
344 "%08lX%08X%08X%08X%08X%08X%08X",
345 "070701", /* magic */
348 (long) uid, /* uid */
349 (long) gid, /* gid */
351 (long) buf.st_mtime, /* mtime */
357 namesize, /* namesize */
364 if (fwrite(filebuf, size, 1, stdout) != 1) {
365 fprintf(stderr, "writing filebuf failed\n");
378 if (filebuf) free(filebuf);
379 if (file >= 0) close(file);
383 static char *cpio_replace_env(char *new_location)
385 char expanded[PATH_MAX + 1];
386 char *start, *end, *var;
388 while ((start = strstr(new_location, "${")) &&
389 (end = strchr(start + 2, '}'))) {
391 var = getenv(start + 2);
392 snprintf(expanded, sizeof expanded, "%s%s%s",
393 new_location, var ? var : "", end + 1);
394 strcpy(new_location, expanded);
400 static int cpio_mkfile_line(const char *line)
402 char name[PATH_MAX + 1];
403 char *dname = NULL; /* malloc'ed buffer for hard links */
404 char location[PATH_MAX + 1];
409 int end = 0, dname_len = 0;
412 if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
414 name, location, &mode, &uid, &gid, &end)) {
415 fprintf(stderr, "Unrecognized file format '%s'", line);
418 if (end && isgraph(line[end])) {
422 dname = malloc(strlen(line));
424 fprintf (stderr, "out of memory (%d)\n", dname_len);
428 dname_len = strlen(name) + 1;
429 memcpy(dname, name, dname_len);
433 if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
436 len = strlen(name) + 1;
437 memcpy(dname + dname_len, name, len);
441 } while (isgraph(line[end]));
445 rc = cpio_mkfile(dname, cpio_replace_env(location),
446 mode, uid, gid, nlinks);
448 if (dname_len) free(dname);
452 static void usage(const char *prog)
454 fprintf(stderr, "Usage:\n"
455 "\t%s [-t <timestamp>] <cpio_list>\n"
457 "<cpio_list> is a file containing newline separated entries that\n"
458 "describe the files to be included in the initramfs archive:\n"
461 "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
462 "dir <name> <mode> <uid> <gid>\n"
463 "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
464 "slink <name> <target> <mode> <uid> <gid>\n"
465 "pipe <name> <mode> <uid> <gid>\n"
466 "sock <name> <mode> <uid> <gid>\n"
468 "<name> name of the file/dir/nod/etc in the archive\n"
469 "<location> location of the file in the current filesystem\n"
470 " expands shell variables quoted with ${}\n"
471 "<target> link target\n"
472 "<mode> mode/permissions of the file\n"
473 "<uid> user id (0=root)\n"
474 "<gid> group id (0=root)\n"
475 "<dev_type> device type (b=block, c=character)\n"
476 "<maj> major number of nod\n"
477 "<min> minor number of nod\n"
478 "<hard links> space separated list of other links to file\n"
481 "# A simple initramfs\n"
482 "dir /dev 0755 0 0\n"
483 "nod /dev/console 0600 0 0 c 5 1\n"
484 "dir /root 0700 0 0\n"
485 "dir /sbin 0755 0 0\n"
486 "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
488 "<timestamp> is time in seconds since Epoch that will be used\n"
489 "as mtime for symlinks, special files and directories. The default\n"
490 "is to use the current time for these entries.\n",
494 struct file_handler file_handler_table[] = {
497 .handler = cpio_mkfile_line,
500 .handler = cpio_mknod_line,
503 .handler = cpio_mkdir_line,
506 .handler = cpio_mkslink_line,
509 .handler = cpio_mkpipe_line,
512 .handler = cpio_mksock_line,
519 #define LINE_SIZE (2 * PATH_MAX + 50)
521 int main (int argc, char *argv[])
524 char line[LINE_SIZE];
528 const char *filename;
530 default_mtime = time(NULL);
532 int opt = getopt(argc, argv, "t:h");
539 default_mtime = strtol(optarg, &invalid, 10);
540 if (!*optarg || *invalid) {
541 fprintf(stderr, "Invalid timestamp: %s\n",
550 exit(opt == 'h' ? 0 : 1);
554 if (argc - optind != 1) {
558 filename = argv[optind];
559 if (!strcmp(filename, "-"))
561 else if (!(cpio_list = fopen(filename, "r"))) {
562 fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
563 filename, strerror(errno));
568 while (fgets(line, LINE_SIZE, cpio_list)) {
570 size_t slen = strlen(line);
575 /* comment - skip to next line */
579 if (! (type = strtok(line, " \t"))) {
581 "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
592 if (slen == strlen(type)) {
593 /* must be an empty line */
597 if (! (args = strtok(NULL, "\n"))) {
599 "ERROR: incorrect format, newline required line %d: '%s'\n",
604 for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
606 if (! strcmp(line, file_handler_table[type_idx].type)) {
607 if ((rc = file_handler_table[type_idx].handler(args))) {
609 fprintf(stderr, " line %d\n", line_nr);
615 if (NULL == file_handler_table[type_idx].type) {
616 fprintf(stderr, "unknown file type line %d: '%s'\n",