diff options
Diffstat (limited to 'usr/gen_init_cpio.c')
| -rw-r--r-- | usr/gen_init_cpio.c | 512 | 
1 files changed, 512 insertions, 0 deletions
| diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c new file mode 100644 index 000000000000..33dbcbf77c5b --- /dev/null +++ b/usr/gen_init_cpio.c @@ -0,0 +1,512 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> +#include <limits.h> + +/* + * Original work by Jeff Garzik + * + * External file lists, symlink, pipe and fifo support by Thayne Harbaugh + */ + +#define xstr(s) #s +#define str(s) xstr(s) + +static unsigned int offset; +static unsigned int ino = 721; + +struct file_handler { +	const char *type; +	int (*handler)(const char *line); +}; + +static void push_string(const char *name) +{ +	unsigned int name_len = strlen(name) + 1; + +	fputs(name, stdout); +	putchar(0); +	offset += name_len; +} + +static void push_pad (void) +{ +	while (offset & 3) { +		putchar(0); +		offset++; +	} +} + +static void push_rest(const char *name) +{ +	unsigned int name_len = strlen(name) + 1; +	unsigned int tmp_ofs; + +	fputs(name, stdout); +	putchar(0); +	offset += name_len; + +	tmp_ofs = name_len + 110; +	while (tmp_ofs & 3) { +		putchar(0); +		offset++; +		tmp_ofs++; +	} +} + +static void push_hdr(const char *s) +{ +	fputs(s, stdout); +	offset += 110; +} + +static void cpio_trailer(void) +{ +	char s[256]; +	const char name[] = "TRAILER!!!"; + +	sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX" +	       "%08X%08X%08X%08X%08X%08X%08X", +		"070701",		/* magic */ +		0,			/* ino */ +		0,			/* mode */ +		(long) 0,		/* uid */ +		(long) 0,		/* gid */ +		1,			/* nlink */ +		(long) 0,		/* mtime */ +		0,			/* filesize */ +		0,			/* major */ +		0,			/* minor */ +		0,			/* rmajor */ +		0,			/* rminor */ +		(unsigned)strlen(name)+1, /* namesize */ +		0);			/* chksum */ +	push_hdr(s); +	push_rest(name); + +	while (offset % 512) { +		putchar(0); +		offset++; +	} +} + +static int cpio_mkslink(const char *name, const char *target, +			 unsigned int mode, uid_t uid, gid_t gid) +{ +	char s[256]; +	time_t mtime = time(NULL); + +	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" +	       "%08X%08X%08X%08X%08X%08X%08X", +		"070701",		/* magic */ +		ino++,			/* ino */ +		S_IFLNK | mode,		/* mode */ +		(long) uid,		/* uid */ +		(long) gid,		/* gid */ +		1,			/* nlink */ +		(long) mtime,		/* mtime */ +		(unsigned)strlen(target)+1, /* filesize */ +		3,			/* major */ +		1,			/* minor */ +		0,			/* rmajor */ +		0,			/* rminor */ +		(unsigned)strlen(name) + 1,/* namesize */ +		0);			/* chksum */ +	push_hdr(s); +	push_string(name); +	push_pad(); +	push_string(target); +	push_pad(); +	return 0; +} + +static int cpio_mkslink_line(const char *line) +{ +	char name[PATH_MAX + 1]; +	char target[PATH_MAX + 1]; +	unsigned int mode; +	int uid; +	int gid; +	int rc = -1; + +	if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) { +		fprintf(stderr, "Unrecognized dir format '%s'", line); +		goto fail; +	} +	rc = cpio_mkslink(name, target, mode, uid, gid); + fail: +	return rc; +} + +static int cpio_mkgeneric(const char *name, unsigned int mode, +		       uid_t uid, gid_t gid) +{ +	char s[256]; +	time_t mtime = time(NULL); + +	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" +	       "%08X%08X%08X%08X%08X%08X%08X", +		"070701",		/* magic */ +		ino++,			/* ino */ +		mode,			/* mode */ +		(long) uid,		/* uid */ +		(long) gid,		/* gid */ +		2,			/* nlink */ +		(long) mtime,		/* mtime */ +		0,			/* filesize */ +		3,			/* major */ +		1,			/* minor */ +		0,			/* rmajor */ +		0,			/* rminor */ +		(unsigned)strlen(name) + 1,/* namesize */ +		0);			/* chksum */ +	push_hdr(s); +	push_rest(name); +	return 0; +} + +enum generic_types { +	GT_DIR, +	GT_PIPE, +	GT_SOCK +}; + +struct generic_type { +	const char *type; +	mode_t mode; +}; + +static struct generic_type generic_type_table[] = { +	[GT_DIR] = { +		.type = "dir", +		.mode = S_IFDIR +	}, +	[GT_PIPE] = { +		.type = "pipe", +		.mode = S_IFIFO +	}, +	[GT_SOCK] = { +		.type = "sock", +		.mode = S_IFSOCK +	} +}; + +static int cpio_mkgeneric_line(const char *line, enum generic_types gt) +{ +	char name[PATH_MAX + 1]; +	unsigned int mode; +	int uid; +	int gid; +	int rc = -1; + +	if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) { +		fprintf(stderr, "Unrecognized %s format '%s'", +			line, generic_type_table[gt].type); +		goto fail; +	} +	mode |= generic_type_table[gt].mode; +	rc = cpio_mkgeneric(name, mode, uid, gid); + fail: +	return rc; +} + +static int cpio_mkdir_line(const char *line) +{ +	return cpio_mkgeneric_line(line, GT_DIR); +} + +static int cpio_mkpipe_line(const char *line) +{ +	return cpio_mkgeneric_line(line, GT_PIPE); +} + +static int cpio_mksock_line(const char *line) +{ +	return cpio_mkgeneric_line(line, GT_SOCK); +} + +static int cpio_mknod(const char *name, unsigned int mode, +		       uid_t uid, gid_t gid, char dev_type, +		       unsigned int maj, unsigned int min) +{ +	char s[256]; +	time_t mtime = time(NULL); + +	if (dev_type == 'b') +		mode |= S_IFBLK; +	else +		mode |= S_IFCHR; + +	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" +	       "%08X%08X%08X%08X%08X%08X%08X", +		"070701",		/* magic */ +		ino++,			/* ino */ +		mode,			/* mode */ +		(long) uid,		/* uid */ +		(long) gid,		/* gid */ +		1,			/* nlink */ +		(long) mtime,		/* mtime */ +		0,			/* filesize */ +		3,			/* major */ +		1,			/* minor */ +		maj,			/* rmajor */ +		min,			/* rminor */ +		(unsigned)strlen(name) + 1,/* namesize */ +		0);			/* chksum */ +	push_hdr(s); +	push_rest(name); +	return 0; +} + +static int cpio_mknod_line(const char *line) +{ +	char name[PATH_MAX + 1]; +	unsigned int mode; +	int uid; +	int gid; +	char dev_type; +	unsigned int maj; +	unsigned int min; +	int rc = -1; + +	if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u", +			 name, &mode, &uid, &gid, &dev_type, &maj, &min)) { +		fprintf(stderr, "Unrecognized nod format '%s'", line); +		goto fail; +	} +	rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min); + fail: +	return rc; +} + +/* Not marked static to keep the compiler quiet, as no one uses this yet... */ +static int cpio_mkfile(const char *name, const char *location, +			unsigned int mode, uid_t uid, gid_t gid) +{ +	char s[256]; +	char *filebuf = NULL; +	struct stat buf; +	int file = -1; +	int retval; +	int rc = -1; + +	mode |= S_IFREG; + +	retval = stat (location, &buf); +	if (retval) { +		fprintf (stderr, "File %s could not be located\n", location); +		goto error; +	} + +	file = open (location, O_RDONLY); +	if (file < 0) { +		fprintf (stderr, "File %s could not be opened for reading\n", location); +		goto error; +	} + +	filebuf = malloc(buf.st_size); +	if (!filebuf) { +		fprintf (stderr, "out of memory\n"); +		goto error; +	} + +	retval = read (file, filebuf, buf.st_size); +	if (retval < 0) { +		fprintf (stderr, "Can not read %s file\n", location); +		goto error; +	} + +	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" +	       "%08X%08X%08X%08X%08X%08X%08X", +		"070701",		/* magic */ +		ino++,			/* ino */ +		mode,			/* mode */ +		(long) uid,		/* uid */ +		(long) gid,		/* gid */ +		1,			/* nlink */ +		(long) buf.st_mtime,	/* mtime */ +		(int) buf.st_size,	/* filesize */ +		3,			/* major */ +		1,			/* minor */ +		0,			/* rmajor */ +		0,			/* rminor */ +		(unsigned)strlen(name) + 1,/* namesize */ +		0);			/* chksum */ +	push_hdr(s); +	push_string(name); +	push_pad(); + +	fwrite(filebuf, buf.st_size, 1, stdout); +	offset += buf.st_size; +	push_pad(); +	rc = 0; +	 +error: +	if (filebuf) free(filebuf); +	if (file >= 0) close(file); +	return rc; +} + +static int cpio_mkfile_line(const char *line) +{ +	char name[PATH_MAX + 1]; +	char location[PATH_MAX + 1]; +	unsigned int mode; +	int uid; +	int gid; +	int rc = -1; + +	if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, location, &mode, &uid, &gid)) { +		fprintf(stderr, "Unrecognized file format '%s'", line); +		goto fail; +	} +	rc = cpio_mkfile(name, location, mode, uid, gid); + fail: +	return rc; +} + +void usage(const char *prog) +{ +	fprintf(stderr, "Usage:\n" +		"\t%s <cpio_list>\n" +		"\n" +		"<cpio_list> is a file containing newline separated entries that\n" +		"describe the files to be included in the initramfs archive:\n" +		"\n" +		"# a comment\n" +		"file <name> <location> <mode> <uid> <gid>\n" +		"dir <name> <mode> <uid> <gid>\n" +		"nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n" +		"slink <name> <target> <mode> <uid> <gid>\n" +		"pipe <name> <mode> <uid> <gid>\n" +		"sock <name> <mode> <uid> <gid>\n" +		"\n" +		"<name>      name of the file/dir/nod/etc in the archive\n" +		"<location>  location of the file in the current filesystem\n" +		"<target>    link target\n" +		"<mode>      mode/permissions of the file\n" +		"<uid>       user id (0=root)\n" +		"<gid>       group id (0=root)\n" +		"<dev_type>  device type (b=block, c=character)\n" +		"<maj>       major number of nod\n" +		"<min>       minor number of nod\n" +		"\n" +		"example:\n" +		"# A simple initramfs\n" +		"dir /dev 0755 0 0\n" +		"nod /dev/console 0600 0 0 c 5 1\n" +		"dir /root 0700 0 0\n" +		"dir /sbin 0755 0 0\n" +		"file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n", +		prog); +} + +struct file_handler file_handler_table[] = { +	{ +		.type    = "file", +		.handler = cpio_mkfile_line, +	}, { +		.type    = "nod", +		.handler = cpio_mknod_line, +	}, { +		.type    = "dir", +		.handler = cpio_mkdir_line, +	}, { +		.type    = "slink", +		.handler = cpio_mkslink_line, +	}, { +		.type    = "pipe", +		.handler = cpio_mkpipe_line, +	}, { +		.type    = "sock", +		.handler = cpio_mksock_line, +	}, { +		.type    = NULL, +		.handler = NULL, +	} +}; + +#define LINE_SIZE (2 * PATH_MAX + 50) + +int main (int argc, char *argv[]) +{ +	FILE *cpio_list; +	char line[LINE_SIZE]; +	char *args, *type; +	int ec = 0; +	int line_nr = 0; + +	if (2 != argc) { +		usage(argv[0]); +		exit(1); +	} + +	if (! (cpio_list = fopen(argv[1], "r"))) { +		fprintf(stderr, "ERROR: unable to open '%s': %s\n\n", +			argv[1], strerror(errno)); +		usage(argv[0]); +		exit(1); +	} + +	while (fgets(line, LINE_SIZE, cpio_list)) { +		int type_idx; +		size_t slen = strlen(line); + +		line_nr++; + +		if ('#' == *line) { +			/* comment - skip to next line */ +			continue; +		} + +		if (! (type = strtok(line, " \t"))) { +			fprintf(stderr, +				"ERROR: incorrect format, could not locate file type line %d: '%s'\n", +				line_nr, line); +			ec = -1; +		} + +		if ('\n' == *type) { +			/* a blank line */ +			continue; +		} + +		if (slen == strlen(type)) { +			/* must be an empty line */ +			continue; +		} + +		if (! (args = strtok(NULL, "\n"))) { +			fprintf(stderr, +				"ERROR: incorrect format, newline required line %d: '%s'\n", +				line_nr, line); +			ec = -1; +		} + +		for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) { +			int rc; +			if (! strcmp(line, file_handler_table[type_idx].type)) { +				if ((rc = file_handler_table[type_idx].handler(args))) { +					ec = rc; +					fprintf(stderr, " line %d\n", line_nr); +				} +				break; +			} +		} + +		if (NULL == file_handler_table[type_idx].type) { +			fprintf(stderr, "unknown file type line %d: '%s'\n", +				line_nr, line); +		} +	} +	cpio_trailer(); + +	exit(ec); +} | 
