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_file_mtime
;
31 static bool do_csum
= false;
35 int (*handler
)(const char *line
);
38 static void push_string(const char *name
)
40 unsigned int name_len
= strlen(name
) + 1;
47 static void push_pad (void)
55 static void push_rest(const char *name
)
57 unsigned int name_len
= strlen(name
) + 1;
64 tmp_ofs
= name_len
+ 110;
72 static void push_hdr(const char *s
)
78 static void cpio_trailer(void)
81 const char name
[] = "TRAILER!!!";
83 sprintf(s
, "%s%08X%08X%08lX%08lX%08X%08lX"
84 "%08X%08X%08X%08X%08X%08X%08X",
85 do_csum
? "070702" : "070701", /* magic */
97 (unsigned)strlen(name
)+1, /* namesize */
102 while (offset
% 512) {
108 static int cpio_mkslink(const char *name
, const char *target
,
109 unsigned int mode
, uid_t uid
, gid_t gid
)
115 sprintf(s
,"%s%08X%08X%08lX%08lX%08X%08lX"
116 "%08X%08X%08X%08X%08X%08X%08X",
117 do_csum
? "070702" : "070701", /* magic */
119 S_IFLNK
| mode
, /* mode */
120 (long) uid
, /* uid */
121 (long) gid
, /* gid */
123 (long) default_mtime
, /* mtime */
124 (unsigned)strlen(target
)+1, /* filesize */
129 (unsigned)strlen(name
) + 1,/* namesize */
139 static int cpio_mkslink_line(const char *line
)
141 char name
[PATH_MAX
+ 1];
142 char target
[PATH_MAX
+ 1];
148 if (5 != sscanf(line
, "%" str(PATH_MAX
) "s %" str(PATH_MAX
) "s %o %d %d", name
, target
, &mode
, &uid
, &gid
)) {
149 fprintf(stderr
, "Unrecognized dir format '%s'", line
);
152 rc
= cpio_mkslink(name
, target
, mode
, uid
, gid
);
157 static int cpio_mkgeneric(const char *name
, unsigned int mode
,
158 uid_t uid
, gid_t gid
)
164 sprintf(s
,"%s%08X%08X%08lX%08lX%08X%08lX"
165 "%08X%08X%08X%08X%08X%08X%08X",
166 do_csum
? "070702" : "070701", /* magic */
169 (long) uid
, /* uid */
170 (long) gid
, /* gid */
172 (long) default_mtime
, /* mtime */
178 (unsigned)strlen(name
) + 1,/* namesize */
191 struct generic_type
{
196 static const struct generic_type generic_type_table
[] = {
211 static int cpio_mkgeneric_line(const char *line
, enum generic_types gt
)
213 char name
[PATH_MAX
+ 1];
219 if (4 != sscanf(line
, "%" str(PATH_MAX
) "s %o %d %d", name
, &mode
, &uid
, &gid
)) {
220 fprintf(stderr
, "Unrecognized %s format '%s'",
221 line
, generic_type_table
[gt
].type
);
224 mode
|= generic_type_table
[gt
].mode
;
225 rc
= cpio_mkgeneric(name
, mode
, uid
, gid
);
230 static int cpio_mkdir_line(const char *line
)
232 return cpio_mkgeneric_line(line
, GT_DIR
);
235 static int cpio_mkpipe_line(const char *line
)
237 return cpio_mkgeneric_line(line
, GT_PIPE
);
240 static int cpio_mksock_line(const char *line
)
242 return cpio_mkgeneric_line(line
, GT_SOCK
);
245 static int cpio_mknod(const char *name
, unsigned int mode
,
246 uid_t uid
, gid_t gid
, char dev_type
,
247 unsigned int maj
, unsigned int min
)
258 sprintf(s
,"%s%08X%08X%08lX%08lX%08X%08lX"
259 "%08X%08X%08X%08X%08X%08X%08X",
260 do_csum
? "070702" : "070701", /* magic */
263 (long) uid
, /* uid */
264 (long) gid
, /* gid */
266 (long) default_mtime
, /* mtime */
272 (unsigned)strlen(name
) + 1,/* namesize */
279 static int cpio_mknod_line(const char *line
)
281 char name
[PATH_MAX
+ 1];
290 if (7 != sscanf(line
, "%" str(PATH_MAX
) "s %o %d %d %c %u %u",
291 name
, &mode
, &uid
, &gid
, &dev_type
, &maj
, &min
)) {
292 fprintf(stderr
, "Unrecognized nod format '%s'", line
);
295 rc
= cpio_mknod(name
, mode
, uid
, gid
, dev_type
, maj
, min
);
300 static int cpio_mkfile_csum(int fd
, unsigned long size
, uint32_t *csum
)
303 unsigned char filebuf
[65536];
305 size_t i
, this_size
= MIN(size
, sizeof(filebuf
));
307 this_read
= read(fd
, filebuf
, this_size
);
308 if (this_read
<= 0 || this_read
> this_size
)
311 for (i
= 0; i
< this_read
; i
++)
316 /* seek back to the start for data segment I/O */
317 if (lseek(fd
, 0, SEEK_SET
) < 0)
323 static int cpio_mkfile(const char *name
, const char *location
,
324 unsigned int mode
, uid_t uid
, gid_t gid
,
340 file
= open (location
, O_RDONLY
);
342 fprintf (stderr
, "File %s could not be opened for reading\n", location
);
346 retval
= fstat(file
, &buf
);
348 fprintf(stderr
, "File %s could not be stat()'ed\n", location
);
353 mtime
= default_mtime
;
355 mtime
= buf
.st_mtime
;
356 if (mtime
> 0xffffffff) {
357 fprintf(stderr
, "%s: Timestamp exceeds maximum cpio timestamp, clipping.\n",
363 fprintf(stderr
, "%s: Timestamp negative, clipping.\n",
369 if (buf
.st_size
> 0xffffffff) {
370 fprintf(stderr
, "%s: Size exceeds maximum cpio file size\n",
375 if (do_csum
&& cpio_mkfile_csum(file
, buf
.st_size
, &csum
) < 0) {
376 fprintf(stderr
, "Failed to checksum file %s\n", location
);
381 for (i
= 1; i
<= nlinks
; i
++) {
382 /* data goes on last link */
388 namesize
= strlen(name
) + 1;
389 sprintf(s
,"%s%08X%08X%08lX%08lX%08X%08lX"
390 "%08lX%08X%08X%08X%08X%08X%08X",
391 do_csum
? "070702" : "070701", /* magic */
394 (long) uid
, /* uid */
395 (long) gid
, /* gid */
397 (long) mtime
, /* mtime */
403 namesize
, /* namesize */
404 size
? csum
: 0); /* chksum */
410 unsigned char filebuf
[65536];
412 size_t this_size
= MIN(size
, sizeof(filebuf
));
414 this_read
= read(file
, filebuf
, this_size
);
415 if (this_read
<= 0 || this_read
> this_size
) {
416 fprintf(stderr
, "Can not read %s file\n", location
);
420 if (fwrite(filebuf
, this_read
, 1, stdout
) != 1) {
421 fprintf(stderr
, "writing filebuf failed\n");
440 static char *cpio_replace_env(char *new_location
)
442 char expanded
[PATH_MAX
+ 1];
443 char *start
, *end
, *var
;
445 while ((start
= strstr(new_location
, "${")) &&
446 (end
= strchr(start
+ 2, '}'))) {
448 var
= getenv(start
+ 2);
449 snprintf(expanded
, sizeof expanded
, "%s%s%s",
450 new_location
, var
? var
: "", end
+ 1);
451 strcpy(new_location
, expanded
);
457 static int cpio_mkfile_line(const char *line
)
459 char name
[PATH_MAX
+ 1];
460 char *dname
= NULL
; /* malloc'ed buffer for hard links */
461 char location
[PATH_MAX
+ 1];
466 int end
= 0, dname_len
= 0;
469 if (5 > sscanf(line
, "%" str(PATH_MAX
) "s %" str(PATH_MAX
)
471 name
, location
, &mode
, &uid
, &gid
, &end
)) {
472 fprintf(stderr
, "Unrecognized file format '%s'", line
);
475 if (end
&& isgraph(line
[end
])) {
479 dname
= malloc(strlen(line
));
481 fprintf (stderr
, "out of memory (%d)\n", dname_len
);
485 dname_len
= strlen(name
) + 1;
486 memcpy(dname
, name
, dname_len
);
490 if (sscanf(line
+ end
, "%" str(PATH_MAX
) "s %n",
493 len
= strlen(name
) + 1;
494 memcpy(dname
+ dname_len
, name
, len
);
498 } while (isgraph(line
[end
]));
502 rc
= cpio_mkfile(dname
, cpio_replace_env(location
),
503 mode
, uid
, gid
, nlinks
);
505 if (dname_len
) free(dname
);
509 static void usage(const char *prog
)
511 fprintf(stderr
, "Usage:\n"
512 "\t%s [-t <timestamp>] [-c] <cpio_list>\n"
514 "<cpio_list> is a file containing newline separated entries that\n"
515 "describe the files to be included in the initramfs archive:\n"
518 "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
519 "dir <name> <mode> <uid> <gid>\n"
520 "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
521 "slink <name> <target> <mode> <uid> <gid>\n"
522 "pipe <name> <mode> <uid> <gid>\n"
523 "sock <name> <mode> <uid> <gid>\n"
525 "<name> name of the file/dir/nod/etc in the archive\n"
526 "<location> location of the file in the current filesystem\n"
527 " expands shell variables quoted with ${}\n"
528 "<target> link target\n"
529 "<mode> mode/permissions of the file\n"
530 "<uid> user id (0=root)\n"
531 "<gid> group id (0=root)\n"
532 "<dev_type> device type (b=block, c=character)\n"
533 "<maj> major number of nod\n"
534 "<min> minor number of nod\n"
535 "<hard links> space separated list of other links to file\n"
538 "# A simple initramfs\n"
539 "dir /dev 0755 0 0\n"
540 "nod /dev/console 0600 0 0 c 5 1\n"
541 "dir /root 0700 0 0\n"
542 "dir /sbin 0755 0 0\n"
543 "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
545 "<timestamp> is time in seconds since Epoch that will be used\n"
546 "as mtime for symlinks, directories, regular and special files.\n"
547 "The default is to use the current time for all files, but\n"
548 "preserve modification time for regular files.\n"
549 "-c: calculate and store 32-bit checksums for file data.\n",
553 static const struct file_handler file_handler_table
[] = {
556 .handler
= cpio_mkfile_line
,
559 .handler
= cpio_mknod_line
,
562 .handler
= cpio_mkdir_line
,
565 .handler
= cpio_mkslink_line
,
568 .handler
= cpio_mkpipe_line
,
571 .handler
= cpio_mksock_line
,
578 #define LINE_SIZE (2 * PATH_MAX + 50)
580 int main (int argc
, char *argv
[])
583 char line
[LINE_SIZE
];
587 const char *filename
;
589 default_mtime
= time(NULL
);
591 int opt
= getopt(argc
, argv
, "t:ch");
598 default_mtime
= strtol(optarg
, &invalid
, 10);
599 if (!*optarg
|| *invalid
) {
600 fprintf(stderr
, "Invalid timestamp: %s\n",
605 do_file_mtime
= true;
613 exit(opt
== 'h' ? 0 : 1);
618 * Timestamps after 2106-02-07 06:28:15 UTC have an ascii hex time_t
619 * representation that exceeds 8 chars and breaks the cpio header
620 * specification. Negative timestamps similarly exceed 8 chars.
622 if (default_mtime
> 0xffffffff || default_mtime
< 0) {
623 fprintf(stderr
, "ERROR: Timestamp out of range for cpio format\n");
627 if (argc
- optind
!= 1) {
631 filename
= argv
[optind
];
632 if (!strcmp(filename
, "-"))
634 else if (!(cpio_list
= fopen(filename
, "r"))) {
635 fprintf(stderr
, "ERROR: unable to open '%s': %s\n\n",
636 filename
, strerror(errno
));
641 while (fgets(line
, LINE_SIZE
, cpio_list
)) {
643 size_t slen
= strlen(line
);
648 /* comment - skip to next line */
652 if (! (type
= strtok(line
, " \t"))) {
654 "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
665 if (slen
== strlen(type
)) {
666 /* must be an empty line */
670 if (! (args
= strtok(NULL
, "\n"))) {
672 "ERROR: incorrect format, newline required line %d: '%s'\n",
677 for (type_idx
= 0; file_handler_table
[type_idx
].type
; type_idx
++) {
679 if (! strcmp(line
, file_handler_table
[type_idx
].type
)) {
680 if ((rc
= file_handler_table
[type_idx
].handler(args
))) {
682 fprintf(stderr
, " line %d\n", line_nr
);
688 if (NULL
== file_handler_table
[type_idx
].type
) {
689 fprintf(stderr
, "unknown file type line %d: '%s'\n",