18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <stdio.h> 38c2ecf20Sopenharmony_ci#include <stdlib.h> 48c2ecf20Sopenharmony_ci#include <sys/types.h> 58c2ecf20Sopenharmony_ci#include <sys/stat.h> 68c2ecf20Sopenharmony_ci#include <string.h> 78c2ecf20Sopenharmony_ci#include <unistd.h> 88c2ecf20Sopenharmony_ci#include <time.h> 98c2ecf20Sopenharmony_ci#include <fcntl.h> 108c2ecf20Sopenharmony_ci#include <errno.h> 118c2ecf20Sopenharmony_ci#include <ctype.h> 128c2ecf20Sopenharmony_ci#include <limits.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * Original work by Jeff Garzik 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * External file lists, symlink, pipe and fifo support by Thayne Harbaugh 188c2ecf20Sopenharmony_ci * Hard link support by Luciano Rocha 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define xstr(s) #s 228c2ecf20Sopenharmony_ci#define str(s) xstr(s) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic unsigned int offset; 258c2ecf20Sopenharmony_cistatic unsigned int ino = 721; 268c2ecf20Sopenharmony_cistatic time_t default_mtime; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct file_handler { 298c2ecf20Sopenharmony_ci const char *type; 308c2ecf20Sopenharmony_ci int (*handler)(const char *line); 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic void push_string(const char *name) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci unsigned int name_len = strlen(name) + 1; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci fputs(name, stdout); 388c2ecf20Sopenharmony_ci putchar(0); 398c2ecf20Sopenharmony_ci offset += name_len; 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void push_pad (void) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci while (offset & 3) { 458c2ecf20Sopenharmony_ci putchar(0); 468c2ecf20Sopenharmony_ci offset++; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void push_rest(const char *name) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci unsigned int name_len = strlen(name) + 1; 538c2ecf20Sopenharmony_ci unsigned int tmp_ofs; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci fputs(name, stdout); 568c2ecf20Sopenharmony_ci putchar(0); 578c2ecf20Sopenharmony_ci offset += name_len; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci tmp_ofs = name_len + 110; 608c2ecf20Sopenharmony_ci while (tmp_ofs & 3) { 618c2ecf20Sopenharmony_ci putchar(0); 628c2ecf20Sopenharmony_ci offset++; 638c2ecf20Sopenharmony_ci tmp_ofs++; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void push_hdr(const char *s) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci fputs(s, stdout); 708c2ecf20Sopenharmony_ci offset += 110; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic void cpio_trailer(void) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci char s[256]; 768c2ecf20Sopenharmony_ci const char name[] = "TRAILER!!!"; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX" 798c2ecf20Sopenharmony_ci "%08X%08X%08X%08X%08X%08X%08X", 808c2ecf20Sopenharmony_ci "070701", /* magic */ 818c2ecf20Sopenharmony_ci 0, /* ino */ 828c2ecf20Sopenharmony_ci 0, /* mode */ 838c2ecf20Sopenharmony_ci (long) 0, /* uid */ 848c2ecf20Sopenharmony_ci (long) 0, /* gid */ 858c2ecf20Sopenharmony_ci 1, /* nlink */ 868c2ecf20Sopenharmony_ci (long) 0, /* mtime */ 878c2ecf20Sopenharmony_ci 0, /* filesize */ 888c2ecf20Sopenharmony_ci 0, /* major */ 898c2ecf20Sopenharmony_ci 0, /* minor */ 908c2ecf20Sopenharmony_ci 0, /* rmajor */ 918c2ecf20Sopenharmony_ci 0, /* rminor */ 928c2ecf20Sopenharmony_ci (unsigned)strlen(name)+1, /* namesize */ 938c2ecf20Sopenharmony_ci 0); /* chksum */ 948c2ecf20Sopenharmony_ci push_hdr(s); 958c2ecf20Sopenharmony_ci push_rest(name); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci while (offset % 512) { 988c2ecf20Sopenharmony_ci putchar(0); 998c2ecf20Sopenharmony_ci offset++; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int cpio_mkslink(const char *name, const char *target, 1048c2ecf20Sopenharmony_ci unsigned int mode, uid_t uid, gid_t gid) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci char s[256]; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (name[0] == '/') 1098c2ecf20Sopenharmony_ci name++; 1108c2ecf20Sopenharmony_ci sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" 1118c2ecf20Sopenharmony_ci "%08X%08X%08X%08X%08X%08X%08X", 1128c2ecf20Sopenharmony_ci "070701", /* magic */ 1138c2ecf20Sopenharmony_ci ino++, /* ino */ 1148c2ecf20Sopenharmony_ci S_IFLNK | mode, /* mode */ 1158c2ecf20Sopenharmony_ci (long) uid, /* uid */ 1168c2ecf20Sopenharmony_ci (long) gid, /* gid */ 1178c2ecf20Sopenharmony_ci 1, /* nlink */ 1188c2ecf20Sopenharmony_ci (long) default_mtime, /* mtime */ 1198c2ecf20Sopenharmony_ci (unsigned)strlen(target)+1, /* filesize */ 1208c2ecf20Sopenharmony_ci 3, /* major */ 1218c2ecf20Sopenharmony_ci 1, /* minor */ 1228c2ecf20Sopenharmony_ci 0, /* rmajor */ 1238c2ecf20Sopenharmony_ci 0, /* rminor */ 1248c2ecf20Sopenharmony_ci (unsigned)strlen(name) + 1,/* namesize */ 1258c2ecf20Sopenharmony_ci 0); /* chksum */ 1268c2ecf20Sopenharmony_ci push_hdr(s); 1278c2ecf20Sopenharmony_ci push_string(name); 1288c2ecf20Sopenharmony_ci push_pad(); 1298c2ecf20Sopenharmony_ci push_string(target); 1308c2ecf20Sopenharmony_ci push_pad(); 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int cpio_mkslink_line(const char *line) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci char name[PATH_MAX + 1]; 1378c2ecf20Sopenharmony_ci char target[PATH_MAX + 1]; 1388c2ecf20Sopenharmony_ci unsigned int mode; 1398c2ecf20Sopenharmony_ci int uid; 1408c2ecf20Sopenharmony_ci int gid; 1418c2ecf20Sopenharmony_ci int rc = -1; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) { 1448c2ecf20Sopenharmony_ci fprintf(stderr, "Unrecognized dir format '%s'", line); 1458c2ecf20Sopenharmony_ci goto fail; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci rc = cpio_mkslink(name, target, mode, uid, gid); 1488c2ecf20Sopenharmony_ci fail: 1498c2ecf20Sopenharmony_ci return rc; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic int cpio_mkgeneric(const char *name, unsigned int mode, 1538c2ecf20Sopenharmony_ci uid_t uid, gid_t gid) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci char s[256]; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (name[0] == '/') 1588c2ecf20Sopenharmony_ci name++; 1598c2ecf20Sopenharmony_ci sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" 1608c2ecf20Sopenharmony_ci "%08X%08X%08X%08X%08X%08X%08X", 1618c2ecf20Sopenharmony_ci "070701", /* magic */ 1628c2ecf20Sopenharmony_ci ino++, /* ino */ 1638c2ecf20Sopenharmony_ci mode, /* mode */ 1648c2ecf20Sopenharmony_ci (long) uid, /* uid */ 1658c2ecf20Sopenharmony_ci (long) gid, /* gid */ 1668c2ecf20Sopenharmony_ci 2, /* nlink */ 1678c2ecf20Sopenharmony_ci (long) default_mtime, /* mtime */ 1688c2ecf20Sopenharmony_ci 0, /* filesize */ 1698c2ecf20Sopenharmony_ci 3, /* major */ 1708c2ecf20Sopenharmony_ci 1, /* minor */ 1718c2ecf20Sopenharmony_ci 0, /* rmajor */ 1728c2ecf20Sopenharmony_ci 0, /* rminor */ 1738c2ecf20Sopenharmony_ci (unsigned)strlen(name) + 1,/* namesize */ 1748c2ecf20Sopenharmony_ci 0); /* chksum */ 1758c2ecf20Sopenharmony_ci push_hdr(s); 1768c2ecf20Sopenharmony_ci push_rest(name); 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cienum generic_types { 1818c2ecf20Sopenharmony_ci GT_DIR, 1828c2ecf20Sopenharmony_ci GT_PIPE, 1838c2ecf20Sopenharmony_ci GT_SOCK 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistruct generic_type { 1878c2ecf20Sopenharmony_ci const char *type; 1888c2ecf20Sopenharmony_ci mode_t mode; 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic struct generic_type generic_type_table[] = { 1928c2ecf20Sopenharmony_ci [GT_DIR] = { 1938c2ecf20Sopenharmony_ci .type = "dir", 1948c2ecf20Sopenharmony_ci .mode = S_IFDIR 1958c2ecf20Sopenharmony_ci }, 1968c2ecf20Sopenharmony_ci [GT_PIPE] = { 1978c2ecf20Sopenharmony_ci .type = "pipe", 1988c2ecf20Sopenharmony_ci .mode = S_IFIFO 1998c2ecf20Sopenharmony_ci }, 2008c2ecf20Sopenharmony_ci [GT_SOCK] = { 2018c2ecf20Sopenharmony_ci .type = "sock", 2028c2ecf20Sopenharmony_ci .mode = S_IFSOCK 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci}; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int cpio_mkgeneric_line(const char *line, enum generic_types gt) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci char name[PATH_MAX + 1]; 2098c2ecf20Sopenharmony_ci unsigned int mode; 2108c2ecf20Sopenharmony_ci int uid; 2118c2ecf20Sopenharmony_ci int gid; 2128c2ecf20Sopenharmony_ci int rc = -1; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) { 2158c2ecf20Sopenharmony_ci fprintf(stderr, "Unrecognized %s format '%s'", 2168c2ecf20Sopenharmony_ci line, generic_type_table[gt].type); 2178c2ecf20Sopenharmony_ci goto fail; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci mode |= generic_type_table[gt].mode; 2208c2ecf20Sopenharmony_ci rc = cpio_mkgeneric(name, mode, uid, gid); 2218c2ecf20Sopenharmony_ci fail: 2228c2ecf20Sopenharmony_ci return rc; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int cpio_mkdir_line(const char *line) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci return cpio_mkgeneric_line(line, GT_DIR); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int cpio_mkpipe_line(const char *line) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci return cpio_mkgeneric_line(line, GT_PIPE); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int cpio_mksock_line(const char *line) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci return cpio_mkgeneric_line(line, GT_SOCK); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int cpio_mknod(const char *name, unsigned int mode, 2418c2ecf20Sopenharmony_ci uid_t uid, gid_t gid, char dev_type, 2428c2ecf20Sopenharmony_ci unsigned int maj, unsigned int min) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci char s[256]; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (dev_type == 'b') 2478c2ecf20Sopenharmony_ci mode |= S_IFBLK; 2488c2ecf20Sopenharmony_ci else 2498c2ecf20Sopenharmony_ci mode |= S_IFCHR; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (name[0] == '/') 2528c2ecf20Sopenharmony_ci name++; 2538c2ecf20Sopenharmony_ci sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" 2548c2ecf20Sopenharmony_ci "%08X%08X%08X%08X%08X%08X%08X", 2558c2ecf20Sopenharmony_ci "070701", /* magic */ 2568c2ecf20Sopenharmony_ci ino++, /* ino */ 2578c2ecf20Sopenharmony_ci mode, /* mode */ 2588c2ecf20Sopenharmony_ci (long) uid, /* uid */ 2598c2ecf20Sopenharmony_ci (long) gid, /* gid */ 2608c2ecf20Sopenharmony_ci 1, /* nlink */ 2618c2ecf20Sopenharmony_ci (long) default_mtime, /* mtime */ 2628c2ecf20Sopenharmony_ci 0, /* filesize */ 2638c2ecf20Sopenharmony_ci 3, /* major */ 2648c2ecf20Sopenharmony_ci 1, /* minor */ 2658c2ecf20Sopenharmony_ci maj, /* rmajor */ 2668c2ecf20Sopenharmony_ci min, /* rminor */ 2678c2ecf20Sopenharmony_ci (unsigned)strlen(name) + 1,/* namesize */ 2688c2ecf20Sopenharmony_ci 0); /* chksum */ 2698c2ecf20Sopenharmony_ci push_hdr(s); 2708c2ecf20Sopenharmony_ci push_rest(name); 2718c2ecf20Sopenharmony_ci return 0; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic int cpio_mknod_line(const char *line) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci char name[PATH_MAX + 1]; 2778c2ecf20Sopenharmony_ci unsigned int mode; 2788c2ecf20Sopenharmony_ci int uid; 2798c2ecf20Sopenharmony_ci int gid; 2808c2ecf20Sopenharmony_ci char dev_type; 2818c2ecf20Sopenharmony_ci unsigned int maj; 2828c2ecf20Sopenharmony_ci unsigned int min; 2838c2ecf20Sopenharmony_ci int rc = -1; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u", 2868c2ecf20Sopenharmony_ci name, &mode, &uid, &gid, &dev_type, &maj, &min)) { 2878c2ecf20Sopenharmony_ci fprintf(stderr, "Unrecognized nod format '%s'", line); 2888c2ecf20Sopenharmony_ci goto fail; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min); 2918c2ecf20Sopenharmony_ci fail: 2928c2ecf20Sopenharmony_ci return rc; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int cpio_mkfile(const char *name, const char *location, 2968c2ecf20Sopenharmony_ci unsigned int mode, uid_t uid, gid_t gid, 2978c2ecf20Sopenharmony_ci unsigned int nlinks) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci char s[256]; 3008c2ecf20Sopenharmony_ci char *filebuf = NULL; 3018c2ecf20Sopenharmony_ci struct stat buf; 3028c2ecf20Sopenharmony_ci long size; 3038c2ecf20Sopenharmony_ci int file = -1; 3048c2ecf20Sopenharmony_ci int retval; 3058c2ecf20Sopenharmony_ci int rc = -1; 3068c2ecf20Sopenharmony_ci int namesize; 3078c2ecf20Sopenharmony_ci unsigned int i; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci mode |= S_IFREG; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci file = open (location, O_RDONLY); 3128c2ecf20Sopenharmony_ci if (file < 0) { 3138c2ecf20Sopenharmony_ci fprintf (stderr, "File %s could not be opened for reading\n", location); 3148c2ecf20Sopenharmony_ci goto error; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci retval = fstat(file, &buf); 3188c2ecf20Sopenharmony_ci if (retval) { 3198c2ecf20Sopenharmony_ci fprintf(stderr, "File %s could not be stat()'ed\n", location); 3208c2ecf20Sopenharmony_ci goto error; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci filebuf = malloc(buf.st_size); 3248c2ecf20Sopenharmony_ci if (!filebuf) { 3258c2ecf20Sopenharmony_ci fprintf (stderr, "out of memory\n"); 3268c2ecf20Sopenharmony_ci goto error; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci retval = read (file, filebuf, buf.st_size); 3308c2ecf20Sopenharmony_ci if (retval < 0) { 3318c2ecf20Sopenharmony_ci fprintf (stderr, "Can not read %s file\n", location); 3328c2ecf20Sopenharmony_ci goto error; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci size = 0; 3368c2ecf20Sopenharmony_ci for (i = 1; i <= nlinks; i++) { 3378c2ecf20Sopenharmony_ci /* data goes on last link */ 3388c2ecf20Sopenharmony_ci if (i == nlinks) size = buf.st_size; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (name[0] == '/') 3418c2ecf20Sopenharmony_ci name++; 3428c2ecf20Sopenharmony_ci namesize = strlen(name) + 1; 3438c2ecf20Sopenharmony_ci sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" 3448c2ecf20Sopenharmony_ci "%08lX%08X%08X%08X%08X%08X%08X", 3458c2ecf20Sopenharmony_ci "070701", /* magic */ 3468c2ecf20Sopenharmony_ci ino, /* ino */ 3478c2ecf20Sopenharmony_ci mode, /* mode */ 3488c2ecf20Sopenharmony_ci (long) uid, /* uid */ 3498c2ecf20Sopenharmony_ci (long) gid, /* gid */ 3508c2ecf20Sopenharmony_ci nlinks, /* nlink */ 3518c2ecf20Sopenharmony_ci (long) buf.st_mtime, /* mtime */ 3528c2ecf20Sopenharmony_ci size, /* filesize */ 3538c2ecf20Sopenharmony_ci 3, /* major */ 3548c2ecf20Sopenharmony_ci 1, /* minor */ 3558c2ecf20Sopenharmony_ci 0, /* rmajor */ 3568c2ecf20Sopenharmony_ci 0, /* rminor */ 3578c2ecf20Sopenharmony_ci namesize, /* namesize */ 3588c2ecf20Sopenharmony_ci 0); /* chksum */ 3598c2ecf20Sopenharmony_ci push_hdr(s); 3608c2ecf20Sopenharmony_ci push_string(name); 3618c2ecf20Sopenharmony_ci push_pad(); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (size) { 3648c2ecf20Sopenharmony_ci if (fwrite(filebuf, size, 1, stdout) != 1) { 3658c2ecf20Sopenharmony_ci fprintf(stderr, "writing filebuf failed\n"); 3668c2ecf20Sopenharmony_ci goto error; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci offset += size; 3698c2ecf20Sopenharmony_ci push_pad(); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci name += namesize; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci ino++; 3758c2ecf20Sopenharmony_ci rc = 0; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cierror: 3788c2ecf20Sopenharmony_ci if (filebuf) free(filebuf); 3798c2ecf20Sopenharmony_ci if (file >= 0) close(file); 3808c2ecf20Sopenharmony_ci return rc; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic char *cpio_replace_env(char *new_location) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci char expanded[PATH_MAX + 1]; 3868c2ecf20Sopenharmony_ci char *start, *end, *var; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci while ((start = strstr(new_location, "${")) && 3898c2ecf20Sopenharmony_ci (end = strchr(start + 2, '}'))) { 3908c2ecf20Sopenharmony_ci *start = *end = 0; 3918c2ecf20Sopenharmony_ci var = getenv(start + 2); 3928c2ecf20Sopenharmony_ci snprintf(expanded, sizeof expanded, "%s%s%s", 3938c2ecf20Sopenharmony_ci new_location, var ? var : "", end + 1); 3948c2ecf20Sopenharmony_ci strcpy(new_location, expanded); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return new_location; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int cpio_mkfile_line(const char *line) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci char name[PATH_MAX + 1]; 4038c2ecf20Sopenharmony_ci char *dname = NULL; /* malloc'ed buffer for hard links */ 4048c2ecf20Sopenharmony_ci char location[PATH_MAX + 1]; 4058c2ecf20Sopenharmony_ci unsigned int mode; 4068c2ecf20Sopenharmony_ci int uid; 4078c2ecf20Sopenharmony_ci int gid; 4088c2ecf20Sopenharmony_ci int nlinks = 1; 4098c2ecf20Sopenharmony_ci int end = 0, dname_len = 0; 4108c2ecf20Sopenharmony_ci int rc = -1; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) 4138c2ecf20Sopenharmony_ci "s %o %d %d %n", 4148c2ecf20Sopenharmony_ci name, location, &mode, &uid, &gid, &end)) { 4158c2ecf20Sopenharmony_ci fprintf(stderr, "Unrecognized file format '%s'", line); 4168c2ecf20Sopenharmony_ci goto fail; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci if (end && isgraph(line[end])) { 4198c2ecf20Sopenharmony_ci int len; 4208c2ecf20Sopenharmony_ci int nend; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci dname = malloc(strlen(line)); 4238c2ecf20Sopenharmony_ci if (!dname) { 4248c2ecf20Sopenharmony_ci fprintf (stderr, "out of memory (%d)\n", dname_len); 4258c2ecf20Sopenharmony_ci goto fail; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci dname_len = strlen(name) + 1; 4298c2ecf20Sopenharmony_ci memcpy(dname, name, dname_len); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci do { 4328c2ecf20Sopenharmony_ci nend = 0; 4338c2ecf20Sopenharmony_ci if (sscanf(line + end, "%" str(PATH_MAX) "s %n", 4348c2ecf20Sopenharmony_ci name, &nend) < 1) 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci len = strlen(name) + 1; 4378c2ecf20Sopenharmony_ci memcpy(dname + dname_len, name, len); 4388c2ecf20Sopenharmony_ci dname_len += len; 4398c2ecf20Sopenharmony_ci nlinks++; 4408c2ecf20Sopenharmony_ci end += nend; 4418c2ecf20Sopenharmony_ci } while (isgraph(line[end])); 4428c2ecf20Sopenharmony_ci } else { 4438c2ecf20Sopenharmony_ci dname = name; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci rc = cpio_mkfile(dname, cpio_replace_env(location), 4468c2ecf20Sopenharmony_ci mode, uid, gid, nlinks); 4478c2ecf20Sopenharmony_ci fail: 4488c2ecf20Sopenharmony_ci if (dname_len) free(dname); 4498c2ecf20Sopenharmony_ci return rc; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic void usage(const char *prog) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci fprintf(stderr, "Usage:\n" 4558c2ecf20Sopenharmony_ci "\t%s [-t <timestamp>] <cpio_list>\n" 4568c2ecf20Sopenharmony_ci "\n" 4578c2ecf20Sopenharmony_ci "<cpio_list> is a file containing newline separated entries that\n" 4588c2ecf20Sopenharmony_ci "describe the files to be included in the initramfs archive:\n" 4598c2ecf20Sopenharmony_ci "\n" 4608c2ecf20Sopenharmony_ci "# a comment\n" 4618c2ecf20Sopenharmony_ci "file <name> <location> <mode> <uid> <gid> [<hard links>]\n" 4628c2ecf20Sopenharmony_ci "dir <name> <mode> <uid> <gid>\n" 4638c2ecf20Sopenharmony_ci "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n" 4648c2ecf20Sopenharmony_ci "slink <name> <target> <mode> <uid> <gid>\n" 4658c2ecf20Sopenharmony_ci "pipe <name> <mode> <uid> <gid>\n" 4668c2ecf20Sopenharmony_ci "sock <name> <mode> <uid> <gid>\n" 4678c2ecf20Sopenharmony_ci "\n" 4688c2ecf20Sopenharmony_ci "<name> name of the file/dir/nod/etc in the archive\n" 4698c2ecf20Sopenharmony_ci "<location> location of the file in the current filesystem\n" 4708c2ecf20Sopenharmony_ci " expands shell variables quoted with ${}\n" 4718c2ecf20Sopenharmony_ci "<target> link target\n" 4728c2ecf20Sopenharmony_ci "<mode> mode/permissions of the file\n" 4738c2ecf20Sopenharmony_ci "<uid> user id (0=root)\n" 4748c2ecf20Sopenharmony_ci "<gid> group id (0=root)\n" 4758c2ecf20Sopenharmony_ci "<dev_type> device type (b=block, c=character)\n" 4768c2ecf20Sopenharmony_ci "<maj> major number of nod\n" 4778c2ecf20Sopenharmony_ci "<min> minor number of nod\n" 4788c2ecf20Sopenharmony_ci "<hard links> space separated list of other links to file\n" 4798c2ecf20Sopenharmony_ci "\n" 4808c2ecf20Sopenharmony_ci "example:\n" 4818c2ecf20Sopenharmony_ci "# A simple initramfs\n" 4828c2ecf20Sopenharmony_ci "dir /dev 0755 0 0\n" 4838c2ecf20Sopenharmony_ci "nod /dev/console 0600 0 0 c 5 1\n" 4848c2ecf20Sopenharmony_ci "dir /root 0700 0 0\n" 4858c2ecf20Sopenharmony_ci "dir /sbin 0755 0 0\n" 4868c2ecf20Sopenharmony_ci "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n" 4878c2ecf20Sopenharmony_ci "\n" 4888c2ecf20Sopenharmony_ci "<timestamp> is time in seconds since Epoch that will be used\n" 4898c2ecf20Sopenharmony_ci "as mtime for symlinks, special files and directories. The default\n" 4908c2ecf20Sopenharmony_ci "is to use the current time for these entries.\n", 4918c2ecf20Sopenharmony_ci prog); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistruct file_handler file_handler_table[] = { 4958c2ecf20Sopenharmony_ci { 4968c2ecf20Sopenharmony_ci .type = "file", 4978c2ecf20Sopenharmony_ci .handler = cpio_mkfile_line, 4988c2ecf20Sopenharmony_ci }, { 4998c2ecf20Sopenharmony_ci .type = "nod", 5008c2ecf20Sopenharmony_ci .handler = cpio_mknod_line, 5018c2ecf20Sopenharmony_ci }, { 5028c2ecf20Sopenharmony_ci .type = "dir", 5038c2ecf20Sopenharmony_ci .handler = cpio_mkdir_line, 5048c2ecf20Sopenharmony_ci }, { 5058c2ecf20Sopenharmony_ci .type = "slink", 5068c2ecf20Sopenharmony_ci .handler = cpio_mkslink_line, 5078c2ecf20Sopenharmony_ci }, { 5088c2ecf20Sopenharmony_ci .type = "pipe", 5098c2ecf20Sopenharmony_ci .handler = cpio_mkpipe_line, 5108c2ecf20Sopenharmony_ci }, { 5118c2ecf20Sopenharmony_ci .type = "sock", 5128c2ecf20Sopenharmony_ci .handler = cpio_mksock_line, 5138c2ecf20Sopenharmony_ci }, { 5148c2ecf20Sopenharmony_ci .type = NULL, 5158c2ecf20Sopenharmony_ci .handler = NULL, 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci}; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci#define LINE_SIZE (2 * PATH_MAX + 50) 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ciint main (int argc, char *argv[]) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci FILE *cpio_list; 5248c2ecf20Sopenharmony_ci char line[LINE_SIZE]; 5258c2ecf20Sopenharmony_ci char *args, *type; 5268c2ecf20Sopenharmony_ci int ec = 0; 5278c2ecf20Sopenharmony_ci int line_nr = 0; 5288c2ecf20Sopenharmony_ci const char *filename; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci default_mtime = time(NULL); 5318c2ecf20Sopenharmony_ci while (1) { 5328c2ecf20Sopenharmony_ci int opt = getopt(argc, argv, "t:h"); 5338c2ecf20Sopenharmony_ci char *invalid; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (opt == -1) 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci switch (opt) { 5388c2ecf20Sopenharmony_ci case 't': 5398c2ecf20Sopenharmony_ci default_mtime = strtol(optarg, &invalid, 10); 5408c2ecf20Sopenharmony_ci if (!*optarg || *invalid) { 5418c2ecf20Sopenharmony_ci fprintf(stderr, "Invalid timestamp: %s\n", 5428c2ecf20Sopenharmony_ci optarg); 5438c2ecf20Sopenharmony_ci usage(argv[0]); 5448c2ecf20Sopenharmony_ci exit(1); 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci case 'h': 5488c2ecf20Sopenharmony_ci case '?': 5498c2ecf20Sopenharmony_ci usage(argv[0]); 5508c2ecf20Sopenharmony_ci exit(opt == 'h' ? 0 : 1); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (argc - optind != 1) { 5558c2ecf20Sopenharmony_ci usage(argv[0]); 5568c2ecf20Sopenharmony_ci exit(1); 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci filename = argv[optind]; 5598c2ecf20Sopenharmony_ci if (!strcmp(filename, "-")) 5608c2ecf20Sopenharmony_ci cpio_list = stdin; 5618c2ecf20Sopenharmony_ci else if (!(cpio_list = fopen(filename, "r"))) { 5628c2ecf20Sopenharmony_ci fprintf(stderr, "ERROR: unable to open '%s': %s\n\n", 5638c2ecf20Sopenharmony_ci filename, strerror(errno)); 5648c2ecf20Sopenharmony_ci usage(argv[0]); 5658c2ecf20Sopenharmony_ci exit(1); 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci while (fgets(line, LINE_SIZE, cpio_list)) { 5698c2ecf20Sopenharmony_ci int type_idx; 5708c2ecf20Sopenharmony_ci size_t slen = strlen(line); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci line_nr++; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if ('#' == *line) { 5758c2ecf20Sopenharmony_ci /* comment - skip to next line */ 5768c2ecf20Sopenharmony_ci continue; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (! (type = strtok(line, " \t"))) { 5808c2ecf20Sopenharmony_ci fprintf(stderr, 5818c2ecf20Sopenharmony_ci "ERROR: incorrect format, could not locate file type line %d: '%s'\n", 5828c2ecf20Sopenharmony_ci line_nr, line); 5838c2ecf20Sopenharmony_ci ec = -1; 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if ('\n' == *type) { 5888c2ecf20Sopenharmony_ci /* a blank line */ 5898c2ecf20Sopenharmony_ci continue; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (slen == strlen(type)) { 5938c2ecf20Sopenharmony_ci /* must be an empty line */ 5948c2ecf20Sopenharmony_ci continue; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (! (args = strtok(NULL, "\n"))) { 5988c2ecf20Sopenharmony_ci fprintf(stderr, 5998c2ecf20Sopenharmony_ci "ERROR: incorrect format, newline required line %d: '%s'\n", 6008c2ecf20Sopenharmony_ci line_nr, line); 6018c2ecf20Sopenharmony_ci ec = -1; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) { 6058c2ecf20Sopenharmony_ci int rc; 6068c2ecf20Sopenharmony_ci if (! strcmp(line, file_handler_table[type_idx].type)) { 6078c2ecf20Sopenharmony_ci if ((rc = file_handler_table[type_idx].handler(args))) { 6088c2ecf20Sopenharmony_ci ec = rc; 6098c2ecf20Sopenharmony_ci fprintf(stderr, " line %d\n", line_nr); 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci break; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (NULL == file_handler_table[type_idx].type) { 6168c2ecf20Sopenharmony_ci fprintf(stderr, "unknown file type line %d: '%s'\n", 6178c2ecf20Sopenharmony_ci line_nr, line); 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci if (ec == 0) 6218c2ecf20Sopenharmony_ci cpio_trailer(); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci exit(ec); 6248c2ecf20Sopenharmony_ci} 625