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