wok diff gen-init-cpio/stuff/gen_init_cpio.c @ rev 5375
Up: grub2 (1.98)
author | Christopher Rogers <slaxemulator@gmail.com> |
---|---|
date | Sat May 01 01:49:05 2010 +0000 (2010-05-01) |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gen-init-cpio/stuff/gen_init_cpio.c Sat May 01 01:49:05 2010 +0000 1.3 @@ -0,0 +1,592 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <sys/types.h> 1.7 +#include <sys/stat.h> 1.8 +#include <string.h> 1.9 +#include <unistd.h> 1.10 +#include <time.h> 1.11 +#include <fcntl.h> 1.12 +#include <errno.h> 1.13 +#include <ctype.h> 1.14 +#include <limits.h> 1.15 + 1.16 +/* 1.17 + * Original work by Jeff Garzik 1.18 + * 1.19 + * External file lists, symlink, pipe and fifo support by Thayne Harbaugh 1.20 + * Hard link support by Luciano Rocha 1.21 + */ 1.22 + 1.23 +#define xstr(s) #s 1.24 +#define str(s) xstr(s) 1.25 + 1.26 +static unsigned int offset; 1.27 +static unsigned int ino = 721; 1.28 + 1.29 +struct file_handler { 1.30 + const char *type; 1.31 + int (*handler)(const char *line); 1.32 +}; 1.33 + 1.34 +static void push_string(const char *name) 1.35 +{ 1.36 + unsigned int name_len = strlen(name) + 1; 1.37 + 1.38 + fputs(name, stdout); 1.39 + putchar(0); 1.40 + offset += name_len; 1.41 +} 1.42 + 1.43 +static void push_pad (void) 1.44 +{ 1.45 + while (offset & 3) { 1.46 + putchar(0); 1.47 + offset++; 1.48 + } 1.49 +} 1.50 + 1.51 +static void push_rest(const char *name) 1.52 +{ 1.53 + unsigned int name_len = strlen(name) + 1; 1.54 + unsigned int tmp_ofs; 1.55 + 1.56 + fputs(name, stdout); 1.57 + putchar(0); 1.58 + offset += name_len; 1.59 + 1.60 + tmp_ofs = name_len + 110; 1.61 + while (tmp_ofs & 3) { 1.62 + putchar(0); 1.63 + offset++; 1.64 + tmp_ofs++; 1.65 + } 1.66 +} 1.67 + 1.68 +static void push_hdr(const char *s) 1.69 +{ 1.70 + fputs(s, stdout); 1.71 + offset += 110; 1.72 +} 1.73 + 1.74 +static void cpio_trailer(void) 1.75 +{ 1.76 + char s[256]; 1.77 + const char name[] = "TRAILER!!!"; 1.78 + 1.79 + sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX" 1.80 + "%08X%08X%08X%08X%08X%08X%08X", 1.81 + "070701", /* magic */ 1.82 + 0, /* ino */ 1.83 + 0, /* mode */ 1.84 + (long) 0, /* uid */ 1.85 + (long) 0, /* gid */ 1.86 + 1, /* nlink */ 1.87 + (long) 0, /* mtime */ 1.88 + 0, /* filesize */ 1.89 + 0, /* major */ 1.90 + 0, /* minor */ 1.91 + 0, /* rmajor */ 1.92 + 0, /* rminor */ 1.93 + (unsigned)strlen(name)+1, /* namesize */ 1.94 + 0); /* chksum */ 1.95 + push_hdr(s); 1.96 + push_rest(name); 1.97 + 1.98 + while (offset % 512) { 1.99 + putchar(0); 1.100 + offset++; 1.101 + } 1.102 +} 1.103 + 1.104 +static int cpio_mkslink(const char *name, const char *target, 1.105 + unsigned int mode, uid_t uid, gid_t gid) 1.106 +{ 1.107 + char s[256]; 1.108 + time_t mtime = time(NULL); 1.109 + 1.110 + sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" 1.111 + "%08X%08X%08X%08X%08X%08X%08X", 1.112 + "070701", /* magic */ 1.113 + ino++, /* ino */ 1.114 + S_IFLNK | mode, /* mode */ 1.115 + (long) uid, /* uid */ 1.116 + (long) gid, /* gid */ 1.117 + 1, /* nlink */ 1.118 + (long) mtime, /* mtime */ 1.119 + (unsigned)strlen(target)+1, /* filesize */ 1.120 + 3, /* major */ 1.121 + 1, /* minor */ 1.122 + 0, /* rmajor */ 1.123 + 0, /* rminor */ 1.124 + (unsigned)strlen(name) + 1,/* namesize */ 1.125 + 0); /* chksum */ 1.126 + push_hdr(s); 1.127 + push_string(name); 1.128 + push_pad(); 1.129 + push_string(target); 1.130 + push_pad(); 1.131 + return 0; 1.132 +} 1.133 + 1.134 +static int cpio_mkslink_line(const char *line) 1.135 +{ 1.136 + char name[PATH_MAX + 1]; 1.137 + char target[PATH_MAX + 1]; 1.138 + unsigned int mode; 1.139 + int uid; 1.140 + int gid; 1.141 + int rc = -1; 1.142 + 1.143 + if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) { 1.144 + fprintf(stderr, "Unrecognized dir format '%s'", line); 1.145 + goto fail; 1.146 + } 1.147 + rc = cpio_mkslink(name, target, mode, uid, gid); 1.148 + fail: 1.149 + return rc; 1.150 +} 1.151 + 1.152 +static int cpio_mkgeneric(const char *name, unsigned int mode, 1.153 + uid_t uid, gid_t gid) 1.154 +{ 1.155 + char s[256]; 1.156 + time_t mtime = time(NULL); 1.157 + 1.158 + sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" 1.159 + "%08X%08X%08X%08X%08X%08X%08X", 1.160 + "070701", /* magic */ 1.161 + ino++, /* ino */ 1.162 + mode, /* mode */ 1.163 + (long) uid, /* uid */ 1.164 + (long) gid, /* gid */ 1.165 + 2, /* nlink */ 1.166 + (long) mtime, /* mtime */ 1.167 + 0, /* filesize */ 1.168 + 3, /* major */ 1.169 + 1, /* minor */ 1.170 + 0, /* rmajor */ 1.171 + 0, /* rminor */ 1.172 + (unsigned)strlen(name) + 1,/* namesize */ 1.173 + 0); /* chksum */ 1.174 + push_hdr(s); 1.175 + push_rest(name); 1.176 + return 0; 1.177 +} 1.178 + 1.179 +enum generic_types { 1.180 + GT_DIR, 1.181 + GT_PIPE, 1.182 + GT_SOCK 1.183 +}; 1.184 + 1.185 +struct generic_type { 1.186 + const char *type; 1.187 + mode_t mode; 1.188 +}; 1.189 + 1.190 +static struct generic_type generic_type_table[] = { 1.191 + [GT_DIR] = { 1.192 + .type = "dir", 1.193 + .mode = S_IFDIR 1.194 + }, 1.195 + [GT_PIPE] = { 1.196 + .type = "pipe", 1.197 + .mode = S_IFIFO 1.198 + }, 1.199 + [GT_SOCK] = { 1.200 + .type = "sock", 1.201 + .mode = S_IFSOCK 1.202 + } 1.203 +}; 1.204 + 1.205 +static int cpio_mkgeneric_line(const char *line, enum generic_types gt) 1.206 +{ 1.207 + char name[PATH_MAX + 1]; 1.208 + unsigned int mode; 1.209 + int uid; 1.210 + int gid; 1.211 + int rc = -1; 1.212 + 1.213 + if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) { 1.214 + fprintf(stderr, "Unrecognized %s format '%s'", 1.215 + line, generic_type_table[gt].type); 1.216 + goto fail; 1.217 + } 1.218 + mode |= generic_type_table[gt].mode; 1.219 + rc = cpio_mkgeneric(name, mode, uid, gid); 1.220 + fail: 1.221 + return rc; 1.222 +} 1.223 + 1.224 +static int cpio_mkdir_line(const char *line) 1.225 +{ 1.226 + return cpio_mkgeneric_line(line, GT_DIR); 1.227 +} 1.228 + 1.229 +static int cpio_mkpipe_line(const char *line) 1.230 +{ 1.231 + return cpio_mkgeneric_line(line, GT_PIPE); 1.232 +} 1.233 + 1.234 +static int cpio_mksock_line(const char *line) 1.235 +{ 1.236 + return cpio_mkgeneric_line(line, GT_SOCK); 1.237 +} 1.238 + 1.239 +static int cpio_mknod(const char *name, unsigned int mode, 1.240 + uid_t uid, gid_t gid, char dev_type, 1.241 + unsigned int maj, unsigned int min) 1.242 +{ 1.243 + char s[256]; 1.244 + time_t mtime = time(NULL); 1.245 + 1.246 + if (dev_type == 'b') 1.247 + mode |= S_IFBLK; 1.248 + else 1.249 + mode |= S_IFCHR; 1.250 + 1.251 + sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" 1.252 + "%08X%08X%08X%08X%08X%08X%08X", 1.253 + "070701", /* magic */ 1.254 + ino++, /* ino */ 1.255 + mode, /* mode */ 1.256 + (long) uid, /* uid */ 1.257 + (long) gid, /* gid */ 1.258 + 1, /* nlink */ 1.259 + (long) mtime, /* mtime */ 1.260 + 0, /* filesize */ 1.261 + 3, /* major */ 1.262 + 1, /* minor */ 1.263 + maj, /* rmajor */ 1.264 + min, /* rminor */ 1.265 + (unsigned)strlen(name) + 1,/* namesize */ 1.266 + 0); /* chksum */ 1.267 + push_hdr(s); 1.268 + push_rest(name); 1.269 + return 0; 1.270 +} 1.271 + 1.272 +static int cpio_mknod_line(const char *line) 1.273 +{ 1.274 + char name[PATH_MAX + 1]; 1.275 + unsigned int mode; 1.276 + int uid; 1.277 + int gid; 1.278 + char dev_type; 1.279 + unsigned int maj; 1.280 + unsigned int min; 1.281 + int rc = -1; 1.282 + 1.283 + if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u", 1.284 + name, &mode, &uid, &gid, &dev_type, &maj, &min)) { 1.285 + fprintf(stderr, "Unrecognized nod format '%s'", line); 1.286 + goto fail; 1.287 + } 1.288 + rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min); 1.289 + fail: 1.290 + return rc; 1.291 +} 1.292 + 1.293 +static int cpio_mkfile(const char *name, const char *location, 1.294 + unsigned int mode, uid_t uid, gid_t gid, 1.295 + unsigned int nlinks) 1.296 +{ 1.297 + char s[256]; 1.298 + char *filebuf = NULL; 1.299 + struct stat buf; 1.300 + long size; 1.301 + int file = -1; 1.302 + int retval; 1.303 + int rc = -1; 1.304 + int namesize; 1.305 + int i; 1.306 + 1.307 + mode |= S_IFREG; 1.308 + 1.309 + retval = stat (location, &buf); 1.310 + if (retval) { 1.311 + fprintf (stderr, "File %s could not be located\n", location); 1.312 + goto error; 1.313 + } 1.314 + 1.315 + file = open (location, O_RDONLY); 1.316 + if (file < 0) { 1.317 + fprintf (stderr, "File %s could not be opened for reading\n", location); 1.318 + goto error; 1.319 + } 1.320 + 1.321 + filebuf = malloc(buf.st_size); 1.322 + if (!filebuf) { 1.323 + fprintf (stderr, "out of memory\n"); 1.324 + goto error; 1.325 + } 1.326 + 1.327 + retval = read (file, filebuf, buf.st_size); 1.328 + if (retval < 0) { 1.329 + fprintf (stderr, "Can not read %s file\n", location); 1.330 + goto error; 1.331 + } 1.332 + 1.333 + size = 0; 1.334 + for (i = 1; i <= nlinks; i++) { 1.335 + /* data goes on last link */ 1.336 + if (i == nlinks) size = buf.st_size; 1.337 + 1.338 + namesize = strlen(name) + 1; 1.339 + sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" 1.340 + "%08lX%08X%08X%08X%08X%08X%08X", 1.341 + "070701", /* magic */ 1.342 + ino, /* ino */ 1.343 + mode, /* mode */ 1.344 + (long) uid, /* uid */ 1.345 + (long) gid, /* gid */ 1.346 + nlinks, /* nlink */ 1.347 + (long) buf.st_mtime, /* mtime */ 1.348 + size, /* filesize */ 1.349 + 3, /* major */ 1.350 + 1, /* minor */ 1.351 + 0, /* rmajor */ 1.352 + 0, /* rminor */ 1.353 + namesize, /* namesize */ 1.354 + 0); /* chksum */ 1.355 + push_hdr(s); 1.356 + push_string(name); 1.357 + push_pad(); 1.358 + 1.359 + if (size) { 1.360 + fwrite(filebuf, size, 1, stdout); 1.361 + offset += size; 1.362 + push_pad(); 1.363 + } 1.364 + 1.365 + name += namesize; 1.366 + } 1.367 + ino++; 1.368 + rc = 0; 1.369 + 1.370 +error: 1.371 + if (filebuf) free(filebuf); 1.372 + if (file >= 0) close(file); 1.373 + return rc; 1.374 +} 1.375 + 1.376 +static char *cpio_replace_env(char *new_location) 1.377 +{ 1.378 + char expanded[PATH_MAX + 1]; 1.379 + char env_var[PATH_MAX + 1]; 1.380 + char *start; 1.381 + char *end; 1.382 + 1.383 + for (start = NULL; (start = strstr(new_location, "${")); ) { 1.384 + end = strchr(start, '}'); 1.385 + if (start < end) { 1.386 + *env_var = *expanded = '\0'; 1.387 + strncat(env_var, start + 2, end - start - 2); 1.388 + strncat(expanded, new_location, start - new_location); 1.389 + strncat(expanded, getenv(env_var), PATH_MAX); 1.390 + strncat(expanded, end + 1, PATH_MAX); 1.391 + strncpy(new_location, expanded, PATH_MAX); 1.392 + } else 1.393 + break; 1.394 + } 1.395 + 1.396 + return new_location; 1.397 +} 1.398 + 1.399 + 1.400 +static int cpio_mkfile_line(const char *line) 1.401 +{ 1.402 + char name[PATH_MAX + 1]; 1.403 + char *dname = NULL; /* malloc'ed buffer for hard links */ 1.404 + char location[PATH_MAX + 1]; 1.405 + unsigned int mode; 1.406 + int uid; 1.407 + int gid; 1.408 + int nlinks = 1; 1.409 + int end = 0, dname_len = 0; 1.410 + int rc = -1; 1.411 + 1.412 + if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) 1.413 + "s %o %d %d %n", 1.414 + name, location, &mode, &uid, &gid, &end)) { 1.415 + fprintf(stderr, "Unrecognized file format '%s'", line); 1.416 + goto fail; 1.417 + } 1.418 + if (end && isgraph(line[end])) { 1.419 + int len; 1.420 + int nend; 1.421 + 1.422 + dname = malloc(strlen(line)); 1.423 + if (!dname) { 1.424 + fprintf (stderr, "out of memory (%d)\n", dname_len); 1.425 + goto fail; 1.426 + } 1.427 + 1.428 + dname_len = strlen(name) + 1; 1.429 + memcpy(dname, name, dname_len); 1.430 + 1.431 + do { 1.432 + nend = 0; 1.433 + if (sscanf(line + end, "%" str(PATH_MAX) "s %n", 1.434 + name, &nend) < 1) 1.435 + break; 1.436 + len = strlen(name) + 1; 1.437 + memcpy(dname + dname_len, name, len); 1.438 + dname_len += len; 1.439 + nlinks++; 1.440 + end += nend; 1.441 + } while (isgraph(line[end])); 1.442 + } else { 1.443 + dname = name; 1.444 + } 1.445 + rc = cpio_mkfile(dname, cpio_replace_env(location), 1.446 + mode, uid, gid, nlinks); 1.447 + fail: 1.448 + if (dname_len) free(dname); 1.449 + return rc; 1.450 +} 1.451 + 1.452 +static void usage(const char *prog) 1.453 +{ 1.454 + fprintf(stderr, "Usage:\n" 1.455 + "\t%s <cpio_list>\n" 1.456 + "\n" 1.457 + "<cpio_list> is a file containing newline separated entries that\n" 1.458 + "describe the files to be included in the initramfs archive:\n" 1.459 + "\n" 1.460 + "# a comment\n" 1.461 + "file <name> <location> <mode> <uid> <gid> [<hard links>]\n" 1.462 + "dir <name> <mode> <uid> <gid>\n" 1.463 + "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n" 1.464 + "slink <name> <target> <mode> <uid> <gid>\n" 1.465 + "pipe <name> <mode> <uid> <gid>\n" 1.466 + "sock <name> <mode> <uid> <gid>\n" 1.467 + "\n" 1.468 + "<name> name of the file/dir/nod/etc in the archive\n" 1.469 + "<location> location of the file in the current filesystem\n" 1.470 + " expands shell variables quoted with ${}\n" 1.471 + "<target> link target\n" 1.472 + "<mode> mode/permissions of the file\n" 1.473 + "<uid> user id (0=root)\n" 1.474 + "<gid> group id (0=root)\n" 1.475 + "<dev_type> device type (b=block, c=character)\n" 1.476 + "<maj> major number of nod\n" 1.477 + "<min> minor number of nod\n" 1.478 + "<hard links> space separated list of other links to file\n" 1.479 + "\n" 1.480 + "example:\n" 1.481 + "# A simple initramfs\n" 1.482 + "dir /dev 0755 0 0\n" 1.483 + "nod /dev/console 0600 0 0 c 5 1\n" 1.484 + "dir /root 0700 0 0\n" 1.485 + "dir /sbin 0755 0 0\n" 1.486 + "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n", 1.487 + prog); 1.488 +} 1.489 + 1.490 +struct file_handler file_handler_table[] = { 1.491 + { 1.492 + .type = "file", 1.493 + .handler = cpio_mkfile_line, 1.494 + }, { 1.495 + .type = "nod", 1.496 + .handler = cpio_mknod_line, 1.497 + }, { 1.498 + .type = "dir", 1.499 + .handler = cpio_mkdir_line, 1.500 + }, { 1.501 + .type = "slink", 1.502 + .handler = cpio_mkslink_line, 1.503 + }, { 1.504 + .type = "pipe", 1.505 + .handler = cpio_mkpipe_line, 1.506 + }, { 1.507 + .type = "sock", 1.508 + .handler = cpio_mksock_line, 1.509 + }, { 1.510 + .type = NULL, 1.511 + .handler = NULL, 1.512 + } 1.513 +}; 1.514 + 1.515 +#define LINE_SIZE (2 * PATH_MAX + 50) 1.516 + 1.517 +int main (int argc, char *argv[]) 1.518 +{ 1.519 + FILE *cpio_list; 1.520 + char line[LINE_SIZE]; 1.521 + char *args, *type; 1.522 + int ec = 0; 1.523 + int line_nr = 0; 1.524 + 1.525 + if (2 != argc) { 1.526 + usage(argv[0]); 1.527 + exit(1); 1.528 + } 1.529 + 1.530 + if (!strcmp(argv[1], "-")) 1.531 + cpio_list = stdin; 1.532 + else if (! (cpio_list = fopen(argv[1], "r"))) { 1.533 + fprintf(stderr, "ERROR: unable to open '%s': %s\n\n", 1.534 + argv[1], strerror(errno)); 1.535 + usage(argv[0]); 1.536 + exit(1); 1.537 + } 1.538 + 1.539 + while (fgets(line, LINE_SIZE, cpio_list)) { 1.540 + int type_idx; 1.541 + size_t slen = strlen(line); 1.542 + 1.543 + line_nr++; 1.544 + 1.545 + if ('#' == *line) { 1.546 + /* comment - skip to next line */ 1.547 + continue; 1.548 + } 1.549 + 1.550 + if (! (type = strtok(line, " \t"))) { 1.551 + fprintf(stderr, 1.552 + "ERROR: incorrect format, could not locate file type line %d: '%s'\n", 1.553 + line_nr, line); 1.554 + ec = -1; 1.555 + break; 1.556 + } 1.557 + 1.558 + if ('\n' == *type) { 1.559 + /* a blank line */ 1.560 + continue; 1.561 + } 1.562 + 1.563 + if (slen == strlen(type)) { 1.564 + /* must be an empty line */ 1.565 + continue; 1.566 + } 1.567 + 1.568 + if (! (args = strtok(NULL, "\n"))) { 1.569 + fprintf(stderr, 1.570 + "ERROR: incorrect format, newline required line %d: '%s'\n", 1.571 + line_nr, line); 1.572 + ec = -1; 1.573 + } 1.574 + 1.575 + for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) { 1.576 + int rc; 1.577 + if (! strcmp(line, file_handler_table[type_idx].type)) { 1.578 + if ((rc = file_handler_table[type_idx].handler(args))) { 1.579 + ec = rc; 1.580 + fprintf(stderr, " line %d\n", line_nr); 1.581 + } 1.582 + break; 1.583 + } 1.584 + } 1.585 + 1.586 + if (NULL == file_handler_table[type_idx].type) { 1.587 + fprintf(stderr, "unknown file type line %d: '%s'\n", 1.588 + line_nr, line); 1.589 + } 1.590 + } 1.591 + if (ec == 0) 1.592 + cpio_trailer(); 1.593 + 1.594 + exit(ec); 1.595 +}