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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164#include "libbb.h"
165#include "common_bufsiz.h"
166#include "bb_archive.h"
167
168enum {
169 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),
178 OPT_OWNER = (1 << 9),
179 OPTBIT_OWNER = 9,
180 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 ,)
185 IF_FEATURE_CPIO_IGNORE_DEVNO(OPTBIT_IGNORE_DEVNO,)
186 IF_FEATURE_CPIO_RENUMBER_INODES(OPTBIT_RENUMBER_INODES,)
187 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,
192 OPT_IGNORE_DEVNO = IF_FEATURE_CPIO_IGNORE_DEVNO((1 << OPTBIT_IGNORE_DEVNO)) + 0,
193 OPT_RENUMBER_INODES = IF_FEATURE_CPIO_RENUMBER_INODES((1 << OPTBIT_RENUMBER_INODES)) + 0,
194};
195
196#define OPTION_STR "it0uvdmLF:R:"
197
198struct globals {
199 struct bb_uidgid_t owner_ugid;
200 ino_t next_inode;
201} FIX_ALIASING;
202#define G (*(struct globals*)bb_common_bufsiz1)
203void BUG_cpio_globals_too_big(void);
204#define INIT_G() do { \
205 setup_common_bufsiz(); \
206 G.owner_ugid.uid = -1L; \
207 G.owner_ugid.gid = -1L; \
208} while (0)
209
210#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
223
224static NOINLINE int cpio_o(void)
225{
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;
234#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
235 ino_t mapped_inode;
236#endif
237 };
238
239 struct inodes_s *links = NULL;
240 off_t bytes = 0;
241
242 while (1) {
243 const char *name;
244 char *line;
245 struct stat st;
246
247 line = (option_mask32 & OPT_NUL_TERMINATED)
248 ? bb_get_chunk_from_file(stdin, NULL)
249 : xmalloc_fgetline(stdin);
250
251 if (line) {
252
253 name = line;
254 while (name[0] == '.' && name[1] == '/') {
255 while (*++name == '/')
256 continue;
257 }
258 if (!*name) {
259 free(line);
260 continue;
261 }
262 if ((option_mask32 & OPT_DEREF)
263 ? stat(name, &st)
264 : lstat(name, &st)
265 ) {
266 abort_cpio_o:
267 bb_simple_perror_msg_and_die(name);
268 }
269
270 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
275 if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
276 st.st_size = 0;
277
278
279 if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
280 struct name_s *n;
281 struct inodes_s *l;
282
283
284 l = links;
285 while (1) {
286 if (l == NULL) {
287
288 l = xzalloc(sizeof(*l));
289 l->st = st;
290 l->next = links;
291#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
292 if (option_mask32 & OPT_RENUMBER_INODES)
293 l->mapped_inode = ++G.next_inode;
294#endif
295 links = l;
296 break;
297 }
298 if (l->st.st_ino == st.st_ino) {
299
300 break;
301 }
302 l = l->next;
303 }
304
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 }
313#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
314 else if (option_mask32 & OPT_RENUMBER_INODES) {
315 st.st_ino = ++G.next_inode;
316 }
317#endif
318 } else {
319 next_link:
320 if (links) {
321
322 st = links->st;
323 name = links->names->name;
324 links->names = links->names->next;
325#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
326 if (links->mapped_inode)
327 st.st_ino = links->mapped_inode;
328#endif
329
330
331 if (links->names == NULL)
332 links = links->next;
333 else
334 st.st_size = 0;
335
336
337 } else {
338
339
340 name = cpio_TRAILER;
341
342
343 memset(&st, 0, sizeof(st));
344
345 }
346 }
347
348#if ENABLE_FEATURE_CPIO_IGNORE_DEVNO
349 if (option_mask32 & OPT_IGNORE_DEVNO)
350 st.st_dev = st.st_rdev = 0;
351#endif
352
353 bytes += printf("070701"
354 "%08X%08X%08X%08X%08X%08X%08X"
355 "%08X%08X%08X%08X"
356 "%08X"
357 "00000000"
358 "%s%c",
359 (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');
372 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 {
382 int fd = xopen(name, O_RDONLY);
383 fflush_all();
384
385 bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
386 bytes += st.st_size;
387 close(fd);
388 }
389 bytes = cpio_pad4(bytes);
390 }
391
392 if (!line) {
393 if (name != cpio_TRAILER)
394 goto next_link;
395
396 return EXIT_SUCCESS;
397 }
398
399 free(line);
400 }
401}
402#endif
403
404int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
405int cpio_main(int argc UNUSED_PARAM, char **argv)
406{
407 archive_handle_t *archive_handle;
408 char *cpio_filename;
409 char *cpio_owner;
410 IF_FEATURE_CPIO_O(const char *cpio_fmt = "";)
411 unsigned opt;
412#if ENABLE_LONG_OPTS
413 const char *long_opts =
414 "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"
419#if ENABLE_FEATURE_CPIO_P
420 "pass-through\0" No_argument "p"
421#endif
422#endif
423 "owner\0" Required_argument "R"
424 "verbose\0" No_argument "v"
425 "null\0" No_argument "0"
426 "quiet\0" No_argument "\xff"
427 "to-stdout\0" No_argument "\xfe"
428#if ENABLE_FEATURE_CPIO_IGNORE_DEVNO
429 "ignore-devno\0" No_argument "\xfd"
430#endif
431#if ENABLE_FEATURE_CPIO_RENUMBER_INODES
432 "renumber-inodes\0" No_argument "\xfc"
433#endif
434 ;
435#endif
436
437 INIT_G();
438 archive_handle = init_handle();
439
440 archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
441
442
443
444
445
446
447#if !ENABLE_FEATURE_CPIO_O
448 opt = getopt32long(argv, OPTION_STR, long_opts, &cpio_filename, &cpio_owner);
449#else
450 opt = getopt32long(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), long_opts,
451 &cpio_filename, &cpio_owner, &cpio_fmt);
452#endif
453 argv += optind;
454 if (opt & OPT_OWNER) {
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
459 if (opt & OPT_FILE) {
460 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
461 }
462#else
463 if ((opt & (OPT_FILE|OPT_CREATE)) == OPT_FILE) {
464 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
465 }
466 if (opt & OPT_PASSTHROUGH) {
467 pid_t pid;
468 struct fd_pair pp;
469
470 if (argv[0] == NULL)
471 bb_show_usage();
472 if (opt & OPT_CREATE_LEADING_DIR)
473
474 bb_make_directory(argv[0], -1, FILEUTILS_RECUR);
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489#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
500 pid = fork_or_rexec(argv - optind);
501 if (pid == 0) {
502 close(pp.rd);
503 xmove_fd(pp.wr, STDOUT_FILENO);
504 goto dump;
505 }
506
507 USE_FOR_NOMMU(argv[-optind][0] &= 0x7f);
508 xchdir(*argv++);
509 close(pp.wr);
510 xmove_fd(pp.rd, STDIN_FILENO);
511
512 opt |= OPT_EXTRACT;
513 goto skip;
514 }
515
516 if (opt & OPT_CREATE) {
517 if (cpio_fmt[0] != 'n')
518 bb_show_usage();
519 if (opt & OPT_FILE) {
520 xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
521 }
522 dump:
523 return cpio_o();
524 }
525 skip:
526#endif
527
528
529 if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) {
530 bb_show_usage();
531 }
532
533 if (opt & OPT_TEST) {
534
535 opt &= ~OPT_EXTRACT;
536 archive_handle->action_header = header_list;
537 }
538 if (opt & OPT_EXTRACT) {
539 archive_handle->action_data = data_extract_all;
540 if (opt & OPT_2STDOUT)
541 archive_handle->action_data = data_extract_to_stdout;
542 }
543 if (opt & OPT_UNCONDITIONAL) {
544 archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD;
545 archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
546 }
547 if (opt & OPT_VERBOSE) {
548 if (archive_handle->action_header == header_list) {
549 archive_handle->action_header = header_verbose_list;
550 } else {
551 archive_handle->action_header = header_list;
552 }
553 }
554 if (opt & OPT_CREATE_LEADING_DIR) {
555 archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
556 }
557 if (opt & OPT_PRESERVE_MTIME) {
558 archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
559 }
560
561 while (*argv) {
562 archive_handle->filter = filter_accept_list;
563 llist_add_to(&archive_handle->accept, *argv);
564 argv++;
565 }
566
567
568 archive_handle->cpio__blocks = (off_t)-1;
569 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
570 continue;
571
572 create_links_from_list(archive_handle->link_placeholders);
573
574 if (archive_handle->cpio__blocks != (off_t)-1
575 && !(opt & OPT_QUIET)
576 ) {
577 fflush_all();
578 fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
579 }
580
581 return EXIT_SUCCESS;
582}
583