1
2
3
4
5
6
7
8
9
10
11
12
13
14#include "libbb.h"
15#include "archive.h"
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
111enum {
112 OPT_EXTRACT = (1 << 0),
113 OPT_TEST = (1 << 1),
114 OPT_NUL_TERMINATED = (1 << 2),
115 OPT_UNCONDITIONAL = (1 << 3),
116 OPT_VERBOSE = (1 << 4),
117 OPT_CREATE_LEADING_DIR = (1 << 5),
118 OPT_PRESERVE_MTIME = (1 << 6),
119 OPT_DEREF = (1 << 7),
120 OPT_FILE = (1 << 8),
121 OPTBIT_FILE = 8,
122 IF_FEATURE_CPIO_O(OPTBIT_CREATE ,)
123 IF_FEATURE_CPIO_O(OPTBIT_FORMAT ,)
124 IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,)
125 IF_LONG_OPTS( OPTBIT_QUIET ,)
126 IF_LONG_OPTS( OPTBIT_2STDOUT ,)
127 OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0,
128 OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0,
129 OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0,
130 OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0,
131 OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0,
132};
133
134#define OPTION_STR "it0uvdmLF:"
135
136#if ENABLE_FEATURE_CPIO_O
137static off_t cpio_pad4(off_t size)
138{
139 int i;
140
141 i = (- size) & 3;
142 size += i;
143 while (--i >= 0)
144 bb_putchar('\0');
145 return size;
146}
147
148
149
150static NOINLINE int cpio_o(void)
151{
152 static const char trailer[] ALIGN1 = "TRAILER!!!";
153 struct name_s {
154 struct name_s *next;
155 char name[1];
156 };
157 struct inodes_s {
158 struct inodes_s *next;
159 struct name_s *names;
160 struct stat st;
161 };
162
163 struct inodes_s *links = NULL;
164 off_t bytes = 0;
165
166 while (1) {
167 const char *name;
168 char *line;
169 struct stat st;
170
171 line = (option_mask32 & OPT_NUL_TERMINATED)
172 ? bb_get_chunk_from_file(stdin, NULL)
173 : xmalloc_fgetline(stdin);
174
175 if (line) {
176
177 name = line;
178 while (name[0] == '.' && name[1] == '/') {
179 while (*++name == '/')
180 continue;
181 }
182 if (!*name) {
183 free(line);
184 continue;
185 }
186 if ((option_mask32 & OPT_DEREF)
187 ? stat(name, &st)
188 : lstat(name, &st)
189 ) {
190 abort_cpio_o:
191 bb_simple_perror_msg_and_die(name);
192 }
193
194 if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
195 st.st_size = 0;
196
197
198 if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
199 struct name_s *n;
200 struct inodes_s *l;
201
202
203 l = links;
204 while (1) {
205 if (l == NULL) {
206
207 l = xzalloc(sizeof(*l));
208 l->st = st;
209 l->next = links;
210 links = l;
211 break;
212 }
213 if (l->st.st_ino == st.st_ino) {
214
215 break;
216 }
217 l = l->next;
218 }
219
220 n = xmalloc(sizeof(*n) + strlen(name));
221 strcpy(n->name, name);
222 n->next = l->names;
223 l->names = n;
224
225 free(line);
226 continue;
227 }
228
229 } else {
230 next_link:
231 if (links) {
232
233 st = links->st;
234 name = links->names->name;
235 links->names = links->names->next;
236
237
238 if (links->names == NULL)
239 links = links->next;
240 else
241 st.st_size = 0;
242
243
244 } else {
245
246
247 name = trailer;
248
249
250 memset(&st, 0, sizeof(st));
251
252 }
253 }
254
255 bytes += printf("070701"
256 "%08X%08X%08X%08X%08X%08X%08X"
257 "%08X%08X%08X%08X"
258 "%08X"
259 "00000000"
260 "%s%c",
261 (unsigned)(uint32_t) st.st_ino,
262 (unsigned)(uint32_t) st.st_mode,
263 (unsigned)(uint32_t) st.st_uid,
264 (unsigned)(uint32_t) st.st_gid,
265 (unsigned)(uint32_t) st.st_nlink,
266 (unsigned)(uint32_t) st.st_mtime,
267 (unsigned)(uint32_t) st.st_size,
268 (unsigned)(uint32_t) major(st.st_dev),
269 (unsigned)(uint32_t) minor(st.st_dev),
270 (unsigned)(uint32_t) major(st.st_rdev),
271 (unsigned)(uint32_t) minor(st.st_rdev),
272 (unsigned)(strlen(name) + 1),
273 name, '\0');
274 bytes = cpio_pad4(bytes);
275
276 if (st.st_size) {
277 if (S_ISLNK(st.st_mode)) {
278 char *lpath = xmalloc_readlink_or_warn(name);
279 if (!lpath)
280 goto abort_cpio_o;
281 bytes += printf("%s", lpath);
282 free(lpath);
283 } else {
284 int fd = xopen(name, O_RDONLY);
285 fflush_all();
286
287 bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
288 bytes += st.st_size;
289 close(fd);
290 }
291 bytes = cpio_pad4(bytes);
292 }
293
294 if (!line) {
295 if (name != trailer)
296 goto next_link;
297
298 return EXIT_SUCCESS;
299 }
300
301 free(line);
302 }
303}
304#endif
305
306int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
307int cpio_main(int argc UNUSED_PARAM, char **argv)
308{
309 archive_handle_t *archive_handle;
310 char *cpio_filename;
311 IF_FEATURE_CPIO_O(const char *cpio_fmt = "";)
312 unsigned opt;
313
314#if ENABLE_LONG_OPTS
315 applet_long_options =
316 "extract\0" No_argument "i"
317 "list\0" No_argument "t"
318#if ENABLE_FEATURE_CPIO_O
319 "create\0" No_argument "o"
320 "format\0" Required_argument "H"
321#if ENABLE_FEATURE_CPIO_P
322 "pass-through\0" No_argument "p"
323#endif
324#endif
325 "verbose\0" No_argument "v"
326 "quiet\0" No_argument "\xff"
327 "to-stdout\0" No_argument "\xfe"
328 ;
329#endif
330
331 archive_handle = init_handle();
332
333 archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
334
335
336
337
338
339
340#if !ENABLE_FEATURE_CPIO_O
341 opt = getopt32(argv, OPTION_STR, &cpio_filename);
342 argv += optind;
343 if (opt & OPT_FILE) {
344 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
345 }
346#else
347 opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt);
348 argv += optind;
349 if ((opt & (OPT_FILE|OPT_CREATE)) == OPT_FILE) {
350 xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
351 }
352 if (opt & OPT_PASSTHROUGH) {
353 pid_t pid;
354 struct fd_pair pp;
355
356 if (argv[0] == NULL)
357 bb_show_usage();
358 if (opt & OPT_CREATE_LEADING_DIR)
359 mkdir(argv[0], 0777);
360
361
362
363
364
365
366
367
368
369#if !BB_MMU
370 pp.rd = 3;
371 pp.wr = 4;
372 if (!re_execed) {
373 close(3);
374 close(4);
375 xpiped_pair(pp);
376 }
377#else
378 xpiped_pair(pp);
379#endif
380 pid = fork_or_rexec(argv - optind);
381 if (pid == 0) {
382 close(pp.rd);
383 xmove_fd(pp.wr, STDOUT_FILENO);
384 goto dump;
385 }
386
387 xchdir(*argv++);
388 close(pp.wr);
389 xmove_fd(pp.rd, STDIN_FILENO);
390
391 opt |= OPT_EXTRACT;
392 goto skip;
393 }
394
395 if (opt & OPT_CREATE) {
396 if (cpio_fmt[0] != 'n')
397 bb_show_usage();
398 if (opt & OPT_FILE) {
399 xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO);
400 }
401 dump:
402 return cpio_o();
403 }
404 skip:
405#endif
406
407
408 if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) {
409 bb_show_usage();
410 }
411
412 if (opt & OPT_TEST) {
413
414 opt &= ~OPT_EXTRACT;
415 archive_handle->action_header = header_list;
416 }
417 if (opt & OPT_EXTRACT) {
418 archive_handle->action_data = data_extract_all;
419 if (opt & OPT_2STDOUT)
420 archive_handle->action_data = data_extract_to_stdout;
421 }
422 if (opt & OPT_UNCONDITIONAL) {
423 archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD;
424 archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
425 }
426 if (opt & OPT_VERBOSE) {
427 if (archive_handle->action_header == header_list) {
428 archive_handle->action_header = header_verbose_list;
429 } else {
430 archive_handle->action_header = header_list;
431 }
432 }
433 if (opt & OPT_CREATE_LEADING_DIR) {
434 archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
435 }
436 if (opt & OPT_PRESERVE_MTIME) {
437 archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
438 }
439
440 while (*argv) {
441 archive_handle->filter = filter_accept_list;
442 llist_add_to(&archive_handle->accept, *argv);
443 argv++;
444 }
445
446
447 archive_handle->cpio__blocks = (off_t)-1;
448 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
449 continue;
450
451 if (archive_handle->cpio__blocks != (off_t)-1
452 && !(opt & OPT_QUIET)
453 ) {
454 fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
455 }
456
457 return EXIT_SUCCESS;
458}
459