blob: 61230532fef10f7261db75e5757a8b2c4366d2d9 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002#include <stdio.h>
3#include <stdlib.h>
David Disseldorpea804872022-05-09 18:29:20 -07004#include <stdint.h>
5#include <stdbool.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006#include <sys/types.h>
7#include <sys/stat.h>
8#include <string.h>
9#include <unistd.h>
10#include <time.h>
11#include <fcntl.h>
12#include <errno.h>
13#include <ctype.h>
14#include <limits.h>
15
16/*
17 * Original work by Jeff Garzik
18 *
19 * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
Luciano Rocha24fa5092007-02-10 01:44:45 -080020 * Hard link support by Luciano Rocha
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 */
22
23#define xstr(s) #s
24#define str(s) xstr(s)
David Disseldorp3a2699c2022-05-09 18:29:20 -070025#define MIN(a, b) ((a) < (b) ? (a) : (b))
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
27static unsigned int offset;
28static unsigned int ino = 721;
Michal Mareka8b80172011-03-31 23:16:42 +020029static time_t default_mtime;
David Disseldorpea804872022-05-09 18:29:20 -070030static bool do_csum = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32struct file_handler {
33 const char *type;
34 int (*handler)(const char *line);
35};
36
37static void push_string(const char *name)
38{
39 unsigned int name_len = strlen(name) + 1;
40
41 fputs(name, stdout);
42 putchar(0);
43 offset += name_len;
44}
45
46static void push_pad (void)
47{
48 while (offset & 3) {
49 putchar(0);
50 offset++;
51 }
52}
53
54static void push_rest(const char *name)
55{
56 unsigned int name_len = strlen(name) + 1;
57 unsigned int tmp_ofs;
58
59 fputs(name, stdout);
60 putchar(0);
61 offset += name_len;
62
63 tmp_ofs = name_len + 110;
64 while (tmp_ofs & 3) {
65 putchar(0);
66 offset++;
67 tmp_ofs++;
68 }
69}
70
71static void push_hdr(const char *s)
72{
73 fputs(s, stdout);
74 offset += 110;
75}
76
77static void cpio_trailer(void)
78{
79 char s[256];
80 const char name[] = "TRAILER!!!";
81
82 sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
83 "%08X%08X%08X%08X%08X%08X%08X",
David Disseldorpea804872022-05-09 18:29:20 -070084 do_csum ? "070702" : "070701", /* magic */
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 0, /* ino */
86 0, /* mode */
87 (long) 0, /* uid */
88 (long) 0, /* gid */
89 1, /* nlink */
90 (long) 0, /* mtime */
91 0, /* filesize */
92 0, /* major */
93 0, /* minor */
94 0, /* rmajor */
95 0, /* rminor */
96 (unsigned)strlen(name)+1, /* namesize */
97 0); /* chksum */
98 push_hdr(s);
99 push_rest(name);
100
101 while (offset % 512) {
102 putchar(0);
103 offset++;
104 }
105}
106
107static int cpio_mkslink(const char *name, const char *target,
108 unsigned int mode, uid_t uid, gid_t gid)
109{
110 char s[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
Thomas Chou43f901f2010-10-06 15:13:53 +0800112 if (name[0] == '/')
113 name++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
115 "%08X%08X%08X%08X%08X%08X%08X",
David Disseldorpea804872022-05-09 18:29:20 -0700116 do_csum ? "070702" : "070701", /* magic */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 ino++, /* ino */
118 S_IFLNK | mode, /* mode */
119 (long) uid, /* uid */
120 (long) gid, /* gid */
121 1, /* nlink */
Michal Mareka8b80172011-03-31 23:16:42 +0200122 (long) default_mtime, /* mtime */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 (unsigned)strlen(target)+1, /* filesize */
124 3, /* major */
125 1, /* minor */
126 0, /* rmajor */
127 0, /* rminor */
128 (unsigned)strlen(name) + 1,/* namesize */
129 0); /* chksum */
130 push_hdr(s);
131 push_string(name);
132 push_pad();
133 push_string(target);
134 push_pad();
135 return 0;
136}
137
138static int cpio_mkslink_line(const char *line)
139{
140 char name[PATH_MAX + 1];
141 char target[PATH_MAX + 1];
142 unsigned int mode;
143 int uid;
144 int gid;
145 int rc = -1;
146
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);
149 goto fail;
150 }
151 rc = cpio_mkslink(name, target, mode, uid, gid);
152 fail:
153 return rc;
154}
155
156static int cpio_mkgeneric(const char *name, unsigned int mode,
157 uid_t uid, gid_t gid)
158{
159 char s[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
Thomas Chou43f901f2010-10-06 15:13:53 +0800161 if (name[0] == '/')
162 name++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
164 "%08X%08X%08X%08X%08X%08X%08X",
David Disseldorpea804872022-05-09 18:29:20 -0700165 do_csum ? "070702" : "070701", /* magic */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 ino++, /* ino */
167 mode, /* mode */
168 (long) uid, /* uid */
169 (long) gid, /* gid */
170 2, /* nlink */
Michal Mareka8b80172011-03-31 23:16:42 +0200171 (long) default_mtime, /* mtime */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 0, /* filesize */
173 3, /* major */
174 1, /* minor */
175 0, /* rmajor */
176 0, /* rminor */
177 (unsigned)strlen(name) + 1,/* namesize */
178 0); /* chksum */
179 push_hdr(s);
180 push_rest(name);
181 return 0;
182}
183
184enum generic_types {
185 GT_DIR,
186 GT_PIPE,
187 GT_SOCK
188};
189
190struct generic_type {
191 const char *type;
192 mode_t mode;
193};
194
Masahiro Yamada3510c5c2021-10-12 11:55:14 +0900195static const struct generic_type generic_type_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 [GT_DIR] = {
197 .type = "dir",
198 .mode = S_IFDIR
199 },
200 [GT_PIPE] = {
201 .type = "pipe",
202 .mode = S_IFIFO
203 },
204 [GT_SOCK] = {
205 .type = "sock",
206 .mode = S_IFSOCK
207 }
208};
209
210static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
211{
212 char name[PATH_MAX + 1];
213 unsigned int mode;
214 int uid;
215 int gid;
216 int rc = -1;
217
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);
221 goto fail;
222 }
223 mode |= generic_type_table[gt].mode;
224 rc = cpio_mkgeneric(name, mode, uid, gid);
225 fail:
226 return rc;
227}
228
229static int cpio_mkdir_line(const char *line)
230{
231 return cpio_mkgeneric_line(line, GT_DIR);
232}
233
234static int cpio_mkpipe_line(const char *line)
235{
236 return cpio_mkgeneric_line(line, GT_PIPE);
237}
238
239static int cpio_mksock_line(const char *line)
240{
241 return cpio_mkgeneric_line(line, GT_SOCK);
242}
243
244static 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)
247{
248 char s[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 if (dev_type == 'b')
251 mode |= S_IFBLK;
252 else
253 mode |= S_IFCHR;
254
Thomas Chou43f901f2010-10-06 15:13:53 +0800255 if (name[0] == '/')
256 name++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
258 "%08X%08X%08X%08X%08X%08X%08X",
David Disseldorpea804872022-05-09 18:29:20 -0700259 do_csum ? "070702" : "070701", /* magic */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 ino++, /* ino */
261 mode, /* mode */
262 (long) uid, /* uid */
263 (long) gid, /* gid */
264 1, /* nlink */
Michal Mareka8b80172011-03-31 23:16:42 +0200265 (long) default_mtime, /* mtime */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 0, /* filesize */
267 3, /* major */
268 1, /* minor */
269 maj, /* rmajor */
270 min, /* rminor */
271 (unsigned)strlen(name) + 1,/* namesize */
272 0); /* chksum */
273 push_hdr(s);
274 push_rest(name);
275 return 0;
276}
277
278static int cpio_mknod_line(const char *line)
279{
280 char name[PATH_MAX + 1];
281 unsigned int mode;
282 int uid;
283 int gid;
284 char dev_type;
285 unsigned int maj;
286 unsigned int min;
287 int rc = -1;
288
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);
292 goto fail;
293 }
294 rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
295 fail:
296 return rc;
297}
298
David Disseldorpea804872022-05-09 18:29:20 -0700299static int cpio_mkfile_csum(int fd, unsigned long size, uint32_t *csum)
300{
301 while (size) {
302 unsigned char filebuf[65536];
303 ssize_t this_read;
304 size_t i, this_size = MIN(size, sizeof(filebuf));
305
306 this_read = read(fd, filebuf, this_size);
307 if (this_read <= 0 || this_read > this_size)
308 return -1;
309
310 for (i = 0; i < this_read; i++)
311 *csum += filebuf[i];
312
313 size -= this_read;
314 }
315 /* seek back to the start for data segment I/O */
316 if (lseek(fd, 0, SEEK_SET) < 0)
317 return -1;
318
319 return 0;
320}
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322static int cpio_mkfile(const char *name, const char *location,
Luciano Rocha24fa5092007-02-10 01:44:45 -0800323 unsigned int mode, uid_t uid, gid_t gid,
324 unsigned int nlinks)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
326 char s[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 struct stat buf;
David Disseldorp3a2699c2022-05-09 18:29:20 -0700328 unsigned long size;
Li zeming462cd772022-09-19 09:44:06 +0800329 int file;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 int retval;
331 int rc = -1;
Luciano Rocha24fa5092007-02-10 01:44:45 -0800332 int namesize;
Kees Cook20f1de62012-10-25 13:38:14 -0700333 unsigned int i;
David Disseldorpea804872022-05-09 18:29:20 -0700334 uint32_t csum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
336 mode |= S_IFREG;
337
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 file = open (location, O_RDONLY);
339 if (file < 0) {
340 fprintf (stderr, "File %s could not be opened for reading\n", location);
341 goto error;
342 }
343
Andrew Mortona3c888f2011-01-05 23:49:53 +0100344 retval = fstat(file, &buf);
Jesper Juhl96aebaf2010-12-24 21:28:56 +0100345 if (retval) {
Andrew Mortona3c888f2011-01-05 23:49:53 +0100346 fprintf(stderr, "File %s could not be stat()'ed\n", location);
Jesper Juhl96aebaf2010-12-24 21:28:56 +0100347 goto error;
348 }
349
Nicolas Schier4c9d4102021-10-12 20:12:20 +0000350 if (buf.st_mtime > 0xffffffff) {
351 fprintf(stderr, "%s: Timestamp exceeds maximum cpio timestamp, clipping.\n",
352 location);
353 buf.st_mtime = 0xffffffff;
354 }
355
Benjamin Gray5efb6852023-03-20 15:08:38 +1100356 if (buf.st_mtime < 0) {
357 fprintf(stderr, "%s: Timestamp negative, clipping.\n",
358 location);
359 buf.st_mtime = 0;
360 }
361
David Disseldorp3a2699c2022-05-09 18:29:20 -0700362 if (buf.st_size > 0xffffffff) {
363 fprintf(stderr, "%s: Size exceeds maximum cpio file size\n",
364 location);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 goto error;
366 }
367
David Disseldorpea804872022-05-09 18:29:20 -0700368 if (do_csum && cpio_mkfile_csum(file, buf.st_size, &csum) < 0) {
369 fprintf(stderr, "Failed to checksum file %s\n", location);
370 goto error;
371 }
372
Luciano Rocha24fa5092007-02-10 01:44:45 -0800373 size = 0;
374 for (i = 1; i <= nlinks; i++) {
375 /* data goes on last link */
David Disseldorp3a2699c2022-05-09 18:29:20 -0700376 if (i == nlinks)
377 size = buf.st_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Thomas Chou43f901f2010-10-06 15:13:53 +0800379 if (name[0] == '/')
380 name++;
Luciano Rocha24fa5092007-02-10 01:44:45 -0800381 namesize = strlen(name) + 1;
382 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
383 "%08lX%08X%08X%08X%08X%08X%08X",
David Disseldorpea804872022-05-09 18:29:20 -0700384 do_csum ? "070702" : "070701", /* magic */
Luciano Rocha24fa5092007-02-10 01:44:45 -0800385 ino, /* ino */
386 mode, /* mode */
387 (long) uid, /* uid */
388 (long) gid, /* gid */
389 nlinks, /* nlink */
390 (long) buf.st_mtime, /* mtime */
391 size, /* filesize */
392 3, /* major */
393 1, /* minor */
394 0, /* rmajor */
395 0, /* rminor */
396 namesize, /* namesize */
David Disseldorpea804872022-05-09 18:29:20 -0700397 size ? csum : 0); /* chksum */
Luciano Rocha24fa5092007-02-10 01:44:45 -0800398 push_hdr(s);
399 push_string(name);
400 push_pad();
401
David Disseldorp3a2699c2022-05-09 18:29:20 -0700402 while (size) {
403 unsigned char filebuf[65536];
404 ssize_t this_read;
405 size_t this_size = MIN(size, sizeof(filebuf));
406
407 this_read = read(file, filebuf, this_size);
408 if (this_read <= 0 || this_read > this_size) {
409 fprintf(stderr, "Can not read %s file\n", location);
410 goto error;
411 }
412
413 if (fwrite(filebuf, this_read, 1, stdout) != 1) {
Mike Frysinger6d87fea2009-12-09 06:55:19 -0500414 fprintf(stderr, "writing filebuf failed\n");
415 goto error;
416 }
David Disseldorp3a2699c2022-05-09 18:29:20 -0700417 offset += this_read;
418 size -= this_read;
Luciano Rocha24fa5092007-02-10 01:44:45 -0800419 }
David Disseldorp3a2699c2022-05-09 18:29:20 -0700420 push_pad();
Luciano Rocha24fa5092007-02-10 01:44:45 -0800421
422 name += namesize;
423 }
424 ino++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 rc = 0;
David Disseldorp3a2699c2022-05-09 18:29:20 -0700426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427error:
David Disseldorp3a2699c2022-05-09 18:29:20 -0700428 if (file >= 0)
429 close(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 return rc;
431}
432
Sally, Gene3b1ec9f2008-10-29 09:54:17 -0400433static char *cpio_replace_env(char *new_location)
434{
Kees Cook20f1de62012-10-25 13:38:14 -0700435 char expanded[PATH_MAX + 1];
Michal Nazarewiczc725ee542013-11-12 15:08:41 -0800436 char *start, *end, *var;
Sally, Gene3b1ec9f2008-10-29 09:54:17 -0400437
Michal Nazarewiczc725ee542013-11-12 15:08:41 -0800438 while ((start = strstr(new_location, "${")) &&
439 (end = strchr(start + 2, '}'))) {
440 *start = *end = 0;
441 var = getenv(start + 2);
442 snprintf(expanded, sizeof expanded, "%s%s%s",
443 new_location, var ? var : "", end + 1);
444 strcpy(new_location, expanded);
Kees Cook20f1de62012-10-25 13:38:14 -0700445 }
Sally, Gene3b1ec9f2008-10-29 09:54:17 -0400446
Kees Cook20f1de62012-10-25 13:38:14 -0700447 return new_location;
Sally, Gene3b1ec9f2008-10-29 09:54:17 -0400448}
449
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450static int cpio_mkfile_line(const char *line)
451{
452 char name[PATH_MAX + 1];
Luciano Rocha24fa5092007-02-10 01:44:45 -0800453 char *dname = NULL; /* malloc'ed buffer for hard links */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 char location[PATH_MAX + 1];
455 unsigned int mode;
456 int uid;
457 int gid;
Luciano Rocha24fa5092007-02-10 01:44:45 -0800458 int nlinks = 1;
459 int end = 0, dname_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 int rc = -1;
461
Luciano Rocha24fa5092007-02-10 01:44:45 -0800462 if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
463 "s %o %d %d %n",
464 name, location, &mode, &uid, &gid, &end)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 fprintf(stderr, "Unrecognized file format '%s'", line);
466 goto fail;
467 }
Luciano Rocha24fa5092007-02-10 01:44:45 -0800468 if (end && isgraph(line[end])) {
469 int len;
470 int nend;
471
472 dname = malloc(strlen(line));
473 if (!dname) {
474 fprintf (stderr, "out of memory (%d)\n", dname_len);
475 goto fail;
476 }
477
478 dname_len = strlen(name) + 1;
479 memcpy(dname, name, dname_len);
480
481 do {
482 nend = 0;
483 if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
484 name, &nend) < 1)
485 break;
486 len = strlen(name) + 1;
487 memcpy(dname + dname_len, name, len);
488 dname_len += len;
489 nlinks++;
490 end += nend;
491 } while (isgraph(line[end]));
492 } else {
493 dname = name;
494 }
Sally, Gene3b1ec9f2008-10-29 09:54:17 -0400495 rc = cpio_mkfile(dname, cpio_replace_env(location),
496 mode, uid, gid, nlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 fail:
Luciano Rocha24fa5092007-02-10 01:44:45 -0800498 if (dname_len) free(dname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 return rc;
500}
501
Trevor Keith5c725132009-09-22 16:43:38 -0700502static void usage(const char *prog)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
504 fprintf(stderr, "Usage:\n"
David Disseldorpea804872022-05-09 18:29:20 -0700505 "\t%s [-t <timestamp>] [-c] <cpio_list>\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 "\n"
507 "<cpio_list> is a file containing newline separated entries that\n"
508 "describe the files to be included in the initramfs archive:\n"
509 "\n"
510 "# a comment\n"
Luciano Rocha24fa5092007-02-10 01:44:45 -0800511 "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 "dir <name> <mode> <uid> <gid>\n"
513 "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
514 "slink <name> <target> <mode> <uid> <gid>\n"
515 "pipe <name> <mode> <uid> <gid>\n"
516 "sock <name> <mode> <uid> <gid>\n"
517 "\n"
Luciano Rocha24fa5092007-02-10 01:44:45 -0800518 "<name> name of the file/dir/nod/etc in the archive\n"
519 "<location> location of the file in the current filesystem\n"
Sally, Gene3b1ec9f2008-10-29 09:54:17 -0400520 " expands shell variables quoted with ${}\n"
Luciano Rocha24fa5092007-02-10 01:44:45 -0800521 "<target> link target\n"
522 "<mode> mode/permissions of the file\n"
523 "<uid> user id (0=root)\n"
524 "<gid> group id (0=root)\n"
525 "<dev_type> device type (b=block, c=character)\n"
526 "<maj> major number of nod\n"
527 "<min> minor number of nod\n"
528 "<hard links> space separated list of other links to file\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 "\n"
530 "example:\n"
531 "# A simple initramfs\n"
532 "dir /dev 0755 0 0\n"
533 "nod /dev/console 0600 0 0 c 5 1\n"
534 "dir /root 0700 0 0\n"
535 "dir /sbin 0755 0 0\n"
Michal Mareka8b80172011-03-31 23:16:42 +0200536 "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
537 "\n"
538 "<timestamp> is time in seconds since Epoch that will be used\n"
539 "as mtime for symlinks, special files and directories. The default\n"
David Disseldorpea804872022-05-09 18:29:20 -0700540 "is to use the current time for these entries.\n"
541 "-c: calculate and store 32-bit checksums for file data.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 prog);
543}
544
Masahiro Yamada3510c5c2021-10-12 11:55:14 +0900545static const struct file_handler file_handler_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 {
547 .type = "file",
548 .handler = cpio_mkfile_line,
549 }, {
550 .type = "nod",
551 .handler = cpio_mknod_line,
552 }, {
553 .type = "dir",
554 .handler = cpio_mkdir_line,
555 }, {
556 .type = "slink",
557 .handler = cpio_mkslink_line,
558 }, {
559 .type = "pipe",
560 .handler = cpio_mkpipe_line,
561 }, {
562 .type = "sock",
563 .handler = cpio_mksock_line,
564 }, {
565 .type = NULL,
566 .handler = NULL,
567 }
568};
569
570#define LINE_SIZE (2 * PATH_MAX + 50)
571
572int main (int argc, char *argv[])
573{
574 FILE *cpio_list;
575 char line[LINE_SIZE];
576 char *args, *type;
577 int ec = 0;
578 int line_nr = 0;
Michal Mareka8b80172011-03-31 23:16:42 +0200579 const char *filename;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Michal Mareka8b80172011-03-31 23:16:42 +0200581 default_mtime = time(NULL);
582 while (1) {
David Disseldorpea804872022-05-09 18:29:20 -0700583 int opt = getopt(argc, argv, "t:ch");
Michal Mareka8b80172011-03-31 23:16:42 +0200584 char *invalid;
585
586 if (opt == -1)
587 break;
588 switch (opt) {
589 case 't':
590 default_mtime = strtol(optarg, &invalid, 10);
591 if (!*optarg || *invalid) {
592 fprintf(stderr, "Invalid timestamp: %s\n",
593 optarg);
594 usage(argv[0]);
595 exit(1);
596 }
597 break;
David Disseldorpea804872022-05-09 18:29:20 -0700598 case 'c':
599 do_csum = true;
600 break;
Michal Mareka8b80172011-03-31 23:16:42 +0200601 case 'h':
602 case '?':
603 usage(argv[0]);
604 exit(opt == 'h' ? 0 : 1);
605 }
606 }
607
Nicolas Schier4c9d4102021-10-12 20:12:20 +0000608 /*
609 * Timestamps after 2106-02-07 06:28:15 UTC have an ascii hex time_t
610 * representation that exceeds 8 chars and breaks the cpio header
Benjamin Gray5efb6852023-03-20 15:08:38 +1100611 * specification. Negative timestamps similarly exceed 8 chars.
Nicolas Schier4c9d4102021-10-12 20:12:20 +0000612 */
Benjamin Gray5efb6852023-03-20 15:08:38 +1100613 if (default_mtime > 0xffffffff || default_mtime < 0) {
614 fprintf(stderr, "ERROR: Timestamp out of range for cpio format\n");
Nicolas Schier4c9d4102021-10-12 20:12:20 +0000615 exit(1);
616 }
617
Michal Mareka8b80172011-03-31 23:16:42 +0200618 if (argc - optind != 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 usage(argv[0]);
620 exit(1);
621 }
Michal Mareka8b80172011-03-31 23:16:42 +0200622 filename = argv[optind];
623 if (!strcmp(filename, "-"))
Mike Frysingerf2434ec2007-05-10 22:44:28 -0700624 cpio_list = stdin;
Michal Mareka8b80172011-03-31 23:16:42 +0200625 else if (!(cpio_list = fopen(filename, "r"))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
Michal Mareka8b80172011-03-31 23:16:42 +0200627 filename, strerror(errno));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 usage(argv[0]);
629 exit(1);
630 }
631
632 while (fgets(line, LINE_SIZE, cpio_list)) {
633 int type_idx;
634 size_t slen = strlen(line);
635
636 line_nr++;
637
638 if ('#' == *line) {
639 /* comment - skip to next line */
640 continue;
641 }
642
643 if (! (type = strtok(line, " \t"))) {
644 fprintf(stderr,
645 "ERROR: incorrect format, could not locate file type line %d: '%s'\n",
646 line_nr, line);
647 ec = -1;
Jesper Juhlaa1e8162006-04-18 22:21:54 -0700648 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 }
650
651 if ('\n' == *type) {
652 /* a blank line */
653 continue;
654 }
655
656 if (slen == strlen(type)) {
657 /* must be an empty line */
658 continue;
659 }
660
661 if (! (args = strtok(NULL, "\n"))) {
662 fprintf(stderr,
663 "ERROR: incorrect format, newline required line %d: '%s'\n",
664 line_nr, line);
665 ec = -1;
666 }
667
668 for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
669 int rc;
670 if (! strcmp(line, file_handler_table[type_idx].type)) {
671 if ((rc = file_handler_table[type_idx].handler(args))) {
672 ec = rc;
673 fprintf(stderr, " line %d\n", line_nr);
674 }
675 break;
676 }
677 }
678
679 if (NULL == file_handler_table[type_idx].type) {
680 fprintf(stderr, "unknown file type line %d: '%s'\n",
681 line_nr, line);
682 }
683 }
Jesper Juhlaa1e8162006-04-18 22:21:54 -0700684 if (ec == 0)
685 cpio_trailer();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
687 exit(ec);
688}