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