xref: /openbmc/linux/usr/gen_init_cpio.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds #include <stdio.h>
31da177e4SLinus Torvalds #include <stdlib.h>
4ea804871SDavid Disseldorp #include <stdint.h>
5ea804871SDavid Disseldorp #include <stdbool.h>
61da177e4SLinus Torvalds #include <sys/types.h>
71da177e4SLinus Torvalds #include <sys/stat.h>
81da177e4SLinus Torvalds #include <string.h>
91da177e4SLinus Torvalds #include <unistd.h>
101da177e4SLinus Torvalds #include <time.h>
111da177e4SLinus Torvalds #include <fcntl.h>
121da177e4SLinus Torvalds #include <errno.h>
131da177e4SLinus Torvalds #include <ctype.h>
141da177e4SLinus Torvalds #include <limits.h>
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds /*
171da177e4SLinus Torvalds  * Original work by Jeff Garzik
181da177e4SLinus Torvalds  *
191da177e4SLinus Torvalds  * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
2024fa5096SLuciano Rocha  * Hard link support by Luciano Rocha
211da177e4SLinus Torvalds  */
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds #define xstr(s) #s
241da177e4SLinus Torvalds #define str(s) xstr(s)
253a2699cfSDavid Disseldorp #define MIN(a, b) ((a) < (b) ? (a) : (b))
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds static unsigned int offset;
281da177e4SLinus Torvalds static unsigned int ino = 721;
29a8b8017cSMichal Marek static time_t default_mtime;
30ea804871SDavid Disseldorp static bool do_csum = false;
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds struct file_handler {
331da177e4SLinus Torvalds 	const char *type;
341da177e4SLinus Torvalds 	int (*handler)(const char *line);
351da177e4SLinus Torvalds };
361da177e4SLinus Torvalds 
push_string(const char * name)371da177e4SLinus Torvalds static void push_string(const char *name)
381da177e4SLinus Torvalds {
391da177e4SLinus Torvalds 	unsigned int name_len = strlen(name) + 1;
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds 	fputs(name, stdout);
421da177e4SLinus Torvalds 	putchar(0);
431da177e4SLinus Torvalds 	offset += name_len;
441da177e4SLinus Torvalds }
451da177e4SLinus Torvalds 
push_pad(void)461da177e4SLinus Torvalds static void push_pad (void)
471da177e4SLinus Torvalds {
481da177e4SLinus Torvalds 	while (offset & 3) {
491da177e4SLinus Torvalds 		putchar(0);
501da177e4SLinus Torvalds 		offset++;
511da177e4SLinus Torvalds 	}
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds 
push_rest(const char * name)541da177e4SLinus Torvalds static void push_rest(const char *name)
551da177e4SLinus Torvalds {
561da177e4SLinus Torvalds 	unsigned int name_len = strlen(name) + 1;
571da177e4SLinus Torvalds 	unsigned int tmp_ofs;
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds 	fputs(name, stdout);
601da177e4SLinus Torvalds 	putchar(0);
611da177e4SLinus Torvalds 	offset += name_len;
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 	tmp_ofs = name_len + 110;
641da177e4SLinus Torvalds 	while (tmp_ofs & 3) {
651da177e4SLinus Torvalds 		putchar(0);
661da177e4SLinus Torvalds 		offset++;
671da177e4SLinus Torvalds 		tmp_ofs++;
681da177e4SLinus Torvalds 	}
691da177e4SLinus Torvalds }
701da177e4SLinus Torvalds 
push_hdr(const char * s)711da177e4SLinus Torvalds static void push_hdr(const char *s)
721da177e4SLinus Torvalds {
731da177e4SLinus Torvalds 	fputs(s, stdout);
741da177e4SLinus Torvalds 	offset += 110;
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds 
cpio_trailer(void)771da177e4SLinus Torvalds static void cpio_trailer(void)
781da177e4SLinus Torvalds {
791da177e4SLinus Torvalds 	char s[256];
801da177e4SLinus Torvalds 	const char name[] = "TRAILER!!!";
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds 	sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
831da177e4SLinus Torvalds 	       "%08X%08X%08X%08X%08X%08X%08X",
84ea804871SDavid Disseldorp 		do_csum ? "070702" : "070701", /* magic */
851da177e4SLinus Torvalds 		0,			/* ino */
861da177e4SLinus Torvalds 		0,			/* mode */
871da177e4SLinus Torvalds 		(long) 0,		/* uid */
881da177e4SLinus Torvalds 		(long) 0,		/* gid */
891da177e4SLinus Torvalds 		1,			/* nlink */
901da177e4SLinus Torvalds 		(long) 0,		/* mtime */
911da177e4SLinus Torvalds 		0,			/* filesize */
921da177e4SLinus Torvalds 		0,			/* major */
931da177e4SLinus Torvalds 		0,			/* minor */
941da177e4SLinus Torvalds 		0,			/* rmajor */
951da177e4SLinus Torvalds 		0,			/* rminor */
961da177e4SLinus Torvalds 		(unsigned)strlen(name)+1, /* namesize */
971da177e4SLinus Torvalds 		0);			/* chksum */
981da177e4SLinus Torvalds 	push_hdr(s);
991da177e4SLinus Torvalds 	push_rest(name);
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 	while (offset % 512) {
1021da177e4SLinus Torvalds 		putchar(0);
1031da177e4SLinus Torvalds 		offset++;
1041da177e4SLinus Torvalds 	}
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds 
cpio_mkslink(const char * name,const char * target,unsigned int mode,uid_t uid,gid_t gid)1071da177e4SLinus Torvalds static int cpio_mkslink(const char *name, const char *target,
1081da177e4SLinus Torvalds 			 unsigned int mode, uid_t uid, gid_t gid)
1091da177e4SLinus Torvalds {
1101da177e4SLinus Torvalds 	char s[256];
1111da177e4SLinus Torvalds 
11243f901fbSThomas Chou 	if (name[0] == '/')
11343f901fbSThomas Chou 		name++;
1141da177e4SLinus Torvalds 	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
1151da177e4SLinus Torvalds 	       "%08X%08X%08X%08X%08X%08X%08X",
116ea804871SDavid Disseldorp 		do_csum ? "070702" : "070701", /* magic */
1171da177e4SLinus Torvalds 		ino++,			/* ino */
1181da177e4SLinus Torvalds 		S_IFLNK | mode,		/* mode */
1191da177e4SLinus Torvalds 		(long) uid,		/* uid */
1201da177e4SLinus Torvalds 		(long) gid,		/* gid */
1211da177e4SLinus Torvalds 		1,			/* nlink */
122a8b8017cSMichal Marek 		(long) default_mtime,	/* mtime */
1231da177e4SLinus Torvalds 		(unsigned)strlen(target)+1, /* filesize */
1241da177e4SLinus Torvalds 		3,			/* major */
1251da177e4SLinus Torvalds 		1,			/* minor */
1261da177e4SLinus Torvalds 		0,			/* rmajor */
1271da177e4SLinus Torvalds 		0,			/* rminor */
1281da177e4SLinus Torvalds 		(unsigned)strlen(name) + 1,/* namesize */
1291da177e4SLinus Torvalds 		0);			/* chksum */
1301da177e4SLinus Torvalds 	push_hdr(s);
1311da177e4SLinus Torvalds 	push_string(name);
1321da177e4SLinus Torvalds 	push_pad();
1331da177e4SLinus Torvalds 	push_string(target);
1341da177e4SLinus Torvalds 	push_pad();
1351da177e4SLinus Torvalds 	return 0;
1361da177e4SLinus Torvalds }
1371da177e4SLinus Torvalds 
cpio_mkslink_line(const char * line)1381da177e4SLinus Torvalds static int cpio_mkslink_line(const char *line)
1391da177e4SLinus Torvalds {
1401da177e4SLinus Torvalds 	char name[PATH_MAX + 1];
1411da177e4SLinus Torvalds 	char target[PATH_MAX + 1];
1421da177e4SLinus Torvalds 	unsigned int mode;
1431da177e4SLinus Torvalds 	int uid;
1441da177e4SLinus Torvalds 	int gid;
1451da177e4SLinus Torvalds 	int rc = -1;
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 	if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
1481da177e4SLinus Torvalds 		fprintf(stderr, "Unrecognized dir format '%s'", line);
1491da177e4SLinus Torvalds 		goto fail;
1501da177e4SLinus Torvalds 	}
1511da177e4SLinus Torvalds 	rc = cpio_mkslink(name, target, mode, uid, gid);
1521da177e4SLinus Torvalds  fail:
1531da177e4SLinus Torvalds 	return rc;
1541da177e4SLinus Torvalds }
1551da177e4SLinus Torvalds 
cpio_mkgeneric(const char * name,unsigned int mode,uid_t uid,gid_t gid)1561da177e4SLinus Torvalds static int cpio_mkgeneric(const char *name, unsigned int mode,
1571da177e4SLinus Torvalds 		       uid_t uid, gid_t gid)
1581da177e4SLinus Torvalds {
1591da177e4SLinus Torvalds 	char s[256];
1601da177e4SLinus Torvalds 
16143f901fbSThomas Chou 	if (name[0] == '/')
16243f901fbSThomas Chou 		name++;
1631da177e4SLinus Torvalds 	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
1641da177e4SLinus Torvalds 	       "%08X%08X%08X%08X%08X%08X%08X",
165ea804871SDavid Disseldorp 		do_csum ? "070702" : "070701", /* magic */
1661da177e4SLinus Torvalds 		ino++,			/* ino */
1671da177e4SLinus Torvalds 		mode,			/* mode */
1681da177e4SLinus Torvalds 		(long) uid,		/* uid */
1691da177e4SLinus Torvalds 		(long) gid,		/* gid */
1701da177e4SLinus Torvalds 		2,			/* nlink */
171a8b8017cSMichal Marek 		(long) default_mtime,	/* mtime */
1721da177e4SLinus Torvalds 		0,			/* filesize */
1731da177e4SLinus Torvalds 		3,			/* major */
1741da177e4SLinus Torvalds 		1,			/* minor */
1751da177e4SLinus Torvalds 		0,			/* rmajor */
1761da177e4SLinus Torvalds 		0,			/* rminor */
1771da177e4SLinus Torvalds 		(unsigned)strlen(name) + 1,/* namesize */
1781da177e4SLinus Torvalds 		0);			/* chksum */
1791da177e4SLinus Torvalds 	push_hdr(s);
1801da177e4SLinus Torvalds 	push_rest(name);
1811da177e4SLinus Torvalds 	return 0;
1821da177e4SLinus Torvalds }
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds enum generic_types {
1851da177e4SLinus Torvalds 	GT_DIR,
1861da177e4SLinus Torvalds 	GT_PIPE,
1871da177e4SLinus Torvalds 	GT_SOCK
1881da177e4SLinus Torvalds };
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds struct generic_type {
1911da177e4SLinus Torvalds 	const char *type;
1921da177e4SLinus Torvalds 	mode_t mode;
1931da177e4SLinus Torvalds };
1941da177e4SLinus Torvalds 
1953510c5cfSMasahiro Yamada static const struct generic_type generic_type_table[] = {
1961da177e4SLinus Torvalds 	[GT_DIR] = {
1971da177e4SLinus Torvalds 		.type = "dir",
1981da177e4SLinus Torvalds 		.mode = S_IFDIR
1991da177e4SLinus Torvalds 	},
2001da177e4SLinus Torvalds 	[GT_PIPE] = {
2011da177e4SLinus Torvalds 		.type = "pipe",
2021da177e4SLinus Torvalds 		.mode = S_IFIFO
2031da177e4SLinus Torvalds 	},
2041da177e4SLinus Torvalds 	[GT_SOCK] = {
2051da177e4SLinus Torvalds 		.type = "sock",
2061da177e4SLinus Torvalds 		.mode = S_IFSOCK
2071da177e4SLinus Torvalds 	}
2081da177e4SLinus Torvalds };
2091da177e4SLinus Torvalds 
cpio_mkgeneric_line(const char * line,enum generic_types gt)2101da177e4SLinus Torvalds static int cpio_mkgeneric_line(const char *line, enum generic_types gt)
2111da177e4SLinus Torvalds {
2121da177e4SLinus Torvalds 	char name[PATH_MAX + 1];
2131da177e4SLinus Torvalds 	unsigned int mode;
2141da177e4SLinus Torvalds 	int uid;
2151da177e4SLinus Torvalds 	int gid;
2161da177e4SLinus Torvalds 	int rc = -1;
2171da177e4SLinus Torvalds 
2181da177e4SLinus Torvalds 	if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
2191da177e4SLinus Torvalds 		fprintf(stderr, "Unrecognized %s format '%s'",
2201da177e4SLinus Torvalds 			line, generic_type_table[gt].type);
2211da177e4SLinus Torvalds 		goto fail;
2221da177e4SLinus Torvalds 	}
2231da177e4SLinus Torvalds 	mode |= generic_type_table[gt].mode;
2241da177e4SLinus Torvalds 	rc = cpio_mkgeneric(name, mode, uid, gid);
2251da177e4SLinus Torvalds  fail:
2261da177e4SLinus Torvalds 	return rc;
2271da177e4SLinus Torvalds }
2281da177e4SLinus Torvalds 
cpio_mkdir_line(const char * line)2291da177e4SLinus Torvalds static int cpio_mkdir_line(const char *line)
2301da177e4SLinus Torvalds {
2311da177e4SLinus Torvalds 	return cpio_mkgeneric_line(line, GT_DIR);
2321da177e4SLinus Torvalds }
2331da177e4SLinus Torvalds 
cpio_mkpipe_line(const char * line)2341da177e4SLinus Torvalds static int cpio_mkpipe_line(const char *line)
2351da177e4SLinus Torvalds {
2361da177e4SLinus Torvalds 	return cpio_mkgeneric_line(line, GT_PIPE);
2371da177e4SLinus Torvalds }
2381da177e4SLinus Torvalds 
cpio_mksock_line(const char * line)2391da177e4SLinus Torvalds static int cpio_mksock_line(const char *line)
2401da177e4SLinus Torvalds {
2411da177e4SLinus Torvalds 	return cpio_mkgeneric_line(line, GT_SOCK);
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds 
cpio_mknod(const char * name,unsigned int mode,uid_t uid,gid_t gid,char dev_type,unsigned int maj,unsigned int min)2441da177e4SLinus Torvalds static int cpio_mknod(const char *name, unsigned int mode,
2451da177e4SLinus Torvalds 		       uid_t uid, gid_t gid, char dev_type,
2461da177e4SLinus Torvalds 		       unsigned int maj, unsigned int min)
2471da177e4SLinus Torvalds {
2481da177e4SLinus Torvalds 	char s[256];
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds 	if (dev_type == 'b')
2511da177e4SLinus Torvalds 		mode |= S_IFBLK;
2521da177e4SLinus Torvalds 	else
2531da177e4SLinus Torvalds 		mode |= S_IFCHR;
2541da177e4SLinus Torvalds 
25543f901fbSThomas Chou 	if (name[0] == '/')
25643f901fbSThomas Chou 		name++;
2571da177e4SLinus Torvalds 	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
2581da177e4SLinus Torvalds 	       "%08X%08X%08X%08X%08X%08X%08X",
259ea804871SDavid Disseldorp 		do_csum ? "070702" : "070701", /* magic */
2601da177e4SLinus Torvalds 		ino++,			/* ino */
2611da177e4SLinus Torvalds 		mode,			/* mode */
2621da177e4SLinus Torvalds 		(long) uid,		/* uid */
2631da177e4SLinus Torvalds 		(long) gid,		/* gid */
2641da177e4SLinus Torvalds 		1,			/* nlink */
265a8b8017cSMichal Marek 		(long) default_mtime,	/* mtime */
2661da177e4SLinus Torvalds 		0,			/* filesize */
2671da177e4SLinus Torvalds 		3,			/* major */
2681da177e4SLinus Torvalds 		1,			/* minor */
2691da177e4SLinus Torvalds 		maj,			/* rmajor */
2701da177e4SLinus Torvalds 		min,			/* rminor */
2711da177e4SLinus Torvalds 		(unsigned)strlen(name) + 1,/* namesize */
2721da177e4SLinus Torvalds 		0);			/* chksum */
2731da177e4SLinus Torvalds 	push_hdr(s);
2741da177e4SLinus Torvalds 	push_rest(name);
2751da177e4SLinus Torvalds 	return 0;
2761da177e4SLinus Torvalds }
2771da177e4SLinus Torvalds 
cpio_mknod_line(const char * line)2781da177e4SLinus Torvalds static int cpio_mknod_line(const char *line)
2791da177e4SLinus Torvalds {
2801da177e4SLinus Torvalds 	char name[PATH_MAX + 1];
2811da177e4SLinus Torvalds 	unsigned int mode;
2821da177e4SLinus Torvalds 	int uid;
2831da177e4SLinus Torvalds 	int gid;
2841da177e4SLinus Torvalds 	char dev_type;
2851da177e4SLinus Torvalds 	unsigned int maj;
2861da177e4SLinus Torvalds 	unsigned int min;
2871da177e4SLinus Torvalds 	int rc = -1;
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 	if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
2901da177e4SLinus Torvalds 			 name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
2911da177e4SLinus Torvalds 		fprintf(stderr, "Unrecognized nod format '%s'", line);
2921da177e4SLinus Torvalds 		goto fail;
2931da177e4SLinus Torvalds 	}
2941da177e4SLinus Torvalds 	rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
2951da177e4SLinus Torvalds  fail:
2961da177e4SLinus Torvalds 	return rc;
2971da177e4SLinus Torvalds }
2981da177e4SLinus Torvalds 
cpio_mkfile_csum(int fd,unsigned long size,uint32_t * csum)299ea804871SDavid Disseldorp static int cpio_mkfile_csum(int fd, unsigned long size, uint32_t *csum)
300ea804871SDavid Disseldorp {
301ea804871SDavid Disseldorp 	while (size) {
302ea804871SDavid Disseldorp 		unsigned char filebuf[65536];
303ea804871SDavid Disseldorp 		ssize_t this_read;
304ea804871SDavid Disseldorp 		size_t i, this_size = MIN(size, sizeof(filebuf));
305ea804871SDavid Disseldorp 
306ea804871SDavid Disseldorp 		this_read = read(fd, filebuf, this_size);
307ea804871SDavid Disseldorp 		if (this_read <= 0 || this_read > this_size)
308ea804871SDavid Disseldorp 			return -1;
309ea804871SDavid Disseldorp 
310ea804871SDavid Disseldorp 		for (i = 0; i < this_read; i++)
311ea804871SDavid Disseldorp 			*csum += filebuf[i];
312ea804871SDavid Disseldorp 
313ea804871SDavid Disseldorp 		size -= this_read;
314ea804871SDavid Disseldorp 	}
315ea804871SDavid Disseldorp 	/* seek back to the start for data segment I/O */
316ea804871SDavid Disseldorp 	if (lseek(fd, 0, SEEK_SET) < 0)
317ea804871SDavid Disseldorp 		return -1;
318ea804871SDavid Disseldorp 
319ea804871SDavid Disseldorp 	return 0;
320ea804871SDavid Disseldorp }
321ea804871SDavid Disseldorp 
cpio_mkfile(const char * name,const char * location,unsigned int mode,uid_t uid,gid_t gid,unsigned int nlinks)3221da177e4SLinus Torvalds static int cpio_mkfile(const char *name, const char *location,
32324fa5096SLuciano Rocha 			unsigned int mode, uid_t uid, gid_t gid,
32424fa5096SLuciano Rocha 			unsigned int nlinks)
3251da177e4SLinus Torvalds {
3261da177e4SLinus Torvalds 	char s[256];
3271da177e4SLinus Torvalds 	struct stat buf;
3283a2699cfSDavid Disseldorp 	unsigned long size;
329462cd772SLi zeming 	int file;
3301da177e4SLinus Torvalds 	int retval;
3311da177e4SLinus Torvalds 	int rc = -1;
33224fa5096SLuciano Rocha 	int namesize;
33320f1de65SKees Cook 	unsigned int i;
334ea804871SDavid Disseldorp 	uint32_t csum = 0;
3351da177e4SLinus Torvalds 
3361da177e4SLinus Torvalds 	mode |= S_IFREG;
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 	file = open (location, O_RDONLY);
3391da177e4SLinus Torvalds 	if (file < 0) {
3401da177e4SLinus Torvalds 		fprintf (stderr, "File %s could not be opened for reading\n", location);
3411da177e4SLinus Torvalds 		goto error;
3421da177e4SLinus Torvalds 	}
3431da177e4SLinus Torvalds 
34496aebafaSJesper Juhl 	retval = fstat(file, &buf);
34596aebafaSJesper Juhl 	if (retval) {
34696aebafaSJesper Juhl 		fprintf(stderr, "File %s could not be stat()'ed\n", location);
34796aebafaSJesper Juhl 		goto error;
34896aebafaSJesper Juhl 	}
34996aebafaSJesper Juhl 
3504c9d410fSNicolas Schier 	if (buf.st_mtime > 0xffffffff) {
3514c9d410fSNicolas Schier 		fprintf(stderr, "%s: Timestamp exceeds maximum cpio timestamp, clipping.\n",
3524c9d410fSNicolas Schier 			location);
3534c9d410fSNicolas Schier 		buf.st_mtime = 0xffffffff;
3544c9d410fSNicolas Schier 	}
3554c9d410fSNicolas Schier 
356*5efb685bSBenjamin Gray 	if (buf.st_mtime < 0) {
357*5efb685bSBenjamin Gray 		fprintf(stderr, "%s: Timestamp negative, clipping.\n",
358*5efb685bSBenjamin Gray 			location);
359*5efb685bSBenjamin Gray 		buf.st_mtime = 0;
360*5efb685bSBenjamin Gray 	}
361*5efb685bSBenjamin Gray 
3623a2699cfSDavid Disseldorp 	if (buf.st_size > 0xffffffff) {
3633a2699cfSDavid Disseldorp 		fprintf(stderr, "%s: Size exceeds maximum cpio file size\n",
3643a2699cfSDavid Disseldorp 			location);
3651da177e4SLinus Torvalds 		goto error;
3661da177e4SLinus Torvalds 	}
3671da177e4SLinus Torvalds 
368ea804871SDavid Disseldorp 	if (do_csum && cpio_mkfile_csum(file, buf.st_size, &csum) < 0) {
369ea804871SDavid Disseldorp 		fprintf(stderr, "Failed to checksum file %s\n", location);
370ea804871SDavid Disseldorp 		goto error;
371ea804871SDavid Disseldorp 	}
372ea804871SDavid Disseldorp 
37324fa5096SLuciano Rocha 	size = 0;
37424fa5096SLuciano Rocha 	for (i = 1; i <= nlinks; i++) {
37524fa5096SLuciano Rocha 		/* data goes on last link */
3763a2699cfSDavid Disseldorp 		if (i == nlinks)
3773a2699cfSDavid Disseldorp 			size = buf.st_size;
37824fa5096SLuciano Rocha 
37943f901fbSThomas Chou 		if (name[0] == '/')
38043f901fbSThomas Chou 			name++;
38124fa5096SLuciano Rocha 		namesize = strlen(name) + 1;
3821da177e4SLinus Torvalds 		sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
38324fa5096SLuciano Rocha 		       "%08lX%08X%08X%08X%08X%08X%08X",
384ea804871SDavid Disseldorp 			do_csum ? "070702" : "070701", /* magic */
38524fa5096SLuciano Rocha 			ino,			/* ino */
3861da177e4SLinus Torvalds 			mode,			/* mode */
3871da177e4SLinus Torvalds 			(long) uid,		/* uid */
3881da177e4SLinus Torvalds 			(long) gid,		/* gid */
38924fa5096SLuciano Rocha 			nlinks,			/* nlink */
3901da177e4SLinus Torvalds 			(long) buf.st_mtime,	/* mtime */
39124fa5096SLuciano Rocha 			size,			/* filesize */
3921da177e4SLinus Torvalds 			3,			/* major */
3931da177e4SLinus Torvalds 			1,			/* minor */
3941da177e4SLinus Torvalds 			0,			/* rmajor */
3951da177e4SLinus Torvalds 			0,			/* rminor */
39624fa5096SLuciano Rocha 			namesize,		/* namesize */
397ea804871SDavid Disseldorp 			size ? csum : 0);	/* chksum */
3981da177e4SLinus Torvalds 		push_hdr(s);
3991da177e4SLinus Torvalds 		push_string(name);
4001da177e4SLinus Torvalds 		push_pad();
4011da177e4SLinus Torvalds 
4023a2699cfSDavid Disseldorp 		while (size) {
4033a2699cfSDavid Disseldorp 			unsigned char filebuf[65536];
4043a2699cfSDavid Disseldorp 			ssize_t this_read;
4053a2699cfSDavid Disseldorp 			size_t this_size = MIN(size, sizeof(filebuf));
4063a2699cfSDavid Disseldorp 
4073a2699cfSDavid Disseldorp 			this_read = read(file, filebuf, this_size);
4083a2699cfSDavid Disseldorp 			if (this_read <= 0 || this_read > this_size) {
4093a2699cfSDavid Disseldorp 				fprintf(stderr, "Can not read %s file\n", location);
4103a2699cfSDavid Disseldorp 				goto error;
4113a2699cfSDavid Disseldorp 			}
4123a2699cfSDavid Disseldorp 
4133a2699cfSDavid Disseldorp 			if (fwrite(filebuf, this_read, 1, stdout) != 1) {
4146d87fea4SMike Frysinger 				fprintf(stderr, "writing filebuf failed\n");
4156d87fea4SMike Frysinger 				goto error;
4166d87fea4SMike Frysinger 			}
4173a2699cfSDavid Disseldorp 			offset += this_read;
4183a2699cfSDavid Disseldorp 			size -= this_read;
41924fa5096SLuciano Rocha 		}
4203a2699cfSDavid Disseldorp 		push_pad();
42124fa5096SLuciano Rocha 
42224fa5096SLuciano Rocha 		name += namesize;
42324fa5096SLuciano Rocha 	}
42424fa5096SLuciano Rocha 	ino++;
4251da177e4SLinus Torvalds 	rc = 0;
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds error:
4283a2699cfSDavid Disseldorp 	if (file >= 0)
4293a2699cfSDavid Disseldorp 		close(file);
4301da177e4SLinus Torvalds 	return rc;
4311da177e4SLinus Torvalds }
4321da177e4SLinus Torvalds 
cpio_replace_env(char * new_location)4333b1ec9fbSSally, Gene static char *cpio_replace_env(char *new_location)
4343b1ec9fbSSally, Gene {
4353b1ec9fbSSally, Gene 	char expanded[PATH_MAX + 1];
436c725ee54SMichal Nazarewicz 	char *start, *end, *var;
4373b1ec9fbSSally, Gene 
438c725ee54SMichal Nazarewicz 	while ((start = strstr(new_location, "${")) &&
439c725ee54SMichal Nazarewicz 	       (end = strchr(start + 2, '}'))) {
440c725ee54SMichal Nazarewicz 		*start = *end = 0;
441c725ee54SMichal Nazarewicz 		var = getenv(start + 2);
442c725ee54SMichal Nazarewicz 		snprintf(expanded, sizeof expanded, "%s%s%s",
443c725ee54SMichal Nazarewicz 			 new_location, var ? var : "", end + 1);
444c725ee54SMichal Nazarewicz 		strcpy(new_location, expanded);
4453b1ec9fbSSally, Gene 	}
4463b1ec9fbSSally, Gene 
4473b1ec9fbSSally, Gene 	return new_location;
4483b1ec9fbSSally, Gene }
4493b1ec9fbSSally, Gene 
cpio_mkfile_line(const char * line)4501da177e4SLinus Torvalds static int cpio_mkfile_line(const char *line)
4511da177e4SLinus Torvalds {
4521da177e4SLinus Torvalds 	char name[PATH_MAX + 1];
45324fa5096SLuciano Rocha 	char *dname = NULL; /* malloc'ed buffer for hard links */
4541da177e4SLinus Torvalds 	char location[PATH_MAX + 1];
4551da177e4SLinus Torvalds 	unsigned int mode;
4561da177e4SLinus Torvalds 	int uid;
4571da177e4SLinus Torvalds 	int gid;
45824fa5096SLuciano Rocha 	int nlinks = 1;
45924fa5096SLuciano Rocha 	int end = 0, dname_len = 0;
4601da177e4SLinus Torvalds 	int rc = -1;
4611da177e4SLinus Torvalds 
46224fa5096SLuciano Rocha 	if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
46324fa5096SLuciano Rocha 				"s %o %d %d %n",
46424fa5096SLuciano Rocha 				name, location, &mode, &uid, &gid, &end)) {
4651da177e4SLinus Torvalds 		fprintf(stderr, "Unrecognized file format '%s'", line);
4661da177e4SLinus Torvalds 		goto fail;
4671da177e4SLinus Torvalds 	}
46824fa5096SLuciano Rocha 	if (end && isgraph(line[end])) {
46924fa5096SLuciano Rocha 		int len;
47024fa5096SLuciano Rocha 		int nend;
47124fa5096SLuciano Rocha 
47224fa5096SLuciano Rocha 		dname = malloc(strlen(line));
47324fa5096SLuciano Rocha 		if (!dname) {
47424fa5096SLuciano Rocha 			fprintf (stderr, "out of memory (%d)\n", dname_len);
47524fa5096SLuciano Rocha 			goto fail;
47624fa5096SLuciano Rocha 		}
47724fa5096SLuciano Rocha 
47824fa5096SLuciano Rocha 		dname_len = strlen(name) + 1;
47924fa5096SLuciano Rocha 		memcpy(dname, name, dname_len);
48024fa5096SLuciano Rocha 
48124fa5096SLuciano Rocha 		do {
48224fa5096SLuciano Rocha 			nend = 0;
48324fa5096SLuciano Rocha 			if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
48424fa5096SLuciano Rocha 					name, &nend) < 1)
48524fa5096SLuciano Rocha 				break;
48624fa5096SLuciano Rocha 			len = strlen(name) + 1;
48724fa5096SLuciano Rocha 			memcpy(dname + dname_len, name, len);
48824fa5096SLuciano Rocha 			dname_len += len;
48924fa5096SLuciano Rocha 			nlinks++;
49024fa5096SLuciano Rocha 			end += nend;
49124fa5096SLuciano Rocha 		} while (isgraph(line[end]));
49224fa5096SLuciano Rocha 	} else {
49324fa5096SLuciano Rocha 		dname = name;
49424fa5096SLuciano Rocha 	}
4953b1ec9fbSSally, Gene 	rc = cpio_mkfile(dname, cpio_replace_env(location),
4963b1ec9fbSSally, Gene 	                 mode, uid, gid, nlinks);
4971da177e4SLinus Torvalds  fail:
49824fa5096SLuciano Rocha 	if (dname_len) free(dname);
4991da177e4SLinus Torvalds 	return rc;
5001da177e4SLinus Torvalds }
5011da177e4SLinus Torvalds 
usage(const char * prog)5025c725138STrevor Keith static void usage(const char *prog)
5031da177e4SLinus Torvalds {
5041da177e4SLinus Torvalds 	fprintf(stderr, "Usage:\n"
505ea804871SDavid Disseldorp 		"\t%s [-t <timestamp>] [-c] <cpio_list>\n"
5061da177e4SLinus Torvalds 		"\n"
5071da177e4SLinus Torvalds 		"<cpio_list> is a file containing newline separated entries that\n"
5081da177e4SLinus Torvalds 		"describe the files to be included in the initramfs archive:\n"
5091da177e4SLinus Torvalds 		"\n"
5101da177e4SLinus Torvalds 		"# a comment\n"
51124fa5096SLuciano Rocha 		"file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
5121da177e4SLinus Torvalds 		"dir <name> <mode> <uid> <gid>\n"
5131da177e4SLinus Torvalds 		"nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
5141da177e4SLinus Torvalds 		"slink <name> <target> <mode> <uid> <gid>\n"
5151da177e4SLinus Torvalds 		"pipe <name> <mode> <uid> <gid>\n"
5161da177e4SLinus Torvalds 		"sock <name> <mode> <uid> <gid>\n"
5171da177e4SLinus Torvalds 		"\n"
5181da177e4SLinus Torvalds 		"<name>       name of the file/dir/nod/etc in the archive\n"
5191da177e4SLinus Torvalds 		"<location>   location of the file in the current filesystem\n"
5203b1ec9fbSSally, Gene 		"             expands shell variables quoted with ${}\n"
5211da177e4SLinus Torvalds 		"<target>     link target\n"
5221da177e4SLinus Torvalds 		"<mode>       mode/permissions of the file\n"
5231da177e4SLinus Torvalds 		"<uid>        user id (0=root)\n"
5241da177e4SLinus Torvalds 		"<gid>        group id (0=root)\n"
5251da177e4SLinus Torvalds 		"<dev_type>   device type (b=block, c=character)\n"
5261da177e4SLinus Torvalds 		"<maj>        major number of nod\n"
5271da177e4SLinus Torvalds 		"<min>        minor number of nod\n"
52824fa5096SLuciano Rocha 		"<hard links> space separated list of other links to file\n"
5291da177e4SLinus Torvalds 		"\n"
5301da177e4SLinus Torvalds 		"example:\n"
5311da177e4SLinus Torvalds 		"# A simple initramfs\n"
5321da177e4SLinus Torvalds 		"dir /dev 0755 0 0\n"
5331da177e4SLinus Torvalds 		"nod /dev/console 0600 0 0 c 5 1\n"
5341da177e4SLinus Torvalds 		"dir /root 0700 0 0\n"
5351da177e4SLinus Torvalds 		"dir /sbin 0755 0 0\n"
536a8b8017cSMichal Marek 		"file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
537a8b8017cSMichal Marek 		"\n"
538a8b8017cSMichal Marek 		"<timestamp> is time in seconds since Epoch that will be used\n"
539a8b8017cSMichal Marek 		"as mtime for symlinks, special files and directories. The default\n"
540ea804871SDavid Disseldorp 		"is to use the current time for these entries.\n"
541ea804871SDavid Disseldorp 		"-c: calculate and store 32-bit checksums for file data.\n",
5421da177e4SLinus Torvalds 		prog);
5431da177e4SLinus Torvalds }
5441da177e4SLinus Torvalds 
5453510c5cfSMasahiro Yamada static const struct file_handler file_handler_table[] = {
5461da177e4SLinus Torvalds 	{
5471da177e4SLinus Torvalds 		.type    = "file",
5481da177e4SLinus Torvalds 		.handler = cpio_mkfile_line,
5491da177e4SLinus Torvalds 	}, {
5501da177e4SLinus Torvalds 		.type    = "nod",
5511da177e4SLinus Torvalds 		.handler = cpio_mknod_line,
5521da177e4SLinus Torvalds 	}, {
5531da177e4SLinus Torvalds 		.type    = "dir",
5541da177e4SLinus Torvalds 		.handler = cpio_mkdir_line,
5551da177e4SLinus Torvalds 	}, {
5561da177e4SLinus Torvalds 		.type    = "slink",
5571da177e4SLinus Torvalds 		.handler = cpio_mkslink_line,
5581da177e4SLinus Torvalds 	}, {
5591da177e4SLinus Torvalds 		.type    = "pipe",
5601da177e4SLinus Torvalds 		.handler = cpio_mkpipe_line,
5611da177e4SLinus Torvalds 	}, {
5621da177e4SLinus Torvalds 		.type    = "sock",
5631da177e4SLinus Torvalds 		.handler = cpio_mksock_line,
5641da177e4SLinus Torvalds 	}, {
5651da177e4SLinus Torvalds 		.type    = NULL,
5661da177e4SLinus Torvalds 		.handler = NULL,
5671da177e4SLinus Torvalds 	}
5681da177e4SLinus Torvalds };
5691da177e4SLinus Torvalds 
5701da177e4SLinus Torvalds #define LINE_SIZE (2 * PATH_MAX + 50)
5711da177e4SLinus Torvalds 
main(int argc,char * argv[])5721da177e4SLinus Torvalds int main (int argc, char *argv[])
5731da177e4SLinus Torvalds {
5741da177e4SLinus Torvalds 	FILE *cpio_list;
5751da177e4SLinus Torvalds 	char line[LINE_SIZE];
5761da177e4SLinus Torvalds 	char *args, *type;
5771da177e4SLinus Torvalds 	int ec = 0;
5781da177e4SLinus Torvalds 	int line_nr = 0;
579a8b8017cSMichal Marek 	const char *filename;
5801da177e4SLinus Torvalds 
581a8b8017cSMichal Marek 	default_mtime = time(NULL);
582a8b8017cSMichal Marek 	while (1) {
583ea804871SDavid Disseldorp 		int opt = getopt(argc, argv, "t:ch");
584a8b8017cSMichal Marek 		char *invalid;
585a8b8017cSMichal Marek 
586a8b8017cSMichal Marek 		if (opt == -1)
587a8b8017cSMichal Marek 			break;
588a8b8017cSMichal Marek 		switch (opt) {
589a8b8017cSMichal Marek 		case 't':
590a8b8017cSMichal Marek 			default_mtime = strtol(optarg, &invalid, 10);
591a8b8017cSMichal Marek 			if (!*optarg || *invalid) {
592a8b8017cSMichal Marek 				fprintf(stderr, "Invalid timestamp: %s\n",
593a8b8017cSMichal Marek 						optarg);
5941da177e4SLinus Torvalds 				usage(argv[0]);
5951da177e4SLinus Torvalds 				exit(1);
5961da177e4SLinus Torvalds 			}
597a8b8017cSMichal Marek 			break;
598ea804871SDavid Disseldorp 		case 'c':
599ea804871SDavid Disseldorp 			do_csum = true;
600ea804871SDavid Disseldorp 			break;
601a8b8017cSMichal Marek 		case 'h':
602a8b8017cSMichal Marek 		case '?':
603a8b8017cSMichal Marek 			usage(argv[0]);
604a8b8017cSMichal Marek 			exit(opt == 'h' ? 0 : 1);
605a8b8017cSMichal Marek 		}
606a8b8017cSMichal Marek 	}
6071da177e4SLinus Torvalds 
6084c9d410fSNicolas Schier 	/*
6094c9d410fSNicolas Schier 	 * Timestamps after 2106-02-07 06:28:15 UTC have an ascii hex time_t
6104c9d410fSNicolas Schier 	 * representation that exceeds 8 chars and breaks the cpio header
611*5efb685bSBenjamin Gray 	 * specification. Negative timestamps similarly exceed 8 chars.
6124c9d410fSNicolas Schier 	 */
613*5efb685bSBenjamin Gray 	if (default_mtime > 0xffffffff || default_mtime < 0) {
614*5efb685bSBenjamin Gray 		fprintf(stderr, "ERROR: Timestamp out of range for cpio format\n");
6154c9d410fSNicolas Schier 		exit(1);
6164c9d410fSNicolas Schier 	}
6174c9d410fSNicolas Schier 
618a8b8017cSMichal Marek 	if (argc - optind != 1) {
619a8b8017cSMichal Marek 		usage(argv[0]);
620a8b8017cSMichal Marek 		exit(1);
621a8b8017cSMichal Marek 	}
622a8b8017cSMichal Marek 	filename = argv[optind];
623a8b8017cSMichal Marek 	if (!strcmp(filename, "-"))
624f2434ec1SMike Frysinger 		cpio_list = stdin;
625a8b8017cSMichal Marek 	else if (!(cpio_list = fopen(filename, "r"))) {
6261da177e4SLinus Torvalds 		fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
627a8b8017cSMichal Marek 			filename, strerror(errno));
6281da177e4SLinus Torvalds 		usage(argv[0]);
6291da177e4SLinus Torvalds 		exit(1);
6301da177e4SLinus Torvalds 	}
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds 	while (fgets(line, LINE_SIZE, cpio_list)) {
6331da177e4SLinus Torvalds 		int type_idx;
6341da177e4SLinus Torvalds 		size_t slen = strlen(line);
6351da177e4SLinus Torvalds 
6361da177e4SLinus Torvalds 		line_nr++;
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds 		if ('#' == *line) {
6391da177e4SLinus Torvalds 			/* comment - skip to next line */
6401da177e4SLinus Torvalds 			continue;
6411da177e4SLinus Torvalds 		}
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds 		if (! (type = strtok(line, " \t"))) {
6441da177e4SLinus Torvalds 			fprintf(stderr,
6451da177e4SLinus Torvalds 				"ERROR: incorrect format, could not locate file type line %d: '%s'\n",
6461da177e4SLinus Torvalds 				line_nr, line);
6471da177e4SLinus Torvalds 			ec = -1;
648aa1e816fSJesper Juhl 			break;
6491da177e4SLinus Torvalds 		}
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds 		if ('\n' == *type) {
6521da177e4SLinus Torvalds 			/* a blank line */
6531da177e4SLinus Torvalds 			continue;
6541da177e4SLinus Torvalds 		}
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds 		if (slen == strlen(type)) {
6571da177e4SLinus Torvalds 			/* must be an empty line */
6581da177e4SLinus Torvalds 			continue;
6591da177e4SLinus Torvalds 		}
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 		if (! (args = strtok(NULL, "\n"))) {
6621da177e4SLinus Torvalds 			fprintf(stderr,
6631da177e4SLinus Torvalds 				"ERROR: incorrect format, newline required line %d: '%s'\n",
6641da177e4SLinus Torvalds 				line_nr, line);
6651da177e4SLinus Torvalds 			ec = -1;
6661da177e4SLinus Torvalds 		}
6671da177e4SLinus Torvalds 
6681da177e4SLinus Torvalds 		for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) {
6691da177e4SLinus Torvalds 			int rc;
6701da177e4SLinus Torvalds 			if (! strcmp(line, file_handler_table[type_idx].type)) {
6711da177e4SLinus Torvalds 				if ((rc = file_handler_table[type_idx].handler(args))) {
6721da177e4SLinus Torvalds 					ec = rc;
6731da177e4SLinus Torvalds 					fprintf(stderr, " line %d\n", line_nr);
6741da177e4SLinus Torvalds 				}
6751da177e4SLinus Torvalds 				break;
6761da177e4SLinus Torvalds 			}
6771da177e4SLinus Torvalds 		}
6781da177e4SLinus Torvalds 
6791da177e4SLinus Torvalds 		if (NULL == file_handler_table[type_idx].type) {
6801da177e4SLinus Torvalds 			fprintf(stderr, "unknown file type line %d: '%s'\n",
6811da177e4SLinus Torvalds 				line_nr, line);
6821da177e4SLinus Torvalds 		}
6831da177e4SLinus Torvalds 	}
684aa1e816fSJesper Juhl 	if (ec == 0)
6851da177e4SLinus Torvalds 		cpio_trailer();
6861da177e4SLinus Torvalds 
6871da177e4SLinus Torvalds 	exit(ec);
6881da177e4SLinus Torvalds }
689