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 xchdir(*argv++);
508 close(pp.wr);
509 xmove_fd(pp.rd, STDIN_FILENO);
510
511 opt |= OPT_EXTRACT;
512 goto skip;
513 }
514
515 if (opt & OPT_CREATE) {
516 if (cpio_fmt[0] != 'n')
517 bb_show_usage();
518 if (opt & OPT_FILE) {
519 xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
520 }
521 dump:
522 return cpio_o();
523 }
524 skip:
525#endif
526
527
528 if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) {
529 bb_show_usage();
530 }
531
532 if (opt & OPT_TEST) {
533
534 opt &= ~OPT_EXTRACT;
535 archive_handle->action_header = header_list;
536 }
537 if (opt & OPT_EXTRACT) {
538 archive_handle->action_data = data_extract_all;
539 if (opt & OPT_2STDOUT)
540 archive_handle->action_data = data_extract_to_stdout;
541 }
542 if (opt & OPT_UNCONDITIONAL) {
543 archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD;
544 archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
545 }
546 if (opt & OPT_VERBOSE) {
547 if (archive_handle->action_header == header_list) {
548 archive_handle->action_header = header_verbose_list;
549 } else {
550 archive_handle->action_header = header_list;
551 }
552 }
553 if (opt & OPT_CREATE_LEADING_DIR) {
554 archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
555 }
556 if (opt & OPT_PRESERVE_MTIME) {
557 archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
558 }
559
560 while (*argv) {
561 archive_handle->filter = filter_accept_list;
562 llist_add_to(&archive_handle->accept, *argv);
563 argv++;
564 }
565
566
567 archive_handle->cpio__blocks = (off_t)-1;
568 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
569 continue;
570
571 create_links_from_list(archive_handle->link_placeholders);
572
573 if (archive_handle->cpio__blocks != (off_t)-1
574 && !(opt & OPT_QUIET)
575 ) {
576 fflush_all();
577 fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
578 }
579
580 return EXIT_SUCCESS;
581}
582