Linux Audio

Check our new training course

Embedded Linux training

Mar 10-20, 2025, special US time zones
Register
Loading...
v3.1
 
  1#include <stdio.h>
  2#include <stdlib.h>
  3#include <sys/types.h>
  4#include <sys/stat.h>
  5#include <string.h>
  6#include <unistd.h>
  7#include <time.h>
  8#include <fcntl.h>
  9#include <errno.h>
 10#include <ctype.h>
 11#include <limits.h>
 12
 13/*
 14 * Original work by Jeff Garzik
 15 *
 16 * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
 17 * Hard link support by Luciano Rocha
 18 */
 19
 20#define xstr(s) #s
 21#define str(s) xstr(s)
 22
 23static unsigned int offset;
 24static unsigned int ino = 721;
 25static time_t default_mtime;
 26
 27struct file_handler {
 28	const char *type;
 29	int (*handler)(const char *line);
 30};
 31
 32static void push_string(const char *name)
 33{
 34	unsigned int name_len = strlen(name) + 1;
 35
 36	fputs(name, stdout);
 37	putchar(0);
 38	offset += name_len;
 39}
 40
 41static void push_pad (void)
 42{
 43	while (offset & 3) {
 44		putchar(0);
 45		offset++;
 46	}
 47}
 48
 49static void push_rest(const char *name)
 50{
 51	unsigned int name_len = strlen(name) + 1;
 52	unsigned int tmp_ofs;
 53
 54	fputs(name, stdout);
 55	putchar(0);
 56	offset += name_len;
 57
 58	tmp_ofs = name_len + 110;
 59	while (tmp_ofs & 3) {
 60		putchar(0);
 61		offset++;
 62		tmp_ofs++;
 63	}
 64}
 65
 66static void push_hdr(const char *s)
 67{
 68	fputs(s, stdout);
 69	offset += 110;
 70}
 71
 72static void cpio_trailer(void)
 73{
 74	char s[256];
 75	const char name[] = "TRAILER!!!";
 76
 77	sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
 78	       "%08X%08X%08X%08X%08X%08X%08X",
 79		"070701",		/* magic */
 80		0,			/* ino */
 81		0,			/* mode */
 82		(long) 0,		/* uid */
 83		(long) 0,		/* gid */
 84		1,			/* nlink */
 85		(long) 0,		/* mtime */
 86		0,			/* filesize */
 87		0,			/* major */
 88		0,			/* minor */
 89		0,			/* rmajor */
 90		0,			/* rminor */
 91		(unsigned)strlen(name)+1, /* namesize */
 92		0);			/* chksum */
 93	push_hdr(s);
 94	push_rest(name);
 95
 96	while (offset % 512) {
 97		putchar(0);
 98		offset++;
 99	}
100}
101
102static int cpio_mkslink(const char *name, const char *target,
103			 unsigned int mode, uid_t uid, gid_t gid)
104{
105	char s[256];
106
107	if (name[0] == '/')
108		name++;
109	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
110	       "%08X%08X%08X%08X%08X%08X%08X",
111		"070701",		/* magic */
112		ino++,			/* ino */
113		S_IFLNK | mode,		/* mode */
114		(long) uid,		/* uid */
115		(long) gid,		/* gid */
116		1,			/* nlink */
117		(long) default_mtime,	/* mtime */
118		(unsigned)strlen(target)+1, /* filesize */
119		3,			/* major */
120		1,			/* minor */
121		0,			/* rmajor */
122		0,			/* rminor */
123		(unsigned)strlen(name) + 1,/* namesize */
124		0);			/* chksum */
125	push_hdr(s);
126	push_string(name);
127	push_pad();
128	push_string(target);
129	push_pad();
130	return 0;
131}
132
133static int cpio_mkslink_line(const char *line)
134{
135	char name[PATH_MAX + 1];
136	char target[PATH_MAX + 1];
137	unsigned int mode;
138	int uid;
139	int gid;
140	int rc = -1;
141
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);
144		goto fail;
145	}
146	rc = cpio_mkslink(name, target, mode, uid, gid);
147 fail:
148	return rc;
149}
150
151static int cpio_mkgeneric(const char *name, unsigned int mode,
152		       uid_t uid, gid_t gid)
153{
154	char s[256];
155
156	if (name[0] == '/')
157		name++;
158	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
159	       "%08X%08X%08X%08X%08X%08X%08X",
160		"070701",		/* magic */
161		ino++,			/* ino */
162		mode,			/* mode */
163		(long) uid,		/* uid */
164		(long) gid,		/* gid */
165		2,			/* nlink */
166		(long) default_mtime,	/* mtime */
167		0,			/* filesize */
168		3,			/* major */
169		1,			/* minor */
170		0,			/* rmajor */
171		0,			/* rminor */
172		(unsigned)strlen(name) + 1,/* namesize */
173		0);			/* chksum */
174	push_hdr(s);
175	push_rest(name);
176	return 0;
177}
178
179enum generic_types {
180	GT_DIR,
181	GT_PIPE,
182	GT_SOCK
183};
184
185struct generic_type {
186	const char *type;
187	mode_t mode;
188};
189
190static struct generic_type generic_type_table[] = {
191	[GT_DIR] = {
192		.type = "dir",
193		.mode = S_IFDIR
194	},
195	[GT_PIPE] = {
196		.type = "pipe",
197		.mode = S_IFIFO
198	},
199	[GT_SOCK] = {
200		.type = "sock",
201		.mode = S_IFSOCK
202	}
203};
204
205static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
206{
207	char name[PATH_MAX + 1];
208	unsigned int mode;
209	int uid;
210	int gid;
211	int rc = -1;
212
213	if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
214		fprintf(stderr, "Unrecognized %s format '%s'",
215			line, generic_type_table[gt].type);
216		goto fail;
217	}
218	mode |= generic_type_table[gt].mode;
219	rc = cpio_mkgeneric(name, mode, uid, gid);
220 fail:
221	return rc;
222}
223
224static int cpio_mkdir_line(const char *line)
225{
226	return cpio_mkgeneric_line(line, GT_DIR);
227}
228
229static int cpio_mkpipe_line(const char *line)
230{
231	return cpio_mkgeneric_line(line, GT_PIPE);
232}
233
234static int cpio_mksock_line(const char *line)
235{
236	return cpio_mkgeneric_line(line, GT_SOCK);
237}
238
239static int cpio_mknod(const char *name, unsigned int mode,
240		       uid_t uid, gid_t gid, char dev_type,
241		       unsigned int maj, unsigned int min)
242{
243	char s[256];
244
245	if (dev_type == 'b')
246		mode |= S_IFBLK;
247	else
248		mode |= S_IFCHR;
249
250	if (name[0] == '/')
251		name++;
252	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
253	       "%08X%08X%08X%08X%08X%08X%08X",
254		"070701",		/* magic */
255		ino++,			/* ino */
256		mode,			/* mode */
257		(long) uid,		/* uid */
258		(long) gid,		/* gid */
259		1,			/* nlink */
260		(long) default_mtime,	/* mtime */
261		0,			/* filesize */
262		3,			/* major */
263		1,			/* minor */
264		maj,			/* rmajor */
265		min,			/* rminor */
266		(unsigned)strlen(name) + 1,/* namesize */
267		0);			/* chksum */
268	push_hdr(s);
269	push_rest(name);
270	return 0;
271}
272
273static int cpio_mknod_line(const char *line)
274{
275	char name[PATH_MAX + 1];
276	unsigned int mode;
277	int uid;
278	int gid;
279	char dev_type;
280	unsigned int maj;
281	unsigned int min;
282	int rc = -1;
283
284	if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
285			 name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
286		fprintf(stderr, "Unrecognized nod format '%s'", line);
287		goto fail;
288	}
289	rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
290 fail:
291	return rc;
292}
293
294static int cpio_mkfile(const char *name, const char *location,
295			unsigned int mode, uid_t uid, gid_t gid,
296			unsigned int nlinks)
297{
298	char s[256];
299	char *filebuf = NULL;
300	struct stat buf;
301	long size;
302	int file = -1;
303	int retval;
304	int rc = -1;
305	int namesize;
306	int i;
307
308	mode |= S_IFREG;
309
310	file = open (location, O_RDONLY);
311	if (file < 0) {
312		fprintf (stderr, "File %s could not be opened for reading\n", location);
313		goto error;
314	}
315
316	retval = fstat(file, &buf);
317	if (retval) {
318		fprintf(stderr, "File %s could not be stat()'ed\n", location);
319		goto error;
320	}
321
322	filebuf = malloc(buf.st_size);
323	if (!filebuf) {
324		fprintf (stderr, "out of memory\n");
325		goto error;
326	}
327
328	retval = read (file, filebuf, buf.st_size);
329	if (retval < 0) {
330		fprintf (stderr, "Can not read %s file\n", location);
331		goto error;
332	}
333
334	size = 0;
335	for (i = 1; i <= nlinks; i++) {
336		/* data goes on last link */
337		if (i == nlinks) size = buf.st_size;
338
339		if (name[0] == '/')
340			name++;
341		namesize = strlen(name) + 1;
342		sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
343		       "%08lX%08X%08X%08X%08X%08X%08X",
344			"070701",		/* magic */
345			ino,			/* ino */
346			mode,			/* mode */
347			(long) uid,		/* uid */
348			(long) gid,		/* gid */
349			nlinks,			/* nlink */
350			(long) buf.st_mtime,	/* mtime */
351			size,			/* filesize */
352			3,			/* major */
353			1,			/* minor */
354			0,			/* rmajor */
355			0,			/* rminor */
356			namesize,		/* namesize */
357			0);			/* chksum */
358		push_hdr(s);
359		push_string(name);
360		push_pad();
361
362		if (size) {
363			if (fwrite(filebuf, size, 1, stdout) != 1) {
364				fprintf(stderr, "writing filebuf failed\n");
365				goto error;
366			}
367			offset += size;
368			push_pad();
369		}
370
371		name += namesize;
372	}
373	ino++;
374	rc = 0;
375	
376error:
377	if (filebuf) free(filebuf);
378	if (file >= 0) close(file);
379	return rc;
380}
381
382static char *cpio_replace_env(char *new_location)
383{
384       char expanded[PATH_MAX + 1];
385       char env_var[PATH_MAX + 1];
386       char *start;
387       char *end;
388
389       for (start = NULL; (start = strstr(new_location, "${")); ) {
390               end = strchr(start, '}');
391               if (start < end) {
392                       *env_var = *expanded = '\0';
393                       strncat(env_var, start + 2, end - start - 2);
394                       strncat(expanded, new_location, start - new_location);
395                       strncat(expanded, getenv(env_var), PATH_MAX);
396                       strncat(expanded, end + 1, PATH_MAX);
397                       strncpy(new_location, expanded, PATH_MAX);
398               } else
399                       break;
400       }
401
402       return new_location;
403}
 
 
 
 
 
 
404
 
 
405
406static int cpio_mkfile_line(const char *line)
407{
408	char name[PATH_MAX + 1];
409	char *dname = NULL; /* malloc'ed buffer for hard links */
410	char location[PATH_MAX + 1];
411	unsigned int mode;
412	int uid;
413	int gid;
414	int nlinks = 1;
415	int end = 0, dname_len = 0;
416	int rc = -1;
417
418	if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
419				"s %o %d %d %n",
420				name, location, &mode, &uid, &gid, &end)) {
421		fprintf(stderr, "Unrecognized file format '%s'", line);
422		goto fail;
423	}
424	if (end && isgraph(line[end])) {
425		int len;
426		int nend;
427
428		dname = malloc(strlen(line));
429		if (!dname) {
430			fprintf (stderr, "out of memory (%d)\n", dname_len);
431			goto fail;
432		}
433
434		dname_len = strlen(name) + 1;
435		memcpy(dname, name, dname_len);
436
437		do {
438			nend = 0;
439			if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
440					name, &nend) < 1)
441				break;
442			len = strlen(name) + 1;
443			memcpy(dname + dname_len, name, len);
444			dname_len += len;
445			nlinks++;
446			end += nend;
447		} while (isgraph(line[end]));
448	} else {
449		dname = name;
450	}
451	rc = cpio_mkfile(dname, cpio_replace_env(location),
452	                 mode, uid, gid, nlinks);
453 fail:
454	if (dname_len) free(dname);
455	return rc;
456}
457
458static void usage(const char *prog)
459{
460	fprintf(stderr, "Usage:\n"
461		"\t%s [-t <timestamp>] <cpio_list>\n"
462		"\n"
463		"<cpio_list> is a file containing newline separated entries that\n"
464		"describe the files to be included in the initramfs archive:\n"
465		"\n"
466		"# a comment\n"
467		"file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
468		"dir <name> <mode> <uid> <gid>\n"
469		"nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
470		"slink <name> <target> <mode> <uid> <gid>\n"
471		"pipe <name> <mode> <uid> <gid>\n"
472		"sock <name> <mode> <uid> <gid>\n"
473		"\n"
474		"<name>       name of the file/dir/nod/etc in the archive\n"
475		"<location>   location of the file in the current filesystem\n"
476		"             expands shell variables quoted with ${}\n"
477		"<target>     link target\n"
478		"<mode>       mode/permissions of the file\n"
479		"<uid>        user id (0=root)\n"
480		"<gid>        group id (0=root)\n"
481		"<dev_type>   device type (b=block, c=character)\n"
482		"<maj>        major number of nod\n"
483		"<min>        minor number of nod\n"
484		"<hard links> space separated list of other links to file\n"
485		"\n"
486		"example:\n"
487		"# A simple initramfs\n"
488		"dir /dev 0755 0 0\n"
489		"nod /dev/console 0600 0 0 c 5 1\n"
490		"dir /root 0700 0 0\n"
491		"dir /sbin 0755 0 0\n"
492		"file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
493		"\n"
494		"<timestamp> is time in seconds since Epoch that will be used\n"
495		"as mtime for symlinks, special files and directories. The default\n"
496		"is to use the current time for these entries.\n",
497		prog);
498}
499
500struct file_handler file_handler_table[] = {
501	{
502		.type    = "file",
503		.handler = cpio_mkfile_line,
504	}, {
505		.type    = "nod",
506		.handler = cpio_mknod_line,
507	}, {
508		.type    = "dir",
509		.handler = cpio_mkdir_line,
510	}, {
511		.type    = "slink",
512		.handler = cpio_mkslink_line,
513	}, {
514		.type    = "pipe",
515		.handler = cpio_mkpipe_line,
516	}, {
517		.type    = "sock",
518		.handler = cpio_mksock_line,
519	}, {
520		.type    = NULL,
521		.handler = NULL,
522	}
523};
524
525#define LINE_SIZE (2 * PATH_MAX + 50)
526
527int main (int argc, char *argv[])
528{
529	FILE *cpio_list;
530	char line[LINE_SIZE];
531	char *args, *type;
532	int ec = 0;
533	int line_nr = 0;
534	const char *filename;
535
536	default_mtime = time(NULL);
537	while (1) {
538		int opt = getopt(argc, argv, "t:h");
539		char *invalid;
540
541		if (opt == -1)
542			break;
543		switch (opt) {
544		case 't':
545			default_mtime = strtol(optarg, &invalid, 10);
546			if (!*optarg || *invalid) {
547				fprintf(stderr, "Invalid timestamp: %s\n",
548						optarg);
549				usage(argv[0]);
550				exit(1);
551			}
552			break;
553		case 'h':
554		case '?':
555			usage(argv[0]);
556			exit(opt == 'h' ? 0 : 1);
557		}
558	}
559
560	if (argc - optind != 1) {
561		usage(argv[0]);
562		exit(1);
563	}
564	filename = argv[optind];
565	if (!strcmp(filename, "-"))
566		cpio_list = stdin;
567	else if (!(cpio_list = fopen(filename, "r"))) {
568		fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
569			filename, strerror(errno));
570		usage(argv[0]);
571		exit(1);
572	}
573
574	while (fgets(line, LINE_SIZE, cpio_list)) {
575		int type_idx;
576		size_t slen = strlen(line);
577
578		line_nr++;
579
580		if ('#' == *line) {
581			/* comment - skip to next line */
582			continue;
583		}
584
585		if (! (type = strtok(line, " \t"))) {
586			fprintf(stderr,
587				"ERROR: incorrect format, could not locate file type line %d: '%s'\n",
588				line_nr, line);
589			ec = -1;
590			break;
591		}
592
593		if ('\n' == *type) {
594			/* a blank line */
595			continue;
596		}
597
598		if (slen == strlen(type)) {
599			/* must be an empty line */
600			continue;
601		}
602
603		if (! (args = strtok(NULL, "\n"))) {
604			fprintf(stderr,
605				"ERROR: incorrect format, newline required line %d: '%s'\n",
606				line_nr, line);
607			ec = -1;
608		}
609
610		for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
611			int rc;
612			if (! strcmp(line, file_handler_table[type_idx].type)) {
613				if ((rc = file_handler_table[type_idx].handler(args))) {
614					ec = rc;
615					fprintf(stderr, " line %d\n", line_nr);
616				}
617				break;
618			}
619		}
620
621		if (NULL == file_handler_table[type_idx].type) {
622			fprintf(stderr, "unknown file type line %d: '%s'\n",
623				line_nr, line);
624		}
625	}
626	if (ec == 0)
627		cpio_trailer();
628
629	exit(ec);
630}
v5.9
  1// SPDX-License-Identifier: GPL-2.0
  2#include <stdio.h>
  3#include <stdlib.h>
  4#include <sys/types.h>
  5#include <sys/stat.h>
  6#include <string.h>
  7#include <unistd.h>
  8#include <time.h>
  9#include <fcntl.h>
 10#include <errno.h>
 11#include <ctype.h>
 12#include <limits.h>
 13
 14/*
 15 * Original work by Jeff Garzik
 16 *
 17 * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
 18 * Hard link support by Luciano Rocha
 19 */
 20
 21#define xstr(s) #s
 22#define str(s) xstr(s)
 23
 24static unsigned int offset;
 25static unsigned int ino = 721;
 26static time_t default_mtime;
 27
 28struct file_handler {
 29	const char *type;
 30	int (*handler)(const char *line);
 31};
 32
 33static void push_string(const char *name)
 34{
 35	unsigned int name_len = strlen(name) + 1;
 36
 37	fputs(name, stdout);
 38	putchar(0);
 39	offset += name_len;
 40}
 41
 42static void push_pad (void)
 43{
 44	while (offset & 3) {
 45		putchar(0);
 46		offset++;
 47	}
 48}
 49
 50static void push_rest(const char *name)
 51{
 52	unsigned int name_len = strlen(name) + 1;
 53	unsigned int tmp_ofs;
 54
 55	fputs(name, stdout);
 56	putchar(0);
 57	offset += name_len;
 58
 59	tmp_ofs = name_len + 110;
 60	while (tmp_ofs & 3) {
 61		putchar(0);
 62		offset++;
 63		tmp_ofs++;
 64	}
 65}
 66
 67static void push_hdr(const char *s)
 68{
 69	fputs(s, stdout);
 70	offset += 110;
 71}
 72
 73static void cpio_trailer(void)
 74{
 75	char s[256];
 76	const char name[] = "TRAILER!!!";
 77
 78	sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
 79	       "%08X%08X%08X%08X%08X%08X%08X",
 80		"070701",		/* magic */
 81		0,			/* ino */
 82		0,			/* mode */
 83		(long) 0,		/* uid */
 84		(long) 0,		/* gid */
 85		1,			/* nlink */
 86		(long) 0,		/* mtime */
 87		0,			/* filesize */
 88		0,			/* major */
 89		0,			/* minor */
 90		0,			/* rmajor */
 91		0,			/* rminor */
 92		(unsigned)strlen(name)+1, /* namesize */
 93		0);			/* chksum */
 94	push_hdr(s);
 95	push_rest(name);
 96
 97	while (offset % 512) {
 98		putchar(0);
 99		offset++;
100	}
101}
102
103static int cpio_mkslink(const char *name, const char *target,
104			 unsigned int mode, uid_t uid, gid_t gid)
105{
106	char s[256];
107
108	if (name[0] == '/')
109		name++;
110	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
111	       "%08X%08X%08X%08X%08X%08X%08X",
112		"070701",		/* magic */
113		ino++,			/* ino */
114		S_IFLNK | mode,		/* mode */
115		(long) uid,		/* uid */
116		(long) gid,		/* gid */
117		1,			/* nlink */
118		(long) default_mtime,	/* mtime */
119		(unsigned)strlen(target)+1, /* filesize */
120		3,			/* major */
121		1,			/* minor */
122		0,			/* rmajor */
123		0,			/* rminor */
124		(unsigned)strlen(name) + 1,/* namesize */
125		0);			/* chksum */
126	push_hdr(s);
127	push_string(name);
128	push_pad();
129	push_string(target);
130	push_pad();
131	return 0;
132}
133
134static int cpio_mkslink_line(const char *line)
135{
136	char name[PATH_MAX + 1];
137	char target[PATH_MAX + 1];
138	unsigned int mode;
139	int uid;
140	int gid;
141	int rc = -1;
142
143	if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
144		fprintf(stderr, "Unrecognized dir format '%s'", line);
145		goto fail;
146	}
147	rc = cpio_mkslink(name, target, mode, uid, gid);
148 fail:
149	return rc;
150}
151
152static int cpio_mkgeneric(const char *name, unsigned int mode,
153		       uid_t uid, gid_t gid)
154{
155	char s[256];
156
157	if (name[0] == '/')
158		name++;
159	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
160	       "%08X%08X%08X%08X%08X%08X%08X",
161		"070701",		/* magic */
162		ino++,			/* ino */
163		mode,			/* mode */
164		(long) uid,		/* uid */
165		(long) gid,		/* gid */
166		2,			/* nlink */
167		(long) default_mtime,	/* mtime */
168		0,			/* filesize */
169		3,			/* major */
170		1,			/* minor */
171		0,			/* rmajor */
172		0,			/* rminor */
173		(unsigned)strlen(name) + 1,/* namesize */
174		0);			/* chksum */
175	push_hdr(s);
176	push_rest(name);
177	return 0;
178}
179
180enum generic_types {
181	GT_DIR,
182	GT_PIPE,
183	GT_SOCK
184};
185
186struct generic_type {
187	const char *type;
188	mode_t mode;
189};
190
191static struct generic_type generic_type_table[] = {
192	[GT_DIR] = {
193		.type = "dir",
194		.mode = S_IFDIR
195	},
196	[GT_PIPE] = {
197		.type = "pipe",
198		.mode = S_IFIFO
199	},
200	[GT_SOCK] = {
201		.type = "sock",
202		.mode = S_IFSOCK
203	}
204};
205
206static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
207{
208	char name[PATH_MAX + 1];
209	unsigned int mode;
210	int uid;
211	int gid;
212	int rc = -1;
213
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);
217		goto fail;
218	}
219	mode |= generic_type_table[gt].mode;
220	rc = cpio_mkgeneric(name, mode, uid, gid);
221 fail:
222	return rc;
223}
224
225static int cpio_mkdir_line(const char *line)
226{
227	return cpio_mkgeneric_line(line, GT_DIR);
228}
229
230static int cpio_mkpipe_line(const char *line)
231{
232	return cpio_mkgeneric_line(line, GT_PIPE);
233}
234
235static int cpio_mksock_line(const char *line)
236{
237	return cpio_mkgeneric_line(line, GT_SOCK);
238}
239
240static 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)
243{
244	char s[256];
245
246	if (dev_type == 'b')
247		mode |= S_IFBLK;
248	else
249		mode |= S_IFCHR;
250
251	if (name[0] == '/')
252		name++;
253	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
254	       "%08X%08X%08X%08X%08X%08X%08X",
255		"070701",		/* magic */
256		ino++,			/* ino */
257		mode,			/* mode */
258		(long) uid,		/* uid */
259		(long) gid,		/* gid */
260		1,			/* nlink */
261		(long) default_mtime,	/* mtime */
262		0,			/* filesize */
263		3,			/* major */
264		1,			/* minor */
265		maj,			/* rmajor */
266		min,			/* rminor */
267		(unsigned)strlen(name) + 1,/* namesize */
268		0);			/* chksum */
269	push_hdr(s);
270	push_rest(name);
271	return 0;
272}
273
274static int cpio_mknod_line(const char *line)
275{
276	char name[PATH_MAX + 1];
277	unsigned int mode;
278	int uid;
279	int gid;
280	char dev_type;
281	unsigned int maj;
282	unsigned int min;
283	int rc = -1;
284
285	if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
286			 name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
287		fprintf(stderr, "Unrecognized nod format '%s'", line);
288		goto fail;
289	}
290	rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
291 fail:
292	return rc;
293}
294
295static int cpio_mkfile(const char *name, const char *location,
296			unsigned int mode, uid_t uid, gid_t gid,
297			unsigned int nlinks)
298{
299	char s[256];
300	char *filebuf = NULL;
301	struct stat buf;
302	long size;
303	int file = -1;
304	int retval;
305	int rc = -1;
306	int namesize;
307	unsigned int i;
308
309	mode |= S_IFREG;
310
311	file = open (location, O_RDONLY);
312	if (file < 0) {
313		fprintf (stderr, "File %s could not be opened for reading\n", location);
314		goto error;
315	}
316
317	retval = fstat(file, &buf);
318	if (retval) {
319		fprintf(stderr, "File %s could not be stat()'ed\n", location);
320		goto error;
321	}
322
323	filebuf = malloc(buf.st_size);
324	if (!filebuf) {
325		fprintf (stderr, "out of memory\n");
326		goto error;
327	}
328
329	retval = read (file, filebuf, buf.st_size);
330	if (retval < 0) {
331		fprintf (stderr, "Can not read %s file\n", location);
332		goto error;
333	}
334
335	size = 0;
336	for (i = 1; i <= nlinks; i++) {
337		/* data goes on last link */
338		if (i == nlinks) size = buf.st_size;
339
340		if (name[0] == '/')
341			name++;
342		namesize = strlen(name) + 1;
343		sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
344		       "%08lX%08X%08X%08X%08X%08X%08X",
345			"070701",		/* magic */
346			ino,			/* ino */
347			mode,			/* mode */
348			(long) uid,		/* uid */
349			(long) gid,		/* gid */
350			nlinks,			/* nlink */
351			(long) buf.st_mtime,	/* mtime */
352			size,			/* filesize */
353			3,			/* major */
354			1,			/* minor */
355			0,			/* rmajor */
356			0,			/* rminor */
357			namesize,		/* namesize */
358			0);			/* chksum */
359		push_hdr(s);
360		push_string(name);
361		push_pad();
362
363		if (size) {
364			if (fwrite(filebuf, size, 1, stdout) != 1) {
365				fprintf(stderr, "writing filebuf failed\n");
366				goto error;
367			}
368			offset += size;
369			push_pad();
370		}
371
372		name += namesize;
373	}
374	ino++;
375	rc = 0;
376	
377error:
378	if (filebuf) free(filebuf);
379	if (file >= 0) close(file);
380	return rc;
381}
382
383static char *cpio_replace_env(char *new_location)
384{
385	char expanded[PATH_MAX + 1];
386	char *start, *end, *var;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
388	while ((start = strstr(new_location, "${")) &&
389	       (end = strchr(start + 2, '}'))) {
390		*start = *end = 0;
391		var = getenv(start + 2);
392		snprintf(expanded, sizeof expanded, "%s%s%s",
393			 new_location, var ? var : "", end + 1);
394		strcpy(new_location, expanded);
395	}
396
397	return new_location;
398}
399
400static int cpio_mkfile_line(const char *line)
401{
402	char name[PATH_MAX + 1];
403	char *dname = NULL; /* malloc'ed buffer for hard links */
404	char location[PATH_MAX + 1];
405	unsigned int mode;
406	int uid;
407	int gid;
408	int nlinks = 1;
409	int end = 0, dname_len = 0;
410	int rc = -1;
411
412	if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
413				"s %o %d %d %n",
414				name, location, &mode, &uid, &gid, &end)) {
415		fprintf(stderr, "Unrecognized file format '%s'", line);
416		goto fail;
417	}
418	if (end && isgraph(line[end])) {
419		int len;
420		int nend;
421
422		dname = malloc(strlen(line));
423		if (!dname) {
424			fprintf (stderr, "out of memory (%d)\n", dname_len);
425			goto fail;
426		}
427
428		dname_len = strlen(name) + 1;
429		memcpy(dname, name, dname_len);
430
431		do {
432			nend = 0;
433			if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
434					name, &nend) < 1)
435				break;
436			len = strlen(name) + 1;
437			memcpy(dname + dname_len, name, len);
438			dname_len += len;
439			nlinks++;
440			end += nend;
441		} while (isgraph(line[end]));
442	} else {
443		dname = name;
444	}
445	rc = cpio_mkfile(dname, cpio_replace_env(location),
446	                 mode, uid, gid, nlinks);
447 fail:
448	if (dname_len) free(dname);
449	return rc;
450}
451
452static void usage(const char *prog)
453{
454	fprintf(stderr, "Usage:\n"
455		"\t%s [-t <timestamp>] <cpio_list>\n"
456		"\n"
457		"<cpio_list> is a file containing newline separated entries that\n"
458		"describe the files to be included in the initramfs archive:\n"
459		"\n"
460		"# a comment\n"
461		"file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
462		"dir <name> <mode> <uid> <gid>\n"
463		"nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
464		"slink <name> <target> <mode> <uid> <gid>\n"
465		"pipe <name> <mode> <uid> <gid>\n"
466		"sock <name> <mode> <uid> <gid>\n"
467		"\n"
468		"<name>       name of the file/dir/nod/etc in the archive\n"
469		"<location>   location of the file in the current filesystem\n"
470		"             expands shell variables quoted with ${}\n"
471		"<target>     link target\n"
472		"<mode>       mode/permissions of the file\n"
473		"<uid>        user id (0=root)\n"
474		"<gid>        group id (0=root)\n"
475		"<dev_type>   device type (b=block, c=character)\n"
476		"<maj>        major number of nod\n"
477		"<min>        minor number of nod\n"
478		"<hard links> space separated list of other links to file\n"
479		"\n"
480		"example:\n"
481		"# A simple initramfs\n"
482		"dir /dev 0755 0 0\n"
483		"nod /dev/console 0600 0 0 c 5 1\n"
484		"dir /root 0700 0 0\n"
485		"dir /sbin 0755 0 0\n"
486		"file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
487		"\n"
488		"<timestamp> is time in seconds since Epoch that will be used\n"
489		"as mtime for symlinks, special files and directories. The default\n"
490		"is to use the current time for these entries.\n",
491		prog);
492}
493
494struct file_handler file_handler_table[] = {
495	{
496		.type    = "file",
497		.handler = cpio_mkfile_line,
498	}, {
499		.type    = "nod",
500		.handler = cpio_mknod_line,
501	}, {
502		.type    = "dir",
503		.handler = cpio_mkdir_line,
504	}, {
505		.type    = "slink",
506		.handler = cpio_mkslink_line,
507	}, {
508		.type    = "pipe",
509		.handler = cpio_mkpipe_line,
510	}, {
511		.type    = "sock",
512		.handler = cpio_mksock_line,
513	}, {
514		.type    = NULL,
515		.handler = NULL,
516	}
517};
518
519#define LINE_SIZE (2 * PATH_MAX + 50)
520
521int main (int argc, char *argv[])
522{
523	FILE *cpio_list;
524	char line[LINE_SIZE];
525	char *args, *type;
526	int ec = 0;
527	int line_nr = 0;
528	const char *filename;
529
530	default_mtime = time(NULL);
531	while (1) {
532		int opt = getopt(argc, argv, "t:h");
533		char *invalid;
534
535		if (opt == -1)
536			break;
537		switch (opt) {
538		case 't':
539			default_mtime = strtol(optarg, &invalid, 10);
540			if (!*optarg || *invalid) {
541				fprintf(stderr, "Invalid timestamp: %s\n",
542						optarg);
543				usage(argv[0]);
544				exit(1);
545			}
546			break;
547		case 'h':
548		case '?':
549			usage(argv[0]);
550			exit(opt == 'h' ? 0 : 1);
551		}
552	}
553
554	if (argc - optind != 1) {
555		usage(argv[0]);
556		exit(1);
557	}
558	filename = argv[optind];
559	if (!strcmp(filename, "-"))
560		cpio_list = stdin;
561	else if (!(cpio_list = fopen(filename, "r"))) {
562		fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
563			filename, strerror(errno));
564		usage(argv[0]);
565		exit(1);
566	}
567
568	while (fgets(line, LINE_SIZE, cpio_list)) {
569		int type_idx;
570		size_t slen = strlen(line);
571
572		line_nr++;
573
574		if ('#' == *line) {
575			/* comment - skip to next line */
576			continue;
577		}
578
579		if (! (type = strtok(line, " \t"))) {
580			fprintf(stderr,
581				"ERROR: incorrect format, could not locate file type line %d: '%s'\n",
582				line_nr, line);
583			ec = -1;
584			break;
585		}
586
587		if ('\n' == *type) {
588			/* a blank line */
589			continue;
590		}
591
592		if (slen == strlen(type)) {
593			/* must be an empty line */
594			continue;
595		}
596
597		if (! (args = strtok(NULL, "\n"))) {
598			fprintf(stderr,
599				"ERROR: incorrect format, newline required line %d: '%s'\n",
600				line_nr, line);
601			ec = -1;
602		}
603
604		for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
605			int rc;
606			if (! strcmp(line, file_handler_table[type_idx].type)) {
607				if ((rc = file_handler_table[type_idx].handler(args))) {
608					ec = rc;
609					fprintf(stderr, " line %d\n", line_nr);
610				}
611				break;
612			}
613		}
614
615		if (NULL == file_handler_table[type_idx].type) {
616			fprintf(stderr, "unknown file type line %d: '%s'\n",
617				line_nr, line);
618		}
619	}
620	if (ec == 0)
621		cpio_trailer();
622
623	exit(ec);
624}