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",