1 /* main.c - main program and argument processing for cpio.
2 Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* Written by Phil Nelson <phil@cs.wwu.edu>,
19 David MacKenzie <djm@gnu.ai.mit.edu>,
20 and John Oleynick <juo@klinzhai.rutgers.edu>. */
22 /* $FreeBSD: src/contrib/cpio/main.c,v 1.3 1999/09/15 01:47:13 peter Exp $ */
23 /* $DragonFly: src/contrib/cpio/main.c,v 1.2 2003/06/17 06:23:58 dillon Exp $ */
27 #include <sys/types.h>
29 #ifdef HAVE_SYS_PARAM_H
30 #include <sys/param.h>
32 #if (defined(BSD) && (BSD >= 199306))
35 #include "filetypes.h"
42 struct option long_opts
[] =
45 {"append", 0, 0, 'A'},
46 {"block-size", 1, 0, 130},
47 {"create", 0, 0, 'o'},
48 {"dereference", 0, 0, 'L'},
50 {"extract", 0, 0, 'i'},
52 {"force-local", 0, &f_force_local
, 1},
53 {"format", 1, 0, 'H'},
55 {"io-size", 1, 0, 'C'},
56 {"link", 0, &link_flag
, TRUE
},
57 {"list", 0, &table_flag
, TRUE
},
58 {"make-directories", 0, &create_dir_flag
, TRUE
},
59 {"message", 1, 0, 'M'},
60 {"no-absolute-filenames", 0, 0, 136},
61 {"no-preserve-owner", 0, 0, 134},
62 {"nonmatching", 0, ©_matching_files
, FALSE
},
63 {"numeric-uid-gid", 0, &numeric_uid
, TRUE
},
64 {"only-verify-crc", 0, 0, 139},
66 {"pass-through", 0, 0, 'p'},
67 {"pattern-file", 1, 0, 'E'},
68 {"preserve-modification-time", 0, &retain_time_flag
, TRUE
},
69 {"rename", 0, &rename_flag
, TRUE
},
70 {"rename-batch-file", 1, 0, 137},
72 {"sparse", 0, 0, 135},
74 {"swap-bytes", 0, 0, 's'},
75 {"swap-halfwords", 0, 0, 'S'},
76 {"reset-access-time", 0, &reset_time_flag
, TRUE
},
77 {"unconditional", 0, &unconditional_flag
, TRUE
},
78 {"verbose", 0, &verbose_flag
, TRUE
},
79 {"version", 0, 0, 131},
81 {"debug", 0, &debug_flag
, TRUE
},
86 /* Print usage message and exit with error. */
94 Usage: %s {-o|--create} [-0acvABLV] [-C bytes] [-H format] [-M message]\n\
95 [-O [[user@]host:]archive] [-F [[user@]host:]archive]\n\
96 [--file=[[user@]host:]archive] [--format=format] [--message=message]\n\
97 [--null] [--reset-access-time] [--verbose] [--dot] [--append]\n\
98 [--block-size=blocks] [--dereference] [--io-size=bytes] [--quiet]\n\
99 [--force-local] [--help] [--version] < name-list [> archive]\n", program_name
);
101 %s {-i|--extract} [-bcdfmnrtsuvBSV] [-C bytes] [-E file] [-H format]\n\
102 [-M message] [-R [user][:.][group]] [-I [[user@]host:]archive]\n\
103 [-F [[user@]host:]archive] [--file=[[user@]host:]archive]\n\
104 [--make-directories] [--nonmatching] [--preserve-modification-time]\n\
105 [--numeric-uid-gid] [--rename] [--list] [--swap-bytes] [--swap] [--dot]\n\
106 [--unconditional] [--verbose] [--block-size=blocks] [--swap-halfwords]\n\
107 [--io-size=bytes] [--pattern-file=file] [--format=format]\n\
108 [--owner=[user][:.][group]] [--no-preserve-owner] [--message=message]\n\
109 [--force-local] [--no-absolute-filenames] [--sparse] [--only-verify-crc]\n\
110 [--quiet] [--help] [--version] [pattern...] [< archive]\n",
113 %s {-p|--pass-through} [-0adlmuvLV] [-R [user][:.][group]]\n\
114 [--null] [--reset-access-time] [--make-directories] [--link] [--quiet]\n\
115 [--preserve-modification-time] [--unconditional] [--verbose] [--dot]\n\
116 [--dereference] [--owner=[user][:.][group]] [--no-preserve-owner]\n\
117 [--sparse] [--help] [--version] destination-directory < name-list\n", program_name
);
121 /* Process the arguments. Set all options and set up the copy pass
122 directory or the copy in patterns. */
125 process_args (argc
, argv
)
129 extern char *version_string
;
130 void (*copy_in
) (); /* Work around for pcc bug. */
133 char *input_archive_name
= 0;
134 char *output_archive_name
= 0;
141 while ((c
= getopt_long (argc
, argv
,
142 "0aAbBcC:dfE:F:H:iI:lLmM:noO:prR:sStuvVz",
143 long_opts
, (int *) 0)) != -1)
147 case 0: /* A long option that just sets a flag. */
150 case '0': /* Read null-terminated filenames. */
154 case 'a': /* Reset access times. */
155 reset_time_flag
= TRUE
;
158 case 'A': /* Append to the archive. */
162 case 'b': /* Swap bytes and halfwords. */
163 swap_bytes_flag
= TRUE
;
164 swap_halfwords_flag
= TRUE
;
167 case 'B': /* Set block size to 5120. */
168 io_block_size
= 5120;
171 case 130: /* --block-size */
172 io_block_size
= atoi (optarg
);
173 if (io_block_size
< 1)
174 error (2, 0, "invalid block size");
175 io_block_size
*= 512;
178 case 'c': /* Use the old portable ASCII format. */
179 if (archive_format
!= arf_unknown
)
182 archive_format
= arf_newascii
; /* -H newc. */
184 archive_format
= arf_oldascii
; /* -H odc. */
188 case 'C': /* Block size. */
189 io_block_size
= atoi (optarg
);
190 if (io_block_size
< 1)
191 error (2, 0, "invalid block size");
194 case 'd': /* Create directories where needed. */
195 create_dir_flag
= TRUE
;
198 case 'f': /* Only copy files not matching patterns. */
199 copy_matching_files
= FALSE
;
202 case 'E': /* Pattern file name. */
203 pattern_file_name
= optarg
;
206 case 'F': /* Archive file name. */
207 archive_name
= optarg
;
210 case 'H': /* Header format name. */
211 if (archive_format
!= arf_unknown
)
213 if (!strcmp (optarg
, "crc") || !strcmp (optarg
, "CRC"))
214 archive_format
= arf_crcascii
;
215 else if (!strcmp (optarg
, "newc") || !strcmp (optarg
, "NEWC"))
216 archive_format
= arf_newascii
;
217 else if (!strcmp (optarg
, "odc") || !strcmp (optarg
, "ODC"))
218 archive_format
= arf_oldascii
;
219 else if (!strcmp (optarg
, "bin") || !strcmp (optarg
, "BIN"))
220 archive_format
= arf_binary
;
221 else if (!strcmp (optarg
, "ustar") || !strcmp (optarg
, "USTAR"))
222 archive_format
= arf_ustar
;
223 else if (!strcmp (optarg
, "tar") || !strcmp (optarg
, "TAR"))
224 archive_format
= arf_tar
;
225 else if (!strcmp (optarg
, "hpodc") || !strcmp (optarg
, "HPODC"))
226 archive_format
= arf_hpoldascii
;
227 else if (!strcmp (optarg
, "hpbin") || !strcmp (optarg
, "HPBIN"))
228 archive_format
= arf_hpbinary
;
231 invalid archive format `%s'; valid formats are:\n\
232 crc newc odc bin ustar tar (all-caps also recognized)", optarg
);
235 case 'i': /* Copy-in mode. */
236 if (copy_function
!= 0)
238 copy_function
= process_copy_in
;
241 case 'I': /* Input archive file name. */
242 input_archive_name
= optarg
;
245 case 'k': /* Handle corrupted archives. We always handle
246 corrupted archives, but recognize this
247 option for compatability. */
250 case 'l': /* Link files when possible. */
254 case 'L': /* Dereference symbolic links. */
258 case 'm': /* Retain previous file modify times. */
259 retain_time_flag
= TRUE
;
262 case 'M': /* New media message. */
263 set_new_media_message (optarg
);
266 case 'n': /* Long list owner and group as numbers. */
270 case 136: /* --no-absolute-filenames */
271 no_abs_paths_flag
= TRUE
;
274 case 134: /* --no-preserve-owner */
275 if (set_owner_flag
|| set_group_flag
)
277 no_chown_flag
= TRUE
;
280 case 'o': /* Copy-out mode. */
281 if (copy_function
!= 0)
283 copy_function
= process_copy_out
;
286 case 'O': /* Output archive file name. */
287 output_archive_name
= optarg
;
291 only_verify_crc_flag
= TRUE
;
294 case 'p': /* Copy-pass mode. */
295 if (copy_function
!= 0)
297 copy_function
= process_copy_pass
;
300 case 'r': /* Interactively rename. */
305 rename_batch_file
= optarg
;
312 case 'R': /* Set the owner. */
319 e
= parse_user_spec (optarg
, &set_owner
, &set_group
, &u
, &g
);
321 error (2, 0, "%s: %s", optarg
, e
);
325 set_owner_flag
= TRUE
;
330 set_group_flag
= TRUE
;
336 case 's': /* Swap bytes. */
337 swap_bytes_flag
= TRUE
;
340 case 'S': /* Swap halfwords. */
341 swap_halfwords_flag
= TRUE
;
344 case 't': /* Only print a list. */
348 case 'u': /* Replace all! Unconditionally! */
349 unconditional_flag
= TRUE
;
352 case 'v': /* Verbose! */
356 case 'V': /* Print `.' for each file. */
361 printf ("GNU cpio %s", version_string
);
369 case 132: /* --help */
378 /* Do error checking and look at other args. */
380 if (copy_function
== 0)
383 copy_function
= process_copy_in
;
388 if ((!table_flag
|| !verbose_flag
) && numeric_uid
)
391 /* Work around for pcc bug. */
392 copy_in
= process_copy_in
;
393 copy_out
= process_copy_out
;
395 if (copy_function
== copy_in
)
398 if (link_flag
|| reset_time_flag
|| xstat
!= lstat
|| append_flag
400 || output_archive_name
401 || (archive_name
&& input_archive_name
))
403 if (archive_format
== arf_crcascii
)
405 num_patterns
= argc
- optind
;
406 save_patterns
= &argv
[optind
];
407 if (input_archive_name
)
408 archive_name
= input_archive_name
;
410 else if (copy_function
== copy_out
)
413 if (argc
!= optind
|| create_dir_flag
|| rename_flag
414 || table_flag
|| unconditional_flag
|| link_flag
415 || retain_time_flag
|| no_chown_flag
|| set_owner_flag
416 || set_group_flag
|| swap_bytes_flag
|| swap_halfwords_flag
417 || (append_flag
&& !(archive_name
|| output_archive_name
))
418 || rename_batch_file
|| no_abs_paths_flag
419 || input_archive_name
|| (archive_name
&& output_archive_name
))
421 if (archive_format
== arf_unknown
)
422 archive_format
= arf_binary
;
423 if (output_archive_name
)
424 archive_name
= output_archive_name
;
430 if (argc
- 1 != optind
|| archive_format
!= arf_unknown
431 || swap_bytes_flag
|| swap_halfwords_flag
432 || table_flag
|| rename_flag
|| append_flag
433 || rename_batch_file
|| no_abs_paths_flag
)
435 directory_name
= argv
[optind
];
440 if (copy_function
!= copy_in
&& copy_function
!= copy_out
)
442 archive_des
= open_archive (archive_name
);
444 error (1, errno
, "%s", archive_name
);
448 /* Prevent SysV non-root users from giving away files inadvertantly.
449 This happens automatically on BSD, where only root can give
451 if (set_owner_flag
== FALSE
&& set_group_flag
== FALSE
&& geteuid ())
452 no_chown_flag
= TRUE
;
456 /* Initialize the input and output buffers to their proper size and
457 initialize all variables associated with the input and output
461 initialize_buffers ()
463 int in_buf_size
, out_buf_size
;
465 if (copy_function
== process_copy_in
)
467 /* Make sure the input buffer can always hold 2 blocks and that it
468 is big enough to hold 1 tar record (512 bytes) even if it
469 is not aligned on a block boundary. The extra buffer space
470 is needed by process_copyin and peek_in_buf to automatically
471 figure out what kind of archive it is reading. */
472 if (io_block_size
>= 512)
473 in_buf_size
= 2 * io_block_size
;
476 out_buf_size
= DISK_IO_BLOCK_SIZE
;
478 else if (copy_function
== process_copy_out
)
480 in_buf_size
= DISK_IO_BLOCK_SIZE
;
481 out_buf_size
= io_block_size
;
485 in_buf_size
= DISK_IO_BLOCK_SIZE
;
486 out_buf_size
= DISK_IO_BLOCK_SIZE
;
489 input_buffer
= (char *) xmalloc (in_buf_size
);
490 in_buff
= input_buffer
;
491 input_buffer_size
= in_buf_size
;
495 output_buffer
= (char *) xmalloc (out_buf_size
);
496 out_buff
= output_buffer
;
500 /* Clear the block of zeros. */
501 bzero (zeros_512
, 512);
509 program_name
= argv
[0];
511 #if (defined(BSD) && (BSD >= 199306))
512 (void) setlocale (LC_ALL
, "");
516 _fmode
= O_BINARY
; /* Put stdin and stdout in binary mode. */
518 #ifdef __EMX__ /* gcc on OS/2. */
519 _response (&argc
, &argv
);
520 _wildcard (&argc
, &argv
);
523 process_args (argc
, argv
);
526 initialize_buffers ();
530 if (archive_des
>= 0 && rmtclose (archive_des
) == -1)
531 error (1, errno
, "error closing archive");