18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <stdio.h>
38c2ecf20Sopenharmony_ci#include <stdlib.h>
48c2ecf20Sopenharmony_ci#include <sys/types.h>
58c2ecf20Sopenharmony_ci#include <sys/stat.h>
68c2ecf20Sopenharmony_ci#include <string.h>
78c2ecf20Sopenharmony_ci#include <unistd.h>
88c2ecf20Sopenharmony_ci#include <time.h>
98c2ecf20Sopenharmony_ci#include <fcntl.h>
108c2ecf20Sopenharmony_ci#include <errno.h>
118c2ecf20Sopenharmony_ci#include <ctype.h>
128c2ecf20Sopenharmony_ci#include <limits.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/*
158c2ecf20Sopenharmony_ci * Original work by Jeff Garzik
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
188c2ecf20Sopenharmony_ci * Hard link support by Luciano Rocha
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define xstr(s) #s
228c2ecf20Sopenharmony_ci#define str(s) xstr(s)
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic unsigned int offset;
258c2ecf20Sopenharmony_cistatic unsigned int ino = 721;
268c2ecf20Sopenharmony_cistatic time_t default_mtime;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct file_handler {
298c2ecf20Sopenharmony_ci	const char *type;
308c2ecf20Sopenharmony_ci	int (*handler)(const char *line);
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic void push_string(const char *name)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	unsigned int name_len = strlen(name) + 1;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	fputs(name, stdout);
388c2ecf20Sopenharmony_ci	putchar(0);
398c2ecf20Sopenharmony_ci	offset += name_len;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic void push_pad (void)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	while (offset & 3) {
458c2ecf20Sopenharmony_ci		putchar(0);
468c2ecf20Sopenharmony_ci		offset++;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic void push_rest(const char *name)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	unsigned int name_len = strlen(name) + 1;
538c2ecf20Sopenharmony_ci	unsigned int tmp_ofs;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	fputs(name, stdout);
568c2ecf20Sopenharmony_ci	putchar(0);
578c2ecf20Sopenharmony_ci	offset += name_len;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	tmp_ofs = name_len + 110;
608c2ecf20Sopenharmony_ci	while (tmp_ofs & 3) {
618c2ecf20Sopenharmony_ci		putchar(0);
628c2ecf20Sopenharmony_ci		offset++;
638c2ecf20Sopenharmony_ci		tmp_ofs++;
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic void push_hdr(const char *s)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	fputs(s, stdout);
708c2ecf20Sopenharmony_ci	offset += 110;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic void cpio_trailer(void)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	char s[256];
768c2ecf20Sopenharmony_ci	const char name[] = "TRAILER!!!";
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
798c2ecf20Sopenharmony_ci	       "%08X%08X%08X%08X%08X%08X%08X",
808c2ecf20Sopenharmony_ci		"070701",		/* magic */
818c2ecf20Sopenharmony_ci		0,			/* ino */
828c2ecf20Sopenharmony_ci		0,			/* mode */
838c2ecf20Sopenharmony_ci		(long) 0,		/* uid */
848c2ecf20Sopenharmony_ci		(long) 0,		/* gid */
858c2ecf20Sopenharmony_ci		1,			/* nlink */
868c2ecf20Sopenharmony_ci		(long) 0,		/* mtime */
878c2ecf20Sopenharmony_ci		0,			/* filesize */
888c2ecf20Sopenharmony_ci		0,			/* major */
898c2ecf20Sopenharmony_ci		0,			/* minor */
908c2ecf20Sopenharmony_ci		0,			/* rmajor */
918c2ecf20Sopenharmony_ci		0,			/* rminor */
928c2ecf20Sopenharmony_ci		(unsigned)strlen(name)+1, /* namesize */
938c2ecf20Sopenharmony_ci		0);			/* chksum */
948c2ecf20Sopenharmony_ci	push_hdr(s);
958c2ecf20Sopenharmony_ci	push_rest(name);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	while (offset % 512) {
988c2ecf20Sopenharmony_ci		putchar(0);
998c2ecf20Sopenharmony_ci		offset++;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic int cpio_mkslink(const char *name, const char *target,
1048c2ecf20Sopenharmony_ci			 unsigned int mode, uid_t uid, gid_t gid)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	char s[256];
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (name[0] == '/')
1098c2ecf20Sopenharmony_ci		name++;
1108c2ecf20Sopenharmony_ci	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
1118c2ecf20Sopenharmony_ci	       "%08X%08X%08X%08X%08X%08X%08X",
1128c2ecf20Sopenharmony_ci		"070701",		/* magic */
1138c2ecf20Sopenharmony_ci		ino++,			/* ino */
1148c2ecf20Sopenharmony_ci		S_IFLNK | mode,		/* mode */
1158c2ecf20Sopenharmony_ci		(long) uid,		/* uid */
1168c2ecf20Sopenharmony_ci		(long) gid,		/* gid */
1178c2ecf20Sopenharmony_ci		1,			/* nlink */
1188c2ecf20Sopenharmony_ci		(long) default_mtime,	/* mtime */
1198c2ecf20Sopenharmony_ci		(unsigned)strlen(target)+1, /* filesize */
1208c2ecf20Sopenharmony_ci		3,			/* major */
1218c2ecf20Sopenharmony_ci		1,			/* minor */
1228c2ecf20Sopenharmony_ci		0,			/* rmajor */
1238c2ecf20Sopenharmony_ci		0,			/* rminor */
1248c2ecf20Sopenharmony_ci		(unsigned)strlen(name) + 1,/* namesize */
1258c2ecf20Sopenharmony_ci		0);			/* chksum */
1268c2ecf20Sopenharmony_ci	push_hdr(s);
1278c2ecf20Sopenharmony_ci	push_string(name);
1288c2ecf20Sopenharmony_ci	push_pad();
1298c2ecf20Sopenharmony_ci	push_string(target);
1308c2ecf20Sopenharmony_ci	push_pad();
1318c2ecf20Sopenharmony_ci	return 0;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic int cpio_mkslink_line(const char *line)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	char name[PATH_MAX + 1];
1378c2ecf20Sopenharmony_ci	char target[PATH_MAX + 1];
1388c2ecf20Sopenharmony_ci	unsigned int mode;
1398c2ecf20Sopenharmony_ci	int uid;
1408c2ecf20Sopenharmony_ci	int gid;
1418c2ecf20Sopenharmony_ci	int rc = -1;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
1448c2ecf20Sopenharmony_ci		fprintf(stderr, "Unrecognized dir format '%s'", line);
1458c2ecf20Sopenharmony_ci		goto fail;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci	rc = cpio_mkslink(name, target, mode, uid, gid);
1488c2ecf20Sopenharmony_ci fail:
1498c2ecf20Sopenharmony_ci	return rc;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int cpio_mkgeneric(const char *name, unsigned int mode,
1538c2ecf20Sopenharmony_ci		       uid_t uid, gid_t gid)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	char s[256];
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (name[0] == '/')
1588c2ecf20Sopenharmony_ci		name++;
1598c2ecf20Sopenharmony_ci	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
1608c2ecf20Sopenharmony_ci	       "%08X%08X%08X%08X%08X%08X%08X",
1618c2ecf20Sopenharmony_ci		"070701",		/* magic */
1628c2ecf20Sopenharmony_ci		ino++,			/* ino */
1638c2ecf20Sopenharmony_ci		mode,			/* mode */
1648c2ecf20Sopenharmony_ci		(long) uid,		/* uid */
1658c2ecf20Sopenharmony_ci		(long) gid,		/* gid */
1668c2ecf20Sopenharmony_ci		2,			/* nlink */
1678c2ecf20Sopenharmony_ci		(long) default_mtime,	/* mtime */
1688c2ecf20Sopenharmony_ci		0,			/* filesize */
1698c2ecf20Sopenharmony_ci		3,			/* major */
1708c2ecf20Sopenharmony_ci		1,			/* minor */
1718c2ecf20Sopenharmony_ci		0,			/* rmajor */
1728c2ecf20Sopenharmony_ci		0,			/* rminor */
1738c2ecf20Sopenharmony_ci		(unsigned)strlen(name) + 1,/* namesize */
1748c2ecf20Sopenharmony_ci		0);			/* chksum */
1758c2ecf20Sopenharmony_ci	push_hdr(s);
1768c2ecf20Sopenharmony_ci	push_rest(name);
1778c2ecf20Sopenharmony_ci	return 0;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cienum generic_types {
1818c2ecf20Sopenharmony_ci	GT_DIR,
1828c2ecf20Sopenharmony_ci	GT_PIPE,
1838c2ecf20Sopenharmony_ci	GT_SOCK
1848c2ecf20Sopenharmony_ci};
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistruct generic_type {
1878c2ecf20Sopenharmony_ci	const char *type;
1888c2ecf20Sopenharmony_ci	mode_t mode;
1898c2ecf20Sopenharmony_ci};
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic struct generic_type generic_type_table[] = {
1928c2ecf20Sopenharmony_ci	[GT_DIR] = {
1938c2ecf20Sopenharmony_ci		.type = "dir",
1948c2ecf20Sopenharmony_ci		.mode = S_IFDIR
1958c2ecf20Sopenharmony_ci	},
1968c2ecf20Sopenharmony_ci	[GT_PIPE] = {
1978c2ecf20Sopenharmony_ci		.type = "pipe",
1988c2ecf20Sopenharmony_ci		.mode = S_IFIFO
1998c2ecf20Sopenharmony_ci	},
2008c2ecf20Sopenharmony_ci	[GT_SOCK] = {
2018c2ecf20Sopenharmony_ci		.type = "sock",
2028c2ecf20Sopenharmony_ci		.mode = S_IFSOCK
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci};
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int cpio_mkgeneric_line(const char *line, enum generic_types gt)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	char name[PATH_MAX + 1];
2098c2ecf20Sopenharmony_ci	unsigned int mode;
2108c2ecf20Sopenharmony_ci	int uid;
2118c2ecf20Sopenharmony_ci	int gid;
2128c2ecf20Sopenharmony_ci	int rc = -1;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
2158c2ecf20Sopenharmony_ci		fprintf(stderr, "Unrecognized %s format '%s'",
2168c2ecf20Sopenharmony_ci			line, generic_type_table[gt].type);
2178c2ecf20Sopenharmony_ci		goto fail;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci	mode |= generic_type_table[gt].mode;
2208c2ecf20Sopenharmony_ci	rc = cpio_mkgeneric(name, mode, uid, gid);
2218c2ecf20Sopenharmony_ci fail:
2228c2ecf20Sopenharmony_ci	return rc;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic int cpio_mkdir_line(const char *line)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	return cpio_mkgeneric_line(line, GT_DIR);
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic int cpio_mkpipe_line(const char *line)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	return cpio_mkgeneric_line(line, GT_PIPE);
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic int cpio_mksock_line(const char *line)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	return cpio_mkgeneric_line(line, GT_SOCK);
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic int cpio_mknod(const char *name, unsigned int mode,
2418c2ecf20Sopenharmony_ci		       uid_t uid, gid_t gid, char dev_type,
2428c2ecf20Sopenharmony_ci		       unsigned int maj, unsigned int min)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	char s[256];
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (dev_type == 'b')
2478c2ecf20Sopenharmony_ci		mode |= S_IFBLK;
2488c2ecf20Sopenharmony_ci	else
2498c2ecf20Sopenharmony_ci		mode |= S_IFCHR;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (name[0] == '/')
2528c2ecf20Sopenharmony_ci		name++;
2538c2ecf20Sopenharmony_ci	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
2548c2ecf20Sopenharmony_ci	       "%08X%08X%08X%08X%08X%08X%08X",
2558c2ecf20Sopenharmony_ci		"070701",		/* magic */
2568c2ecf20Sopenharmony_ci		ino++,			/* ino */
2578c2ecf20Sopenharmony_ci		mode,			/* mode */
2588c2ecf20Sopenharmony_ci		(long) uid,		/* uid */
2598c2ecf20Sopenharmony_ci		(long) gid,		/* gid */
2608c2ecf20Sopenharmony_ci		1,			/* nlink */
2618c2ecf20Sopenharmony_ci		(long) default_mtime,	/* mtime */
2628c2ecf20Sopenharmony_ci		0,			/* filesize */
2638c2ecf20Sopenharmony_ci		3,			/* major */
2648c2ecf20Sopenharmony_ci		1,			/* minor */
2658c2ecf20Sopenharmony_ci		maj,			/* rmajor */
2668c2ecf20Sopenharmony_ci		min,			/* rminor */
2678c2ecf20Sopenharmony_ci		(unsigned)strlen(name) + 1,/* namesize */
2688c2ecf20Sopenharmony_ci		0);			/* chksum */
2698c2ecf20Sopenharmony_ci	push_hdr(s);
2708c2ecf20Sopenharmony_ci	push_rest(name);
2718c2ecf20Sopenharmony_ci	return 0;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic int cpio_mknod_line(const char *line)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	char name[PATH_MAX + 1];
2778c2ecf20Sopenharmony_ci	unsigned int mode;
2788c2ecf20Sopenharmony_ci	int uid;
2798c2ecf20Sopenharmony_ci	int gid;
2808c2ecf20Sopenharmony_ci	char dev_type;
2818c2ecf20Sopenharmony_ci	unsigned int maj;
2828c2ecf20Sopenharmony_ci	unsigned int min;
2838c2ecf20Sopenharmony_ci	int rc = -1;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
2868c2ecf20Sopenharmony_ci			 name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
2878c2ecf20Sopenharmony_ci		fprintf(stderr, "Unrecognized nod format '%s'", line);
2888c2ecf20Sopenharmony_ci		goto fail;
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci	rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
2918c2ecf20Sopenharmony_ci fail:
2928c2ecf20Sopenharmony_ci	return rc;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic int cpio_mkfile(const char *name, const char *location,
2968c2ecf20Sopenharmony_ci			unsigned int mode, uid_t uid, gid_t gid,
2978c2ecf20Sopenharmony_ci			unsigned int nlinks)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	char s[256];
3008c2ecf20Sopenharmony_ci	char *filebuf = NULL;
3018c2ecf20Sopenharmony_ci	struct stat buf;
3028c2ecf20Sopenharmony_ci	long size;
3038c2ecf20Sopenharmony_ci	int file = -1;
3048c2ecf20Sopenharmony_ci	int retval;
3058c2ecf20Sopenharmony_ci	int rc = -1;
3068c2ecf20Sopenharmony_ci	int namesize;
3078c2ecf20Sopenharmony_ci	unsigned int i;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	mode |= S_IFREG;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	file = open (location, O_RDONLY);
3128c2ecf20Sopenharmony_ci	if (file < 0) {
3138c2ecf20Sopenharmony_ci		fprintf (stderr, "File %s could not be opened for reading\n", location);
3148c2ecf20Sopenharmony_ci		goto error;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	retval = fstat(file, &buf);
3188c2ecf20Sopenharmony_ci	if (retval) {
3198c2ecf20Sopenharmony_ci		fprintf(stderr, "File %s could not be stat()'ed\n", location);
3208c2ecf20Sopenharmony_ci		goto error;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	filebuf = malloc(buf.st_size);
3248c2ecf20Sopenharmony_ci	if (!filebuf) {
3258c2ecf20Sopenharmony_ci		fprintf (stderr, "out of memory\n");
3268c2ecf20Sopenharmony_ci		goto error;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	retval = read (file, filebuf, buf.st_size);
3308c2ecf20Sopenharmony_ci	if (retval < 0) {
3318c2ecf20Sopenharmony_ci		fprintf (stderr, "Can not read %s file\n", location);
3328c2ecf20Sopenharmony_ci		goto error;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	size = 0;
3368c2ecf20Sopenharmony_ci	for (i = 1; i <= nlinks; i++) {
3378c2ecf20Sopenharmony_ci		/* data goes on last link */
3388c2ecf20Sopenharmony_ci		if (i == nlinks) size = buf.st_size;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci		if (name[0] == '/')
3418c2ecf20Sopenharmony_ci			name++;
3428c2ecf20Sopenharmony_ci		namesize = strlen(name) + 1;
3438c2ecf20Sopenharmony_ci		sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
3448c2ecf20Sopenharmony_ci		       "%08lX%08X%08X%08X%08X%08X%08X",
3458c2ecf20Sopenharmony_ci			"070701",		/* magic */
3468c2ecf20Sopenharmony_ci			ino,			/* ino */
3478c2ecf20Sopenharmony_ci			mode,			/* mode */
3488c2ecf20Sopenharmony_ci			(long) uid,		/* uid */
3498c2ecf20Sopenharmony_ci			(long) gid,		/* gid */
3508c2ecf20Sopenharmony_ci			nlinks,			/* nlink */
3518c2ecf20Sopenharmony_ci			(long) buf.st_mtime,	/* mtime */
3528c2ecf20Sopenharmony_ci			size,			/* filesize */
3538c2ecf20Sopenharmony_ci			3,			/* major */
3548c2ecf20Sopenharmony_ci			1,			/* minor */
3558c2ecf20Sopenharmony_ci			0,			/* rmajor */
3568c2ecf20Sopenharmony_ci			0,			/* rminor */
3578c2ecf20Sopenharmony_ci			namesize,		/* namesize */
3588c2ecf20Sopenharmony_ci			0);			/* chksum */
3598c2ecf20Sopenharmony_ci		push_hdr(s);
3608c2ecf20Sopenharmony_ci		push_string(name);
3618c2ecf20Sopenharmony_ci		push_pad();
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci		if (size) {
3648c2ecf20Sopenharmony_ci			if (fwrite(filebuf, size, 1, stdout) != 1) {
3658c2ecf20Sopenharmony_ci				fprintf(stderr, "writing filebuf failed\n");
3668c2ecf20Sopenharmony_ci				goto error;
3678c2ecf20Sopenharmony_ci			}
3688c2ecf20Sopenharmony_ci			offset += size;
3698c2ecf20Sopenharmony_ci			push_pad();
3708c2ecf20Sopenharmony_ci		}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci		name += namesize;
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci	ino++;
3758c2ecf20Sopenharmony_ci	rc = 0;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cierror:
3788c2ecf20Sopenharmony_ci	if (filebuf) free(filebuf);
3798c2ecf20Sopenharmony_ci	if (file >= 0) close(file);
3808c2ecf20Sopenharmony_ci	return rc;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic char *cpio_replace_env(char *new_location)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	char expanded[PATH_MAX + 1];
3868c2ecf20Sopenharmony_ci	char *start, *end, *var;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	while ((start = strstr(new_location, "${")) &&
3898c2ecf20Sopenharmony_ci	       (end = strchr(start + 2, '}'))) {
3908c2ecf20Sopenharmony_ci		*start = *end = 0;
3918c2ecf20Sopenharmony_ci		var = getenv(start + 2);
3928c2ecf20Sopenharmony_ci		snprintf(expanded, sizeof expanded, "%s%s%s",
3938c2ecf20Sopenharmony_ci			 new_location, var ? var : "", end + 1);
3948c2ecf20Sopenharmony_ci		strcpy(new_location, expanded);
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	return new_location;
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic int cpio_mkfile_line(const char *line)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	char name[PATH_MAX + 1];
4038c2ecf20Sopenharmony_ci	char *dname = NULL; /* malloc'ed buffer for hard links */
4048c2ecf20Sopenharmony_ci	char location[PATH_MAX + 1];
4058c2ecf20Sopenharmony_ci	unsigned int mode;
4068c2ecf20Sopenharmony_ci	int uid;
4078c2ecf20Sopenharmony_ci	int gid;
4088c2ecf20Sopenharmony_ci	int nlinks = 1;
4098c2ecf20Sopenharmony_ci	int end = 0, dname_len = 0;
4108c2ecf20Sopenharmony_ci	int rc = -1;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
4138c2ecf20Sopenharmony_ci				"s %o %d %d %n",
4148c2ecf20Sopenharmony_ci				name, location, &mode, &uid, &gid, &end)) {
4158c2ecf20Sopenharmony_ci		fprintf(stderr, "Unrecognized file format '%s'", line);
4168c2ecf20Sopenharmony_ci		goto fail;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci	if (end && isgraph(line[end])) {
4198c2ecf20Sopenharmony_ci		int len;
4208c2ecf20Sopenharmony_ci		int nend;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		dname = malloc(strlen(line));
4238c2ecf20Sopenharmony_ci		if (!dname) {
4248c2ecf20Sopenharmony_ci			fprintf (stderr, "out of memory (%d)\n", dname_len);
4258c2ecf20Sopenharmony_ci			goto fail;
4268c2ecf20Sopenharmony_ci		}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci		dname_len = strlen(name) + 1;
4298c2ecf20Sopenharmony_ci		memcpy(dname, name, dname_len);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		do {
4328c2ecf20Sopenharmony_ci			nend = 0;
4338c2ecf20Sopenharmony_ci			if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
4348c2ecf20Sopenharmony_ci					name, &nend) < 1)
4358c2ecf20Sopenharmony_ci				break;
4368c2ecf20Sopenharmony_ci			len = strlen(name) + 1;
4378c2ecf20Sopenharmony_ci			memcpy(dname + dname_len, name, len);
4388c2ecf20Sopenharmony_ci			dname_len += len;
4398c2ecf20Sopenharmony_ci			nlinks++;
4408c2ecf20Sopenharmony_ci			end += nend;
4418c2ecf20Sopenharmony_ci		} while (isgraph(line[end]));
4428c2ecf20Sopenharmony_ci	} else {
4438c2ecf20Sopenharmony_ci		dname = name;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci	rc = cpio_mkfile(dname, cpio_replace_env(location),
4468c2ecf20Sopenharmony_ci	                 mode, uid, gid, nlinks);
4478c2ecf20Sopenharmony_ci fail:
4488c2ecf20Sopenharmony_ci	if (dname_len) free(dname);
4498c2ecf20Sopenharmony_ci	return rc;
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic void usage(const char *prog)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	fprintf(stderr, "Usage:\n"
4558c2ecf20Sopenharmony_ci		"\t%s [-t <timestamp>] <cpio_list>\n"
4568c2ecf20Sopenharmony_ci		"\n"
4578c2ecf20Sopenharmony_ci		"<cpio_list> is a file containing newline separated entries that\n"
4588c2ecf20Sopenharmony_ci		"describe the files to be included in the initramfs archive:\n"
4598c2ecf20Sopenharmony_ci		"\n"
4608c2ecf20Sopenharmony_ci		"# a comment\n"
4618c2ecf20Sopenharmony_ci		"file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
4628c2ecf20Sopenharmony_ci		"dir <name> <mode> <uid> <gid>\n"
4638c2ecf20Sopenharmony_ci		"nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
4648c2ecf20Sopenharmony_ci		"slink <name> <target> <mode> <uid> <gid>\n"
4658c2ecf20Sopenharmony_ci		"pipe <name> <mode> <uid> <gid>\n"
4668c2ecf20Sopenharmony_ci		"sock <name> <mode> <uid> <gid>\n"
4678c2ecf20Sopenharmony_ci		"\n"
4688c2ecf20Sopenharmony_ci		"<name>       name of the file/dir/nod/etc in the archive\n"
4698c2ecf20Sopenharmony_ci		"<location>   location of the file in the current filesystem\n"
4708c2ecf20Sopenharmony_ci		"             expands shell variables quoted with ${}\n"
4718c2ecf20Sopenharmony_ci		"<target>     link target\n"
4728c2ecf20Sopenharmony_ci		"<mode>       mode/permissions of the file\n"
4738c2ecf20Sopenharmony_ci		"<uid>        user id (0=root)\n"
4748c2ecf20Sopenharmony_ci		"<gid>        group id (0=root)\n"
4758c2ecf20Sopenharmony_ci		"<dev_type>   device type (b=block, c=character)\n"
4768c2ecf20Sopenharmony_ci		"<maj>        major number of nod\n"
4778c2ecf20Sopenharmony_ci		"<min>        minor number of nod\n"
4788c2ecf20Sopenharmony_ci		"<hard links> space separated list of other links to file\n"
4798c2ecf20Sopenharmony_ci		"\n"
4808c2ecf20Sopenharmony_ci		"example:\n"
4818c2ecf20Sopenharmony_ci		"# A simple initramfs\n"
4828c2ecf20Sopenharmony_ci		"dir /dev 0755 0 0\n"
4838c2ecf20Sopenharmony_ci		"nod /dev/console 0600 0 0 c 5 1\n"
4848c2ecf20Sopenharmony_ci		"dir /root 0700 0 0\n"
4858c2ecf20Sopenharmony_ci		"dir /sbin 0755 0 0\n"
4868c2ecf20Sopenharmony_ci		"file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
4878c2ecf20Sopenharmony_ci		"\n"
4888c2ecf20Sopenharmony_ci		"<timestamp> is time in seconds since Epoch that will be used\n"
4898c2ecf20Sopenharmony_ci		"as mtime for symlinks, special files and directories. The default\n"
4908c2ecf20Sopenharmony_ci		"is to use the current time for these entries.\n",
4918c2ecf20Sopenharmony_ci		prog);
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistruct file_handler file_handler_table[] = {
4958c2ecf20Sopenharmony_ci	{
4968c2ecf20Sopenharmony_ci		.type    = "file",
4978c2ecf20Sopenharmony_ci		.handler = cpio_mkfile_line,
4988c2ecf20Sopenharmony_ci	}, {
4998c2ecf20Sopenharmony_ci		.type    = "nod",
5008c2ecf20Sopenharmony_ci		.handler = cpio_mknod_line,
5018c2ecf20Sopenharmony_ci	}, {
5028c2ecf20Sopenharmony_ci		.type    = "dir",
5038c2ecf20Sopenharmony_ci		.handler = cpio_mkdir_line,
5048c2ecf20Sopenharmony_ci	}, {
5058c2ecf20Sopenharmony_ci		.type    = "slink",
5068c2ecf20Sopenharmony_ci		.handler = cpio_mkslink_line,
5078c2ecf20Sopenharmony_ci	}, {
5088c2ecf20Sopenharmony_ci		.type    = "pipe",
5098c2ecf20Sopenharmony_ci		.handler = cpio_mkpipe_line,
5108c2ecf20Sopenharmony_ci	}, {
5118c2ecf20Sopenharmony_ci		.type    = "sock",
5128c2ecf20Sopenharmony_ci		.handler = cpio_mksock_line,
5138c2ecf20Sopenharmony_ci	}, {
5148c2ecf20Sopenharmony_ci		.type    = NULL,
5158c2ecf20Sopenharmony_ci		.handler = NULL,
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci};
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci#define LINE_SIZE (2 * PATH_MAX + 50)
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ciint main (int argc, char *argv[])
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	FILE *cpio_list;
5248c2ecf20Sopenharmony_ci	char line[LINE_SIZE];
5258c2ecf20Sopenharmony_ci	char *args, *type;
5268c2ecf20Sopenharmony_ci	int ec = 0;
5278c2ecf20Sopenharmony_ci	int line_nr = 0;
5288c2ecf20Sopenharmony_ci	const char *filename;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	default_mtime = time(NULL);
5318c2ecf20Sopenharmony_ci	while (1) {
5328c2ecf20Sopenharmony_ci		int opt = getopt(argc, argv, "t:h");
5338c2ecf20Sopenharmony_ci		char *invalid;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci		if (opt == -1)
5368c2ecf20Sopenharmony_ci			break;
5378c2ecf20Sopenharmony_ci		switch (opt) {
5388c2ecf20Sopenharmony_ci		case 't':
5398c2ecf20Sopenharmony_ci			default_mtime = strtol(optarg, &invalid, 10);
5408c2ecf20Sopenharmony_ci			if (!*optarg || *invalid) {
5418c2ecf20Sopenharmony_ci				fprintf(stderr, "Invalid timestamp: %s\n",
5428c2ecf20Sopenharmony_ci						optarg);
5438c2ecf20Sopenharmony_ci				usage(argv[0]);
5448c2ecf20Sopenharmony_ci				exit(1);
5458c2ecf20Sopenharmony_ci			}
5468c2ecf20Sopenharmony_ci			break;
5478c2ecf20Sopenharmony_ci		case 'h':
5488c2ecf20Sopenharmony_ci		case '?':
5498c2ecf20Sopenharmony_ci			usage(argv[0]);
5508c2ecf20Sopenharmony_ci			exit(opt == 'h' ? 0 : 1);
5518c2ecf20Sopenharmony_ci		}
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	if (argc - optind != 1) {
5558c2ecf20Sopenharmony_ci		usage(argv[0]);
5568c2ecf20Sopenharmony_ci		exit(1);
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci	filename = argv[optind];
5598c2ecf20Sopenharmony_ci	if (!strcmp(filename, "-"))
5608c2ecf20Sopenharmony_ci		cpio_list = stdin;
5618c2ecf20Sopenharmony_ci	else if (!(cpio_list = fopen(filename, "r"))) {
5628c2ecf20Sopenharmony_ci		fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
5638c2ecf20Sopenharmony_ci			filename, strerror(errno));
5648c2ecf20Sopenharmony_ci		usage(argv[0]);
5658c2ecf20Sopenharmony_ci		exit(1);
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	while (fgets(line, LINE_SIZE, cpio_list)) {
5698c2ecf20Sopenharmony_ci		int type_idx;
5708c2ecf20Sopenharmony_ci		size_t slen = strlen(line);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci		line_nr++;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci		if ('#' == *line) {
5758c2ecf20Sopenharmony_ci			/* comment - skip to next line */
5768c2ecf20Sopenharmony_ci			continue;
5778c2ecf20Sopenharmony_ci		}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		if (! (type = strtok(line, " \t"))) {
5808c2ecf20Sopenharmony_ci			fprintf(stderr,
5818c2ecf20Sopenharmony_ci				"ERROR: incorrect format, could not locate file type line %d: '%s'\n",
5828c2ecf20Sopenharmony_ci				line_nr, line);
5838c2ecf20Sopenharmony_ci			ec = -1;
5848c2ecf20Sopenharmony_ci			break;
5858c2ecf20Sopenharmony_ci		}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		if ('\n' == *type) {
5888c2ecf20Sopenharmony_ci			/* a blank line */
5898c2ecf20Sopenharmony_ci			continue;
5908c2ecf20Sopenharmony_ci		}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci		if (slen == strlen(type)) {
5938c2ecf20Sopenharmony_ci			/* must be an empty line */
5948c2ecf20Sopenharmony_ci			continue;
5958c2ecf20Sopenharmony_ci		}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci		if (! (args = strtok(NULL, "\n"))) {
5988c2ecf20Sopenharmony_ci			fprintf(stderr,
5998c2ecf20Sopenharmony_ci				"ERROR: incorrect format, newline required line %d: '%s'\n",
6008c2ecf20Sopenharmony_ci				line_nr, line);
6018c2ecf20Sopenharmony_ci			ec = -1;
6028c2ecf20Sopenharmony_ci		}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci		for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
6058c2ecf20Sopenharmony_ci			int rc;
6068c2ecf20Sopenharmony_ci			if (! strcmp(line, file_handler_table[type_idx].type)) {
6078c2ecf20Sopenharmony_ci				if ((rc = file_handler_table[type_idx].handler(args))) {
6088c2ecf20Sopenharmony_ci					ec = rc;
6098c2ecf20Sopenharmony_ci					fprintf(stderr, " line %d\n", line_nr);
6108c2ecf20Sopenharmony_ci				}
6118c2ecf20Sopenharmony_ci				break;
6128c2ecf20Sopenharmony_ci			}
6138c2ecf20Sopenharmony_ci		}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci		if (NULL == file_handler_table[type_idx].type) {
6168c2ecf20Sopenharmony_ci			fprintf(stderr, "unknown file type line %d: '%s'\n",
6178c2ecf20Sopenharmony_ci				line_nr, line);
6188c2ecf20Sopenharmony_ci		}
6198c2ecf20Sopenharmony_ci	}
6208c2ecf20Sopenharmony_ci	if (ec == 0)
6218c2ecf20Sopenharmony_ci		cpio_trailer();
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	exit(ec);
6248c2ecf20Sopenharmony_ci}
625