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