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