xref: /linux/usr/gen_init_cpio.c (revision c04022dccb2f9cf2b1cfe65807149500d1fc080a)
1 // SPDX-License-Identifier: GPL-2.0
2 #define _GNU_SOURCE
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <stdint.h>
6 #include <stdbool.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <time.h>
12 #include <fcntl.h>
13 #include <errno.h>
14 #include <ctype.h>
15 #include <limits.h>
16 
17 /*
18  * Original work by Jeff Garzik
19  *
20  * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
21  * Hard link support by Luciano Rocha
22  */
23 
24 #define xstr(s) #s
25 #define str(s) xstr(s)
26 #define MIN(a, b) ((a) < (b) ? (a) : (b))
27 #define CPIO_HDR_LEN 110
28 #define CPIO_TRAILER "TRAILER!!!"
29 #define padlen(_off, _align) (((_align) - ((_off) & ((_align) - 1))) % (_align))
30 
31 /* zero-padding the filename field for data alignment is limited by PATH_MAX */
32 static char padding[PATH_MAX];
33 static unsigned int offset;
34 static unsigned int ino = 721;
35 static time_t default_mtime;
36 static bool do_file_mtime;
37 static bool do_csum = false;
38 static int outfd = STDOUT_FILENO;
39 static unsigned int dalign;
40 
41 struct file_handler {
42 	const char *type;
43 	int (*handler)(const char *line);
44 };
45 
push_buf(const char * name,size_t name_len)46 static int push_buf(const char *name, size_t name_len)
47 {
48 	ssize_t len;
49 
50 	len = write(outfd, name, name_len);
51 	if (len != name_len)
52 		return -1;
53 
54 	offset += name_len;
55 	return 0;
56 }
57 
push_pad(size_t padlen)58 static int push_pad(size_t padlen)
59 {
60 	ssize_t len = 0;
61 
62 	if (!padlen)
63 		return 0;
64 
65 	if (padlen < sizeof(padding))
66 		len = write(outfd, padding, padlen);
67 	if (len != padlen)
68 		return -1;
69 
70 	offset += padlen;
71 	return 0;
72 }
73 
push_rest(const char * name,size_t name_len)74 static int push_rest(const char *name, size_t name_len)
75 {
76 	ssize_t len;
77 
78 	len = write(outfd, name, name_len);
79 	if (len != name_len)
80 		return -1;
81 
82 	offset += name_len;
83 
84 	return push_pad(padlen(name_len + CPIO_HDR_LEN, 4));
85 }
86 
cpio_trailer(void)87 static int cpio_trailer(void)
88 {
89 	int len;
90 	unsigned int namesize = sizeof(CPIO_TRAILER);
91 
92 	len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
93 	       "%08X%08X%08X%08X%08X%08X%08X",
94 		do_csum ? "070702" : "070701", /* magic */
95 		0,			/* ino */
96 		0,			/* mode */
97 		(long) 0,		/* uid */
98 		(long) 0,		/* gid */
99 		1,			/* nlink */
100 		(long) 0,		/* mtime */
101 		0,			/* filesize */
102 		0,			/* major */
103 		0,			/* minor */
104 		0,			/* rmajor */
105 		0,			/* rminor */
106 		namesize,		/* namesize */
107 		0);			/* chksum */
108 	offset += len;
109 
110 	if (len != CPIO_HDR_LEN ||
111 	    push_rest(CPIO_TRAILER, namesize) < 0 ||
112 	    push_pad(padlen(offset, 512)) < 0)
113 		return -1;
114 
115 	if (fsync(outfd) < 0 && errno != EINVAL)
116 		return -1;
117 
118 	return 0;
119 }
120 
cpio_mkslink(const char * name,const char * target,unsigned int mode,uid_t uid,gid_t gid)121 static int cpio_mkslink(const char *name, const char *target,
122 			 unsigned int mode, uid_t uid, gid_t gid)
123 {
124 	int len;
125 	unsigned int namesize, targetsize = strlen(target) + 1;
126 
127 	if (name[0] == '/')
128 		name++;
129 	namesize = strlen(name) + 1;
130 
131 	len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
132 	       "%08X%08X%08X%08X%08X%08X%08X",
133 		do_csum ? "070702" : "070701", /* magic */
134 		ino++,			/* ino */
135 		S_IFLNK | mode,		/* mode */
136 		(long) uid,		/* uid */
137 		(long) gid,		/* gid */
138 		1,			/* nlink */
139 		(long) default_mtime,	/* mtime */
140 		targetsize,		/* filesize */
141 		3,			/* major */
142 		1,			/* minor */
143 		0,			/* rmajor */
144 		0,			/* rminor */
145 		namesize,		/* namesize */
146 		0);			/* chksum */
147 	offset += len;
148 
149 	if (len != CPIO_HDR_LEN ||
150 	    push_buf(name, namesize) < 0 ||
151 	    push_pad(padlen(offset, 4)) < 0 ||
152 	    push_buf(target, targetsize) < 0 ||
153 	    push_pad(padlen(offset, 4)) < 0)
154 		return -1;
155 
156 	return 0;
157 
158 }
159 
cpio_mkslink_line(const char * line)160 static int cpio_mkslink_line(const char *line)
161 {
162 	char name[PATH_MAX + 1];
163 	char target[PATH_MAX + 1];
164 	unsigned int mode;
165 	int uid;
166 	int gid;
167 	int rc = -1;
168 
169 	if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
170 		fprintf(stderr, "Unrecognized dir format '%s'", line);
171 		goto fail;
172 	}
173 	rc = cpio_mkslink(name, target, mode, uid, gid);
174  fail:
175 	return rc;
176 }
177 
cpio_mkgeneric(const char * name,unsigned int mode,uid_t uid,gid_t gid)178 static int cpio_mkgeneric(const char *name, unsigned int mode,
179 		       uid_t uid, gid_t gid)
180 {
181 	int len;
182 	unsigned int namesize;
183 
184 	if (name[0] == '/')
185 		name++;
186 	namesize = strlen(name) + 1;
187 
188 	len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
189 	       "%08X%08X%08X%08X%08X%08X%08X",
190 		do_csum ? "070702" : "070701", /* magic */
191 		ino++,			/* ino */
192 		mode,			/* mode */
193 		(long) uid,		/* uid */
194 		(long) gid,		/* gid */
195 		2,			/* nlink */
196 		(long) default_mtime,	/* mtime */
197 		0,			/* filesize */
198 		3,			/* major */
199 		1,			/* minor */
200 		0,			/* rmajor */
201 		0,			/* rminor */
202 		namesize,		/* namesize */
203 		0);			/* chksum */
204 	offset += len;
205 
206 	if (len != CPIO_HDR_LEN ||
207 	    push_rest(name, namesize) < 0)
208 		return -1;
209 
210 	return 0;
211 }
212 
213 enum generic_types {
214 	GT_DIR,
215 	GT_PIPE,
216 	GT_SOCK
217 };
218 
219 struct generic_type {
220 	const char *type;
221 	mode_t mode;
222 };
223 
224 static const struct generic_type generic_type_table[] = {
225 	[GT_DIR] = {
226 		.type = "dir",
227 		.mode = S_IFDIR
228 	},
229 	[GT_PIPE] = {
230 		.type = "pipe",
231 		.mode = S_IFIFO
232 	},
233 	[GT_SOCK] = {
234 		.type = "sock",
235 		.mode = S_IFSOCK
236 	}
237 };
238 
cpio_mkgeneric_line(const char * line,enum generic_types gt)239 static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
240 {
241 	char name[PATH_MAX + 1];
242 	unsigned int mode;
243 	int uid;
244 	int gid;
245 	int rc = -1;
246 
247 	if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
248 		fprintf(stderr, "Unrecognized %s format '%s'",
249 			line, generic_type_table[gt].type);
250 		goto fail;
251 	}
252 	mode |= generic_type_table[gt].mode;
253 	rc = cpio_mkgeneric(name, mode, uid, gid);
254  fail:
255 	return rc;
256 }
257 
cpio_mkdir_line(const char * line)258 static int cpio_mkdir_line(const char *line)
259 {
260 	return cpio_mkgeneric_line(line, GT_DIR);
261 }
262 
cpio_mkpipe_line(const char * line)263 static int cpio_mkpipe_line(const char *line)
264 {
265 	return cpio_mkgeneric_line(line, GT_PIPE);
266 }
267 
cpio_mksock_line(const char * line)268 static int cpio_mksock_line(const char *line)
269 {
270 	return cpio_mkgeneric_line(line, GT_SOCK);
271 }
272 
cpio_mknod(const char * name,unsigned int mode,uid_t uid,gid_t gid,char dev_type,unsigned int maj,unsigned int min)273 static int cpio_mknod(const char *name, unsigned int mode,
274 		       uid_t uid, gid_t gid, char dev_type,
275 		       unsigned int maj, unsigned int min)
276 {
277 	int len;
278 	unsigned int namesize;
279 
280 	if (dev_type == 'b')
281 		mode |= S_IFBLK;
282 	else
283 		mode |= S_IFCHR;
284 
285 	if (name[0] == '/')
286 		name++;
287 	namesize = strlen(name) + 1;
288 
289 	len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
290 	       "%08X%08X%08X%08X%08X%08X%08X",
291 		do_csum ? "070702" : "070701", /* magic */
292 		ino++,			/* ino */
293 		mode,			/* mode */
294 		(long) uid,		/* uid */
295 		(long) gid,		/* gid */
296 		1,			/* nlink */
297 		(long) default_mtime,	/* mtime */
298 		0,			/* filesize */
299 		3,			/* major */
300 		1,			/* minor */
301 		maj,			/* rmajor */
302 		min,			/* rminor */
303 		namesize,		/* namesize */
304 		0);			/* chksum */
305 	offset += len;
306 
307 	if (len != CPIO_HDR_LEN ||
308 	    push_rest(name, namesize) < 0)
309 		return -1;
310 
311 	return 0;
312 }
313 
cpio_mknod_line(const char * line)314 static int cpio_mknod_line(const char *line)
315 {
316 	char name[PATH_MAX + 1];
317 	unsigned int mode;
318 	int uid;
319 	int gid;
320 	char dev_type;
321 	unsigned int maj;
322 	unsigned int min;
323 	int rc = -1;
324 
325 	if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
326 			 name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
327 		fprintf(stderr, "Unrecognized nod format '%s'", line);
328 		goto fail;
329 	}
330 	rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
331  fail:
332 	return rc;
333 }
334 
cpio_mkfile_csum(int fd,unsigned long size,uint32_t * csum)335 static int cpio_mkfile_csum(int fd, unsigned long size, uint32_t *csum)
336 {
337 	while (size) {
338 		unsigned char filebuf[65536];
339 		ssize_t this_read;
340 		size_t i, this_size = MIN(size, sizeof(filebuf));
341 
342 		this_read = read(fd, filebuf, this_size);
343 		if (this_read <= 0 || this_read > this_size)
344 			return -1;
345 
346 		for (i = 0; i < this_read; i++)
347 			*csum += filebuf[i];
348 
349 		size -= this_read;
350 	}
351 	/* seek back to the start for data segment I/O */
352 	if (lseek(fd, 0, SEEK_SET) < 0)
353 		return -1;
354 
355 	return 0;
356 }
357 
cpio_mkfile(const char * name,const char * location,unsigned int mode,uid_t uid,gid_t gid,unsigned int nlinks)358 static int cpio_mkfile(const char *name, const char *location,
359 			unsigned int mode, uid_t uid, gid_t gid,
360 			unsigned int nlinks)
361 {
362 	struct stat buf;
363 	unsigned long size;
364 	int file, retval, len;
365 	int rc = -1;
366 	time_t mtime;
367 	int namesize, namepadlen;
368 	unsigned int i;
369 	uint32_t csum = 0;
370 	ssize_t this_read;
371 
372 	mode |= S_IFREG;
373 
374 	file = open (location, O_RDONLY);
375 	if (file < 0) {
376 		fprintf (stderr, "File %s could not be opened for reading\n", location);
377 		goto error;
378 	}
379 
380 	retval = fstat(file, &buf);
381 	if (retval) {
382 		fprintf(stderr, "File %s could not be stat()'ed\n", location);
383 		goto error;
384 	}
385 
386 	if (do_file_mtime) {
387 		mtime = default_mtime;
388 	} else {
389 		mtime = buf.st_mtime;
390 		if (mtime > 0xffffffff) {
391 			fprintf(stderr, "%s: Timestamp exceeds maximum cpio timestamp, clipping.\n",
392 					location);
393 			mtime = 0xffffffff;
394 		}
395 
396 		if (mtime < 0) {
397 			fprintf(stderr, "%s: Timestamp negative, clipping.\n",
398 					location);
399 			mtime = 0;
400 		}
401 	}
402 
403 	if (buf.st_size > 0xffffffff) {
404 		fprintf(stderr, "%s: Size exceeds maximum cpio file size\n",
405 			location);
406 		goto error;
407 	}
408 
409 	if (do_csum && cpio_mkfile_csum(file, buf.st_size, &csum) < 0) {
410 		fprintf(stderr, "Failed to checksum file %s\n", location);
411 		goto error;
412 	}
413 
414 	size = 0;
415 	namepadlen = 0;
416 	for (i = 1; i <= nlinks; i++) {
417 		if (name[0] == '/')
418 			name++;
419 		namesize = strlen(name) + 1;
420 
421 		/* data goes on last link, after any alignment padding */
422 		if (i == nlinks)
423 			size = buf.st_size;
424 
425 		if (dalign && size > dalign) {
426 			namepadlen = padlen(offset + CPIO_HDR_LEN + namesize,
427 					    dalign);
428 			if (namesize + namepadlen > PATH_MAX) {
429 				fprintf(stderr,
430 					"%s: best-effort alignment %u missed\n",
431 					name, dalign);
432 				namepadlen = 0;
433 			}
434 		}
435 
436 		len = dprintf(outfd, "%s%08X%08X%08lX%08lX%08X%08lX"
437 		       "%08lX%08X%08X%08X%08X%08X%08X",
438 			do_csum ? "070702" : "070701", /* magic */
439 			ino,			/* ino */
440 			mode,			/* mode */
441 			(long) uid,		/* uid */
442 			(long) gid,		/* gid */
443 			nlinks,			/* nlink */
444 			(long) mtime,		/* mtime */
445 			size,			/* filesize */
446 			3,			/* major */
447 			1,			/* minor */
448 			0,			/* rmajor */
449 			0,			/* rminor */
450 			namesize + namepadlen,	/* namesize */
451 			size ? csum : 0);	/* chksum */
452 		offset += len;
453 
454 		if (len != CPIO_HDR_LEN ||
455 		    push_buf(name, namesize) < 0 ||
456 		    push_pad(namepadlen ? namepadlen : padlen(offset, 4)) < 0)
457 			goto error;
458 
459 		if (size) {
460 			this_read = copy_file_range(file, NULL, outfd, NULL, size, 0);
461 			if (this_read > 0) {
462 				if (this_read > size)
463 					goto error;
464 				offset += this_read;
465 				size -= this_read;
466 			}
467 			/* short or failed copy falls back to read/write... */
468 		}
469 
470 		while (size) {
471 			unsigned char filebuf[65536];
472 			size_t this_size = MIN(size, sizeof(filebuf));
473 
474 			this_read = read(file, filebuf, this_size);
475 			if (this_read <= 0 || this_read > this_size) {
476 				fprintf(stderr, "Can not read %s file\n", location);
477 				goto error;
478 			}
479 
480 			if (write(outfd, filebuf, this_read) != this_read) {
481 				fprintf(stderr, "writing filebuf failed\n");
482 				goto error;
483 			}
484 			offset += this_read;
485 			size -= this_read;
486 		}
487 		if (push_pad(padlen(offset, 4)) < 0)
488 			goto error;
489 
490 		name += namesize;
491 	}
492 	ino++;
493 	rc = 0;
494 
495 error:
496 	if (file >= 0)
497 		close(file);
498 	return rc;
499 }
500 
cpio_replace_env(char * new_location)501 static char *cpio_replace_env(char *new_location)
502 {
503 	char expanded[PATH_MAX + 1];
504 	char *start, *end, *var;
505 
506 	while ((start = strstr(new_location, "${")) &&
507 	       (end = strchr(start + 2, '}'))) {
508 		*start = *end = 0;
509 		var = getenv(start + 2);
510 		snprintf(expanded, sizeof expanded, "%s%s%s",
511 			 new_location, var ? var : "", end + 1);
512 		strcpy(new_location, expanded);
513 	}
514 
515 	return new_location;
516 }
517 
cpio_mkfile_line(const char * line)518 static int cpio_mkfile_line(const char *line)
519 {
520 	char name[PATH_MAX + 1];
521 	char *dname = NULL; /* malloc'ed buffer for hard links */
522 	char location[PATH_MAX + 1];
523 	unsigned int mode;
524 	int uid;
525 	int gid;
526 	int nlinks = 1;
527 	int end = 0, dname_len = 0;
528 	int rc = -1;
529 
530 	if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
531 				"s %o %d %d %n",
532 				name, location, &mode, &uid, &gid, &end)) {
533 		fprintf(stderr, "Unrecognized file format '%s'", line);
534 		goto fail;
535 	}
536 	if (end && isgraph(line[end])) {
537 		int len;
538 		int nend;
539 
540 		dname = malloc(strlen(line));
541 		if (!dname) {
542 			fprintf (stderr, "out of memory (%d)\n", dname_len);
543 			goto fail;
544 		}
545 
546 		dname_len = strlen(name) + 1;
547 		memcpy(dname, name, dname_len);
548 
549 		do {
550 			nend = 0;
551 			if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
552 					name, &nend) < 1)
553 				break;
554 			len = strlen(name) + 1;
555 			memcpy(dname + dname_len, name, len);
556 			dname_len += len;
557 			nlinks++;
558 			end += nend;
559 		} while (isgraph(line[end]));
560 	} else {
561 		dname = name;
562 	}
563 	rc = cpio_mkfile(dname, cpio_replace_env(location),
564 	                 mode, uid, gid, nlinks);
565  fail:
566 	if (dname_len) free(dname);
567 	return rc;
568 }
569 
usage(const char * prog)570 static void usage(const char *prog)
571 {
572 	fprintf(stderr, "Usage:\n"
573 		"\t%s [-t <timestamp>] [-c] [-o <output_file>] [-a <data_align>] <cpio_list>\n"
574 		"\n"
575 		"<cpio_list> is a file containing newline separated entries that\n"
576 		"describe the files to be included in the initramfs archive:\n"
577 		"\n"
578 		"# a comment\n"
579 		"file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
580 		"dir <name> <mode> <uid> <gid>\n"
581 		"nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
582 		"slink <name> <target> <mode> <uid> <gid>\n"
583 		"pipe <name> <mode> <uid> <gid>\n"
584 		"sock <name> <mode> <uid> <gid>\n"
585 		"\n"
586 		"<name>       name of the file/dir/nod/etc in the archive\n"
587 		"<location>   location of the file in the current filesystem\n"
588 		"             expands shell variables quoted with ${}\n"
589 		"<target>     link target\n"
590 		"<mode>       mode/permissions of the file\n"
591 		"<uid>        user id (0=root)\n"
592 		"<gid>        group id (0=root)\n"
593 		"<dev_type>   device type (b=block, c=character)\n"
594 		"<maj>        major number of nod\n"
595 		"<min>        minor number of nod\n"
596 		"<hard links> space separated list of other links to file\n"
597 		"\n"
598 		"example:\n"
599 		"# A simple initramfs\n"
600 		"dir /dev 0755 0 0\n"
601 		"nod /dev/console 0600 0 0 c 5 1\n"
602 		"dir /root 0700 0 0\n"
603 		"dir /sbin 0755 0 0\n"
604 		"file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
605 		"\n"
606 		"<timestamp> is time in seconds since Epoch that will be used\n"
607 		"as mtime for symlinks, directories, regular and special files.\n"
608 		"The default is to use the current time for all files, but\n"
609 		"preserve modification time for regular files.\n"
610 		"-c: calculate and store 32-bit checksums for file data.\n"
611 		"<output_file>: write cpio to this file instead of stdout\n"
612 		"<data_align>: attempt to align file data by zero-padding the\n"
613 		"filename field up to data_align. Must be a multiple of 4.\n"
614 		"Alignment is best-effort; PATH_MAX limits filename padding.\n",
615 		prog);
616 }
617 
618 static const struct file_handler file_handler_table[] = {
619 	{
620 		.type    = "file",
621 		.handler = cpio_mkfile_line,
622 	}, {
623 		.type    = "nod",
624 		.handler = cpio_mknod_line,
625 	}, {
626 		.type    = "dir",
627 		.handler = cpio_mkdir_line,
628 	}, {
629 		.type    = "slink",
630 		.handler = cpio_mkslink_line,
631 	}, {
632 		.type    = "pipe",
633 		.handler = cpio_mkpipe_line,
634 	}, {
635 		.type    = "sock",
636 		.handler = cpio_mksock_line,
637 	}, {
638 		.type    = NULL,
639 		.handler = NULL,
640 	}
641 };
642 
643 #define LINE_SIZE (2 * PATH_MAX + 50)
644 
main(int argc,char * argv[])645 int main (int argc, char *argv[])
646 {
647 	FILE *cpio_list;
648 	char line[LINE_SIZE];
649 	char *args, *type;
650 	int ec = 0;
651 	int line_nr = 0;
652 	const char *filename;
653 
654 	default_mtime = time(NULL);
655 	while (1) {
656 		int opt = getopt(argc, argv, "t:cho:a:");
657 		char *invalid;
658 
659 		if (opt == -1)
660 			break;
661 		switch (opt) {
662 		case 't':
663 			default_mtime = strtol(optarg, &invalid, 10);
664 			if (!*optarg || *invalid) {
665 				fprintf(stderr, "Invalid timestamp: %s\n",
666 						optarg);
667 				usage(argv[0]);
668 				exit(1);
669 			}
670 			do_file_mtime = true;
671 			break;
672 		case 'c':
673 			do_csum = true;
674 			break;
675 		case 'o':
676 			outfd = open(optarg,
677 				     O_WRONLY | O_CREAT | O_LARGEFILE | O_TRUNC,
678 				     0600);
679 			if (outfd < 0) {
680 				fprintf(stderr, "failed to open %s\n", optarg);
681 				usage(argv[0]);
682 				exit(1);
683 			}
684 			break;
685 		case 'a':
686 			dalign = strtoul(optarg, &invalid, 10);
687 			if (!*optarg || *invalid || (dalign & 3)) {
688 				fprintf(stderr, "Invalid data_align: %s\n",
689 						optarg);
690 				usage(argv[0]);
691 				exit(1);
692 			}
693 			break;
694 		case 'h':
695 		case '?':
696 			usage(argv[0]);
697 			exit(opt == 'h' ? 0 : 1);
698 		}
699 	}
700 
701 	/*
702 	 * Timestamps after 2106-02-07 06:28:15 UTC have an ascii hex time_t
703 	 * representation that exceeds 8 chars and breaks the cpio header
704 	 * specification. Negative timestamps similarly exceed 8 chars.
705 	 */
706 	if (default_mtime > 0xffffffff || default_mtime < 0) {
707 		fprintf(stderr, "ERROR: Timestamp out of range for cpio format\n");
708 		exit(1);
709 	}
710 
711 	if (argc - optind != 1) {
712 		usage(argv[0]);
713 		exit(1);
714 	}
715 	filename = argv[optind];
716 	if (!strcmp(filename, "-"))
717 		cpio_list = stdin;
718 	else if (!(cpio_list = fopen(filename, "r"))) {
719 		fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
720 			filename, strerror(errno));
721 		usage(argv[0]);
722 		exit(1);
723 	}
724 
725 	while (fgets(line, LINE_SIZE, cpio_list)) {
726 		int type_idx;
727 		size_t slen = strlen(line);
728 
729 		line_nr++;
730 
731 		if ('#' == *line) {
732 			/* comment - skip to next line */
733 			continue;
734 		}
735 
736 		if (! (type = strtok(line, " \t"))) {
737 			fprintf(stderr,
738 				"ERROR: incorrect format, could not locate file type line %d: '%s'\n",
739 				line_nr, line);
740 			ec = -1;
741 			break;
742 		}
743 
744 		if ('\n' == *type) {
745 			/* a blank line */
746 			continue;
747 		}
748 
749 		if (slen == strlen(type)) {
750 			/* must be an empty line */
751 			continue;
752 		}
753 
754 		if (! (args = strtok(NULL, "\n"))) {
755 			fprintf(stderr,
756 				"ERROR: incorrect format, newline required line %d: '%s'\n",
757 				line_nr, line);
758 			ec = -1;
759 		}
760 
761 		for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
762 			int rc;
763 			if (! strcmp(line, file_handler_table[type_idx].type)) {
764 				if ((rc = file_handler_table[type_idx].handler(args))) {
765 					ec = rc;
766 					fprintf(stderr, " line %d\n", line_nr);
767 				}
768 				break;
769 			}
770 		}
771 
772 		if (NULL == file_handler_table[type_idx].type) {
773 			fprintf(stderr, "unknown file type line %d: '%s'\n",
774 				line_nr, line);
775 		}
776 	}
777 	if (ec == 0)
778 		ec = cpio_trailer();
779 
780 	exit(ec);
781 }
782