blob: 7149782d7570ae9b03d8e427018c924bb3c495e2 [file] [log] [blame]
Glenn L McGrath8f5b63e2001-06-22 09:22:06 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Mini cpio implementation for busybox
4 *
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005 * Copyright (C) 2001 by Glenn McGrath
Glenn L McGrath8f5b63e2001-06-22 09:22:06 +00006 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02007 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Glenn L McGrath8f5b63e2001-06-22 09:22:06 +00008 *
9 * Limitations:
Denis Vlasenko261f2372008-04-05 00:07:46 +000010 * Doesn't check CRC's
11 * Only supports new ASCII and CRC formats
Glenn L McGrath8f5b63e2001-06-22 09:22:06 +000012 */
Denys Vlasenkof6beef62013-11-14 11:39:00 +010013//config:config CPIO
Denys Vlasenkob097a842018-12-28 03:20:17 +010014//config: bool "cpio (15 kb)"
Denys Vlasenkof6beef62013-11-14 11:39:00 +010015//config: default y
16//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020017//config: cpio is an archival utility program used to create, modify, and
18//config: extract contents from archives.
19//config: cpio has 110 bytes of overheads for every stored file.
Denys Vlasenkof6beef62013-11-14 11:39:00 +010020//config:
Denys Vlasenko72089cf2017-07-21 09:50:55 +020021//config: This implementation of cpio can extract cpio archives created in the
22//config: "newc" or "crc" format.
Denys Vlasenkof6beef62013-11-14 11:39:00 +010023//config:
Denys Vlasenko72089cf2017-07-21 09:50:55 +020024//config: Unless you have a specific application which requires cpio, you
25//config: should probably say N here.
Denys Vlasenkof6beef62013-11-14 11:39:00 +010026//config:
27//config:config FEATURE_CPIO_O
Denys Vlasenkof5604222017-01-10 14:58:54 +010028//config: bool "Support archive creation"
Denys Vlasenkof6beef62013-11-14 11:39:00 +010029//config: default y
30//config: depends on CPIO
31//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020032//config: This implementation of cpio can create cpio archives in the "newc"
33//config: format only.
Denys Vlasenkof6beef62013-11-14 11:39:00 +010034//config:
35//config:config FEATURE_CPIO_P
Denys Vlasenkof5604222017-01-10 14:58:54 +010036//config: bool "Support passthrough mode"
Denys Vlasenkof6beef62013-11-14 11:39:00 +010037//config: default y
38//config: depends on FEATURE_CPIO_O
39//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020040//config: Passthrough mode. Rarely used.
Ariadne Conill8aa55852021-06-28 08:25:59 -060041//config:
42//config:config FEATURE_CPIO_IGNORE_DEVNO
43//config: bool "Support --ignore-devno like GNU cpio"
44//config: default y
45//config: depends on FEATURE_CPIO_O && LONG_OPTS
46//config: help
47//config: Optionally ignore device numbers when creating archives.
Ariadne Conill836b7922021-06-28 08:31:23 -060048//config:
49//config:config FEATURE_CPIO_RENUMBER_INODES
50//config: bool "Support --renumber-inodes like GNU cpio"
51//config: default y
52//config: depends on FEATURE_CPIO_O && LONG_OPTS
53//config: help
54//config: Optionally renumber inodes when creating archives.
Denys Vlasenkof6beef62013-11-14 11:39:00 +010055
Denys Vlasenko36184a42013-11-14 09:54:24 +010056//applet:IF_CPIO(APPLET(cpio, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko0c4dbd42017-09-18 16:28:43 +020057
Denys Vlasenko66620fa2013-11-14 09:53:52 +010058//kbuild:lib-$(CONFIG_CPIO) += cpio.o
59
Denys Vlasenko1f937d62010-12-26 02:22:51 +010060//usage:#define cpio_trivial_usage
Aaro Koskinen2735bc02015-10-16 17:24:46 +020061//usage: "[-dmvu] [-F FILE] [-R USER[:GRP]]" IF_FEATURE_CPIO_O(" [-H newc]")
Denys Vlasenko1f937d62010-12-26 02:22:51 +010062//usage: " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]")
63//usage: " [EXTR_FILE]..."
64//usage:#define cpio_full_usage "\n\n"
Denys Vlasenkod2f42412016-07-08 12:52:24 +020065//usage: "Extract (-i) or list (-t) files from a cpio archive"
Denys Vlasenko1f937d62010-12-26 02:22:51 +010066//usage: IF_FEATURE_CPIO_O(", or"
Denys Vlasenkod2f42412016-07-08 12:52:24 +020067//usage: "\ntake file list from stdin and create an archive (-o)"
68//usage: IF_FEATURE_CPIO_P(" or copy files (-p)")
Denys Vlasenko1f937d62010-12-26 02:22:51 +010069//usage: )
70//usage: "\n"
71//usage: "\nMain operation mode:"
72//usage: "\n -t List"
73//usage: "\n -i Extract EXTR_FILEs (or all)"
74//usage: IF_FEATURE_CPIO_O(
75//usage: "\n -o Create (requires -H newc)"
76//usage: )
77//usage: IF_FEATURE_CPIO_P(
78//usage: "\n -p DIR Copy files to DIR"
79//usage: )
Denys Vlasenko184b2662014-06-30 17:19:17 +020080//usage: "\nOptions:"
Denys Vlasenko4d0e2d52018-07-06 20:49:08 +020081//usage: IF_FEATURE_CPIO_O(
82//usage: "\n -H newc Archive format"
83//usage: )
Denys Vlasenko1f937d62010-12-26 02:22:51 +010084//usage: "\n -d Make leading directories"
Denys Vlasenkoa2f18d92020-12-18 04:12:51 +010085//usage: "\n -m Restore mtime"
Denys Vlasenko1f937d62010-12-26 02:22:51 +010086//usage: "\n -v Verbose"
87//usage: "\n -u Overwrite"
88//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file"
Aaro Koskinen2735bc02015-10-16 17:24:46 +020089//usage: "\n -R USER[:GRP] Set owner of created files"
Denys Vlasenko4d0e2d52018-07-06 20:49:08 +020090//usage: "\n -L Dereference symlinks"
Denys Vlasenko1e7ca182021-08-22 15:43:29 +020091//usage: "\n -0 NUL terminated input"
Ariadne Conill8aa55852021-06-28 08:25:59 -060092//usage: IF_FEATURE_CPIO_IGNORE_DEVNO(
93//usage: "\n --ignore-devno"
94//usage: )
Ariadne Conill836b7922021-06-28 08:31:23 -060095//usage: IF_FEATURE_CPIO_RENUMBER_INODES(
96//usage: "\n --renumber-inodes"
97//usage: )
Denys Vlasenko1f937d62010-12-26 02:22:51 +010098
Denis Vlasenko05af8322009-03-20 23:01:48 +000099/* GNU cpio 2.9 --help (abridged):
100
101 Modes:
102 -t, --list List the archive
103 -i, --extract Extract files from an archive
104 -o, --create Create the archive
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100105 -p, --pass-through Copy-pass mode
Denis Vlasenko05af8322009-03-20 23:01:48 +0000106
107 Options valid in any mode:
108 --block-size=SIZE I/O block size = SIZE * 512 bytes
109 -B I/O block size = 5120 bytes
110 -c Use the old portable (ASCII) archive format
111 -C, --io-size=NUMBER I/O block size in bytes
112 -f, --nonmatching Only copy files that do not match given pattern
113 -F, --file=FILE Use FILE instead of standard input or output
114 -H, --format=FORMAT Use given archive FORMAT
115 -M, --message=STRING Print STRING when the end of a volume of the
116 backup media is reached
117 -n, --numeric-uid-gid If -v, show numeric UID and GID
118 --quiet Do not print the number of blocks copied
119 --rsh-command=COMMAND Use remote COMMAND instead of rsh
120 -v, --verbose Verbosely list the files processed
121 -V, --dot Print a "." for each file processed
122 -W, --warning=FLAG Control warning display: 'none','truncate','all';
123 multiple options accumulate
124
125 Options valid only in --extract mode:
126 -b, --swap Swap both halfwords of words and bytes of
127 halfwords in the data (equivalent to -sS)
128 -r, --rename Interactively rename files
129 -s, --swap-bytes Swap the bytes of each halfword in the files
130 -S, --swap-halfwords Swap the halfwords of each word (4 bytes)
131 --to-stdout Extract files to standard output
132 -E, --pattern-file=FILE Read additional patterns specifying filenames to
133 extract or list from FILE
134 --only-verify-crc Verify CRC's, don't actually extract the files
135
136 Options valid only in --create mode:
137 -A, --append Append to an existing archive
138 -O FILE File to use instead of standard output
139
140 Options valid only in --pass-through mode:
141 -l, --link Link files instead of copying them, when possible
142
143 Options valid in --extract and --create modes:
144 --absolute-filenames Do not strip file system prefix components from
145 the file names
146 --no-absolute-filenames Create all files relative to the current dir
147
148 Options valid in --create and --pass-through modes:
149 -0, --null A list of filenames is terminated by a NUL
150 -a, --reset-access-time Reset the access times of files after reading them
151 -I FILE File to use instead of standard input
152 -L, --dereference Dereference symbolic links (copy the files
153 that they point to instead of copying the links)
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200154 -R, --owner=[USER][:.][GRP] Set owner of created files
Denis Vlasenko05af8322009-03-20 23:01:48 +0000155
156 Options valid in --extract and --pass-through modes:
157 -d, --make-directories Create leading directories where needed
158 -m, --preserve-modification-time Retain mtime when creating files
159 --no-preserve-owner Do not change the ownership of the files
160 --sparse Write files with blocks of zeros as sparse files
161 -u, --unconditional Replace all files unconditionally
162 */
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100163
Denys Vlasenko0c4dbd42017-09-18 16:28:43 +0200164#include "libbb.h"
165#include "common_bufsiz.h"
166#include "bb_archive.h"
167
Denis Vlasenko05af8322009-03-20 23:01:48 +0000168enum {
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100169 OPT_EXTRACT = (1 << 0),
170 OPT_TEST = (1 << 1),
171 OPT_NUL_TERMINATED = (1 << 2),
172 OPT_UNCONDITIONAL = (1 << 3),
173 OPT_VERBOSE = (1 << 4),
174 OPT_CREATE_LEADING_DIR = (1 << 5),
175 OPT_PRESERVE_MTIME = (1 << 6),
176 OPT_DEREF = (1 << 7),
177 OPT_FILE = (1 << 8),
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200178 OPT_OWNER = (1 << 9),
179 OPTBIT_OWNER = 9,
Denys Vlasenkod30b89c2009-06-26 01:55:45 +0200180 IF_FEATURE_CPIO_O(OPTBIT_CREATE ,)
181 IF_FEATURE_CPIO_O(OPTBIT_FORMAT ,)
182 IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,)
183 IF_LONG_OPTS( OPTBIT_QUIET ,)
184 IF_LONG_OPTS( OPTBIT_2STDOUT ,)
Ariadne Conill8aa55852021-06-28 08:25:59 -0600185 IF_FEATURE_CPIO_IGNORE_DEVNO(OPTBIT_IGNORE_DEVNO,)
Ariadne Conill836b7922021-06-28 08:31:23 -0600186 IF_FEATURE_CPIO_RENUMBER_INODES(OPTBIT_RENUMBER_INODES,)
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100187 OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0,
188 OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0,
189 OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0,
190 OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0,
191 OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0,
Ariadne Conill8aa55852021-06-28 08:25:59 -0600192 OPT_IGNORE_DEVNO = IF_FEATURE_CPIO_IGNORE_DEVNO((1 << OPTBIT_IGNORE_DEVNO)) + 0,
Ariadne Conill836b7922021-06-28 08:31:23 -0600193 OPT_RENUMBER_INODES = IF_FEATURE_CPIO_RENUMBER_INODES((1 << OPTBIT_RENUMBER_INODES)) + 0,
Denis Vlasenko05af8322009-03-20 23:01:48 +0000194};
195
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200196#define OPTION_STR "it0uvdmLF:R:"
197
198struct globals {
199 struct bb_uidgid_t owner_ugid;
Ariadne Conill836b7922021-06-28 08:31:23 -0600200 ino_t next_inode;
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200201} FIX_ALIASING;
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200202#define G (*(struct globals*)bb_common_bufsiz1)
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200203void BUG_cpio_globals_too_big(void);
204#define INIT_G() do { \
Denys Vlasenko47cfbf32016-04-21 18:18:48 +0200205 setup_common_bufsiz(); \
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200206 G.owner_ugid.uid = -1L; \
207 G.owner_ugid.gid = -1L; \
208} while (0)
Denis Vlasenko05af8322009-03-20 23:01:48 +0000209
Denis Vlasenko261f2372008-04-05 00:07:46 +0000210#if ENABLE_FEATURE_CPIO_O
211static off_t cpio_pad4(off_t size)
212{
213 int i;
214
215 i = (- size) & 3;
216 size += i;
217 while (--i >= 0)
218 bb_putchar('\0');
219 return size;
220}
221
222/* Return value will become exit code.
223 * It's ok to exit instead of return. */
Denys Vlasenkoa7bb3c12009-10-08 12:28:08 +0200224static NOINLINE int cpio_o(void)
Denis Vlasenko261f2372008-04-05 00:07:46 +0000225{
226 struct name_s {
227 struct name_s *next;
228 char name[1];
229 };
230 struct inodes_s {
231 struct inodes_s *next;
232 struct name_s *names;
233 struct stat st;
Ariadne Conill836b7922021-06-28 08:31:23 -0600234#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
235 ino_t mapped_inode;
236#endif
Denis Vlasenko261f2372008-04-05 00:07:46 +0000237 };
238
239 struct inodes_s *links = NULL;
240 off_t bytes = 0; /* output bytes count */
241
242 while (1) {
243 const char *name;
244 char *line;
245 struct stat st;
246
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100247 line = (option_mask32 & OPT_NUL_TERMINATED)
Denis Vlasenko05af8322009-03-20 23:01:48 +0000248 ? bb_get_chunk_from_file(stdin, NULL)
249 : xmalloc_fgetline(stdin);
Denis Vlasenko261f2372008-04-05 00:07:46 +0000250
251 if (line) {
252 /* Strip leading "./[./]..." from the filename */
253 name = line;
254 while (name[0] == '.' && name[1] == '/') {
255 while (*++name == '/')
256 continue;
257 }
258 if (!*name) { /* line is empty */
259 free(line);
260 continue;
261 }
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100262 if ((option_mask32 & OPT_DEREF)
Denis Vlasenko05af8322009-03-20 23:01:48 +0000263 ? stat(name, &st)
264 : lstat(name, &st)
265 ) {
Denis Vlasenko261f2372008-04-05 00:07:46 +0000266 abort_cpio_o:
267 bb_simple_perror_msg_and_die(name);
268 }
269
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200270 if (G.owner_ugid.uid != (uid_t)-1L)
271 st.st_uid = G.owner_ugid.uid;
272 if (G.owner_ugid.gid != (gid_t)-1L)
273 st.st_gid = G.owner_ugid.gid;
274
Denis Vlasenko261f2372008-04-05 00:07:46 +0000275 if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
276 st.st_size = 0; /* paranoia */
277
278 /* Store hardlinks for later processing, dont output them */
279 if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
280 struct name_s *n;
281 struct inodes_s *l;
282
283 /* Do we have this hardlink remembered? */
284 l = links;
285 while (1) {
286 if (l == NULL) {
287 /* Not found: add new item to "links" list */
288 l = xzalloc(sizeof(*l));
289 l->st = st;
290 l->next = links;
Ariadne Conill836b7922021-06-28 08:31:23 -0600291#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
292 if (option_mask32 & OPT_RENUMBER_INODES)
293 l->mapped_inode = ++G.next_inode;
294#endif
Denis Vlasenko261f2372008-04-05 00:07:46 +0000295 links = l;
296 break;
297 }
298 if (l->st.st_ino == st.st_ino) {
299 /* found */
300 break;
301 }
302 l = l->next;
303 }
304 /* Add new name to "l->names" list */
305 n = xmalloc(sizeof(*n) + strlen(name));
306 strcpy(n->name, name);
307 n->next = l->names;
308 l->names = n;
309
310 free(line);
311 continue;
312 }
Ariadne Conill836b7922021-06-28 08:31:23 -0600313#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
314 else if (option_mask32 & OPT_RENUMBER_INODES) {
315 st.st_ino = ++G.next_inode;
316 }
317#endif
Denis Vlasenko261f2372008-04-05 00:07:46 +0000318 } else { /* line == NULL: EOF */
319 next_link:
320 if (links) {
321 /* Output hardlink's data */
322 st = links->st;
323 name = links->names->name;
324 links->names = links->names->next;
Ariadne Conill836b7922021-06-28 08:31:23 -0600325#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
326 if (links->mapped_inode)
327 st.st_ino = links->mapped_inode;
328#endif
Denis Vlasenko261f2372008-04-05 00:07:46 +0000329 /* GNU cpio is reported to emit file data
330 * only for the last instance. Mimic that. */
331 if (links->names == NULL)
332 links = links->next;
333 else
334 st.st_size = 0;
335 /* NB: we leak links->names and/or links,
336 * this is intended (we exit soon anyway) */
337 } else {
338 /* If no (more) hardlinks to output,
339 * output "trailer" entry */
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200340 name = cpio_TRAILER;
Denis Vlasenko261f2372008-04-05 00:07:46 +0000341 /* st.st_size == 0 is a must, but for uniformity
342 * in the output, we zero out everything */
343 memset(&st, 0, sizeof(st));
344 /* st.st_nlink = 1; - GNU cpio does this */
345 }
346 }
347
Ariadne Conill8aa55852021-06-28 08:25:59 -0600348#if ENABLE_FEATURE_CPIO_IGNORE_DEVNO
349 if (option_mask32 & OPT_IGNORE_DEVNO)
350 st.st_dev = st.st_rdev = 0;
351#endif
352
Denis Vlasenko261f2372008-04-05 00:07:46 +0000353 bytes += printf("070701"
Denys Vlasenko60cb48c2013-01-14 15:57:44 +0100354 "%08X%08X%08X%08X%08X%08X%08X"
355 "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */
Denis Vlasenko261f2372008-04-05 00:07:46 +0000356 /* strlen+1: */ "%08X"
357 /* chksum: */ "00000000" /* (only for "070702" files) */
358 /* name,NUL: */ "%s%c",
Denys Vlasenko60cb48c2013-01-14 15:57:44 +0100359 (unsigned)(uint32_t) st.st_ino,
360 (unsigned)(uint32_t) st.st_mode,
361 (unsigned)(uint32_t) st.st_uid,
362 (unsigned)(uint32_t) st.st_gid,
363 (unsigned)(uint32_t) st.st_nlink,
364 (unsigned)(uint32_t) st.st_mtime,
365 (unsigned)(uint32_t) st.st_size,
366 (unsigned)(uint32_t) major(st.st_dev),
367 (unsigned)(uint32_t) minor(st.st_dev),
368 (unsigned)(uint32_t) major(st.st_rdev),
369 (unsigned)(uint32_t) minor(st.st_rdev),
370 (unsigned)(strlen(name) + 1),
371 name, '\0');
Denis Vlasenko261f2372008-04-05 00:07:46 +0000372 bytes = cpio_pad4(bytes);
373
374 if (st.st_size) {
375 if (S_ISLNK(st.st_mode)) {
376 char *lpath = xmalloc_readlink_or_warn(name);
377 if (!lpath)
378 goto abort_cpio_o;
379 bytes += printf("%s", lpath);
380 free(lpath);
381 } else { /* S_ISREG */
382 int fd = xopen(name, O_RDONLY);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100383 fflush_all();
Denis Vlasenko261f2372008-04-05 00:07:46 +0000384 /* We must abort if file got shorter too! */
Denis Vlasenko1af00ed2008-04-05 02:44:30 +0000385 bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
Denis Vlasenko261f2372008-04-05 00:07:46 +0000386 bytes += st.st_size;
387 close(fd);
388 }
389 bytes = cpio_pad4(bytes);
390 }
391
392 if (!line) {
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200393 if (name != cpio_TRAILER)
Denis Vlasenko261f2372008-04-05 00:07:46 +0000394 goto next_link;
395 /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */
396 return EXIT_SUCCESS;
397 }
398
399 free(line);
400 } /* end of "while (1)" */
401}
402#endif
Glenn L McGrath10b78132004-02-25 09:30:06 +0000403
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000404int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000405int cpio_main(int argc UNUSED_PARAM, char **argv)
Glenn L McGrath8f5b63e2001-06-22 09:22:06 +0000406{
Glenn L McGrath7ca04f32002-09-25 02:47:48 +0000407 archive_handle_t *archive_handle;
Denis Vlasenko261f2372008-04-05 00:07:46 +0000408 char *cpio_filename;
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200409 char *cpio_owner;
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000410 IF_FEATURE_CPIO_O(const char *cpio_fmt = "";)
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000411 unsigned opt;
Denys Vlasenkof3b92d32009-06-19 12:10:38 +0200412#if ENABLE_LONG_OPTS
Denys Vlasenko036585a2017-08-08 16:38:18 +0200413 const char *long_opts =
Denis Vlasenko2b407b12008-07-11 21:42:12 +0000414 "extract\0" No_argument "i"
415 "list\0" No_argument "t"
416#if ENABLE_FEATURE_CPIO_O
417 "create\0" No_argument "o"
418 "format\0" Required_argument "H"
Denis Vlasenko83518d12009-03-20 22:17:13 +0000419#if ENABLE_FEATURE_CPIO_P
420 "pass-through\0" No_argument "p"
421#endif
Denis Vlasenko2b407b12008-07-11 21:42:12 +0000422#endif
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200423 "owner\0" Required_argument "R"
Denys Vlasenkod30b89c2009-06-26 01:55:45 +0200424 "verbose\0" No_argument "v"
Denys Vlasenko9be4d4f2018-07-06 20:50:30 +0200425 "null\0" No_argument "0"
Denys Vlasenkod30b89c2009-06-26 01:55:45 +0200426 "quiet\0" No_argument "\xff"
427 "to-stdout\0" No_argument "\xfe"
Ariadne Conill8aa55852021-06-28 08:25:59 -0600428#if ENABLE_FEATURE_CPIO_IGNORE_DEVNO
429 "ignore-devno\0" No_argument "\xfd"
430#endif
Ariadne Conill836b7922021-06-28 08:31:23 -0600431#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
432 "renumber-inodes\0" No_argument "\xfc"
433#endif
Denis Vlasenko2b407b12008-07-11 21:42:12 +0000434 ;
435#endif
Glenn L McGrath7ca04f32002-09-25 02:47:48 +0000436
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200437 INIT_G();
Denys Vlasenko607f65d2010-01-09 20:23:03 +0100438 archive_handle = init_handle();
439 /* archive_handle->src_fd = STDIN_FILENO; - done by init_handle */
440 archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
441
Denis Vlasenko83518d12009-03-20 22:17:13 +0000442 /* As of now we do not enforce this: */
443 /* -i,-t,-o,-p are mutually exclusive */
444 /* -u,-d,-m make sense only with -i or -p */
Denis Vlasenko05af8322009-03-20 23:01:48 +0000445 /* -L makes sense only with -o or -p */
446
Denis Vlasenko83518d12009-03-20 22:17:13 +0000447#if !ENABLE_FEATURE_CPIO_O
Denys Vlasenko036585a2017-08-08 16:38:18 +0200448 opt = getopt32long(argv, OPTION_STR, long_opts, &cpio_filename, &cpio_owner);
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200449#else
Denys Vlasenko036585a2017-08-08 16:38:18 +0200450 opt = getopt32long(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), long_opts,
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200451 &cpio_filename, &cpio_owner, &cpio_fmt);
452#endif
Denys Vlasenkoff0e8752010-05-10 04:16:43 +0200453 argv += optind;
Aaro Koskinen2735bc02015-10-16 17:24:46 +0200454 if (opt & OPT_OWNER) { /* -R */
455 parse_chown_usergroup_or_die(&G.owner_ugid, cpio_owner);
456 archive_handle->cpio__owner = G.owner_ugid;
457 }
458#if !ENABLE_FEATURE_CPIO_O
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100459 if (opt & OPT_FILE) { /* -F */
Denys Vlasenko02dd96f2010-01-09 20:25:42 +0100460 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
Denys Vlasenko607f65d2010-01-09 20:23:03 +0100461 }
Denis Vlasenko83518d12009-03-20 22:17:13 +0000462#else
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100463 if ((opt & (OPT_FILE|OPT_CREATE)) == OPT_FILE) { /* -F without -o */
Denys Vlasenko607f65d2010-01-09 20:23:03 +0100464 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
465 }
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100466 if (opt & OPT_PASSTHROUGH) {
Denis Vlasenko83518d12009-03-20 22:17:13 +0000467 pid_t pid;
468 struct fd_pair pp;
Glenn L McGrath10b78132004-02-25 09:30:06 +0000469
Denys Vlasenko40e5a302010-01-04 14:30:37 +0100470 if (argv[0] == NULL)
Denis Vlasenko83518d12009-03-20 22:17:13 +0000471 bb_show_usage();
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100472 if (opt & OPT_CREATE_LEADING_DIR)
Denys Vlasenkob1a27622021-06-03 20:26:30 +0200473 /* GNU cpio 2.13: "cpio -d -p a/b/c" works */
474 bb_make_directory(argv[0], -1, FILEUTILS_RECUR);
Denis Vlasenko83518d12009-03-20 22:17:13 +0000475 /* Crude existence check:
Denys Vlasenko40e5a302010-01-04 14:30:37 +0100476 * close(xopen(argv[0], O_RDONLY | O_DIRECTORY));
Denis Vlasenko83518d12009-03-20 22:17:13 +0000477 * We can also xopen, fstat, IS_DIR, later fchdir.
478 * This would check for existence earlier and cleaner.
479 * As it stands now, if we fail xchdir later,
480 * child dies on EPIPE, unless it caught
481 * a diffrerent problem earlier.
482 * This is good enough for now.
483 */
Denys Vlasenkob1a27622021-06-03 20:26:30 +0200484//FIXME: GNU cpio -d -p DIR does not immediately create DIR -
485//it just prepends "DIR/" to the names of files to be created.
486//The first file (fails to) be copied, and then the -d logic
487//triggers and creates all necessary directories.
488//IOW: bare "cpio -d -p DIR" + ^C shouldn't create anything.
Denis Vlasenko83518d12009-03-20 22:17:13 +0000489#if !BB_MMU
490 pp.rd = 3;
491 pp.wr = 4;
492 if (!re_execed) {
493 close(3);
494 close(4);
495 xpiped_pair(pp);
496 }
497#else
498 xpiped_pair(pp);
499#endif
Denys Vlasenko40e5a302010-01-04 14:30:37 +0100500 pid = fork_or_rexec(argv - optind);
Denis Vlasenko83518d12009-03-20 22:17:13 +0000501 if (pid == 0) { /* child */
502 close(pp.rd);
503 xmove_fd(pp.wr, STDOUT_FILENO);
504 goto dump;
505 }
506 /* parent */
Denys Vlasenkod2277e22011-11-22 17:19:26 +0100507 USE_FOR_NOMMU(argv[-optind][0] &= 0x7f); /* undo fork_or_rexec() damage */
Denys Vlasenko40e5a302010-01-04 14:30:37 +0100508 xchdir(*argv++);
Denis Vlasenko83518d12009-03-20 22:17:13 +0000509 close(pp.wr);
510 xmove_fd(pp.rd, STDIN_FILENO);
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100511 //opt &= ~OPT_PASSTHROUGH;
512 opt |= OPT_EXTRACT;
Denis Vlasenko83518d12009-03-20 22:17:13 +0000513 goto skip;
514 }
515 /* -o */
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100516 if (opt & OPT_CREATE) {
Denys Vlasenko93ac7d82010-01-09 19:56:15 +0100517 if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */
Denis Vlasenko261f2372008-04-05 00:07:46 +0000518 bb_show_usage();
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100519 if (opt & OPT_FILE) {
Denys Vlasenkoc05387d2010-10-18 02:38:27 +0200520 xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
Denis Vlasenko261f2372008-04-05 00:07:46 +0000521 }
Denis Vlasenko83518d12009-03-20 22:17:13 +0000522 dump:
Denis Vlasenko261f2372008-04-05 00:07:46 +0000523 return cpio_o();
524 }
Denis Vlasenko83518d12009-03-20 22:17:13 +0000525 skip:
Denis Vlasenko261f2372008-04-05 00:07:46 +0000526#endif
Glenn L McGrath10b78132004-02-25 09:30:06 +0000527
528 /* One of either extract or test options must be given */
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100529 if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) {
Glenn L McGrath10b78132004-02-25 09:30:06 +0000530 bb_show_usage();
531 }
532
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100533 if (opt & OPT_TEST) {
Rob Landleyb7128c62005-09-11 01:05:30 +0000534 /* if both extract and test options are given, ignore extract option */
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100535 opt &= ~OPT_EXTRACT;
Glenn L McGrath10b78132004-02-25 09:30:06 +0000536 archive_handle->action_header = header_list;
537 }
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100538 if (opt & OPT_EXTRACT) {
Glenn L McGrath10b78132004-02-25 09:30:06 +0000539 archive_handle->action_data = data_extract_all;
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100540 if (opt & OPT_2STDOUT)
Denys Vlasenkod30b89c2009-06-26 01:55:45 +0200541 archive_handle->action_data = data_extract_to_stdout;
Glenn L McGrath10b78132004-02-25 09:30:06 +0000542 }
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100543 if (opt & OPT_UNCONDITIONAL) {
Denys Vlasenkod57d6262009-09-17 02:43:14 +0200544 archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD;
Denis Vlasenkoa60936d2008-06-28 05:04:09 +0000545 archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
Glenn L McGrath10b78132004-02-25 09:30:06 +0000546 }
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100547 if (opt & OPT_VERBOSE) {
Glenn L McGrath10b78132004-02-25 09:30:06 +0000548 if (archive_handle->action_header == header_list) {
549 archive_handle->action_header = header_verbose_list;
550 } else {
551 archive_handle->action_header = header_list;
Glenn L McGrath8f5b63e2001-06-22 09:22:06 +0000552 }
553 }
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100554 if (opt & OPT_CREATE_LEADING_DIR) {
Denis Vlasenkoa60936d2008-06-28 05:04:09 +0000555 archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
Glenn L McGrath10b78132004-02-25 09:30:06 +0000556 }
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100557 if (opt & OPT_PRESERVE_MTIME) {
Denys Vlasenkod57d6262009-09-17 02:43:14 +0200558 archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
Denis Vlasenkobbd55c92008-06-27 15:52:07 +0000559 }
Glenn L McGrath8f5b63e2001-06-22 09:22:06 +0000560
Denis Vlasenko261f2372008-04-05 00:07:46 +0000561 while (*argv) {
Glenn L McGrath7ca04f32002-09-25 02:47:48 +0000562 archive_handle->filter = filter_accept_list;
Denys Vlasenko40e5a302010-01-04 14:30:37 +0100563 llist_add_to(&archive_handle->accept, *argv);
Denis Vlasenko261f2372008-04-05 00:07:46 +0000564 argv++;
Glenn L McGrath8f5b63e2001-06-22 09:22:06 +0000565 }
566
Denis Vlasenkocf4dd072008-10-17 14:11:04 +0000567 /* see get_header_cpio */
Denys Vlasenkoaa4977d2010-01-06 10:53:17 +0100568 archive_handle->cpio__blocks = (off_t)-1;
Denis Vlasenko261f2372008-04-05 00:07:46 +0000569 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
570 continue;
Glenn L McGrath7ca04f32002-09-25 02:47:48 +0000571
Harald van Dijk8c24af92018-05-22 17:34:31 +0200572 create_links_from_list(archive_handle->link_placeholders);
Natanael Copad9503222018-03-30 20:18:12 +0200573
Denys Vlasenkoaa4977d2010-01-06 10:53:17 +0100574 if (archive_handle->cpio__blocks != (off_t)-1
Denys Vlasenko1f937d62010-12-26 02:22:51 +0100575 && !(opt & OPT_QUIET)
Denys Vlasenko607f65d2010-01-09 20:23:03 +0100576 ) {
Denys Vlasenko7c443d12020-06-24 00:27:37 +0200577 fflush_all();
Matheus Izvekov4640ccc2010-04-26 13:53:57 +0200578 fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
Denys Vlasenko607f65d2010-01-09 20:23:03 +0100579 }
Denis Vlasenkod83676e2008-10-17 14:03:56 +0000580
Denis Vlasenko079f8af2006-11-27 16:49:31 +0000581 return EXIT_SUCCESS;
Glenn L McGrath8f5b63e2001-06-22 09:22:06 +0000582}