1/* vi: set sw=4 ts=4: */ 2/* 3 * Mini cpio implementation for busybox 4 * 5 * Copyright (C) 2001 by Glenn McGrath 6 * 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 8 * 9 * Limitations: 10 * Doesn't check CRC's 11 * Only supports new ASCII and CRC formats 12 * 13 */ 14#include "libbb.h" 15#include "unarchive.h" 16 17/* GNU cpio 2.9 --help (abridged): 18 19 Modes: 20 -t, --list List the archive 21 -i, --extract Extract files from an archive 22 -o, --create Create the archive 23 -p, --pass-through Copy-pass mode [was ist das?!] 24 25 Options valid in any mode: 26 --block-size=SIZE I/O block size = SIZE * 512 bytes 27 -B I/O block size = 5120 bytes 28 -c Use the old portable (ASCII) archive format 29 -C, --io-size=NUMBER I/O block size in bytes 30 -f, --nonmatching Only copy files that do not match given pattern 31 -F, --file=FILE Use FILE instead of standard input or output 32 -H, --format=FORMAT Use given archive FORMAT 33 -M, --message=STRING Print STRING when the end of a volume of the 34 backup media is reached 35 -n, --numeric-uid-gid If -v, show numeric UID and GID 36 --quiet Do not print the number of blocks copied 37 --rsh-command=COMMAND Use remote COMMAND instead of rsh 38 -v, --verbose Verbosely list the files processed 39 -V, --dot Print a "." for each file processed 40 -W, --warning=FLAG Control warning display: 'none','truncate','all'; 41 multiple options accumulate 42 43 Options valid only in --extract mode: 44 -b, --swap Swap both halfwords of words and bytes of 45 halfwords in the data (equivalent to -sS) 46 -r, --rename Interactively rename files 47 -s, --swap-bytes Swap the bytes of each halfword in the files 48 -S, --swap-halfwords Swap the halfwords of each word (4 bytes) 49 --to-stdout Extract files to standard output 50 -E, --pattern-file=FILE Read additional patterns specifying filenames to 51 extract or list from FILE 52 --only-verify-crc Verify CRC's, don't actually extract the files 53 54 Options valid only in --create mode: 55 -A, --append Append to an existing archive 56 -O FILE File to use instead of standard output 57 58 Options valid only in --pass-through mode: 59 -l, --link Link files instead of copying them, when possible 60 61 Options valid in --extract and --create modes: 62 --absolute-filenames Do not strip file system prefix components from 63 the file names 64 --no-absolute-filenames Create all files relative to the current dir 65 66 Options valid in --create and --pass-through modes: 67 -0, --null A list of filenames is terminated by a NUL 68 -a, --reset-access-time Reset the access times of files after reading them 69 -I FILE File to use instead of standard input 70 -L, --dereference Dereference symbolic links (copy the files 71 that they point to instead of copying the links) 72 -R, --owner=[USER][:.][GROUP] Set owner of created files 73 74 Options valid in --extract and --pass-through modes: 75 -d, --make-directories Create leading directories where needed 76 -m, --preserve-modification-time Retain mtime when creating files 77 --no-preserve-owner Do not change the ownership of the files 78 --sparse Write files with blocks of zeros as sparse files 79 -u, --unconditional Replace all files unconditionally 80 */ 81enum { 82 CPIO_OPT_EXTRACT = (1 << 0), 83 CPIO_OPT_TEST = (1 << 1), 84 CPIO_OPT_NUL_TERMINATED = (1 << 2), 85 CPIO_OPT_UNCONDITIONAL = (1 << 3), 86 CPIO_OPT_VERBOSE = (1 << 4), 87 CPIO_OPT_CREATE_LEADING_DIR = (1 << 5), 88 CPIO_OPT_PRESERVE_MTIME = (1 << 6), 89 CPIO_OPT_DEREF = (1 << 7), 90 CPIO_OPT_FILE = (1 << 8), 91 OPTBIT_FILE = 8, 92 IF_FEATURE_CPIO_O(OPTBIT_CREATE ,) 93 IF_FEATURE_CPIO_O(OPTBIT_FORMAT ,) 94 IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,) 95 IF_LONG_OPTS( OPTBIT_QUIET ,) 96 IF_LONG_OPTS( OPTBIT_2STDOUT ,) 97 CPIO_OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0, 98 CPIO_OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0, 99 CPIO_OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0, 100 CPIO_OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0, 101 CPIO_OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0, 102}; 103 104#define OPTION_STR "it0uvdmLF:" 105 106#if ENABLE_FEATURE_CPIO_O 107static off_t cpio_pad4(off_t size) 108{ 109 int i; 110 111 i = (- size) & 3; 112 size += i; 113 while (--i >= 0) 114 bb_putchar('\0'); 115 return size; 116} 117 118/* Return value will become exit code. 119 * It's ok to exit instead of return. */ 120static NOINLINE int cpio_o(void) 121{ 122 static const char trailer[] ALIGN1 = "TRAILER!!!"; 123 struct name_s { 124 struct name_s *next; 125 char name[1]; 126 }; 127 struct inodes_s { 128 struct inodes_s *next; 129 struct name_s *names; 130 struct stat st; 131 }; 132 133 struct inodes_s *links = NULL; 134 off_t bytes = 0; /* output bytes count */ 135 136 while (1) { 137 const char *name; 138 char *line; 139 struct stat st; 140 141 line = (option_mask32 & CPIO_OPT_NUL_TERMINATED) 142 ? bb_get_chunk_from_file(stdin, NULL) 143 : xmalloc_fgetline(stdin); 144 145 if (line) { 146 /* Strip leading "./[./]..." from the filename */ 147 name = line; 148 while (name[0] == '.' && name[1] == '/') { 149 while (*++name == '/') 150 continue; 151 } 152 if (!*name) { /* line is empty */ 153 free(line); 154 continue; 155 } 156 if ((option_mask32 & CPIO_OPT_DEREF) 157 ? stat(name, &st) 158 : lstat(name, &st) 159 ) { 160 abort_cpio_o: 161 bb_simple_perror_msg_and_die(name); 162 } 163 164 if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode))) 165 st.st_size = 0; /* paranoia */ 166 167 /* Store hardlinks for later processing, dont output them */ 168 if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) { 169 struct name_s *n; 170 struct inodes_s *l; 171 172 /* Do we have this hardlink remembered? */ 173 l = links; 174 while (1) { 175 if (l == NULL) { 176 /* Not found: add new item to "links" list */ 177 l = xzalloc(sizeof(*l)); 178 l->st = st; 179 l->next = links; 180 links = l; 181 break; 182 } 183 if (l->st.st_ino == st.st_ino) { 184 /* found */ 185 break; 186 } 187 l = l->next; 188 } 189 /* Add new name to "l->names" list */ 190 n = xmalloc(sizeof(*n) + strlen(name)); 191 strcpy(n->name, name); 192 n->next = l->names; 193 l->names = n; 194 195 free(line); 196 continue; 197 } 198 199 } else { /* line == NULL: EOF */ 200 next_link: 201 if (links) { 202 /* Output hardlink's data */ 203 st = links->st; 204 name = links->names->name; 205 links->names = links->names->next; 206 /* GNU cpio is reported to emit file data 207 * only for the last instance. Mimic that. */ 208 if (links->names == NULL) 209 links = links->next; 210 else 211 st.st_size = 0; 212 /* NB: we leak links->names and/or links, 213 * this is intended (we exit soon anyway) */ 214 } else { 215 /* If no (more) hardlinks to output, 216 * output "trailer" entry */ 217 name = trailer; 218 /* st.st_size == 0 is a must, but for uniformity 219 * in the output, we zero out everything */ 220 memset(&st, 0, sizeof(st)); 221 /* st.st_nlink = 1; - GNU cpio does this */ 222 } 223 } 224 225 bytes += printf("070701" 226 "%08X%08X%08X%08X%08X%08X%08X" 227 "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ 228 /* strlen+1: */ "%08X" 229 /* chksum: */ "00000000" /* (only for "070702" files) */ 230 /* name,NUL: */ "%s%c", 231 (unsigned)(uint32_t) st.st_ino, 232 (unsigned)(uint32_t) st.st_mode, 233 (unsigned)(uint32_t) st.st_uid, 234 (unsigned)(uint32_t) st.st_gid, 235 (unsigned)(uint32_t) st.st_nlink, 236 (unsigned)(uint32_t) st.st_mtime, 237 (unsigned)(uint32_t) st.st_size, 238 (unsigned)(uint32_t) major(st.st_dev), 239 (unsigned)(uint32_t) minor(st.st_dev), 240 (unsigned)(uint32_t) major(st.st_rdev), 241 (unsigned)(uint32_t) minor(st.st_rdev), 242 (unsigned)(strlen(name) + 1), 243 name, '\0'); 244 bytes = cpio_pad4(bytes); 245 246 if (st.st_size) { 247 if (S_ISLNK(st.st_mode)) { 248 char *lpath = xmalloc_readlink_or_warn(name); 249 if (!lpath) 250 goto abort_cpio_o; 251 bytes += printf("%s", lpath); 252 free(lpath); 253 } else { /* S_ISREG */ 254 int fd = xopen(name, O_RDONLY); 255 fflush_all(); 256 /* We must abort if file got shorter too! */ 257 bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size); 258 bytes += st.st_size; 259 close(fd); 260 } 261 bytes = cpio_pad4(bytes); 262 } 263 264 if (!line) { 265 if (name != trailer) 266 goto next_link; 267 /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */ 268 return EXIT_SUCCESS; 269 } 270 271 free(line); 272 } /* end of "while (1)" */ 273} 274#endif 275 276int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 277int cpio_main(int argc UNUSED_PARAM, char **argv) 278{ 279 archive_handle_t *archive_handle; 280 char *cpio_filename; 281 IF_FEATURE_CPIO_O(const char *cpio_fmt = "";) 282 unsigned opt; 283 284#if ENABLE_LONG_OPTS 285 applet_long_options = 286 "extract\0" No_argument "i" 287 "list\0" No_argument "t" 288#if ENABLE_FEATURE_CPIO_O 289 "create\0" No_argument "o" 290 "format\0" Required_argument "H" 291#if ENABLE_FEATURE_CPIO_P 292 "pass-through\0" No_argument "p" 293#endif 294#endif 295 "verbose\0" No_argument "v" 296 "quiet\0" No_argument "\xff" 297 "to-stdout\0" No_argument "\xfe" 298 ; 299#endif 300 301 archive_handle = init_handle(); 302 /* archive_handle->src_fd = STDIN_FILENO; - done by init_handle */ 303 archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER; 304 305 /* As of now we do not enforce this: */ 306 /* -i,-t,-o,-p are mutually exclusive */ 307 /* -u,-d,-m make sense only with -i or -p */ 308 /* -L makes sense only with -o or -p */ 309 310#if !ENABLE_FEATURE_CPIO_O 311 /* no parameters */ 312 opt_complementary = "=0"; 313 opt = getopt32(argv, OPTION_STR, &cpio_filename); 314 argv += optind; 315 if (opt & CPIO_OPT_FILE) { /* -F */ 316 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); 317 } 318#else 319 /* _exactly_ one parameter for -p, thus <= 1 param if -p is allowed */ 320 opt_complementary = ENABLE_FEATURE_CPIO_P ? "?1" : "=0"; 321 opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt); 322 argv += optind; 323 if ((opt & (CPIO_OPT_FILE|CPIO_OPT_CREATE)) == CPIO_OPT_FILE) { /* -F without -o */ 324 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); 325 } 326 if (opt & CPIO_OPT_PASSTHROUGH) { 327 pid_t pid; 328 struct fd_pair pp; 329 330 if (argv[0] == NULL) 331 bb_show_usage(); 332 if (opt & CPIO_OPT_CREATE_LEADING_DIR) 333 mkdir(argv[0], 0777); 334 /* Crude existence check: 335 * close(xopen(argv[0], O_RDONLY | O_DIRECTORY)); 336 * We can also xopen, fstat, IS_DIR, later fchdir. 337 * This would check for existence earlier and cleaner. 338 * As it stands now, if we fail xchdir later, 339 * child dies on EPIPE, unless it caught 340 * a diffrerent problem earlier. 341 * This is good enough for now. 342 */ 343#if !BB_MMU 344 pp.rd = 3; 345 pp.wr = 4; 346 if (!re_execed) { 347 close(3); 348 close(4); 349 xpiped_pair(pp); 350 } 351#else 352 xpiped_pair(pp); 353#endif 354 pid = fork_or_rexec(argv - optind); 355 if (pid == 0) { /* child */ 356 close(pp.rd); 357 xmove_fd(pp.wr, STDOUT_FILENO); 358 goto dump; 359 } 360 /* parent */ 361 xchdir(*argv++); 362 close(pp.wr); 363 xmove_fd(pp.rd, STDIN_FILENO); 364 //opt &= ~CPIO_OPT_PASSTHROUGH; 365 opt |= CPIO_OPT_EXTRACT; 366 goto skip; 367 } 368 /* -o */ 369 if (opt & CPIO_OPT_CREATE) { 370 if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */ 371 bb_show_usage(); 372 if (opt & CPIO_OPT_FILE) { 373 xmove_fd(xopen3(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666), STDOUT_FILENO); 374 } 375 dump: 376 return cpio_o(); 377 } 378 skip: 379#endif 380 381 /* One of either extract or test options must be given */ 382 if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) { 383 bb_show_usage(); 384 } 385 386 if (opt & CPIO_OPT_TEST) { 387 /* if both extract and test options are given, ignore extract option */ 388 opt &= ~CPIO_OPT_EXTRACT; 389 archive_handle->action_header = header_list; 390 } 391 if (opt & CPIO_OPT_EXTRACT) { 392 archive_handle->action_data = data_extract_all; 393 if (opt & CPIO_OPT_2STDOUT) 394 archive_handle->action_data = data_extract_to_stdout; 395 } 396 if (opt & CPIO_OPT_UNCONDITIONAL) { 397 archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD; 398 archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER; 399 } 400 if (opt & CPIO_OPT_VERBOSE) { 401 if (archive_handle->action_header == header_list) { 402 archive_handle->action_header = header_verbose_list; 403 } else { 404 archive_handle->action_header = header_list; 405 } 406 } 407 if (opt & CPIO_OPT_CREATE_LEADING_DIR) { 408 archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS; 409 } 410 if (opt & CPIO_OPT_PRESERVE_MTIME) { 411 archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE; 412 } 413 414 while (*argv) { 415 archive_handle->filter = filter_accept_list; 416 llist_add_to(&archive_handle->accept, *argv); 417 argv++; 418 } 419 420 /* see get_header_cpio */ 421 archive_handle->cpio__blocks = (off_t)-1; 422 while (get_header_cpio(archive_handle) == EXIT_SUCCESS) 423 continue; 424 425 if (archive_handle->cpio__blocks != (off_t)-1 426 && !(opt & CPIO_OPT_QUIET) 427 ) { 428 fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks); 429 } 430 431 return EXIT_SUCCESS; 432} 433