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