Merge from vendor branch GCC:
[dragonfly.git] / contrib / cpio / main.c
1 /* main.c - main program and argument processing for cpio.
2    Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
3
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)
7    any later version.
8
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.
13
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.  */
17
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>.  */
21
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 04:23:58 dillon Exp $ */
24
25 #include <stdio.h>
26 #include <getopt.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #ifdef HAVE_SYS_PARAM_H
30 #include <sys/param.h>
31 #endif
32 #if (defined(BSD) && (BSD >= 199306))
33 #include <locale.h>
34 #endif
35 #include "filetypes.h"
36 #include "system.h"
37 #include "cpiohdr.h"
38 #include "dstring.h"
39 #include "extern.h"
40 #include "rmt.h"
41
42 struct option long_opts[] =
43 {
44   {"null", 0, 0, '0'},
45   {"append", 0, 0, 'A'},
46   {"block-size", 1, 0, 130},
47   {"create", 0, 0, 'o'},
48   {"dereference", 0, 0, 'L'},
49   {"dot", 0, 0, 'V'},
50   {"extract", 0, 0, 'i'},
51   {"file", 1, 0, 'F'},
52   {"force-local", 0, &f_force_local, 1},
53   {"format", 1, 0, 'H'},
54   {"help", 0, 0, 132},
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, &copy_matching_files, FALSE},
63   {"numeric-uid-gid", 0, &numeric_uid, TRUE},
64   {"only-verify-crc", 0, 0, 139},
65   {"owner", 1, 0, 'R'},
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},
71   {"quiet", 0, 0, 138},
72   {"sparse", 0, 0, 135},
73   {"swap", 0, 0, 'b'},
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},
80 #ifdef DEBUG_CPIO
81   {"debug", 0, &debug_flag, TRUE},
82 #endif
83   {0, 0, 0, 0}
84 };
85
86 /*  Print usage message and exit with error.  */
87
88 void
89 usage (fp, status)
90   FILE *fp;
91   int status;
92 {
93   fprintf (fp, "\
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);
100   fprintf (fp, "\
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",
111            program_name);
112   fprintf (fp, "\
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);
118   exit (status);
119 }
120
121 /* Process the arguments.  Set all options and set up the copy pass
122    directory or the copy in patterns.  */
123
124 void
125 process_args (argc, argv)
126      int argc;
127      char *argv[];
128 {
129   extern char *version_string;
130   void (*copy_in) ();           /* Work around for pcc bug.  */
131   void (*copy_out) ();
132   int c;
133   char *input_archive_name = 0;
134   char *output_archive_name = 0;
135
136   if (argc < 2)
137     usage (stderr, 2);
138
139   xstat = lstat;
140
141   while ((c = getopt_long (argc, argv,
142                            "0aAbBcC:dfE:F:H:iI:lLmM:noO:prR:sStuvVz",
143                            long_opts, (int *) 0)) != -1)
144     {
145       switch (c)
146         {
147         case 0:                 /* A long option that just sets a flag.  */
148           break;
149
150         case '0':               /* Read null-terminated filenames.  */
151           name_end = '\0';
152           break;
153
154         case 'a':               /* Reset access times.  */
155           reset_time_flag = TRUE;
156           break;
157
158         case 'A':               /* Append to the archive.  */
159           append_flag = TRUE;
160           break;
161
162         case 'b':               /* Swap bytes and halfwords.  */
163           swap_bytes_flag = TRUE;
164           swap_halfwords_flag = TRUE;
165           break;
166
167         case 'B':               /* Set block size to 5120.  */
168           io_block_size = 5120;
169           break;
170
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;
176           break;
177
178         case 'c':               /* Use the old portable ASCII format.  */
179           if (archive_format != arf_unknown)
180             usage (stderr, 2);
181 #ifdef SVR4_COMPAT
182           archive_format = arf_newascii; /* -H newc.  */
183 #else
184           archive_format = arf_oldascii; /* -H odc.  */
185 #endif
186           break;
187
188         case 'C':               /* Block size.  */
189           io_block_size = atoi (optarg);
190           if (io_block_size < 1)
191             error (2, 0, "invalid block size");
192           break;
193
194         case 'd':               /* Create directories where needed.  */
195           create_dir_flag = TRUE;
196           break;
197
198         case 'f':               /* Only copy files not matching patterns.  */
199           copy_matching_files = FALSE;
200           break;
201
202         case 'E':               /* Pattern file name.  */
203           pattern_file_name = optarg;
204           break;
205
206         case 'F':               /* Archive file name.  */
207           archive_name = optarg;
208           break;
209
210         case 'H':               /* Header format name.  */
211           if (archive_format != arf_unknown)
212             usage (stderr, 2);
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;
229           else
230             error (2, 0, "\
231 invalid archive format `%s'; valid formats are:\n\
232 crc newc odc bin ustar tar (all-caps also recognized)", optarg);
233           break;
234
235         case 'i':               /* Copy-in mode.  */
236           if (copy_function != 0)
237             usage (stderr, 2);
238           copy_function = process_copy_in;
239           break;
240
241         case 'I':               /* Input archive file name.  */
242           input_archive_name = optarg;
243           break;
244
245         case 'k':               /* Handle corrupted archives.  We always handle
246                                    corrupted archives, but recognize this
247                                    option for compatability.  */
248           break;
249
250         case 'l':               /* Link files when possible.  */
251           link_flag = TRUE;
252           break;
253
254         case 'L':               /* Dereference symbolic links.  */
255           xstat = stat;
256           break;
257
258         case 'm':               /* Retain previous file modify times.  */
259           retain_time_flag = TRUE;
260           break;
261
262         case 'M':               /* New media message.  */
263           set_new_media_message (optarg);
264           break;
265
266         case 'n':               /* Long list owner and group as numbers.  */
267           numeric_uid = TRUE;
268           break;
269
270         case 136:               /* --no-absolute-filenames */
271           no_abs_paths_flag = TRUE;
272           break;
273         
274         case 134:               /* --no-preserve-owner */
275           if (set_owner_flag || set_group_flag)
276             usage (stderr, 2);
277           no_chown_flag = TRUE;
278           break;
279
280         case 'o':               /* Copy-out mode.  */
281           if (copy_function != 0)
282             usage (stderr, 2);
283           copy_function = process_copy_out;
284           break;
285
286         case 'O':               /* Output archive file name.  */
287           output_archive_name = optarg;
288           break;
289
290         case 139:
291           only_verify_crc_flag = TRUE;
292           break;
293
294         case 'p':               /* Copy-pass mode.  */
295           if (copy_function != 0)
296             usage (stderr, 2);
297           copy_function = process_copy_pass;
298           break;
299
300         case 'r':               /* Interactively rename.  */
301           rename_flag = TRUE;
302           break;
303
304         case 137:
305           rename_batch_file = optarg;
306           break;
307
308         case 138:
309           quiet_flag = TRUE;
310           break;
311
312         case 'R':               /* Set the owner.  */
313           if (no_chown_flag)
314             usage (stderr, 2);
315 #ifndef __MSDOS__
316           {
317             char *e, *u, *g;
318
319             e = parse_user_spec (optarg, &set_owner, &set_group, &u, &g);
320             if (e)
321               error (2, 0, "%s: %s", optarg, e);
322             if (u)
323               {
324                 free (u);
325                 set_owner_flag = TRUE;
326               }
327             if (g)
328               {
329                 free (g);
330                 set_group_flag = TRUE;
331               }
332           }
333 #endif
334           break;
335
336         case 's':               /* Swap bytes.  */
337           swap_bytes_flag = TRUE;
338           break;
339
340         case 'S':               /* Swap halfwords.  */
341           swap_halfwords_flag = TRUE;
342           break;
343
344         case 't':               /* Only print a list.  */
345           table_flag = TRUE;
346           break;
347
348         case 'u':               /* Replace all!  Unconditionally!  */
349           unconditional_flag = TRUE;
350           break;
351
352         case 'v':               /* Verbose!  */
353           verbose_flag = TRUE;
354           break;
355
356         case 'V':               /* Print `.' for each file.  */
357           dot_flag = TRUE;
358           break;
359
360         case 131:
361           printf ("GNU cpio %s", version_string);
362           exit (0);
363           break;
364
365         case 135:
366           sparse_flag = TRUE;
367           break;
368
369         case 132:               /* --help */
370           usage (stdout, 0);
371           break;
372
373         default:
374           usage (stderr, 2);
375         }
376     }
377
378   /* Do error checking and look at other args.  */
379
380   if (copy_function == 0)
381     {
382       if (table_flag)
383         copy_function = process_copy_in;
384       else
385         usage (stderr, 2);
386     }
387
388   if ((!table_flag || !verbose_flag) && numeric_uid)
389     usage (stderr, 2);
390
391   /* Work around for pcc bug.  */
392   copy_in = process_copy_in;
393   copy_out = process_copy_out;
394
395   if (copy_function == copy_in)
396     {
397       archive_des = 0;
398       if (link_flag || reset_time_flag || xstat != lstat || append_flag
399           || sparse_flag
400           || output_archive_name
401           || (archive_name && input_archive_name))
402         usage (stderr, 2);
403       if (archive_format == arf_crcascii)
404         crc_i_flag = TRUE;
405       num_patterns = argc - optind;
406       save_patterns = &argv[optind];
407       if (input_archive_name)
408         archive_name = input_archive_name;
409     }
410   else if (copy_function == copy_out)
411     {
412       archive_des = 1;
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))
420         usage (stderr, 2);
421       if (archive_format == arf_unknown)
422         archive_format = arf_binary;
423       if (output_archive_name)
424         archive_name = output_archive_name;
425     }
426   else
427     {
428       /* Copy pass.  */
429       archive_des = -1;
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)
434         usage (stderr, 2);
435       directory_name = argv[optind];
436     }
437
438   if (archive_name)
439     {
440       if (copy_function != copy_in && copy_function != copy_out)
441         usage (stderr, 2);
442       archive_des = open_archive (archive_name);
443       if (archive_des < 0)
444         error (1, errno, "%s", archive_name);
445     }
446
447 #ifndef __MSDOS__
448   /* Prevent SysV non-root users from giving away files inadvertantly.
449      This happens automatically on BSD, where only root can give
450      away files.  */
451   if (set_owner_flag == FALSE && set_group_flag == FALSE && geteuid ())
452     no_chown_flag = TRUE;
453 #endif
454 }
455
456 /* Initialize the input and output buffers to their proper size and
457    initialize all variables associated with the input and output
458    buffers.  */
459
460 void
461 initialize_buffers ()
462 {
463   int in_buf_size, out_buf_size;
464
465   if (copy_function == process_copy_in)
466     {
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;
474       else
475         in_buf_size = 1024;
476       out_buf_size = DISK_IO_BLOCK_SIZE;
477     }
478   else if (copy_function == process_copy_out)
479     {
480       in_buf_size = DISK_IO_BLOCK_SIZE;
481       out_buf_size = io_block_size;
482     }
483   else
484     {
485       in_buf_size = DISK_IO_BLOCK_SIZE;
486       out_buf_size = DISK_IO_BLOCK_SIZE;
487     }
488
489   input_buffer = (char *) xmalloc (in_buf_size);
490   in_buff = input_buffer;
491   input_buffer_size = in_buf_size;
492   input_size = 0;
493   input_bytes = 0;
494
495   output_buffer = (char *) xmalloc (out_buf_size);
496   out_buff = output_buffer;
497   output_size = 0;
498   output_bytes = 0;
499
500   /* Clear the block of zeros.  */
501   bzero (zeros_512, 512);
502 }
503
504 int
505 main (argc, argv)
506      int argc;
507      char *argv[];
508 {
509   program_name = argv[0];
510
511 #if (defined(BSD) && (BSD >= 199306))
512   (void) setlocale (LC_ALL, "");
513 #endif
514
515 #ifdef __TURBOC__
516   _fmode = O_BINARY;            /* Put stdin and stdout in binary mode.  */
517 #endif
518 #ifdef __EMX__                  /* gcc on OS/2.  */
519   _response (&argc, &argv);
520   _wildcard (&argc, &argv);
521 #endif
522
523   process_args (argc, argv);
524   umask (0);
525
526   initialize_buffers ();
527
528   (*copy_function) ();
529
530   if (archive_des >= 0 && rmtclose (archive_des) == -1)
531     error (1, errno, "error closing archive");
532
533   exit (0);
534 }