1 // SPDX-License-Identifier: GPL-2.0
17 * Original work by Jeff Garzik
19 * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
20 * Hard link support by Luciano Rocha
24 #define str(s) xstr(s)
25 #define MIN(a, b) ((a) < (b) ? (a) : (b))
27 static unsigned int offset;
28 static unsigned int ino = 721;
29 static time_t default_mtime;
30 static bool do_csum = false;
34 int (*handler)(const char *line);
37 static void push_string(const char *name)
39 unsigned int name_len = strlen(name) + 1;
46 static void push_pad (void)
54 static void push_rest(const char *name)
56 unsigned int name_len = strlen(name) + 1;
63 tmp_ofs = name_len + 110;
71 static void push_hdr(const char *s)
77 static void cpio_trailer(void)
80 const char name[] = "TRAILER!!!";
82 sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
83 "%08X%08X%08X%08X%08X%08X%08X",
84 do_csum ? "070702" : "070701", /* magic */
96 (unsigned)strlen(name)+1, /* namesize */
101 while (offset % 512) {
107 static int cpio_mkslink(const char *name, const char *target,
108 unsigned int mode, uid_t uid, gid_t gid)
114 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
115 "%08X%08X%08X%08X%08X%08X%08X",
116 do_csum ? "070702" : "070701", /* magic */
118 S_IFLNK | mode, /* mode */
119 (long) uid, /* uid */
120 (long) gid, /* gid */
122 (long) default_mtime, /* mtime */
123 (unsigned)strlen(target)+1, /* filesize */
128 (unsigned)strlen(name) + 1,/* namesize */
138 static int cpio_mkslink_line(const char *line)
140 char name[PATH_MAX + 1];
141 char target[PATH_MAX + 1];
147 if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
148 fprintf(stderr, "Unrecognized dir format '%s'", line);
151 rc = cpio_mkslink(name, target, mode, uid, gid);
156 static int cpio_mkgeneric(const char *name, unsigned int mode,
157 uid_t uid, gid_t gid)
163 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
164 "%08X%08X%08X%08X%08X%08X%08X",
165 do_csum ? "070702" : "070701", /* magic */
168 (long) uid, /* uid */
169 (long) gid, /* gid */
171 (long) default_mtime, /* mtime */
177 (unsigned)strlen(name) + 1,/* namesize */
190 struct generic_type {
195 static const struct generic_type generic_type_table[] = {
210 static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
212 char name[PATH_MAX + 1];
218 if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
219 fprintf(stderr, "Unrecognized %s format '%s'",
220 line, generic_type_table[gt].type);
223 mode |= generic_type_table[gt].mode;
224 rc = cpio_mkgeneric(name, mode, uid, gid);
229 static int cpio_mkdir_line(const char *line)
231 return cpio_mkgeneric_line(line, GT_DIR);
234 static int cpio_mkpipe_line(const char *line)
236 return cpio_mkgeneric_line(line, GT_PIPE);
239 static int cpio_mksock_line(const char *line)
241 return cpio_mkgeneric_line(line, GT_SOCK);
244 static int cpio_mknod(const char *name, unsigned int mode,
245 uid_t uid, gid_t gid, char dev_type,
246 unsigned int maj, unsigned int min)
257 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
258 "%08X%08X%08X%08X%08X%08X%08X",
259 do_csum ? "070702" : "070701", /* magic */
262 (long) uid, /* uid */
263 (long) gid, /* gid */
265 (long) default_mtime, /* mtime */
271 (unsigned)strlen(name) + 1,/* namesize */
278 static int cpio_mknod_line(const char *line)
280 char name[PATH_MAX + 1];
289 if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
290 name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
291 fprintf(stderr, "Unrecognized nod format '%s'", line);
294 rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
299 static int cpio_mkfile_csum(int fd, unsigned long size, uint32_t *csum)
302 unsigned char filebuf[65536];
304 size_t i, this_size = MIN(size, sizeof(filebuf));
306 this_read = read(fd, filebuf, this_size);
307 if (this_read <= 0 || this_read > this_size)
310 for (i = 0; i < this_read; i++)
315 /* seek back to the start for data segment I/O */
316 if (lseek(fd, 0, SEEK_SET) < 0)
322 static int cpio_mkfile(const char *name, const char *location,
323 unsigned int mode, uid_t uid, gid_t gid,
338 file = open (location, O_RDONLY);
340 fprintf (stderr, "File %s could not be opened for reading\n", location);
344 retval = fstat(file, &buf);
346 fprintf(stderr, "File %s could not be stat()'ed\n", location);
350 if (buf.st_mtime > 0xffffffff) {
351 fprintf(stderr, "%s: Timestamp exceeds maximum cpio timestamp, clipping.\n",
353 buf.st_mtime = 0xffffffff;
356 if (buf.st_size > 0xffffffff) {
357 fprintf(stderr, "%s: Size exceeds maximum cpio file size\n",
362 if (do_csum && cpio_mkfile_csum(file, buf.st_size, &csum) < 0) {
363 fprintf(stderr, "Failed to checksum file %s\n", location);
368 for (i = 1; i <= nlinks; i++) {
369 /* data goes on last link */
375 namesize = strlen(name) + 1;
376 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
377 "%08lX%08X%08X%08X%08X%08X%08X",
378 do_csum ? "070702" : "070701", /* magic */
381 (long) uid, /* uid */
382 (long) gid, /* gid */
384 (long) buf.st_mtime, /* mtime */
390 namesize, /* namesize */
391 size ? csum : 0); /* chksum */
397 unsigned char filebuf[65536];
399 size_t this_size = MIN(size, sizeof(filebuf));
401 this_read = read(file, filebuf, this_size);
402 if (this_read <= 0 || this_read > this_size) {
403 fprintf(stderr, "Can not read %s file\n", location);
407 if (fwrite(filebuf, this_read, 1, stdout) != 1) {
408 fprintf(stderr, "writing filebuf failed\n");
427 static char *cpio_replace_env(char *new_location)
429 char expanded[PATH_MAX + 1];
430 char *start, *end, *var;
432 while ((start = strstr(new_location, "${")) &&
433 (end = strchr(start + 2, '}'))) {
435 var = getenv(start + 2);
436 snprintf(expanded, sizeof expanded, "%s%s%s",
437 new_location, var ? var : "", end + 1);
438 strcpy(new_location, expanded);
444 static int cpio_mkfile_line(const char *line)
446 char name[PATH_MAX + 1];
447 char *dname = NULL; /* malloc'ed buffer for hard links */
448 char location[PATH_MAX + 1];
453 int end = 0, dname_len = 0;
456 if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
458 name, location, &mode, &uid, &gid, &end)) {
459 fprintf(stderr, "Unrecognized file format '%s'", line);
462 if (end && isgraph(line[end])) {
466 dname = malloc(strlen(line));
468 fprintf (stderr, "out of memory (%d)\n", dname_len);
472 dname_len = strlen(name) + 1;
473 memcpy(dname, name, dname_len);
477 if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
480 len = strlen(name) + 1;
481 memcpy(dname + dname_len, name, len);
485 } while (isgraph(line[end]));
489 rc = cpio_mkfile(dname, cpio_replace_env(location),
490 mode, uid, gid, nlinks);
492 if (dname_len) free(dname);
496 static void usage(const char *prog)
498 fprintf(stderr, "Usage:\n"
499 "\t%s [-t <timestamp>] [-c] <cpio_list>\n"
501 "<cpio_list> is a file containing newline separated entries that\n"
502 "describe the files to be included in the initramfs archive:\n"
505 "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
506 "dir <name> <mode> <uid> <gid>\n"
507 "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
508 "slink <name> <target> <mode> <uid> <gid>\n"
509 "pipe <name> <mode> <uid> <gid>\n"
510 "sock <name> <mode> <uid> <gid>\n"
512 "<name> name of the file/dir/nod/etc in the archive\n"
513 "<location> location of the file in the current filesystem\n"
514 " expands shell variables quoted with ${}\n"
515 "<target> link target\n"
516 "<mode> mode/permissions of the file\n"
517 "<uid> user id (0=root)\n"
518 "<gid> group id (0=root)\n"
519 "<dev_type> device type (b=block, c=character)\n"
520 "<maj> major number of nod\n"
521 "<min> minor number of nod\n"
522 "<hard links> space separated list of other links to file\n"
525 "# A simple initramfs\n"
526 "dir /dev 0755 0 0\n"
527 "nod /dev/console 0600 0 0 c 5 1\n"
528 "dir /root 0700 0 0\n"
529 "dir /sbin 0755 0 0\n"
530 "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
532 "<timestamp> is time in seconds since Epoch that will be used\n"
533 "as mtime for symlinks, special files and directories. The default\n"
534 "is to use the current time for these entries.\n"
535 "-c: calculate and store 32-bit checksums for file data.\n",
539 static const struct file_handler file_handler_table[] = {
542 .handler = cpio_mkfile_line,
545 .handler = cpio_mknod_line,
548 .handler = cpio_mkdir_line,
551 .handler = cpio_mkslink_line,
554 .handler = cpio_mkpipe_line,
557 .handler = cpio_mksock_line,
564 #define LINE_SIZE (2 * PATH_MAX + 50)
566 int main (int argc, char *argv[])
569 char line[LINE_SIZE];
573 const char *filename;
575 default_mtime = time(NULL);
577 int opt = getopt(argc, argv, "t:ch");
584 default_mtime = strtol(optarg, &invalid, 10);
585 if (!*optarg || *invalid) {
586 fprintf(stderr, "Invalid timestamp: %s\n",
598 exit(opt == 'h' ? 0 : 1);
603 * Timestamps after 2106-02-07 06:28:15 UTC have an ascii hex time_t
604 * representation that exceeds 8 chars and breaks the cpio header
607 if (default_mtime > 0xffffffff) {
608 fprintf(stderr, "ERROR: Timestamp too large for cpio format\n");
612 if (argc - optind != 1) {
616 filename = argv[optind];
617 if (!strcmp(filename, "-"))
619 else if (!(cpio_list = fopen(filename, "r"))) {
620 fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
621 filename, strerror(errno));
626 while (fgets(line, LINE_SIZE, cpio_list)) {
628 size_t slen = strlen(line);
633 /* comment - skip to next line */
637 if (! (type = strtok(line, " \t"))) {
639 "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
650 if (slen == strlen(type)) {
651 /* must be an empty line */
655 if (! (args = strtok(NULL, "\n"))) {
657 "ERROR: incorrect format, newline required line %d: '%s'\n",
662 for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
664 if (! strcmp(line, file_handler_table[type_idx].type)) {
665 if ((rc = file_handler_table[type_idx].handler(args))) {
667 fprintf(stderr, " line %d\n", line_nr);
673 if (NULL == file_handler_table[type_idx].type) {
674 fprintf(stderr, "unknown file type line %d: '%s'\n",