1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144#include "libbb.h"
145#include "common_bufsiz.h"
146#include "bb_archive.h"
147
148enum {
149 OPT_EXTRACT = (1 << 0),
150 OPT_TEST = (1 << 1),
151 OPT_NUL_TERMINATED = (1 << 2),
152 OPT_UNCONDITIONAL = (1 << 3),
153 OPT_VERBOSE = (1 << 4),
154 OPT_CREATE_LEADING_DIR = (1 << 5),
155 OPT_PRESERVE_MTIME = (1 << 6),
156 OPT_DEREF = (1 << 7),
157 OPT_FILE = (1 << 8),
158 OPT_OWNER = (1 << 9),
159 OPTBIT_OWNER = 9,
160 IF_FEATURE_CPIO_O(OPTBIT_CREATE ,)
161 IF_FEATURE_CPIO_O(OPTBIT_FORMAT ,)
162 IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,)
163 IF_LONG_OPTS( OPTBIT_QUIET ,)
164 IF_LONG_OPTS( OPTBIT_2STDOUT ,)
165 OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0,
166 OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0,
167 OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0,
168 OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0,
169 OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0,
170};
171
172#define OPTION_STR "it0uvdmLF:R:"
173
174struct globals {
175 struct bb_uidgid_t owner_ugid;
176} FIX_ALIASING;
177#define G (*(struct globals*)bb_common_bufsiz1)
178void BUG_cpio_globals_too_big(void);
179#define INIT_G() do { \
180 setup_common_bufsiz(); \
181 G.owner_ugid.uid = -1L; \
182 G.owner_ugid.gid = -1L; \
183} while (0)
184
185#if ENABLE_FEATURE_CPIO_O
186static off_t cpio_pad4(off_t size)
187{
188 int i;
189
190 i = (- size) & 3;
191 size += i;
192 while (--i >= 0)
193 bb_putchar('\0');
194 return size;
195}
196
197
198
199static NOINLINE int cpio_o(void)
200{
201 struct name_s {
202 struct name_s *next;
203 char name[1];
204 };
205 struct inodes_s {
206 struct inodes_s *next;
207 struct name_s *names;
208 struct stat st;
209 };
210
211 struct inodes_s *links = NULL;
212 off_t bytes = 0;
213
214 while (1) {
215 const char *name;
216 char *line;
217 struct stat st;
218
219 line = (option_mask32 & OPT_NUL_TERMINATED)
220 ? bb_get_chunk_from_file(stdin, NULL)
221 : xmalloc_fgetline(stdin);
222
223 if (line) {
224
225 name = line;
226 while (name[0] == '.' && name[1] == '/') {
227 while (*++name == '/')
228 continue;
229 }
230 if (!*name) {
231 free(line);
232 continue;
233 }
234 if ((option_mask32 & OPT_DEREF)
235 ? stat(name, &st)
236 : lstat(name, &st)
237 ) {
238 abort_cpio_o:
239 bb_simple_perror_msg_and_die(name);
240 }
241
242 if (G.owner_ugid.uid != (uid_t)-1L)
243 st.st_uid = G.owner_ugid.uid;
244 if (G.owner_ugid.gid != (gid_t)-1L)
245 st.st_gid = G.owner_ugid.gid;
246
247 if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
248 st.st_size = 0;
249
250
251 if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
252 struct name_s *n;
253 struct inodes_s *l;
254
255
256 l = links;
257 while (1) {
258 if (l == NULL) {
259
260 l = xzalloc(sizeof(*l));
261 l->st = st;
262 l->next = links;
263 links = l;
264 break;
265 }
266 if (l->st.st_ino == st.st_ino) {
267
268 break;
269 }
270 l = l->next;
271 }
272
273 n = xmalloc(sizeof(*n) + strlen(name));
274 strcpy(n->name, name);
275 n->next = l->names;
276 l->names = n;
277
278 free(line);
279 continue;
280 }
281 } else {
282 next_link:
283 if (links) {
284
285 st = links->st;
286 name = links->names->name;
287 links->names = links->names->next;
288
289
290 if (links->names == NULL)
291 links = links->next;
292 else
293 st.st_size = 0;
294
295
296 } else {
297
298
299 name = cpio_TRAILER;
300
301
302 memset(&st, 0, sizeof(st));
303
304 }
305 }
306
307 bytes += printf("070701"
308 "%08X%08X%08X%08X%08X%08X%08X"
309 "%08X%08X%08X%08X"
310 "%08X"
311 "00000000"
312 "%s%c",
313 (unsigned)(uint32_t) st.st_ino,
314 (unsigned)(uint32_t) st.st_mode,
315 (unsigned)(uint32_t) st.st_uid,
316 (unsigned)(uint32_t) st.st_gid,
317 (unsigned)(uint32_t) st.st_nlink,
318 (unsigned)(uint32_t) st.st_mtime,
319 (unsigned)(uint32_t) st.st_size,
320 (unsigned)(uint32_t) major(st.st_dev),
321 (unsigned)(uint32_t) minor(st.st_dev),
322 (unsigned)(uint32_t) major(st.st_rdev),
323 (unsigned)(uint32_t) minor(st.st_rdev),
324 (unsigned)(strlen(name) + 1),
325 name, '\0');
326 bytes = cpio_pad4(bytes);
327
328 if (st.st_size) {
329 if (S_ISLNK(st.st_mode)) {
330 char *lpath = xmalloc_readlink_or_warn(name);
331 if (!lpath)
332 goto abort_cpio_o;
333 bytes += printf("%s", lpath);
334 free(lpath);
335 } else {
336 int fd = xopen(name, O_RDONLY);
337 fflush_all();
338
339 bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
340 bytes += st.st_size;
341 close(fd);
342 }
343 bytes = cpio_pad4(bytes);
344 }
345
346 if (!line) {
347 if (name != cpio_TRAILER)
348 goto next_link;
349
350 return EXIT_SUCCESS;
351 }
352
353 free(line);
354 }
355}
356#endif
357
358int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
359int cpio_main(int argc UNUSED_PARAM, char **argv)
360{
361 archive_handle_t *archive_handle;
362 char *cpio_filename;
363 char *cpio_owner;
364 IF_FEATURE_CPIO_O(const char *cpio_fmt = "";)
365 unsigned opt;
366#if ENABLE_LONG_OPTS
367 const char *long_opts =
368 "extract\0" No_argument "i"
369 "list\0" No_argument "t"
370#if ENABLE_FEATURE_CPIO_O
371 "create\0" No_argument "o"
372 "format\0" Required_argument "H"
373#if ENABLE_FEATURE_CPIO_P
374 "pass-through\0" No_argument "p"
375#endif
376#endif
377 "owner\0" Required_argument "R"
378 "verbose\0" No_argument "v"
379 "null\0" No_argument "0"
380 "quiet\0" No_argument "\xff"
381 "to-stdout\0" No_argument "\xfe"
382 ;
383#endif
384
385 INIT_G();
386 archive_handle = init_handle();
387
388 archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
389
390
391
392
393
394
395#if !ENABLE_FEATURE_CPIO_O
396 opt = getopt32long(argv, OPTION_STR, long_opts, &cpio_filename, &cpio_owner);
397#else
398 opt = getopt32long(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), long_opts,
399 &cpio_filename, &cpio_owner, &cpio_fmt);
400#endif
401 argv += optind;
402 if (opt & OPT_OWNER) {
403 parse_chown_usergroup_or_die(&G.owner_ugid, cpio_owner);
404 archive_handle->cpio__owner = G.owner_ugid;
405 }
406#if !ENABLE_FEATURE_CPIO_O
407 if (opt & OPT_FILE) {
408 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
409 }
410#else
411 if ((opt & (OPT_FILE|OPT_CREATE)) == OPT_FILE) {
412 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
413 }
414 if (opt & OPT_PASSTHROUGH) {
415 pid_t pid;
416 struct fd_pair pp;
417
418 if (argv[0] == NULL)
419 bb_show_usage();
420 if (opt & OPT_CREATE_LEADING_DIR)
421 mkdir(argv[0], 0777);
422
423
424
425
426
427
428
429
430
431#if !BB_MMU
432 pp.rd = 3;
433 pp.wr = 4;
434 if (!re_execed) {
435 close(3);
436 close(4);
437 xpiped_pair(pp);
438 }
439#else
440 xpiped_pair(pp);
441#endif
442 pid = fork_or_rexec(argv - optind);
443 if (pid == 0) {
444 close(pp.rd);
445 xmove_fd(pp.wr, STDOUT_FILENO);
446 goto dump;
447 }
448
449 USE_FOR_NOMMU(argv[-optind][0] &= 0x7f);
450 xchdir(*argv++);
451 close(pp.wr);
452 xmove_fd(pp.rd, STDIN_FILENO);
453
454 opt |= OPT_EXTRACT;
455 goto skip;
456 }
457
458 if (opt & OPT_CREATE) {
459 if (cpio_fmt[0] != 'n')
460 bb_show_usage();
461 if (opt & OPT_FILE) {
462 xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
463 }
464 dump:
465 return cpio_o();
466 }
467 skip:
468#endif
469
470
471 if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) {
472 bb_show_usage();
473 }
474
475 if (opt & OPT_TEST) {
476
477 opt &= ~OPT_EXTRACT;
478 archive_handle->action_header = header_list;
479 }
480 if (opt & OPT_EXTRACT) {
481 archive_handle->action_data = data_extract_all;
482 if (opt & OPT_2STDOUT)
483 archive_handle->action_data = data_extract_to_stdout;
484 }
485 if (opt & OPT_UNCONDITIONAL) {
486 archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD;
487 archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
488 }
489 if (opt & OPT_VERBOSE) {
490 if (archive_handle->action_header == header_list) {
491 archive_handle->action_header = header_verbose_list;
492 } else {
493 archive_handle->action_header = header_list;
494 }
495 }
496 if (opt & OPT_CREATE_LEADING_DIR) {
497 archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
498 }
499 if (opt & OPT_PRESERVE_MTIME) {
500 archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
501 }
502
503 while (*argv) {
504 archive_handle->filter = filter_accept_list;
505 llist_add_to(&archive_handle->accept, *argv);
506 argv++;
507 }
508
509
510 archive_handle->cpio__blocks = (off_t)-1;
511 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
512 continue;
513
514 create_links_from_list(archive_handle->link_placeholders);
515
516 if (archive_handle->cpio__blocks != (off_t)-1
517 && !(opt & OPT_QUIET)
518 ) {
519 fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
520 }
521
522 return EXIT_SUCCESS;
523}
524