1b2441318SGreg Kroah-Hartman// SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds#include <stdio.h>
31da177e4SLinus Torvalds#include <stdlib.h>
41da177e4SLinus Torvalds#include <sys/types.h>
51da177e4SLinus Torvalds#include <sys/stat.h>
61da177e4SLinus Torvalds#include <string.h>
71da177e4SLinus Torvalds#include <unistd.h>
81da177e4SLinus Torvalds#include <time.h>
91da177e4SLinus Torvalds#include <fcntl.h>
101da177e4SLinus Torvalds#include <errno.h>
111da177e4SLinus Torvalds#include <ctype.h>
121da177e4SLinus Torvalds#include <limits.h>
131da177e4SLinus Torvalds
141da177e4SLinus Torvalds/*
151da177e4SLinus Torvalds * Original work by Jeff Garzik
161da177e4SLinus Torvalds *
171da177e4SLinus Torvalds * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
1824fa5096SLuciano Rocha * Hard link support by Luciano Rocha
191da177e4SLinus Torvalds */
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds#define xstr(s) #s
221da177e4SLinus Torvalds#define str(s) xstr(s)
231da177e4SLinus Torvalds
241da177e4SLinus Torvaldsstatic unsigned int offset;
251da177e4SLinus Torvaldsstatic unsigned int ino = 721;
26a8b8017cSMichal Marekstatic time_t default_mtime;
271da177e4SLinus Torvalds
281da177e4SLinus Torvaldsstruct file_handler {
291da177e4SLinus Torvalds	const char *type;
301da177e4SLinus Torvalds	int (*handler)(const char *line);
311da177e4SLinus Torvalds};
321da177e4SLinus Torvalds
331da177e4SLinus Torvaldsstatic void push_string(const char *name)
341da177e4SLinus Torvalds{
351da177e4SLinus Torvalds	unsigned int name_len = strlen(name) + 1;
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds	fputs(name, stdout);
381da177e4SLinus Torvalds	putchar(0);
391da177e4SLinus Torvalds	offset += name_len;
401da177e4SLinus Torvalds}
411da177e4SLinus Torvalds
421da177e4SLinus Torvaldsstatic void push_pad (void)
431da177e4SLinus Torvalds{
441da177e4SLinus Torvalds	while (offset & 3) {
451da177e4SLinus Torvalds		putchar(0);
461da177e4SLinus Torvalds		offset++;
471da177e4SLinus Torvalds	}
481da177e4SLinus Torvalds}
491da177e4SLinus Torvalds
501da177e4SLinus Torvaldsstatic void push_rest(const char *name)
511da177e4SLinus Torvalds{
521da177e4SLinus Torvalds	unsigned int name_len = strlen(name) + 1;
531da177e4SLinus Torvalds	unsigned int tmp_ofs;
541da177e4SLinus Torvalds
551da177e4SLinus Torvalds	fputs(name, stdout);
561da177e4SLinus Torvalds	putchar(0);
571da177e4SLinus Torvalds	offset += name_len;
581da177e4SLinus Torvalds
591da177e4SLinus Torvalds	tmp_ofs = name_len + 110;
601da177e4SLinus Torvalds	while (tmp_ofs & 3) {
611da177e4SLinus Torvalds		putchar(0);
621da177e4SLinus Torvalds		offset++;
631da177e4SLinus Torvalds		tmp_ofs++;
641da177e4SLinus Torvalds	}
651da177e4SLinus Torvalds}
661da177e4SLinus Torvalds
671da177e4SLinus Torvaldsstatic void push_hdr(const char *s)
681da177e4SLinus Torvalds{
691da177e4SLinus Torvalds	fputs(s, stdout);
701da177e4SLinus Torvalds	offset += 110;
711da177e4SLinus Torvalds}
721da177e4SLinus Torvalds
731da177e4SLinus Torvaldsstatic void cpio_trailer(void)
741da177e4SLinus Torvalds{
751da177e4SLinus Torvalds	char s[256];
761da177e4SLinus Torvalds	const char name[] = "TRAILER!!!";
771da177e4SLinus Torvalds
781da177e4SLinus Torvalds	sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX"
791da177e4SLinus Torvalds	       "%08X%08X%08X%08X%08X%08X%08X",
801da177e4SLinus Torvalds		"070701",		/* magic */
811da177e4SLinus Torvalds		0,			/* ino */
821da177e4SLinus Torvalds		0,			/* mode */
831da177e4SLinus Torvalds		(long) 0,		/* uid */
841da177e4SLinus Torvalds		(long) 0,		/* gid */
851da177e4SLinus Torvalds		1,			/* nlink */
861da177e4SLinus Torvalds		(long) 0,		/* mtime */
871da177e4SLinus Torvalds		0,			/* filesize */
881da177e4SLinus Torvalds		0,			/* major */
891da177e4SLinus Torvalds		0,			/* minor */
901da177e4SLinus Torvalds		0,			/* rmajor */
911da177e4SLinus Torvalds		0,			/* rminor */
921da177e4SLinus Torvalds		(unsigned)strlen(name)+1, /* namesize */
931da177e4SLinus Torvalds		0);			/* chksum */
941da177e4SLinus Torvalds	push_hdr(s);
951da177e4SLinus Torvalds	push_rest(name);
961da177e4SLinus Torvalds
971da177e4SLinus Torvalds	while (offset % 512) {
981da177e4SLinus Torvalds		putchar(0);
991da177e4SLinus Torvalds		offset++;
1001da177e4SLinus Torvalds	}
1011da177e4SLinus Torvalds}
1021da177e4SLinus Torvalds
1031da177e4SLinus Torvaldsstatic int cpio_mkslink(const char *name, const char *target,
1041da177e4SLinus Torvalds			 unsigned int mode, uid_t uid, gid_t gid)
1051da177e4SLinus Torvalds{
1061da177e4SLinus Torvalds	char s[256];
1071da177e4SLinus Torvalds
10843f901fbSThomas Chou	if (name[0] == '/')
10943f901fbSThomas Chou		name++;
1101da177e4SLinus Torvalds	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
1111da177e4SLinus Torvalds	       "%08X%08X%08X%08X%08X%08X%08X",
1121da177e4SLinus Torvalds		"070701",		/* magic */
1131da177e4SLinus Torvalds		ino++,			/* ino */
1141da177e4SLinus Torvalds		S_IFLNK | mode,		/* mode */
1151da177e4SLinus Torvalds		(long) uid,		/* uid */
1161da177e4SLinus Torvalds		(long) gid,		/* gid */
1171da177e4SLinus Torvalds		1,			/* nlink */
118a8b8017cSMichal Marek		(long) default_mtime,	/* mtime */
1191da177e4SLinus Torvalds		(unsigned)strlen(target)+1, /* filesize */
1201da177e4SLinus Torvalds		3,			/* major */
1211da177e4SLinus Torvalds		1,			/* minor */
1221da177e4SLinus Torvalds		0,			/* rmajor */
1231da177e4SLinus Torvalds		0,			/* rminor */
1241da177e4SLinus Torvalds		(unsigned)strlen(name) + 1,/* namesize */
1251da177e4SLinus Torvalds		0);			/* chksum */
1261da177e4SLinus Torvalds	push_hdr(s);
1271da177e4SLinus Torvalds	push_string(name);
1281da177e4SLinus Torvalds	push_pad();
1291da177e4SLinus Torvalds	push_string(target);
1301da177e4SLinus Torvalds	push_pad();
1311da177e4SLinus Torvalds	return 0;
1321da177e4SLinus Torvalds}
1331da177e4SLinus Torvalds
1341da177e4SLinus Torvaldsstatic int cpio_mkslink_line(const char *line)
1351da177e4SLinus Torvalds{
1361da177e4SLinus Torvalds	char name[PATH_MAX + 1];
1371da177e4SLinus Torvalds	char target[PATH_MAX + 1];
1381da177e4SLinus Torvalds	unsigned int mode;
1391da177e4SLinus Torvalds	int uid;
1401da177e4SLinus Torvalds	int gid;
1411da177e4SLinus Torvalds	int rc = -1;
1421da177e4SLinus Torvalds
1431da177e4SLinus Torvalds	if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) {
1441da177e4SLinus Torvalds		fprintf(stderr, "Unrecognized dir format '%s'", line);
1451da177e4SLinus Torvalds		goto fail;
1461da177e4SLinus Torvalds	}
1471da177e4SLinus Torvalds	rc = cpio_mkslink(name, target, mode, uid, gid);
1481da177e4SLinus Torvalds fail:
1491da177e4SLinus Torvalds	return rc;
1501da177e4SLinus Torvalds}
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvaldsstatic int cpio_mkgeneric(const char *name, unsigned int mode,
1531da177e4SLinus Torvalds		       uid_t uid, gid_t gid)
1541da177e4SLinus Torvalds{
1551da177e4SLinus Torvalds	char s[256];
1561da177e4SLinus Torvalds
15743f901fbSThomas Chou	if (name[0] == '/')
15843f901fbSThomas Chou		name++;
1591da177e4SLinus Torvalds	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
1601da177e4SLinus Torvalds	       "%08X%08X%08X%08X%08X%08X%08X",
1611da177e4SLinus Torvalds		"070701",		/* magic */
1621da177e4SLinus Torvalds		ino++,			/* ino */
1631da177e4SLinus Torvalds		mode,			/* mode */
1641da177e4SLinus Torvalds		(long) uid,		/* uid */
1651da177e4SLinus Torvalds		(long) gid,		/* gid */
1661da177e4SLinus Torvalds		2,			/* nlink */
167a8b8017cSMichal Marek		(long) default_mtime,	/* mtime */
1681da177e4SLinus Torvalds		0,			/* filesize */
1691da177e4SLinus Torvalds		3,			/* major */
1701da177e4SLinus Torvalds		1,			/* minor */
1711da177e4SLinus Torvalds		0,			/* rmajor */
1721da177e4SLinus Torvalds		0,			/* rminor */
1731da177e4SLinus Torvalds		(unsigned)strlen(name) + 1,/* namesize */
1741da177e4SLinus Torvalds		0);			/* chksum */
1751da177e4SLinus Torvalds	push_hdr(s);
1761da177e4SLinus Torvalds	push_rest(name);
1771da177e4SLinus Torvalds	return 0;
1781da177e4SLinus Torvalds}
1791da177e4SLinus Torvalds
1801da177e4SLinus Torvaldsenum generic_types {
1811da177e4SLinus Torvalds	GT_DIR,
1821da177e4SLinus Torvalds	GT_PIPE,
1831da177e4SLinus Torvalds	GT_SOCK
1841da177e4SLinus Torvalds};
1851da177e4SLinus Torvalds
1861da177e4SLinus Torvaldsstruct generic_type {
1871da177e4SLinus Torvalds	const char *type;
1881da177e4SLinus Torvalds	mode_t mode;
1891da177e4SLinus Torvalds};
1901da177e4SLinus Torvalds
1911da177e4SLinus Torvaldsstatic struct generic_type generic_type_table[] = {
1921da177e4SLinus Torvalds	[GT_DIR] = {
1931da177e4SLinus Torvalds		.type = "dir",
1941da177e4SLinus Torvalds		.mode = S_IFDIR
1951da177e4SLinus Torvalds	},
1961da177e4SLinus Torvalds	[GT_PIPE] = {
1971da177e4SLinus Torvalds		.type = "pipe",
1981da177e4SLinus Torvalds		.mode = S_IFIFO
1991da177e4SLinus Torvalds	},
2001da177e4SLinus Torvalds	[GT_SOCK] = {
2011da177e4SLinus Torvalds		.type = "sock",
2021da177e4SLinus Torvalds		.mode = S_IFSOCK
2031da177e4SLinus Torvalds	}
2041da177e4SLinus Torvalds};
2051da177e4SLinus Torvalds
2061da177e4SLinus Torvaldsstatic int cpio_mkgeneric_line(const char *line, enum generic_types gt)
2071da177e4SLinus Torvalds{
2081da177e4SLinus Torvalds	char name[PATH_MAX + 1];
2091da177e4SLinus Torvalds	unsigned int mode;
2101da177e4SLinus Torvalds	int uid;
2111da177e4SLinus Torvalds	int gid;
2121da177e4SLinus Torvalds	int rc = -1;
2131da177e4SLinus Torvalds
2141da177e4SLinus Torvalds	if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) {
2151da177e4SLinus Torvalds		fprintf(stderr, "Unrecognized %s format '%s'",
2161da177e4SLinus Torvalds			line, generic_type_table[gt].type);
2171da177e4SLinus Torvalds		goto fail;
2181da177e4SLinus Torvalds	}
2191da177e4SLinus Torvalds	mode |= generic_type_table[gt].mode;
2201da177e4SLinus Torvalds	rc = cpio_mkgeneric(name, mode, uid, gid);
2211da177e4SLinus Torvalds fail:
2221da177e4SLinus Torvalds	return rc;
2231da177e4SLinus Torvalds}
2241da177e4SLinus Torvalds
2251da177e4SLinus Torvaldsstatic int cpio_mkdir_line(const char *line)
2261da177e4SLinus Torvalds{
2271da177e4SLinus Torvalds	return cpio_mkgeneric_line(line, GT_DIR);
2281da177e4SLinus Torvalds}
2291da177e4SLinus Torvalds
2301da177e4SLinus Torvaldsstatic int cpio_mkpipe_line(const char *line)
2311da177e4SLinus Torvalds{
2321da177e4SLinus Torvalds	return cpio_mkgeneric_line(line, GT_PIPE);
2331da177e4SLinus Torvalds}
2341da177e4SLinus Torvalds
2351da177e4SLinus Torvaldsstatic int cpio_mksock_line(const char *line)
2361da177e4SLinus Torvalds{
2371da177e4SLinus Torvalds	return cpio_mkgeneric_line(line, GT_SOCK);
2381da177e4SLinus Torvalds}
2391da177e4SLinus Torvalds
2401da177e4SLinus Torvaldsstatic int cpio_mknod(const char *name, unsigned int mode,
2411da177e4SLinus Torvalds		       uid_t uid, gid_t gid, char dev_type,
2421da177e4SLinus Torvalds		       unsigned int maj, unsigned int min)
2431da177e4SLinus Torvalds{
2441da177e4SLinus Torvalds	char s[256];
2451da177e4SLinus Torvalds
2461da177e4SLinus Torvalds	if (dev_type == 'b')
2471da177e4SLinus Torvalds		mode |= S_IFBLK;
2481da177e4SLinus Torvalds	else
2491da177e4SLinus Torvalds		mode |= S_IFCHR;
2501da177e4SLinus Torvalds
25143f901fbSThomas Chou	if (name[0] == '/')
25243f901fbSThomas Chou		name++;
2531da177e4SLinus Torvalds	sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
2541da177e4SLinus Torvalds	       "%08X%08X%08X%08X%08X%08X%08X",
2551da177e4SLinus Torvalds		"070701",		/* magic */
2561da177e4SLinus Torvalds		ino++,			/* ino */
2571da177e4SLinus Torvalds		mode,			/* mode */
2581da177e4SLinus Torvalds		(long) uid,		/* uid */
2591da177e4SLinus Torvalds		(long) gid,		/* gid */
2601da177e4SLinus Torvalds		1,			/* nlink */
261a8b8017cSMichal Marek		(long) default_mtime,	/* mtime */
2621da177e4SLinus Torvalds		0,			/* filesize */
2631da177e4SLinus Torvalds		3,			/* major */
2641da177e4SLinus Torvalds		1,			/* minor */
2651da177e4SLinus Torvalds		maj,			/* rmajor */
2661da177e4SLinus Torvalds		min,			/* rminor */
2671da177e4SLinus Torvalds		(unsigned)strlen(name) + 1,/* namesize */
2681da177e4SLinus Torvalds		0);			/* chksum */
2691da177e4SLinus Torvalds	push_hdr(s);
2701da177e4SLinus Torvalds	push_rest(name);
2711da177e4SLinus Torvalds	return 0;
2721da177e4SLinus Torvalds}
2731da177e4SLinus Torvalds
2741da177e4SLinus Torvaldsstatic int cpio_mknod_line(const char *line)
2751da177e4SLinus Torvalds{
2761da177e4SLinus Torvalds	char name[PATH_MAX + 1];
2771da177e4SLinus Torvalds	unsigned int mode;
2781da177e4SLinus Torvalds	int uid;
2791da177e4SLinus Torvalds	int gid;
2801da177e4SLinus Torvalds	char dev_type;
2811da177e4SLinus Torvalds	unsigned int maj;
2821da177e4SLinus Torvalds	unsigned int min;
2831da177e4SLinus Torvalds	int rc = -1;
2841da177e4SLinus Torvalds
2851da177e4SLinus Torvalds	if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u",
2861da177e4SLinus Torvalds			 name, &mode, &uid, &gid, &dev_type, &maj, &min)) {
2871da177e4SLinus Torvalds		fprintf(stderr, "Unrecognized nod format '%s'", line);
2881da177e4SLinus Torvalds		goto fail;
2891da177e4SLinus Torvalds	}
2901da177e4SLinus Torvalds	rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min);
2911da177e4SLinus Torvalds fail:
2921da177e4SLinus Torvalds	return rc;
2931da177e4SLinus Torvalds}
2941da177e4SLinus Torvalds
2951da177e4SLinus Torvaldsstatic int cpio_mkfile(const char *name, const char *location,
29624fa5096SLuciano Rocha			unsigned int mode, uid_t uid, gid_t gid,
29724fa5096SLuciano Rocha			unsigned int nlinks)
2981da177e4SLinus Torvalds{
2991da177e4SLinus Torvalds	char s[256];
3001da177e4SLinus Torvalds	char *filebuf = NULL;
3011da177e4SLinus Torvalds	struct stat buf;
30224fa5096SLuciano Rocha	long size;
3031da177e4SLinus Torvalds	int file = -1;
3041da177e4SLinus Torvalds	int retval;
3051da177e4SLinus Torvalds	int rc = -1;
30624fa5096SLuciano Rocha	int namesize;
30720f1de65SKees Cook	unsigned int i;
3081da177e4SLinus Torvalds
3091da177e4SLinus Torvalds	mode |= S_IFREG;
3101da177e4SLinus Torvalds
3111da177e4SLinus Torvalds	file = open (location, O_RDONLY);
3121da177e4SLinus Torvalds	if (file < 0) {
3131da177e4SLinus Torvalds		fprintf (stderr, "File %s could not be opened for reading\n", location);
3141da177e4SLinus Torvalds		goto error;
3151da177e4SLinus Torvalds	}
3161da177e4SLinus Torvalds
317a3c888fcSAndrew Morton	retval = fstat(file, &buf);
31896aebafaSJesper Juhl	if (retval) {
319a3c888fcSAndrew Morton		fprintf(stderr, "File %s could not be stat()'ed\n", location);
32096aebafaSJesper Juhl		goto error;
32196aebafaSJesper Juhl	}
32296aebafaSJesper Juhl
3231da177e4SLinus Torvalds	filebuf = malloc(buf.st_size);
3241da177e4SLinus Torvalds	if (!filebuf) {
3251da177e4SLinus Torvalds		fprintf (stderr, "out of memory\n");
3261da177e4SLinus Torvalds		goto error;
3271da177e4SLinus Torvalds	}
3281da177e4SLinus Torvalds
3291da177e4SLinus Torvalds	retval = read (file, filebuf, buf.st_size);
3301da177e4SLinus Torvalds	if (retval < 0) {
3311da177e4SLinus Torvalds		fprintf (stderr, "Can not read %s file\n", location);
3321da177e4SLinus Torvalds		goto error;
3331da177e4SLinus Torvalds	}
3341da177e4SLinus Torvalds
33524fa5096SLuciano Rocha	size = 0;
33624fa5096SLuciano Rocha	for (i = 1; i <= nlinks; i++) {
33724fa5096SLuciano Rocha		/* data goes on last link */
33824fa5096SLuciano Rocha		if (i == nlinks) size = buf.st_size;
33924fa5096SLuciano Rocha
34043f901fbSThomas Chou		if (name[0] == '/')
34143f901fbSThomas Chou			name++;
34224fa5096SLuciano Rocha		namesize = strlen(name) + 1;
34324fa5096SLuciano Rocha		sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
34424fa5096SLuciano Rocha		       "%08lX%08X%08X%08X%08X%08X%08X",
34524fa5096SLuciano Rocha			"070701",		/* magic */
34624fa5096SLuciano Rocha			ino,			/* ino */
34724fa5096SLuciano Rocha			mode,			/* mode */
34824fa5096SLuciano Rocha			(long) uid,		/* uid */
34924fa5096SLuciano Rocha			(long) gid,		/* gid */
35024fa5096SLuciano Rocha			nlinks,			/* nlink */
35124fa5096SLuciano Rocha			(long) buf.st_mtime,	/* mtime */
35224fa5096SLuciano Rocha			size,			/* filesize */
35324fa5096SLuciano Rocha			3,			/* major */
35424fa5096SLuciano Rocha			1,			/* minor */
35524fa5096SLuciano Rocha			0,			/* rmajor */
35624fa5096SLuciano Rocha			0,			/* rminor */
35724fa5096SLuciano Rocha			namesize,		/* namesize */
35824fa5096SLuciano Rocha			0);			/* chksum */
35924fa5096SLuciano Rocha		push_hdr(s);
36024fa5096SLuciano Rocha		push_string(name);
36124fa5096SLuciano Rocha		push_pad();
36224fa5096SLuciano Rocha
36324fa5096SLuciano Rocha		if (size) {
3646d87fea4SMike Frysinger			if (fwrite(filebuf, size, 1, stdout) != 1) {
3656d87fea4SMike Frysinger				fprintf(stderr, "writing filebuf failed\n");
3666d87fea4SMike Frysinger				goto error;
3676d87fea4SMike Frysinger			}
36824fa5096SLuciano Rocha			offset += size;
36924fa5096SLuciano Rocha			push_pad();
37024fa5096SLuciano Rocha		}
37124fa5096SLuciano Rocha
37224fa5096SLuciano Rocha		name += namesize;
37324fa5096SLuciano Rocha	}
37424fa5096SLuciano Rocha	ino++;
3751da177e4SLinus Torvalds	rc = 0;
3761da177e4SLinus Torvalds
3771da177e4SLinus Torvaldserror:
3781da177e4SLinus Torvalds	if (filebuf) free(filebuf);
3791da177e4SLinus Torvalds	if (file >= 0) close(file);
3801da177e4SLinus Torvalds	return rc;
3811da177e4SLinus Torvalds}
3821da177e4SLinus Torvalds
3833b1ec9fbSSally, Genestatic char *cpio_replace_env(char *new_location)
3843b1ec9fbSSally, Gene{
38520f1de65SKees Cook	char expanded[PATH_MAX + 1];
386c725ee54SMichal Nazarewicz	char *start, *end, *var;
387c725ee54SMichal Nazarewicz
388c725ee54SMichal Nazarewicz	while ((start = strstr(new_location, "${")) &&
389c725ee54SMichal Nazarewicz	       (end = strchr(start + 2, '}'))) {
390c725ee54SMichal Nazarewicz		*start = *end = 0;
391c725ee54SMichal Nazarewicz		var = getenv(start + 2);
392c725ee54SMichal Nazarewicz		snprintf(expanded, sizeof expanded, "%s%s%s",
393c725ee54SMichal Nazarewicz			 new_location, var ? var : "", end + 1);
394c725ee54SMichal Nazarewicz		strcpy(new_location, expanded);
39520f1de65SKees Cook	}
39620f1de65SKees Cook
39720f1de65SKees Cook	return new_location;
3983b1ec9fbSSally, Gene}
3993b1ec9fbSSally, Gene
4001da177e4SLinus Torvaldsstatic int cpio_mkfile_line(const char *line)
4011da177e4SLinus Torvalds{
4021da177e4SLinus Torvalds	char name[PATH_MAX + 1];
40324fa5096SLuciano Rocha	char *dname = NULL; /* malloc'ed buffer for hard links */
4041da177e4SLinus Torvalds	char location[PATH_MAX + 1];
4051da177e4SLinus Torvalds	unsigned int mode;
4061da177e4SLinus Torvalds	int uid;
4071da177e4SLinus Torvalds	int gid;
40824fa5096SLuciano Rocha	int nlinks = 1;
40924fa5096SLuciano Rocha	int end = 0, dname_len = 0;
4101da177e4SLinus Torvalds	int rc = -1;
4111da177e4SLinus Torvalds
41224fa5096SLuciano Rocha	if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
41324fa5096SLuciano Rocha				"s %o %d %d %n",
41424fa5096SLuciano Rocha				name, location, &mode, &uid, &gid, &end)) {
4151da177e4SLinus Torvalds		fprintf(stderr, "Unrecognized file format '%s'", line);
4161da177e4SLinus Torvalds		goto fail;
4171da177e4SLinus Torvalds	}
41824fa5096SLuciano Rocha	if (end && isgraph(line[end])) {
41924fa5096SLuciano Rocha		int len;
42024fa5096SLuciano Rocha		int nend;
42124fa5096SLuciano Rocha
42224fa5096SLuciano Rocha		dname = malloc(strlen(line));
42324fa5096SLuciano Rocha		if (!dname) {
42424fa5096SLuciano Rocha			fprintf (stderr, "out of memory (%d)\n", dname_len);
42524fa5096SLuciano Rocha			goto fail;
42624fa5096SLuciano Rocha		}
42724fa5096SLuciano Rocha
42824fa5096SLuciano Rocha		dname_len = strlen(name) + 1;
42924fa5096SLuciano Rocha		memcpy(dname, name, dname_len);
43024fa5096SLuciano Rocha
43124fa5096SLuciano Rocha		do {
43224fa5096SLuciano Rocha			nend = 0;
43324fa5096SLuciano Rocha			if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
43424fa5096SLuciano Rocha					name, &nend) < 1)
43524fa5096SLuciano Rocha				break;
43624fa5096SLuciano Rocha			len = strlen(name) + 1;
43724fa5096SLuciano Rocha			memcpy(dname + dname_len, name, len);
43824fa5096SLuciano Rocha			dname_len += len;
43924fa5096SLuciano Rocha			nlinks++;
44024fa5096SLuciano Rocha			end += nend;
44124fa5096SLuciano Rocha		} while (isgraph(line[end]));
44224fa5096SLuciano Rocha	} else {
44324fa5096SLuciano Rocha		dname = name;
44424fa5096SLuciano Rocha	}
4453b1ec9fbSSally, Gene	rc = cpio_mkfile(dname, cpio_replace_env(location),
4463b1ec9fbSSally, Gene	                 mode, uid, gid, nlinks);
4471da177e4SLinus Torvalds fail:
44824fa5096SLuciano Rocha	if (dname_len) free(dname);
4491da177e4SLinus Torvalds	return rc;
4501da177e4SLinus Torvalds}
4511da177e4SLinus Torvalds
4525c725138STrevor Keithstatic void usage(const char *prog)
4531da177e4SLinus Torvalds{
4541da177e4SLinus Torvalds	fprintf(stderr, "Usage:\n"
455a8b8017cSMichal Marek		"\t%s [-t <timestamp>] <cpio_list>\n"
4561da177e4SLinus Torvalds		"\n"
4571da177e4SLinus Torvalds		"<cpio_list> is a file containing newline separated entries that\n"
4581da177e4SLinus Torvalds		"describe the files to be included in the initramfs archive:\n"
4591da177e4SLinus Torvalds		"\n"
4601da177e4SLinus Torvalds		"# a comment\n"
46124fa5096SLuciano Rocha		"file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
4621da177e4SLinus Torvalds		"dir <name> <mode> <uid> <gid>\n"
4631da177e4SLinus Torvalds		"nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
4641da177e4SLinus Torvalds		"slink <name> <target> <mode> <uid> <gid>\n"
4651da177e4SLinus Torvalds		"pipe <name> <mode> <uid> <gid>\n"
4661da177e4SLinus Torvalds		"sock <name> <mode> <uid> <gid>\n"
4671da177e4SLinus Torvalds		"\n"
46824fa5096SLuciano Rocha		"<name>       name of the file/dir/nod/etc in the archive\n"
46924fa5096SLuciano Rocha		"<location>   location of the file in the current filesystem\n"
4703b1ec9fbSSally, Gene		"             expands shell variables quoted with ${}\n"
47124fa5096SLuciano Rocha		"<target>     link target\n"
47224fa5096SLuciano Rocha		"<mode>       mode/permissions of the file\n"
47324fa5096SLuciano Rocha		"<uid>        user id (0=root)\n"
47424fa5096SLuciano Rocha		"<gid>        group id (0=root)\n"
47524fa5096SLuciano Rocha		"<dev_type>   device type (b=block, c=character)\n"
47624fa5096SLuciano Rocha		"<maj>        major number of nod\n"
47724fa5096SLuciano Rocha		"<min>        minor number of nod\n"
47824fa5096SLuciano Rocha		"<hard links> space separated list of other links to file\n"
4791da177e4SLinus Torvalds		"\n"
4801da177e4SLinus Torvalds		"example:\n"
4811da177e4SLinus Torvalds		"# A simple initramfs\n"
4821da177e4SLinus Torvalds		"dir /dev 0755 0 0\n"
4831da177e4SLinus Torvalds		"nod /dev/console 0600 0 0 c 5 1\n"
4841da177e4SLinus Torvalds		"dir /root 0700 0 0\n"
4851da177e4SLinus Torvalds		"dir /sbin 0755 0 0\n"
486a8b8017cSMichal Marek		"file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
487a8b8017cSMichal Marek		"\n"
488a8b8017cSMichal Marek		"<timestamp> is time in seconds since Epoch that will be used\n"
489a8b8017cSMichal Marek		"as mtime for symlinks, special files and directories. The default\n"
490a8b8017cSMichal Marek		"is to use the current time for these entries.\n",
4911da177e4SLinus Torvalds		prog);
4921da177e4SLinus Torvalds}
4931da177e4SLinus Torvalds
4941da177e4SLinus Torvaldsstruct file_handler file_handler_table[] = {
4951da177e4SLinus Torvalds	{
4961da177e4SLinus Torvalds		.type    = "file",
4971da177e4SLinus Torvalds		.handler = cpio_mkfile_line,
4981da177e4SLinus Torvalds	}, {
4991da177e4SLinus Torvalds		.type    = "nod",
5001da177e4SLinus Torvalds		.handler = cpio_mknod_line,
5011da177e4SLinus Torvalds	}, {
5021da177e4SLinus Torvalds		.type    = "dir",
5031da177e4SLinus Torvalds		.handler = cpio_mkdir_line,
5041da177e4SLinus Torvalds	}, {
5051da177e4SLinus Torvalds		.type    = "slink",
5061da177e4SLinus Torvalds		.handler = cpio_mkslink_line,
5071da177e4SLinus Torvalds	}, {
5081da177e4SLinus Torvalds		.type    = "pipe",
5091da177e4SLinus Torvalds		.handler = cpio_mkpipe_line,
5101da177e4SLinus Torvalds	}, {
5111da177e4SLinus Torvalds		.type    = "sock",
5121da177e4SLinus Torvalds		.handler = cpio_mksock_line,
5131da177e4SLinus Torvalds	}, {
5141da177e4SLinus Torvalds		.type    = NULL,
5151da177e4SLinus Torvalds		.handler = NULL,
5161da177e4SLinus Torvalds	}
5171da177e4SLinus Torvalds};
5181da177e4SLinus Torvalds
5191da177e4SLinus Torvalds#define LINE_SIZE (2 * PATH_MAX + 50)
5201da177e4SLinus Torvalds
5211da177e4SLinus Torvaldsint main (int argc, char *argv[])
5221da177e4SLinus Torvalds{
5231da177e4SLinus Torvalds	FILE *cpio_list;
5241da177e4SLinus Torvalds	char line[LINE_SIZE];
5251da177e4SLinus Torvalds	char *args, *type;
5261da177e4SLinus Torvalds	int ec = 0;
5271da177e4SLinus Torvalds	int line_nr = 0;
528a8b8017cSMichal Marek	const char *filename;
529a8b8017cSMichal Marek
530a8b8017cSMichal Marek	default_mtime = time(NULL);
531a8b8017cSMichal Marek	while (1) {
532a8b8017cSMichal Marek		int opt = getopt(argc, argv, "t:h");
533a8b8017cSMichal Marek		char *invalid;
534a8b8017cSMichal Marek
535