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