Linux Audio

Check our new training course

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}
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2#include <stdio.h>
  3#include <stdlib.h>
  4#include <stdint.h>
  5#include <stdbool.h>
  6#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
 20 * Hard link support by Luciano Rocha
 21 */
 22
 23#define xstr(s) #s
 24#define str(s) xstr(s)
 25#define MIN(a, b) ((a) < (b) ? (a) : (b))
 26
 27static unsigned int offset;
 28static unsigned int ino = 721;
 29static time_t default_mtime;
 30static bool do_csum = false;
 31
 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",
 84		do_csum ? "070702" : "070701", /* magic */
 85		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];
111
112	if (name[0] == '/')
113		name++;
114	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
115	       "%08X%08X%08X%08X%08X%08X%08X",
116		do_csum ? "070702" : "070701", /* magic */
117		ino++,			/* ino */
118		S_IFLNK | mode,		/* mode */
119		(long) uid,		/* uid */
120		(long) gid,		/* gid */
121		1,			/* nlink */
122		(long) default_mtime,	/* mtime */
123		(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];
160
161	if (name[0] == '/')
162		name++;
163	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
164	       "%08X%08X%08X%08X%08X%08X%08X",
165		do_csum ? "070702" : "070701", /* magic */
166		ino++,			/* ino */
167		mode,			/* mode */
168		(long) uid,		/* uid */
169		(long) gid,		/* gid */
170		2,			/* nlink */
171		(long) default_mtime,	/* mtime */
172		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
195static const struct generic_type generic_type_table[] = {
196	[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];
249
250	if (dev_type == 'b')
251		mode |= S_IFBLK;
252	else
253		mode |= S_IFCHR;
254
255	if (name[0] == '/')
256		name++;
257	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
258	       "%08X%08X%08X%08X%08X%08X%08X",
259		do_csum ? "070702" : "070701", /* magic */
260		ino++,			/* ino */
261		mode,			/* mode */
262		(long) uid,		/* uid */
263		(long) gid,		/* gid */
264		1,			/* nlink */
265		(long) default_mtime,	/* mtime */
266		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
299static 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
322static int cpio_mkfile(const char *name, const char *location,
323			unsigned int mode, uid_t uid, gid_t gid,
324			unsigned int nlinks)
325{
326	char s[256];
 
327	struct stat buf;
328	unsigned long size;
329	int file;
330	int retval;
331	int rc = -1;
332	int namesize;
333	unsigned int i;
334	uint32_t csum = 0;
335
336	mode |= S_IFREG;
337
338	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
344	retval = fstat(file, &buf);
345	if (retval) {
346		fprintf(stderr, "File %s could not be stat()'ed\n", location);
347		goto error;
348	}
349
350	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
356	if (buf.st_size > 0xffffffff) {
357		fprintf(stderr, "%s: Size exceeds maximum cpio file size\n",
358			location);
359		goto error;
360	}
361
362	if (do_csum && cpio_mkfile_csum(file, buf.st_size, &csum) < 0) {
363		fprintf(stderr, "Failed to checksum file %s\n", location);
 
364		goto error;
365	}
366
367	size = 0;
368	for (i = 1; i <= nlinks; i++) {
369		/* data goes on last link */
370		if (i == nlinks)
371			size = buf.st_size;
372
373		if (name[0] == '/')
374			name++;
375		namesize = strlen(name) + 1;
376		sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
377		       "%08lX%08X%08X%08X%08X%08X%08X",
378			do_csum ? "070702" : "070701", /* magic */
379			ino,			/* ino */
380			mode,			/* mode */
381			(long) uid,		/* uid */
382			(long) gid,		/* gid */
383			nlinks,			/* nlink */
384			(long) buf.st_mtime,	/* mtime */
385			size,			/* filesize */
386			3,			/* major */
387			1,			/* minor */
388			0,			/* rmajor */
389			0,			/* rminor */
390			namesize,		/* namesize */
391			size ? csum : 0);	/* chksum */
392		push_hdr(s);
393		push_string(name);
394		push_pad();
395
396		while (size) {
397			unsigned char filebuf[65536];
398			ssize_t this_read;
399			size_t this_size = MIN(size, sizeof(filebuf));
400
401			this_read = read(file, filebuf, this_size);
402			if (this_read <= 0 || this_read > this_size) {
403				fprintf(stderr, "Can not read %s file\n", location);
404				goto error;
405			}
406
407			if (fwrite(filebuf, this_read, 1, stdout) != 1) {
408				fprintf(stderr, "writing filebuf failed\n");
409				goto error;
410			}
411			offset += this_read;
412			size -= this_read;
413		}
414		push_pad();
415
416		name += namesize;
417	}
418	ino++;
419	rc = 0;
420
421error:
422	if (file >= 0)
423		close(file);
424	return rc;
425}
426
427static char *cpio_replace_env(char *new_location)
428{
429	char expanded[PATH_MAX + 1];
430	char *start, *end, *var;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
431
432	while ((start = strstr(new_location, "${")) &&
433	       (end = strchr(start + 2, '}'))) {
434		*start = *end = 0;
435		var = getenv(start + 2);
436		snprintf(expanded, sizeof expanded, "%s%s%s",
437			 new_location, var ? var : "", end + 1);
438		strcpy(new_location, expanded);
439	}
440
441	return new_location;
442}
443
444static int cpio_mkfile_line(const char *line)
445{
446	char name[PATH_MAX + 1];
447	char *dname = NULL; /* malloc'ed buffer for hard links */
448	char location[PATH_MAX + 1];
449	unsigned int mode;
450	int uid;
451	int gid;
452	int nlinks = 1;
453	int end = 0, dname_len = 0;
454	int rc = -1;
455
456	if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
457				"s %o %d %d %n",
458				name, location, &mode, &uid, &gid, &end)) {
459		fprintf(stderr, "Unrecognized file format '%s'", line);
460		goto fail;
461	}
462	if (end && isgraph(line[end])) {
463		int len;
464		int nend;
465
466		dname = malloc(strlen(line));
467		if (!dname) {
468			fprintf (stderr, "out of memory (%d)\n", dname_len);
469			goto fail;
470		}
471
472		dname_len = strlen(name) + 1;
473		memcpy(dname, name, dname_len);
474
475		do {
476			nend = 0;
477			if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
478					name, &nend) < 1)
479				break;
480			len = strlen(name) + 1;
481			memcpy(dname + dname_len, name, len);
482			dname_len += len;
483			nlinks++;
484			end += nend;
485		} while (isgraph(line[end]));
486	} else {
487		dname = name;
488	}
489	rc = cpio_mkfile(dname, cpio_replace_env(location),
490	                 mode, uid, gid, nlinks);
491 fail:
492	if (dname_len) free(dname);
493	return rc;
494}
495
496static void usage(const char *prog)
497{
498	fprintf(stderr, "Usage:\n"
499		"\t%s [-t <timestamp>] [-c] <cpio_list>\n"
500		"\n"
501		"<cpio_list> is a file containing newline separated entries that\n"
502		"describe the files to be included in the initramfs archive:\n"
503		"\n"
504		"# a comment\n"
505		"file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
506		"dir <name> <mode> <uid> <gid>\n"
507		"nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
508		"slink <name> <target> <mode> <uid> <gid>\n"
509		"pipe <name> <mode> <uid> <gid>\n"
510		"sock <name> <mode> <uid> <gid>\n"
511		"\n"
512		"<name>       name of the file/dir/nod/etc in the archive\n"
513		"<location>   location of the file in the current filesystem\n"
514		"             expands shell variables quoted with ${}\n"
515		"<target>     link target\n"
516		"<mode>       mode/permissions of the file\n"
517		"<uid>        user id (0=root)\n"
518		"<gid>        group id (0=root)\n"
519		"<dev_type>   device type (b=block, c=character)\n"
520		"<maj>        major number of nod\n"
521		"<min>        minor number of nod\n"
522		"<hard links> space separated list of other links to file\n"
523		"\n"
524		"example:\n"
525		"# A simple initramfs\n"
526		"dir /dev 0755 0 0\n"
527		"nod /dev/console 0600 0 0 c 5 1\n"
528		"dir /root 0700 0 0\n"
529		"dir /sbin 0755 0 0\n"
530		"file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
531		"\n"
532		"<timestamp> is time in seconds since Epoch that will be used\n"
533		"as mtime for symlinks, special files and directories. The default\n"
534		"is to use the current time for these entries.\n"
535		"-c: calculate and store 32-bit checksums for file data.\n",
536		prog);
537}
538
539static const struct file_handler file_handler_table[] = {
540	{
541		.type    = "file",
542		.handler = cpio_mkfile_line,
543	}, {
544		.type    = "nod",
545		.handler = cpio_mknod_line,
546	}, {
547		.type    = "dir",
548		.handler = cpio_mkdir_line,
549	}, {
550		.type    = "slink",
551		.handler = cpio_mkslink_line,
552	}, {
553		.type    = "pipe",
554		.handler = cpio_mkpipe_line,
555	}, {
556		.type    = "sock",
557		.handler = cpio_mksock_line,
558	}, {
559		.type    = NULL,
560		.handler = NULL,
561	}
562};
563
564#define LINE_SIZE (2 * PATH_MAX + 50)
565
566int main (int argc, char *argv[])
567{
568	FILE *cpio_list;
569	char line[LINE_SIZE];
570	char *args, *type;
571	int ec = 0;
572	int line_nr = 0;
573	const char *filename;
574
575	default_mtime = time(NULL);
576	while (1) {
577		int opt = getopt(argc, argv, "t:ch");
578		char *invalid;
579
580		if (opt == -1)
581			break;
582		switch (opt) {
583		case 't':
584			default_mtime = strtol(optarg, &invalid, 10);
585			if (!*optarg || *invalid) {
586				fprintf(stderr, "Invalid timestamp: %s\n",
587						optarg);
588				usage(argv[0]);
589				exit(1);
590			}
591			break;
592		case 'c':
593			do_csum = true;
594			break;
595		case 'h':
596		case '?':
597			usage(argv[0]);
598			exit(opt == 'h' ? 0 : 1);
599		}
600	}
601
602	/*
603	 * Timestamps after 2106-02-07 06:28:15 UTC have an ascii hex time_t
604	 * representation that exceeds 8 chars and breaks the cpio header
605	 * specification.
606	 */
607	if (default_mtime > 0xffffffff) {
608		fprintf(stderr, "ERROR: Timestamp too large for cpio format\n");
609		exit(1);
610	}
611
612	if (argc - optind != 1) {
613		usage(argv[0]);
614		exit(1);
615	}
616	filename = argv[optind];
617	if (!strcmp(filename, "-"))
618		cpio_list = stdin;
619	else if (!(cpio_list = fopen(filename, "r"))) {
620		fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
621			filename, strerror(errno));
622		usage(argv[0]);
623		exit(1);
624	}
625
626	while (fgets(line, LINE_SIZE, cpio_list)) {
627		int type_idx;
628		size_t slen = strlen(line);
629
630		line_nr++;
631
632		if ('#' == *line) {
633			/* comment - skip to next line */
634			continue;
635		}
636
637		if (! (type = strtok(line, " \t"))) {
638			fprintf(stderr,
639				"ERROR: incorrect format, could not locate file type line %d: '%s'\n",
640				line_nr, line);
641			ec = -1;
642			break;
643		}
644
645		if ('\n' == *type) {
646			/* a blank line */
647			continue;
648		}
649
650		if (slen == strlen(type)) {
651			/* must be an empty line */
652			continue;
653		}
654
655		if (! (args = strtok(NULL, "\n"))) {
656			fprintf(stderr,
657				"ERROR: incorrect format, newline required line %d: '%s'\n",
658				line_nr, line);
659			ec = -1;
660		}
661
662		for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
663			int rc;
664			if (! strcmp(line, file_handler_table[type_idx].type)) {
665				if ((rc = file_handler_table[type_idx].handler(args))) {
666					ec = rc;
667					fprintf(stderr, " line %d\n", line_nr);
668				}
669				break;
670			}
671		}
672
673		if (NULL == file_handler_table[type_idx].type) {
674			fprintf(stderr, "unknown file type line %d: '%s'\n",
675				line_nr, line);
676		}
677	}
678	if (ec == 0)
679		cpio_trailer();
680
681	exit(ec);
682}