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