1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <string.h> 6 #include <unistd.h> 7 #include <time.h> 8 #include <fcntl.h> 9 #include <errno.h> 10 #include <ctype.h> 11 #include <limits.h> 12 13 /* 14 * Original work by Jeff Garzik 15 * 16 * External file lists, symlink, pipe and fifo support by Thayne Harbaugh 17 */ 18 19 #define xstr(s) #s 20 #define str(s) xstr(s) 21 22 static unsigned int offset; 23 static unsigned int ino = 721; 24 25 struct file_handler { 26 const char *type; 27 int (*handler)(const char *line); 28 }; 29 30 static void push_string(const char *name) 31 { 32 unsigned int name_len = strlen(name) + 1; 33 34 fputs(name, stdout); 35 putchar(0); 36 offset += name_len; 37 } 38 39 static void push_pad (void) 40 { 41 while (offset & 3) { 42 putchar(0); 43 offset++; 44 } 45 } 46 47 static void push_rest(const char *name) 48 { 49 unsigned int name_len = strlen(name) + 1; 50 unsigned int tmp_ofs; 51 52 fputs(name, stdout); 53 putchar(0); 54 offset += name_len; 55 56 tmp_ofs = name_len + 110; 57 while (tmp_ofs & 3) { 58 putchar(0); 59 offset++; 60 tmp_ofs++; 61 } 62 } 63 64 static void push_hdr(const char *s) 65 { 66 fputs(s, stdout); 67 offset += 110; 68 } 69 70 static void cpio_trailer(void) 71 { 72 char s[256]; 73 const char name[] = "TRAILER!!!"; 74 75 sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX" 76 "%08X%08X%08X%08X%08X%08X%08X", 77 "070701", /* magic */ 78 0, /* ino */ 79 0, /* mode */ 80 (long) 0, /* uid */ 81 (long) 0, /* gid */ 82 1, /* nlink */ 83 (long) 0, /* mtime */ 84 0, /* filesize */ 85 0, /* major */ 86 0, /* minor */ 87 0, /* rmajor */ 88 0, /* rminor */ 89 (unsigned)strlen(name)+1, /* namesize */ 90 0); /* chksum */ 91 push_hdr(s); 92 push_rest(name); 93 94 while (offset % 512) { 95 putchar(0); 96 offset++; 97 } 98 } 99 100 static int cpio_mkslink(const char *name, const char *target, 101 unsigned int mode, uid_t uid, gid_t gid) 102 { 103 char s[256]; 104 time_t mtime = time(NULL); 105 106 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" 107 "%08X%08X%08X%08X%08X%08X%08X", 108 "070701", /* magic */ 109 ino++, /* ino */ 110 S_IFLNK | mode, /* mode */ 111 (long) uid, /* uid */ 112 (long) gid, /* gid */ 113 1, /* nlink */ 114 (long) mtime, /* mtime */ 115 (unsigned)strlen(target)+1, /* filesize */ 116 3, /* major */ 117 1, /* minor */ 118 0, /* rmajor */ 119 0, /* rminor */ 120 (unsigned)strlen(name) + 1,/* namesize */ 121 0); /* chksum */ 122 push_hdr(s); 123 push_string(name); 124 push_pad(); 125 push_string(target); 126 push_pad(); 127 return 0; 128 } 129 130 static int cpio_mkslink_line(const char *line) 131 { 132 char name[PATH_MAX + 1]; 133 char target[PATH_MAX + 1]; 134 unsigned int mode; 135 int uid; 136 int gid; 137 int rc = -1; 138 139 if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, target, &mode, &uid, &gid)) { 140 fprintf(stderr, "Unrecognized dir format '%s'", line); 141 goto fail; 142 } 143 rc = cpio_mkslink(name, target, mode, uid, gid); 144 fail: 145 return rc; 146 } 147 148 static int cpio_mkgeneric(const char *name, unsigned int mode, 149 uid_t uid, gid_t gid) 150 { 151 char s[256]; 152 time_t mtime = time(NULL); 153 154 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" 155 "%08X%08X%08X%08X%08X%08X%08X", 156 "070701", /* magic */ 157 ino++, /* ino */ 158 mode, /* mode */ 159 (long) uid, /* uid */ 160 (long) gid, /* gid */ 161 2, /* nlink */ 162 (long) mtime, /* mtime */ 163 0, /* filesize */ 164 3, /* major */ 165 1, /* minor */ 166 0, /* rmajor */ 167 0, /* rminor */ 168 (unsigned)strlen(name) + 1,/* namesize */ 169 0); /* chksum */ 170 push_hdr(s); 171 push_rest(name); 172 return 0; 173 } 174 175 enum generic_types { 176 GT_DIR, 177 GT_PIPE, 178 GT_SOCK 179 }; 180 181 struct generic_type { 182 const char *type; 183 mode_t mode; 184 }; 185 186 static struct generic_type generic_type_table[] = { 187 [GT_DIR] = { 188 .type = "dir", 189 .mode = S_IFDIR 190 }, 191 [GT_PIPE] = { 192 .type = "pipe", 193 .mode = S_IFIFO 194 }, 195 [GT_SOCK] = { 196 .type = "sock", 197 .mode = S_IFSOCK 198 } 199 }; 200 201 static int cpio_mkgeneric_line(const char *line, enum generic_types gt) 202 { 203 char name[PATH_MAX + 1]; 204 unsigned int mode; 205 int uid; 206 int gid; 207 int rc = -1; 208 209 if (4 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d", name, &mode, &uid, &gid)) { 210 fprintf(stderr, "Unrecognized %s format '%s'", 211 line, generic_type_table[gt].type); 212 goto fail; 213 } 214 mode |= generic_type_table[gt].mode; 215 rc = cpio_mkgeneric(name, mode, uid, gid); 216 fail: 217 return rc; 218 } 219 220 static int cpio_mkdir_line(const char *line) 221 { 222 return cpio_mkgeneric_line(line, GT_DIR); 223 } 224 225 static int cpio_mkpipe_line(const char *line) 226 { 227 return cpio_mkgeneric_line(line, GT_PIPE); 228 } 229 230 static int cpio_mksock_line(const char *line) 231 { 232 return cpio_mkgeneric_line(line, GT_SOCK); 233 } 234 235 static int cpio_mknod(const char *name, unsigned int mode, 236 uid_t uid, gid_t gid, char dev_type, 237 unsigned int maj, unsigned int min) 238 { 239 char s[256]; 240 time_t mtime = time(NULL); 241 242 if (dev_type == 'b') 243 mode |= S_IFBLK; 244 else 245 mode |= S_IFCHR; 246 247 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" 248 "%08X%08X%08X%08X%08X%08X%08X", 249 "070701", /* magic */ 250 ino++, /* ino */ 251 mode, /* mode */ 252 (long) uid, /* uid */ 253 (long) gid, /* gid */ 254 1, /* nlink */ 255 (long) mtime, /* mtime */ 256 0, /* filesize */ 257 3, /* major */ 258 1, /* minor */ 259 maj, /* rmajor */ 260 min, /* rminor */ 261 (unsigned)strlen(name) + 1,/* namesize */ 262 0); /* chksum */ 263 push_hdr(s); 264 push_rest(name); 265 return 0; 266 } 267 268 static int cpio_mknod_line(const char *line) 269 { 270 char name[PATH_MAX + 1]; 271 unsigned int mode; 272 int uid; 273 int gid; 274 char dev_type; 275 unsigned int maj; 276 unsigned int min; 277 int rc = -1; 278 279 if (7 != sscanf(line, "%" str(PATH_MAX) "s %o %d %d %c %u %u", 280 name, &mode, &uid, &gid, &dev_type, &maj, &min)) { 281 fprintf(stderr, "Unrecognized nod format '%s'", line); 282 goto fail; 283 } 284 rc = cpio_mknod(name, mode, uid, gid, dev_type, maj, min); 285 fail: 286 return rc; 287 } 288 289 /* Not marked static to keep the compiler quiet, as no one uses this yet... */ 290 static int cpio_mkfile(const char *name, const char *location, 291 unsigned int mode, uid_t uid, gid_t gid) 292 { 293 char s[256]; 294 char *filebuf = NULL; 295 struct stat buf; 296 int file = -1; 297 int retval; 298 int rc = -1; 299 300 mode |= S_IFREG; 301 302 retval = stat (location, &buf); 303 if (retval) { 304 fprintf (stderr, "File %s could not be located\n", location); 305 goto error; 306 } 307 308 file = open (location, O_RDONLY); 309 if (file < 0) { 310 fprintf (stderr, "File %s could not be opened for reading\n", location); 311 goto error; 312 } 313 314 filebuf = malloc(buf.st_size); 315 if (!filebuf) { 316 fprintf (stderr, "out of memory\n"); 317 goto error; 318 } 319 320 retval = read (file, filebuf, buf.st_size); 321 if (retval < 0) { 322 fprintf (stderr, "Can not read %s file\n", location); 323 goto error; 324 } 325 326 sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" 327 "%08X%08X%08X%08X%08X%08X%08X", 328 "070701", /* magic */ 329 ino++, /* ino */ 330 mode, /* mode */ 331 (long) uid, /* uid */ 332 (long) gid, /* gid */ 333 1, /* nlink */ 334 (long) buf.st_mtime, /* mtime */ 335 (int) buf.st_size, /* filesize */ 336 3, /* major */ 337 1, /* minor */ 338 0, /* rmajor */ 339 0, /* rminor */ 340 (unsigned)strlen(name) + 1,/* namesize */ 341 0); /* chksum */ 342 push_hdr(s); 343 push_string(name); 344 push_pad(); 345 346 fwrite(filebuf, buf.st_size, 1, stdout); 347 offset += buf.st_size; 348 push_pad(); 349 rc = 0; 350 351 error: 352 if (filebuf) free(filebuf); 353 if (file >= 0) close(file); 354 return rc; 355 } 356 357 static int cpio_mkfile_line(const char *line) 358 { 359 char name[PATH_MAX + 1]; 360 char location[PATH_MAX + 1]; 361 unsigned int mode; 362 int uid; 363 int gid; 364 int rc = -1; 365 366 if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, location, &mode, &uid, &gid)) { 367 fprintf(stderr, "Unrecognized file format '%s'", line); 368 goto fail; 369 } 370 rc = cpio_mkfile(name, location, mode, uid, gid); 371 fail: 372 return rc; 373 } 374 375 void usage(const char *prog) 376 { 377 fprintf(stderr, "Usage:\n" 378 "\t%s <cpio_list>\n" 379 "\n" 380 "<cpio_list> is a file containing newline separated entries that\n" 381 "describe the files to be included in the initramfs archive:\n" 382 "\n" 383 "# a comment\n" 384 "file <name> <location> <mode> <uid> <gid>\n" 385 "dir <name> <mode> <uid> <gid>\n" 386 "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n" 387 "slink <name> <target> <mode> <uid> <gid>\n" 388 "pipe <name> <mode> <uid> <gid>\n" 389 "sock <name> <mode> <uid> <gid>\n" 390 "\n" 391 "<name> name of the file/dir/nod/etc in the archive\n" 392 "<location> location of the file in the current filesystem\n" 393 "<target> link target\n" 394 "<mode> mode/permissions of the file\n" 395 "<uid> user id (0=root)\n" 396 "<gid> group id (0=root)\n" 397 "<dev_type> device type (b=block, c=character)\n" 398 "<maj> major number of nod\n" 399 "<min> minor number of nod\n" 400 "\n" 401 "example:\n" 402 "# A simple initramfs\n" 403 "dir /dev 0755 0 0\n" 404 "nod /dev/console 0600 0 0 c 5 1\n" 405 "dir /root 0700 0 0\n" 406 "dir /sbin 0755 0 0\n" 407 "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n", 408 prog); 409 } 410 411 struct file_handler file_handler_table[] = { 412 { 413 .type = "file", 414 .handler = cpio_mkfile_line, 415 }, { 416 .type = "nod", 417 .handler = cpio_mknod_line, 418 }, { 419 .type = "dir", 420 .handler = cpio_mkdir_line, 421 }, { 422 .type = "slink", 423 .handler = cpio_mkslink_line, 424 }, { 425 .type = "pipe", 426 .handler = cpio_mkpipe_line, 427 }, { 428 .type = "sock", 429 .handler = cpio_mksock_line, 430 }, { 431 .type = NULL, 432 .handler = NULL, 433 } 434 }; 435 436 #define LINE_SIZE (2 * PATH_MAX + 50) 437 438 int main (int argc, char *argv[]) 439 { 440 FILE *cpio_list; 441 char line[LINE_SIZE]; 442 char *args, *type; 443 int ec = 0; 444 int line_nr = 0; 445 446 if (2 != argc) { 447 usage(argv[0]); 448 exit(1); 449 } 450 451 if (! (cpio_list = fopen(argv[1], "r"))) { 452 fprintf(stderr, "ERROR: unable to open '%s': %s\n\n", 453 argv[1], strerror(errno)); 454 usage(argv[0]); 455 exit(1); 456 } 457 458 while (fgets(line, LINE_SIZE, cpio_list)) { 459 int type_idx; 460 size_t slen = strlen(line); 461 462 line_nr++; 463 464 if ('#' == *line) { 465 /* comment - skip to next line */ 466 continue; 467 } 468 469 if (! (type = strtok(line, " \t"))) { 470 fprintf(stderr, 471 "ERROR: incorrect format, could not locate file type line %d: '%s'\n", 472 line_nr, line); 473 ec = -1; 474 break; 475 } 476 477 if ('\n' == *type) { 478 /* a blank line */ 479 continue; 480 } 481 482 if (slen == strlen(type)) { 483 /* must be an empty line */ 484 continue; 485 } 486 487 if (! (args = strtok(NULL, "\n"))) { 488 fprintf(stderr, 489 "ERROR: incorrect format, newline required line %d: '%s'\n", 490 line_nr, line); 491 ec = -1; 492 } 493 494 for (type_idx = 0; file_handler_table[type_idx].type; type_idx++) { 495 int rc; 496 if (! strcmp(line, file_handler_table[type_idx].type)) { 497 if ((rc = file_handler_table[type_idx].handler(args))) { 498 ec = rc; 499 fprintf(stderr, " line %d\n", line_nr); 500 } 501 break; 502 } 503 } 504 505 if (NULL == file_handler_table[type_idx].type) { 506 fprintf(stderr, "unknown file type line %d: '%s'\n", 507 line_nr, line); 508 } 509 } 510 if (ec == 0) 511 cpio_trailer(); 512 513 exit(ec); 514 } 515