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