| 1 |
/** $MirOS: src/bin/pax/options.c,v 1.24 2007/02/17 04:52:41 tg Exp $ */ |
| 2 |
/* $OpenBSD: options.c,v 1.64 2006/04/09 03:35:34 jaredy Exp $ */ |
| 3 |
/* $NetBSD: options.c,v 1.6 1996/03/26 23:54:18 mrg Exp $ */ |
| 4 |
|
| 5 |
/*- |
| 6 |
* Copyright (c) 2005, 2006, 2007 Thorsten Glaser <tg@66h.42h.de> |
| 7 |
* Copyright (c) 1992 Keith Muller. |
| 8 |
* Copyright (c) 1992, 1993 |
| 9 |
* The Regents of the University of California. All rights reserved. |
| 10 |
* |
| 11 |
* This code is derived from software contributed to Berkeley by |
| 12 |
* Keith Muller of the University of California, San Diego. |
| 13 |
* |
| 14 |
* Redistribution and use in source and binary forms, with or without |
| 15 |
* modification, are permitted provided that the following conditions |
| 16 |
* are met: |
| 17 |
* 1. Redistributions of source code must retain the above copyright |
| 18 |
* notice, this list of conditions and the following disclaimer. |
| 19 |
* 2. Redistributions in binary form must reproduce the above copyright |
| 20 |
* notice, this list of conditions and the following disclaimer in the |
| 21 |
* documentation and/or other materials provided with the distribution. |
| 22 |
* 3. Neither the name of the University nor the names of its contributors |
| 23 |
* may be used to endorse or promote products derived from this software |
| 24 |
* without specific prior written permission. |
| 25 |
* |
| 26 |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 27 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 28 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 29 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| 30 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 31 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 32 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 33 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 34 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 35 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 36 |
* SUCH DAMAGE. |
| 37 |
*/ |
| 38 |
|
| 39 |
#include <sys/param.h> |
| 40 |
#include <sys/time.h> |
| 41 |
#include <sys/stat.h> |
| 42 |
#ifndef __INTERIX |
| 43 |
#include <sys/mtio.h> |
| 44 |
#endif |
| 45 |
#include <stdio.h> |
| 46 |
#include <string.h> |
| 47 |
#include <err.h> |
| 48 |
#include <errno.h> |
| 49 |
#include <unistd.h> |
| 50 |
#include <stdlib.h> |
| 51 |
#include <limits.h> |
| 52 |
#include <paths.h> |
| 53 |
#include "pax.h" |
| 54 |
#include "options.h" |
| 55 |
#include "cpio.h" |
| 56 |
#include "tar.h" |
| 57 |
#include "extern.h" |
| 58 |
|
| 59 |
__SCCSID("@(#)options.c 8.2 (Berkeley) 4/18/94"); |
| 60 |
__RCSID("$MirOS: src/bin/pax/options.c,v 1.24 2007/02/17 04:52:41 tg Exp $"); |
| 61 |
|
| 62 |
#ifdef __GLIBC__ |
| 63 |
char *fgetln(FILE *, size_t *); |
| 64 |
#endif |
| 65 |
|
| 66 |
/* |
| 67 |
* Routines which handle command line options |
| 68 |
*/ |
| 69 |
|
| 70 |
static char flgch[] = FLGCH; /* list of all possible flags */ |
| 71 |
static OPLIST *ophead = NULL; /* head for format specific options -x */ |
| 72 |
static OPLIST *optail = NULL; /* option tail */ |
| 73 |
|
| 74 |
static int no_op(void); |
| 75 |
static void printflg(unsigned int); |
| 76 |
static int c_frmt(const void *, const void *); |
| 77 |
static off_t str_offt(char *); |
| 78 |
static char *getline(FILE *fp); |
| 79 |
static void pax_options(int, char **); |
| 80 |
static void pax_usage(void) __attribute__((noreturn)); |
| 81 |
static void tar_set_action(int); |
| 82 |
static void tar_options(int, char **); |
| 83 |
static void tar_usage(void) __attribute__((noreturn)); |
| 84 |
static void cpio_set_action(int); |
| 85 |
static void cpio_options(int, char **); |
| 86 |
static void cpio_usage(void) __attribute__((noreturn)); |
| 87 |
int mkpath(char *); |
| 88 |
|
| 89 |
static void process_M(const char *, void (*)(void)); |
| 90 |
|
| 91 |
/* errors from getline */ |
| 92 |
#define GETLINE_FILE_CORRUPT 1 |
| 93 |
#define GETLINE_OUT_OF_MEM 2 |
| 94 |
static int getline_error; |
| 95 |
|
| 96 |
|
| 97 |
#define GZIP_CMD "gzip" /* command to run as gzip */ |
| 98 |
#define COMPRESS_CMD "compress" /* command to run as compress */ |
| 99 |
|
| 100 |
/* |
| 101 |
* Format specific routine table - MUST BE IN SORTED ORDER BY NAME |
| 102 |
* (see pax.h for description of each function) |
| 103 |
* |
| 104 |
* name, blksz, hdsz, udev, hlk, blkagn, inhead, id, st_read, |
| 105 |
* read, end_read, st_write, write, end_write, trail, |
| 106 |
* rd_data, wr_data, options |
| 107 |
*/ |
| 108 |
|
| 109 |
FSUB fsub[] = { |
| 110 |
/* 0: OLD BINARY CPIO */ |
| 111 |
{"bcpio", 5120, sizeof(HD_BCPIO), 1, 0, 0, 1, bcpio_id, cpio_strd, |
| 112 |
bcpio_rd, bcpio_endrd, cpio_stwr, bcpio_wr, cpio_endwr, cpio_trail, |
| 113 |
rd_wrfile, wr_rdfile, bad_opt}, |
| 114 |
|
| 115 |
/* 1: OLD OCTAL CHARACTER CPIO */ |
| 116 |
{"cpio", 5120, sizeof(HD_CPIO), 1, 0, 0, 1, cpio_id, cpio_strd, |
| 117 |
cpio_rd, cpio_endrd, cpio_stwr, cpio_wr, cpio_endwr, cpio_trail, |
| 118 |
rd_wrfile, wr_rdfile, bad_opt}, |
| 119 |
|
| 120 |
/* 2: OLD OCTAL CHARACTER CPIO, UID/GID CLEARED (ANONYMISED) */ |
| 121 |
{"dist", 512, sizeof(HD_CPIO), 1, 0, 0, 1, cpio_id, cpio_strd, |
| 122 |
cpio_rd, cpio_endrd, dist_stwr, cpio_wr, cpio_endwr, cpio_trail, |
| 123 |
rd_wrfile, wr_rdfile, bad_opt}, |
| 124 |
|
| 125 |
/* 3: SVR4 HEX CPIO */ |
| 126 |
{"sv4cpio", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, vcpio_id, cpio_strd, |
| 127 |
vcpio_rd, vcpio_endrd, cpio_stwr, vcpio_wr, cpio_endwr, cpio_trail, |
| 128 |
rd_wrfile, wr_rdfile, bad_opt}, |
| 129 |
|
| 130 |
/* 4: SVR4 HEX CPIO WITH CRC */ |
| 131 |
{"sv4crc", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd, |
| 132 |
vcpio_rd, vcpio_endrd, crc_stwr, vcpio_wr, cpio_endwr, cpio_trail, |
| 133 |
rd_wrfile, wr_rdfile, bad_opt}, |
| 134 |
|
| 135 |
/* 5: OLD TAR */ |
| 136 |
{"tar", 10240, BLKMULT, 0, 1, BLKMULT, 0, tar_id, no_op, |
| 137 |
tar_rd, tar_endrd, no_op, tar_wr, tar_endwr, tar_trail, |
| 138 |
rd_wrfile, wr_rdfile, tar_opt}, |
| 139 |
|
| 140 |
/* 6: POSIX USTAR */ |
| 141 |
{"ustar", 10240, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, ustar_strd, |
| 142 |
ustar_rd, tar_endrd, ustar_stwr, ustar_wr, tar_endwr, tar_trail, |
| 143 |
rd_wrfile, wr_rdfile, bad_opt}, |
| 144 |
|
| 145 |
/* 7: SVR4 HEX CPIO WITH CRC, UID/GID/MTIME CLEARED (NORMALISED) */ |
| 146 |
{"v4norm", 512, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd, |
| 147 |
vcpio_rd, vcpio_endrd, v4norm_stwr, vcpio_wr, cpio_endwr, cpio_trail, |
| 148 |
rd_wrfile, wr_rdfile, bad_opt}, |
| 149 |
|
| 150 |
/* 8: SVR4 HEX CPIO WITH CRC, UID/GID CLEARED (ANONYMISED) */ |
| 151 |
{"v4root", 512, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd, |
| 152 |
vcpio_rd, vcpio_endrd, v4root_stwr, vcpio_wr, cpio_endwr, cpio_trail, |
| 153 |
rd_wrfile, wr_rdfile, bad_opt}, |
| 154 |
}; |
| 155 |
#define F_OCPIO 0 /* format when called as cpio -6 */ |
| 156 |
#define F_ACPIO 1 /* format when called as cpio -c */ |
| 157 |
#define F_NCPIO 3 /* format when called as tar -R */ |
| 158 |
#define F_CPIO 4 /* format when called as cpio or tar -S */ |
| 159 |
#define F_OTAR 5 /* format when called as tar -o */ |
| 160 |
#define F_TAR 6 /* format when called as tar */ |
| 161 |
#define DEFLT 6 /* default write format from list above */ |
| 162 |
|
| 163 |
/* |
| 164 |
* ford is the archive search order used by get_arc() to determine what kind |
| 165 |
* of archive we are dealing with. This helps to properly id archive formats |
| 166 |
* some formats may be subsets of others.... |
| 167 |
*/ |
| 168 |
int ford[] = {6, 5, 4, 3, 1, 0, -1 }; |
| 169 |
|
| 170 |
/* normalise archives */ |
| 171 |
int anonarch = 0; |
| 172 |
|
| 173 |
/* extract to standard output */ |
| 174 |
int to_stdout = 0; |
| 175 |
|
| 176 |
/* |
| 177 |
* options() |
| 178 |
* figure out if we are pax, tar or cpio. Call the appropriate options |
| 179 |
* parser |
| 180 |
*/ |
| 181 |
|
| 182 |
void |
| 183 |
options(int argc, char **argv) |
| 184 |
{ |
| 185 |
|
| 186 |
/* |
| 187 |
* Are we acting like pax, tar or cpio (based on argv[0]) |
| 188 |
*/ |
| 189 |
if ((argv0 = strrchr(argv[0], '/')) != NULL) |
| 190 |
argv0++; |
| 191 |
else |
| 192 |
argv0 = argv[0]; |
| 193 |
|
| 194 |
if (strcmp(NM_TAR, argv0) == 0) { |
| 195 |
tar_options(argc, argv); |
| 196 |
return; |
| 197 |
} else if (strcmp(NM_CPIO, argv0) == 0) { |
| 198 |
cpio_options(argc, argv); |
| 199 |
return; |
| 200 |
} |
| 201 |
/* |
| 202 |
* assume pax as the default |
| 203 |
*/ |
| 204 |
argv0 = NM_PAX; |
| 205 |
pax_options(argc, argv); |
| 206 |
} |
| 207 |
|
| 208 |
/* |
| 209 |
* pax_options() |
| 210 |
* look at the user specified flags. set globals as required and check if |
| 211 |
* the user specified a legal set of flags. If not, complain and exit |
| 212 |
*/ |
| 213 |
|
| 214 |
static void |
| 215 |
pax_options(int argc, char **argv) |
| 216 |
{ |
| 217 |
int c; |
| 218 |
size_t i; |
| 219 |
unsigned int flg = 0; |
| 220 |
unsigned int bflg = 0; |
| 221 |
char *pt; |
| 222 |
FSUB tmp; |
| 223 |
|
| 224 |
/* |
| 225 |
* process option flags |
| 226 |
*/ |
| 227 |
while ((c=getopt(argc,argv,"ab:cdf:iklno:p:rs:tuvwx:zB:DE:G:HLM:OPT:U:XYZ0")) |
| 228 |
!= -1) { |
| 229 |
switch (c) { |
| 230 |
case 'a': |
| 231 |
/* |
| 232 |
* append |
| 233 |
*/ |
| 234 |
flg |= AF; |
| 235 |
break; |
| 236 |
case 'b': |
| 237 |
/* |
| 238 |
* specify blocksize |
| 239 |
*/ |
| 240 |
flg |= BF; |
| 241 |
if ((wrblksz = (int)str_offt(optarg)) <= 0) { |
| 242 |
paxwarn(1, "Invalid block size %s", optarg); |
| 243 |
pax_usage(); |
| 244 |
} |
| 245 |
break; |
| 246 |
case 'c': |
| 247 |
/* |
| 248 |
* inverse match on patterns |
| 249 |
*/ |
| 250 |
cflag = 1; |
| 251 |
flg |= CF; |
| 252 |
break; |
| 253 |
case 'd': |
| 254 |
/* |
| 255 |
* match only dir on extract, not the subtree at dir |
| 256 |
*/ |
| 257 |
dflag = 1; |
| 258 |
flg |= DF; |
| 259 |
break; |
| 260 |
case 'f': |
| 261 |
/* |
| 262 |
* filename where the archive is stored |
| 263 |
*/ |
| 264 |
arcname = optarg; |
| 265 |
flg |= FF; |
| 266 |
break; |
| 267 |
case 'i': |
| 268 |
/* |
| 269 |
* interactive file rename |
| 270 |
*/ |
| 271 |
iflag = 1; |
| 272 |
flg |= IF; |
| 273 |
break; |
| 274 |
case 'k': |
| 275 |
/* |
| 276 |
* do not clobber files that exist |
| 277 |
*/ |
| 278 |
kflag = 1; |
| 279 |
flg |= KF; |
| 280 |
break; |
| 281 |
case 'l': |
| 282 |
/* |
| 283 |
* try to link src to dest with copy (-rw) |
| 284 |
*/ |
| 285 |
lflag = 1; |
| 286 |
flg |= LF; |
| 287 |
break; |
| 288 |
case 'n': |
| 289 |
/* |
| 290 |
* select first match for a pattern only |
| 291 |
*/ |
| 292 |
nflag = 1; |
| 293 |
flg |= NF; |
| 294 |
break; |
| 295 |
case 'o': |
| 296 |
/* |
| 297 |
* pass format specific options |
| 298 |
*/ |
| 299 |
flg |= OF; |
| 300 |
if (opt_add(optarg) < 0) |
| 301 |
pax_usage(); |
| 302 |
break; |
| 303 |
case 'p': |
| 304 |
/* |
| 305 |
* specify file characteristic options |
| 306 |
*/ |
| 307 |
for (pt = optarg; *pt != '\0'; ++pt) { |
| 308 |
switch (*pt) { |
| 309 |
case 'a': |
| 310 |
/* |
| 311 |
* do not preserve access time |
| 312 |
*/ |
| 313 |
patime = 0; |
| 314 |
break; |
| 315 |
case 'e': |
| 316 |
/* |
| 317 |
* preserve user id, group id, file |
| 318 |
* mode, access/modification times |
| 319 |
*/ |
| 320 |
pids = 1; |
| 321 |
pmode = 1; |
| 322 |
patime = 1; |
| 323 |
pmtime = 1; |
| 324 |
break; |
| 325 |
case 'm': |
| 326 |
/* |
| 327 |
* do not preserve modification time |
| 328 |
*/ |
| 329 |
pmtime = 0; |
| 330 |
break; |
| 331 |
case 'o': |
| 332 |
/* |
| 333 |
* preserve uid/gid |
| 334 |
*/ |
| 335 |
pids = 1; |
| 336 |
break; |
| 337 |
case 'p': |
| 338 |
/* |
| 339 |
* preserve file mode bits |
| 340 |
*/ |
| 341 |
pmode = 1; |
| 342 |
break; |
| 343 |
default: |
| 344 |
paxwarn(1, "Invalid -p string: %c", *pt); |
| 345 |
pax_usage(); |
| 346 |
break; |
| 347 |
} |
| 348 |
} |
| 349 |
flg |= PF; |
| 350 |
break; |
| 351 |
case 'r': |
| 352 |
/* |
| 353 |
* read the archive |
| 354 |
*/ |
| 355 |
flg |= RF; |
| 356 |
break; |
| 357 |
case 's': |
| 358 |
/* |
| 359 |
* file name substitution name pattern |
| 360 |
*/ |
| 361 |
if (rep_add(optarg) < 0) { |
| 362 |
pax_usage(); |
| 363 |
break; |
| 364 |
} |
| 365 |
flg |= SF; |
| 366 |
break; |
| 367 |
case 't': |
| 368 |
/* |
| 369 |
* preserve access time on filesystem nodes we read |
| 370 |
*/ |
| 371 |
tflag = 1; |
| 372 |
flg |= TF; |
| 373 |
break; |
| 374 |
case 'u': |
| 375 |
/* |
| 376 |
* ignore those older files |
| 377 |
*/ |
| 378 |
uflag = 1; |
| 379 |
flg |= UF; |
| 380 |
break; |
| 381 |
case 'v': |
| 382 |
/* |
| 383 |
* verbose operation mode |
| 384 |
*/ |
| 385 |
vflag = 1; |
| 386 |
flg |= VF; |
| 387 |
break; |
| 388 |
case 'w': |
| 389 |
/* |
| 390 |
* write an archive |
| 391 |
*/ |
| 392 |
flg |= WF; |
| 393 |
break; |
| 394 |
case 'x': |
| 395 |
/* |
| 396 |
* specify an archive format on write |
| 397 |
*/ |
| 398 |
tmp.name = optarg; |
| 399 |
if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub, |
| 400 |
sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL) { |
| 401 |
flg |= XF; |
| 402 |
break; |
| 403 |
} |
| 404 |
paxwarn(1, "Unknown -x format: %s", optarg); |
| 405 |
(void)fputs("pax: Known -x formats are:", stderr); |
| 406 |
for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i) |
| 407 |
(void)fprintf(stderr, " %s", fsub[i].name); |
| 408 |
(void)fputs("\n\n", stderr); |
| 409 |
pax_usage(); |
| 410 |
break; |
| 411 |
case 'z': |
| 412 |
/* |
| 413 |
* use gzip. Non standard option. |
| 414 |
*/ |
| 415 |
gzip_program = GZIP_CMD; |
| 416 |
break; |
| 417 |
case 'B': |
| 418 |
/* |
| 419 |
* non-standard option on number of bytes written on a |
| 420 |
* single archive volume. |
| 421 |
*/ |
| 422 |
if ((wrlimit = str_offt(optarg)) <= 0) { |
| 423 |
paxwarn(1, "Invalid write limit %s", optarg); |
| 424 |
pax_usage(); |
| 425 |
} |
| 426 |
if (wrlimit % BLKMULT) { |
| 427 |
paxwarn(1, "Write limit is not a %d byte multiple", |
| 428 |
BLKMULT); |
| 429 |
pax_usage(); |
| 430 |
} |
| 431 |
flg |= CBF; |
| 432 |
break; |
| 433 |
case 'D': |
| 434 |
/* |
| 435 |
* On extraction check file inode change time before the |
| 436 |
* modification of the file name. Non standard option. |
| 437 |
*/ |
| 438 |
Dflag = 1; |
| 439 |
flg |= CDF; |
| 440 |
break; |
| 441 |
case 'E': |
| 442 |
/* |
| 443 |
* non-standard limit on read faults |
| 444 |
* 0 indicates stop after first error, values |
| 445 |
* indicate a limit, "NONE" try forever |
| 446 |
*/ |
| 447 |
flg |= CEF; |
| 448 |
if (strcmp(NONE, optarg) == 0) |
| 449 |
maxflt = -1; |
| 450 |
else if ((maxflt = atoi(optarg)) < 0) { |
| 451 |
paxwarn(1, "Error count value must be positive"); |
| 452 |
pax_usage(); |
| 453 |
} |
| 454 |
break; |
| 455 |
case 'G': |
| 456 |
/* |
| 457 |
* non-standard option for selecting files within an |
| 458 |
* archive by group (gid or name) |
| 459 |
*/ |
| 460 |
if (grp_add(optarg) < 0) { |
| 461 |
pax_usage(); |
| 462 |
break; |
| 463 |
} |
| 464 |
flg |= CGF; |
| 465 |
break; |
| 466 |
case 'H': |
| 467 |
/* |
| 468 |
* follow command line symlinks only |
| 469 |
*/ |
| 470 |
Hflag = 1; |
| 471 |
flg |= CHF; |
| 472 |
break; |
| 473 |
case 'L': |
| 474 |
/* |
| 475 |
* follow symlinks |
| 476 |
*/ |
| 477 |
Lflag = 1; |
| 478 |
flg |= CLF; |
| 479 |
break; |
| 480 |
case 'M': |
| 481 |
/* |
| 482 |
* MirOS extension: archive normaliser |
| 483 |
*/ |
| 484 |
process_M(optarg, pax_usage); |
| 485 |
break; |
| 486 |
case 'O': |
| 487 |
/* |
| 488 |
* Force one volume. Non standard option. |
| 489 |
*/ |
| 490 |
force_one_volume = 1; |
| 491 |
break; |
| 492 |
case 'P': |
| 493 |
/* |
| 494 |
* do NOT follow symlinks (default) |
| 495 |
*/ |
| 496 |
Lflag = 0; |
| 497 |
flg |= CPF; |
| 498 |
break; |
| 499 |
case 'T': |
| 500 |
/* |
| 501 |
* non-standard option for selecting files within an |
| 502 |
* archive by modification time range (lower,upper) |
| 503 |
*/ |
| 504 |
if (trng_add(optarg) < 0) { |
| 505 |
pax_usage(); |
| 506 |
break; |
| 507 |
} |
| 508 |
flg |= CTF; |
| 509 |
break; |
| 510 |
case 'U': |
| 511 |
/* |
| 512 |
* non-standard option for selecting files within an |
| 513 |
* archive by user (uid or name) |
| 514 |
*/ |
| 515 |
if (usr_add(optarg) < 0) { |
| 516 |
pax_usage(); |
| 517 |
break; |
| 518 |
} |
| 519 |
flg |= CUF; |
| 520 |
break; |
| 521 |
case 'X': |
| 522 |
/* |
| 523 |
* do not pass over mount points in the file system |
| 524 |
*/ |
| 525 |
Xflag = 1; |
| 526 |
flg |= CXF; |
| 527 |
break; |
| 528 |
case 'Y': |
| 529 |
/* |
| 530 |
* On extraction check file inode change time after the |
| 531 |
* modification of the file name. Non standard option. |
| 532 |
*/ |
| 533 |
Yflag = 1; |
| 534 |
flg |= CYF; |
| 535 |
break; |
| 536 |
case 'Z': |
| 537 |
/* |
| 538 |
* On extraction check modification time after the |
| 539 |
* modification of the file name. Non standard option. |
| 540 |
*/ |
| 541 |
Zflag = 1; |
| 542 |
flg |= CZF; |
| 543 |
break; |
| 544 |
case '0': |
| 545 |
/* |
| 546 |
* Use \0 as pathname terminator. |
| 547 |
* (For use with the -print0 option of find(1).) |
| 548 |
*/ |
| 549 |
zeroflag = 1; |
| 550 |
flg |= C0F; |
| 551 |
break; |
| 552 |
default: |
| 553 |
pax_usage(); |
| 554 |
break; |
| 555 |
} |
| 556 |
} |
| 557 |
|
| 558 |
/* |
| 559 |
* figure out the operation mode of pax read,write,extract,copy,append |
| 560 |
* or list. check that we have not been given a bogus set of flags |
| 561 |
* for the operation mode. |
| 562 |
*/ |
| 563 |
if (ISLIST(flg)) { |
| 564 |
act = LIST; |
| 565 |
listf = stdout; |
| 566 |
bflg = flg & BDLIST; |
| 567 |
} else if (ISEXTRACT(flg)) { |
| 568 |
act = EXTRACT; |
| 569 |
bflg = flg & BDEXTR; |
| 570 |
} else if (ISARCHIVE(flg)) { |
| 571 |
act = ARCHIVE; |
| 572 |
bflg = flg & BDARCH; |
| 573 |
} else if (ISAPPND(flg)) { |
| 574 |
act = APPND; |
| 575 |
bflg = flg & BDARCH; |
| 576 |
} else if (ISCOPY(flg)) { |
| 577 |
act = COPY; |
| 578 |
bflg = flg & BDCOPY; |
| 579 |
} else |
| 580 |
pax_usage(); |
| 581 |
if (bflg) { |
| 582 |
printflg(flg); |
| 583 |
pax_usage(); |
| 584 |
} |
| 585 |
|
| 586 |
/* |
| 587 |
* if we are writing (ARCHIVE) we use the default format if the user |
| 588 |
* did not specify a format. when we write during an APPEND, we will |
| 589 |
* adopt the format of the existing archive if none was supplied. |
| 590 |
*/ |
| 591 |
if (!(flg & XF) && (act == ARCHIVE)) |
| 592 |
frmt = &(fsub[DEFLT]); |
| 593 |
|
| 594 |
/* |
| 595 |
* process the args as they are interpreted by the operation mode |
| 596 |
*/ |
| 597 |
switch (act) { |
| 598 |
case LIST: |
| 599 |
case EXTRACT: |
| 600 |
for (; optind < argc; optind++) |
| 601 |
if (pat_add(argv[optind], NULL) < 0) |
| 602 |
pax_usage(); |
| 603 |
break; |
| 604 |
case COPY: |
| 605 |
if (optind >= argc) { |
| 606 |
paxwarn(0, "Destination directory was not supplied"); |
| 607 |
pax_usage(); |
| 608 |
} |
| 609 |
--argc; |
| 610 |
dirptr = argv[argc]; |
| 611 |
/* FALL THROUGH */ |
| 612 |
case ARCHIVE: |
| 613 |
case APPND: |
| 614 |
for (; optind < argc; optind++) |
| 615 |
if (ftree_add(argv[optind], 0) < 0) |
| 616 |
pax_usage(); |
| 617 |
/* |
| 618 |
* no read errors allowed on updates/append operation! |
| 619 |
*/ |
| 620 |
maxflt = 0; |
| 621 |
break; |
| 622 |
} |
| 623 |
} |
| 624 |
|
| 625 |
|
| 626 |
/* |
| 627 |
* tar_options() |
| 628 |
* look at the user specified flags. set globals as required and check if |
| 629 |
* the user specified a legal set of flags. If not, complain and exit |
| 630 |
*/ |
| 631 |
|
| 632 |
static void |
| 633 |
tar_set_action(int op) |
| 634 |
{ |
| 635 |
if (act != ERROR && act != op) |
| 636 |
tar_usage(); |
| 637 |
act = op; |
| 638 |
} |
| 639 |
|
| 640 |
static void |
| 641 |
tar_options(int argc, char **argv) |
| 642 |
{ |
| 643 |
int c; |
| 644 |
int fstdin = 0; |
| 645 |
int Oflag = 0; |
| 646 |
int nincfiles = 0; |
| 647 |
int incfiles_max = 0; |
| 648 |
struct incfile { |
| 649 |
char *file; |
| 650 |
char *dir; |
| 651 |
}; |
| 652 |
struct incfile *incfiles = NULL; |
| 653 |
|
| 654 |
/* |
| 655 |
* Set default values. |
| 656 |
*/ |
| 657 |
rmleadslash = 1; |
| 658 |
|
| 659 |
/* |
| 660 |
* process option flags |
| 661 |
*/ |
| 662 |
while ((c = getoldopt(argc, argv, |
| 663 |
"b:cef:hmopqruts:vwxzBC:HI:LM:OPRSXZ014578")) != -1) { |
| 664 |
switch (c) { |
| 665 |
case 'b': |
| 666 |
/* |
| 667 |
* specify blocksize in 512-byte blocks |
| 668 |
*/ |
| 669 |
if ((wrblksz = (int)str_offt(optarg)) <= 0) { |
| 670 |
paxwarn(1, "Invalid block size %s", optarg); |
| 671 |
tar_usage(); |
| 672 |
} |
| 673 |
wrblksz *= 512; /* XXX - check for int oflow */ |
| 674 |
break; |
| 675 |
case 'c': |
| 676 |
/* |
| 677 |
* create an archive |
| 678 |
*/ |
| 679 |
tar_set_action(ARCHIVE); |
| 680 |
break; |
| 681 |
case 'e': |
| 682 |
/* |
| 683 |
* stop after first error |
| 684 |
*/ |
| 685 |
maxflt = 0; |
| 686 |
break; |
| 687 |
case 'f': |
| 688 |
/* |
| 689 |
* filename where the archive is stored |
| 690 |
*/ |
| 691 |
if ((optarg[0] == '-') && (optarg[1]== '\0')) { |
| 692 |
/* |
| 693 |
* treat a - as stdin |
| 694 |
*/ |
| 695 |
fstdin = 1; |
| 696 |
arcname = NULL; |
| 697 |
break; |
| 698 |
} |
| 699 |
fstdin = 0; |
| 700 |
arcname = optarg; |
| 701 |
break; |
| 702 |
case 'h': |
| 703 |
/* |
| 704 |
* follow symlinks |
| 705 |
*/ |
| 706 |
Lflag = 1; |
| 707 |
break; |
| 708 |
case 'm': |
| 709 |
/* |
| 710 |
* do not preserve modification time |
| 711 |
*/ |
| 712 |
pmtime = 0; |
| 713 |
break; |
| 714 |
case 'O': |
| 715 |
Oflag = 1; |
| 716 |
to_stdout = 2; |
| 717 |
break; |
| 718 |
case 'o': |
| 719 |
Oflag = 2; |
| 720 |
break; |
| 721 |
case 'p': |
| 722 |
/* |
| 723 |
* preserve uid/gid and file mode, regardless of umask |
| 724 |
*/ |
| 725 |
pmode = 1; |
| 726 |
pids = 1; |
| 727 |
break; |
| 728 |
case 'q': |
| 729 |
/* |
| 730 |
* select first match for a pattern only |
| 731 |
*/ |
| 732 |
nflag = 1; |
| 733 |
break; |
| 734 |
case 'r': |
| 735 |
case 'u': |
| 736 |
/* |
| 737 |
* append to the archive |
| 738 |
*/ |
| 739 |
tar_set_action(APPND); |
| 740 |
break; |
| 741 |
case 'R': |
| 742 |
Oflag = 3; |
| 743 |
anonarch = ANON_INODES | ANON_HARDLINKS; |
| 744 |
break; |
| 745 |
case 'S': |
| 746 |
Oflag = 4; |
| 747 |
anonarch = ANON_INODES | ANON_HARDLINKS; |
| 748 |
break; |
| 749 |
case 's': |
| 750 |
/* |
| 751 |
* file name substitution name pattern |
| 752 |
*/ |
| 753 |
if (rep_add(optarg) < 0) { |
| 754 |
tar_usage(); |
| 755 |
break; |
| 756 |
} |
| 757 |
break; |
| 758 |
case 't': |
| 759 |
/* |
| 760 |
* list contents of the tape |
| 761 |
*/ |
| 762 |
tar_set_action(LIST); |
| 763 |
break; |
| 764 |
case 'v': |
| 765 |
/* |
| 766 |
* verbose operation mode |
| 767 |
*/ |
| 768 |
vflag++; |
| 769 |
break; |
| 770 |
case 'w': |
| 771 |
/* |
| 772 |
* interactive file rename |
| 773 |
*/ |
| 774 |
iflag = 1; |
| 775 |
break; |
| 776 |
case 'x': |
| 777 |
/* |
| 778 |
* extract an archive, preserving mode, |
| 779 |
* and mtime if possible. |
| 780 |
*/ |
| 781 |
tar_set_action(EXTRACT); |
| 782 |
pmtime = 1; |
| 783 |
break; |
| 784 |
case 'z': |
| 785 |
/* |
| 786 |
* use gzip. Non standard option. |
| 787 |
*/ |
| 788 |
gzip_program = GZIP_CMD; |
| 789 |
break; |
| 790 |
case 'B': |
| 791 |
/* |
| 792 |
* Nothing to do here, this is pax default |
| 793 |
*/ |
| 794 |
break; |
| 795 |
case 'C': |
| 796 |
chdname = optarg; |
| 797 |
break; |
| 798 |
case 'H': |
| 799 |
/* |
| 800 |
* follow command line symlinks only |
| 801 |
*/ |
| 802 |
Hflag = 1; |
| 803 |
break; |
| 804 |
case 'I': |
| 805 |
if (++nincfiles > incfiles_max) { |
| 806 |
incfiles_max = nincfiles + 3; |
| 807 |
incfiles = realloc(incfiles, |
| 808 |
sizeof(*incfiles) * incfiles_max); |
| 809 |
if (incfiles == NULL) { |
| 810 |
paxwarn(0, "Unable to allocate space " |
| 811 |
"for option list"); |
| 812 |
exit(1); |
| 813 |
} |
| 814 |
} |
| 815 |
incfiles[nincfiles - 1].file = optarg; |
| 816 |
incfiles[nincfiles - 1].dir = chdname; |
| 817 |
break; |
| 818 |
case 'L': |
| 819 |
/* |
| 820 |
* follow symlinks |
| 821 |
*/ |
| 822 |
Lflag = 1; |
| 823 |
break; |
| 824 |
case 'M': |
| 825 |
process_M(optarg, tar_usage); |
| 826 |
break; |
| 827 |
case 'P': |
| 828 |
/* |
| 829 |
* do not remove leading '/' from pathnames |
| 830 |
*/ |
| 831 |
rmleadslash = 0; |
| 832 |
break; |
| 833 |
case 'X': |
| 834 |
/* |
| 835 |
* do not pass over mount points in the file system |
| 836 |
*/ |
| 837 |
Xflag = 1; |
| 838 |
break; |
| 839 |
case 'Z': |
| 840 |
/* |
| 841 |
* use compress. |
| 842 |
*/ |
| 843 |
gzip_program = COMPRESS_CMD; |
| 844 |
break; |
| 845 |
case '0': |
| 846 |
arcname = DEV_0; |
| 847 |
break; |
| 848 |
case '1': |
| 849 |
arcname = DEV_1; |
| 850 |
break; |
| 851 |
case '4': |
| 852 |
arcname = DEV_4; |
| 853 |
break; |
| 854 |
case '5': |
| 855 |
arcname = DEV_5; |
| 856 |
break; |
| 857 |
case '7': |
| 858 |
arcname = DEV_7; |
| 859 |
break; |
| 860 |
case '8': |
| 861 |
arcname = DEV_8; |
| 862 |
break; |
| 863 |
default: |
| 864 |
tar_usage(); |
| 865 |
break; |
| 866 |
} |
| 867 |
} |
| 868 |
argc -= optind; |
| 869 |
argv += optind; |
| 870 |
|
| 871 |
/* Tar requires an action. */ |
| 872 |
if (act == ERROR) |
| 873 |
tar_usage(); |
| 874 |
|
| 875 |
/* Traditional tar behaviour (pax uses stderr unless in list mode) */ |
| 876 |
if (fstdin == 1 && act == ARCHIVE) |
| 877 |
listf = stderr; |
| 878 |
else |
| 879 |
listf = stdout; |
| 880 |
|
| 881 |
/* Traditional tar behaviour (pax wants to read file list from stdin) */ |
| 882 |
if ((act == ARCHIVE || act == APPND) && argc == 0 && nincfiles == 0) |
| 883 |
exit(0); |
| 884 |
|
| 885 |
/* |
| 886 |
* process the args as they are interpreted by the operation mode |
| 887 |
*/ |
| 888 |
switch (act) { |
| 889 |
case EXTRACT: |
| 890 |
if (to_stdout == 2) |
| 891 |
to_stdout = 1; |
| 892 |
case LIST: |
| 893 |
default: |
| 894 |
{ |
| 895 |
int sawpat = 0; |
| 896 |
char *file, *dir = NULL; |
| 897 |
|
| 898 |
while (nincfiles || *argv != NULL) { |
| 899 |
/* |
| 900 |
* If we queued up any include files, |
| 901 |
* pull them in now. Otherwise, check |
| 902 |
* for -I and -C positional flags. |
| 903 |
* Anything else must be a file to |
| 904 |
* extract. |
| 905 |
*/ |
| 906 |
if (nincfiles) { |
| 907 |
file = incfiles->file; |
| 908 |
dir = incfiles->dir; |
| 909 |
incfiles++; |
| 910 |
nincfiles--; |
| 911 |
} else if (strcmp(*argv, "-I") == 0) { |
| 912 |
if (*++argv == NULL) |
| 913 |
break; |
| 914 |
file = *argv++; |
| 915 |
dir = chdname; |
| 916 |
} else |
| 917 |
file = NULL; |
| 918 |
if (file != NULL) { |
| 919 |
FILE *fp; |
| 920 |
char *str; |
| 921 |
|
| 922 |
if (strcmp(file, "-") == 0) |
| 923 |
fp = stdin; |
| 924 |
else if ((fp = fopen(file, "r")) == NULL) { |
| 925 |
paxwarn(1, "Unable to open file '%s' for read", file); |
| 926 |
tar_usage(); |
| 927 |
} |
| 928 |
while ((str = getline(fp)) != NULL) { |
| 929 |
if (pat_add(str, dir) < 0) |
| 930 |
tar_usage(); |
| 931 |
sawpat = 1; |
| 932 |
} |
| 933 |
if (strcmp(file, "-") != 0) |
| 934 |
fclose(fp); |
| 935 |
if (getline_error) { |
| 936 |
paxwarn(1, "Problem with file '%s'", file); |
| 937 |
tar_usage(); |
| 938 |
} |
| 939 |
} else if (strcmp(*argv, "-C") == 0) { |
| 940 |
if (*++argv == NULL) |
| 941 |
break; |
| 942 |
chdname = *argv++; |
| 943 |
} else if (pat_add(*argv++, chdname) < 0) |
| 944 |
tar_usage(); |
| 945 |
else |
| 946 |
sawpat = 1; |
| 947 |
} |
| 948 |
/* |
| 949 |
* if patterns were added, we are doing chdir() |
| 950 |
* on a file-by-file basis, else, just one |
| 951 |
* global chdir (if any) after opening input. |
| 952 |
*/ |
| 953 |
if (sawpat > 0) |
| 954 |
chdname = NULL; |
| 955 |
} |
| 956 |
break; |
| 957 |
case ARCHIVE: |
| 958 |
case APPND: |
| 959 |
switch(Oflag) { |
| 960 |
case 0: |
| 961 |
frmt = &(fsub[F_TAR]); |
| 962 |
break; |
| 963 |
case 1: |
| 964 |
frmt = &(fsub[F_OTAR]); |
| 965 |
break; |
| 966 |
case 2: |
| 967 |
frmt = &(fsub[F_OTAR]); |
| 968 |
if (opt_add("write_opt=nodir") < 0) |
| 969 |
tar_usage(); |
| 970 |
break; |
| 971 |
case 3: |
| 972 |
frmt = &(fsub[F_NCPIO]); |
| 973 |
break; |
| 974 |
case 4: |
| 975 |
frmt = &(fsub[F_CPIO]); |
| 976 |
break; |
| 977 |
default: |
| 978 |
tar_usage(); |
| 979 |
break; |
| 980 |
} |
| 981 |
|
| 982 |
if (chdname != NULL) { /* initial chdir() */ |
| 983 |
if (ftree_add(chdname, 1) < 0) |
| 984 |
tar_usage(); |
| 985 |
} |
| 986 |
|
| 987 |
while (nincfiles || *argv != NULL) { |
| 988 |
char *file, *dir = NULL; |
| 989 |
|
| 990 |
/* |
| 991 |
* If we queued up any include files, pull them in |
| 992 |
* now. Otherwise, check for -I and -C positional |
| 993 |
* flags. Anything else must be a file to include |
| 994 |
* in the archive. |
| 995 |
*/ |
| 996 |
if (nincfiles) { |
| 997 |
file = incfiles->file; |
| 998 |
dir = incfiles->dir; |
| 999 |
incfiles++; |
| 1000 |
nincfiles--; |
| 1001 |
} else if (strcmp(*argv, "-I") == 0) { |
| 1002 |
if (*++argv == NULL) |
| 1003 |
break; |
| 1004 |
file = *argv++; |
| 1005 |
dir = NULL; |
| 1006 |
} else |
| 1007 |
file = NULL; |
| 1008 |
if (file != NULL) { |
| 1009 |
FILE *fp; |
| 1010 |
char *str; |
| 1011 |
|
| 1012 |
/* Set directory if needed */ |
| 1013 |
if (dir) { |
| 1014 |
if (ftree_add(dir, 1) < 0) |
| 1015 |
tar_usage(); |
| 1016 |
} |
| 1017 |
|
| 1018 |
if (strcmp(file, "-") == 0) |
| 1019 |
fp = stdin; |
| 1020 |
else if ((fp = fopen(file, "r")) == NULL) { |
| 1021 |
paxwarn(1, "Unable to open file '%s' for read", file); |
| 1022 |
tar_usage(); |
| 1023 |
} |
| 1024 |
while ((str = getline(fp)) != NULL) { |
| 1025 |
if (ftree_add(str, 0) < 0) |
| 1026 |
tar_usage(); |
| 1027 |
} |
| 1028 |
if (strcmp(file, "-") != 0) |
| 1029 |
fclose(fp); |
| 1030 |
if (getline_error) { |
| 1031 |
paxwarn(1, "Problem with file '%s'", |
| 1032 |
file); |
| 1033 |
tar_usage(); |
| 1034 |
} |
| 1035 |
} else if (strcmp(*argv, "-C") == 0) { |
| 1036 |
if (*++argv == NULL) |
| 1037 |
break; |
| 1038 |
if (ftree_add(*argv++, 1) < 0) |
| 1039 |
tar_usage(); |
| 1040 |
} else if (ftree_add(*argv++, 0) < 0) |
| 1041 |
tar_usage(); |
| 1042 |
} |
| 1043 |
/* |
| 1044 |
* no read errors allowed on updates/append operation! |
| 1045 |
*/ |
| 1046 |
maxflt = 0; |
| 1047 |
break; |
| 1048 |
} |
| 1049 |
if (to_stdout != 1) |
| 1050 |
to_stdout = 0; |
| 1051 |
if (!fstdin && ((arcname == NULL) || (*arcname == '\0'))) { |
| 1052 |
arcname = getenv("TAPE"); |
| 1053 |
#ifdef _PATH_DEFTAPE |
| 1054 |
if ((arcname == NULL) || (*arcname == '\0')) |
| 1055 |
arcname = _PATH_DEFTAPE; |
| 1056 |
#endif |
| 1057 |
} |
| 1058 |
} |
| 1059 |
|
| 1060 |
int |
| 1061 |
mkpath(char *path) |
| 1062 |
{ |
| 1063 |
struct stat sb; |
| 1064 |
char *slash; |
| 1065 |
int done = 0; |
| 1066 |
|
| 1067 |
slash = path; |
| 1068 |
|
| 1069 |
while (!done) { |
| 1070 |
slash += strspn(slash, "/"); |
| 1071 |
slash += strcspn(slash, "/"); |
| 1072 |
|
| 1073 |
done = (*slash == '\0'); |
| 1074 |
*slash = '\0'; |
| 1075 |
|
| 1076 |
if (stat(path, &sb)) { |
| 1077 |
if (errno != ENOENT || mkdir(path, 0777)) { |
| 1078 |
paxwarn(1, "%s", path); |
| 1079 |
return (-1); |
| 1080 |
} |
| 1081 |
} else if (!S_ISDIR(sb.st_mode)) { |
| 1082 |
syswarn(1, ENOTDIR, "%s", path); |
| 1083 |
return (-1); |
| 1084 |
} |
| 1085 |
|
| 1086 |
if (!done) |
| 1087 |
*slash = '/'; |
| 1088 |
} |
| 1089 |
|
| 1090 |
return (0); |
| 1091 |
} |
| 1092 |
|
| 1093 |
static void |
| 1094 |
cpio_set_action(int op) |
| 1095 |
{ |
| 1096 |
if ((act == APPND && op == ARCHIVE) || (act == ARCHIVE && op == APPND)) |
| 1097 |
act = APPND; |
| 1098 |
else if ((act == LIST && op == EXTRACT) || (act == EXTRACT && op == LIST)) |
| 1099 |
act = LIST; |
| 1100 |
else if (act != ERROR && act != op) |
| 1101 |
cpio_usage(); |
| 1102 |
else |
| 1103 |
act = op; |
| 1104 |
} |
| 1105 |
|
| 1106 |
/* |
| 1107 |
* cpio_options() |
| 1108 |
* look at the user specified flags. set globals as required and check if |
| 1109 |
* the user specified a legal set of flags. If not, complain and exit |
| 1110 |
*/ |
| 1111 |
|
| 1112 |
static void |
| 1113 |
cpio_options(int argc, char **argv) |
| 1114 |
{ |
| 1115 |
int c; |
| 1116 |
size_t i; |
| 1117 |
char *str; |
| 1118 |
FSUB tmp; |
| 1119 |
FILE *fp; |
| 1120 |
|
| 1121 |
kflag = 1; |
| 1122 |
pids = 1; |
| 1123 |
pmode = 1; |
| 1124 |
pmtime = 0; |
| 1125 |
arcname = NULL; |
| 1126 |
dflag = 1; |
| 1127 |
nodirs = 1; |
| 1128 |
while ((c=getopt(argc,argv,"abcdfiklmoprstuvzABC:E:F:H:I:LM:O:SZ6")) != -1) |
| 1129 |
switch (c) { |
| 1130 |
case 'a': |
| 1131 |
/* |
| 1132 |
* preserve access time on files read |
| 1133 |
*/ |
| 1134 |
tflag = 1; |
| 1135 |
break; |
| 1136 |
case 'b': |
| 1137 |
/* |
| 1138 |
* swap bytes and half-words when reading data |
| 1139 |
*/ |
| 1140 |
break; |
| 1141 |
case 'c': |
| 1142 |
/* |
| 1143 |
* ASCII cpio header |
| 1144 |
*/ |
| 1145 |
frmt = &(fsub[F_ACPIO]); |
| 1146 |
break; |
| 1147 |
case 'd': |
| 1148 |
/* |
| 1149 |
* create directories as needed |
| 1150 |
*/ |
| 1151 |
nodirs = 0; |
| 1152 |
break; |
| 1153 |
case 'f': |
| 1154 |
/* |
| 1155 |
* invert meaning of pattern list |
| 1156 |
*/ |
| 1157 |
cflag = 1; |
| 1158 |
break; |
| 1159 |
case 'i': |
| 1160 |
/* |
| 1161 |
* restore an archive |
| 1162 |
*/ |
| 1163 |
cpio_set_action(EXTRACT); |
| 1164 |
break; |
| 1165 |
case 'k': |
| 1166 |
break; |
| 1167 |
case 'l': |
| 1168 |
/* |
| 1169 |
* use links instead of copies when possible |
| 1170 |
*/ |
| 1171 |
lflag = 1; |
| 1172 |
break; |
| 1173 |
case 'm': |
| 1174 |
/* |
| 1175 |
* preserve modification time |
| 1176 |
*/ |
| 1177 |
pmtime = 1; |
| 1178 |
break; |
| 1179 |
case 'o': |
| 1180 |
/* |
| 1181 |
* create an archive |
| 1182 |
*/ |
| 1183 |
cpio_set_action(ARCHIVE); |
| 1184 |
frmt = &(fsub[F_CPIO]); |
| 1185 |
break; |
| 1186 |
case 'p': |
| 1187 |
/* |
| 1188 |
* copy-pass mode |
| 1189 |
*/ |
| 1190 |
cpio_set_action(COPY); |
| 1191 |
break; |
| 1192 |
case 'r': |
| 1193 |
/* |
| 1194 |
* interactively rename files |
| 1195 |
*/ |
| 1196 |
iflag = 1; |
| 1197 |
break; |
| 1198 |
case 's': |
| 1199 |
/* |
| 1200 |
* swap bytes after reading data |
| 1201 |
*/ |
| 1202 |
break; |
| 1203 |
case 't': |
| 1204 |
/* |
| 1205 |
* list contents of archive |
| 1206 |
*/ |
| 1207 |
cpio_set_action(LIST); |
| 1208 |
listf = stdout; |
| 1209 |
break; |
| 1210 |
case 'u': |
| 1211 |
/* |
| 1212 |
* replace newer files |
| 1213 |
*/ |
| 1214 |
kflag = 0; |
| 1215 |
break; |
| 1216 |
case 'v': |
| 1217 |
/* |
| 1218 |
* verbose operation mode |
| 1219 |
*/ |
| 1220 |
vflag = 1; |
| 1221 |
break; |
| 1222 |
case 'z': |
| 1223 |
/* |
| 1224 |
* use gzip. Non standard option. |
| 1225 |
*/ |
| 1226 |
gzip_program = GZIP_CMD; |
| 1227 |
break; |
| 1228 |
case 'A': |
| 1229 |
/* |
| 1230 |
* append mode |
| 1231 |
*/ |
| 1232 |
cpio_set_action(APPND); |
| 1233 |
break; |
| 1234 |
case 'B': |
| 1235 |
/* |
| 1236 |
* Use 5120 byte block size |
| 1237 |
*/ |
| 1238 |
wrblksz = 5120; |
| 1239 |
break; |
| 1240 |
case 'C': |
| 1241 |
/* |
| 1242 |
* set block size in bytes |
| 1243 |
*/ |
| 1244 |
wrblksz = atoi(optarg); |
| 1245 |
break; |
| 1246 |
case 'E': |
| 1247 |
/* |
| 1248 |
* file with patterns to extract or list |
| 1249 |
*/ |
| 1250 |
if ((fp = fopen(optarg, "r")) == NULL) { |
| 1251 |
paxwarn(1, "Unable to open file '%s' for read", optarg); |
| 1252 |
cpio_usage(); |
| 1253 |
} |
| 1254 |
while ((str = getline(fp)) != NULL) { |
| 1255 |
pat_add(str, NULL); |
| 1256 |
} |
| 1257 |
fclose(fp); |
| 1258 |
if (getline_error) { |
| 1259 |
paxwarn(1, "Problem with file '%s'", optarg); |
| 1260 |
cpio_usage(); |
| 1261 |
} |
| 1262 |
break; |
| 1263 |
case 'F': |
| 1264 |
case 'I': |
| 1265 |
case 'O': |
| 1266 |
/* |
| 1267 |
* filename where the archive is stored |
| 1268 |
*/ |
| 1269 |
if ((optarg[0] == '-') && (optarg[1]== '\0')) { |
| 1270 |
/* |
| 1271 |
* treat a - as stdin |
| 1272 |
*/ |
| 1273 |
arcname = NULL; |
| 1274 |
break; |
| 1275 |
} |
| 1276 |
arcname = optarg; |
| 1277 |
break; |
| 1278 |
case 'H': |
| 1279 |
/* |
| 1280 |
* specify an archive format on write |
| 1281 |
*/ |
| 1282 |
if (!strcmp(optarg, "bin")) { |
| 1283 |
tmp.name = "bcpio"; |
| 1284 |
} else if (!strcmp(optarg, "crc")) { |
| 1285 |
tmp.name = "sv4crc"; |
| 1286 |
} else if (!strcmp(optarg, "newc")) { |
| 1287 |
tmp.name = "sv4cpio"; |
| 1288 |
} else if (!strcmp(optarg, "odc")) { |
| 1289 |
tmp.name = "cpio"; |
| 1290 |
} else { |
| 1291 |
tmp.name = optarg; |
| 1292 |
} |
| 1293 |
if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub, |
| 1294 |
sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL) |
| 1295 |
break; |
| 1296 |
paxwarn(1, "Unknown -H format: %s", optarg); |
| 1297 |
(void)fputs("cpio: Known -H formats are:", stderr); |
| 1298 |
for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i) |
| 1299 |
(void)fprintf(stderr, " %s", fsub[i].name); |
| 1300 |
(void)fputs("\n\n", stderr); |
| 1301 |
cpio_usage(); |
| 1302 |
break; |
| 1303 |
case 'L': |
| 1304 |
/* |
| 1305 |
* follow symbolic links |
| 1306 |
*/ |
| 1307 |
Lflag = 1; |
| 1308 |
break; |
| 1309 |
case 'M': |
| 1310 |
process_M(optarg, cpio_usage); |
| 1311 |
break; |
| 1312 |
case 'S': |
| 1313 |
/* |
| 1314 |
* swap halfwords after reading data |
| 1315 |
*/ |
| 1316 |
break; |
| 1317 |
case 'Z': |
| 1318 |
/* |
| 1319 |
* use compress. Non standard option. |
| 1320 |
*/ |
| 1321 |
gzip_program = COMPRESS_CMD; |
| 1322 |
break; |
| 1323 |
case '6': |
| 1324 |
/* |
| 1325 |
* process Version 6 cpio format |
| 1326 |
*/ |
| 1327 |
frmt = &(fsub[F_OCPIO]); |
| 1328 |
break; |
| 1329 |
case '?': |
| 1330 |
default: |
| 1331 |
cpio_usage(); |
| 1332 |
break; |
| 1333 |
} |
| 1334 |
argc -= optind; |
| 1335 |
argv += optind; |
| 1336 |
|
| 1337 |
/* |
| 1338 |
* process the args as they are interpreted by the operation mode |
| 1339 |
*/ |
| 1340 |
switch (act) { |
| 1341 |
case LIST: |
| 1342 |
case EXTRACT: |
| 1343 |
while (*argv != NULL) |
| 1344 |
if (pat_add(*argv++, NULL) < 0) |
| 1345 |
cpio_usage(); |
| 1346 |
break; |
| 1347 |
case COPY: |
| 1348 |
if (*argv == NULL) { |
| 1349 |
paxwarn(0, "Destination directory was not supplied"); |
| 1350 |
cpio_usage(); |
| 1351 |
} |
| 1352 |
dirptr = *argv; |
| 1353 |
if (mkpath(dirptr) < 0) |
| 1354 |
cpio_usage(); |
| 1355 |
--argc; |
| 1356 |
++argv; |
| 1357 |
/* FALL THROUGH */ |
| 1358 |
case ARCHIVE: |
| 1359 |
case APPND: |
| 1360 |
if (*argv != NULL) |
| 1361 |
cpio_usage(); |
| 1362 |
/* |
| 1363 |
* no read errors allowed on updates/append operation! |
| 1364 |
*/ |
| 1365 |
maxflt = 0; |
| 1366 |
while ((str = getline(stdin)) != NULL) { |
| 1367 |
ftree_add(str, 0); |
| 1368 |
} |
| 1369 |
if (getline_error) { |
| 1370 |
paxwarn(1, "Problem while reading stdin"); |
| 1371 |
cpio_usage(); |
| 1372 |
} |
| 1373 |
break; |
| 1374 |
default: |
| 1375 |
cpio_usage(); |
| 1376 |
break; |
| 1377 |
} |
| 1378 |
} |
| 1379 |
|
| 1380 |
/* |
| 1381 |
* printflg() |
| 1382 |
* print out those invalid flag sets found to the user |
| 1383 |
*/ |
| 1384 |
|
| 1385 |
static void |
| 1386 |
printflg(unsigned int flg) |
| 1387 |
{ |
| 1388 |
int nxt; |
| 1389 |
int pos = 0; |
| 1390 |
|
| 1391 |
(void)fprintf(stderr,"%s: Invalid combination of options:", argv0); |
| 1392 |
while ((nxt = ffs(flg)) != 0) { |
| 1393 |
flg = flg >> nxt; |
| 1394 |
pos += nxt; |
| 1395 |
(void)fprintf(stderr, " -%c", flgch[pos-1]); |
| 1396 |
} |
| 1397 |
(void)putc('\n', stderr); |
| 1398 |
} |
| 1399 |
|
| 1400 |
/* |
| 1401 |
* c_frmt() |
| 1402 |
* comparison routine used by bsearch to find the format specified |
| 1403 |
* by the user |
| 1404 |
*/ |
| 1405 |
|
| 1406 |
static int |
| 1407 |
c_frmt(const void *a, const void *b) |
| 1408 |
{ |
| 1409 |
return(strcmp(((const FSUB *)a)->name, ((const FSUB *)b)->name)); |
| 1410 |
} |
| 1411 |
|
| 1412 |
/* |
| 1413 |
* opt_next() |
| 1414 |
* called by format specific options routines to get each format specific |
| 1415 |
* flag and value specified with -o |
| 1416 |
* Return: |
| 1417 |
* pointer to next OPLIST entry or NULL (end of list). |
| 1418 |
*/ |
| 1419 |
|
| 1420 |
OPLIST * |
| 1421 |
opt_next(void) |
| 1422 |
{ |
| 1423 |
OPLIST *opt; |
| 1424 |
|
| 1425 |
if ((opt = ophead) != NULL) |
| 1426 |
ophead = ophead->fow; |
| 1427 |
return(opt); |
| 1428 |
} |
| 1429 |
|
| 1430 |
/* |
| 1431 |
* bad_opt() |
| 1432 |
* generic routine used to complain about a format specific options |
| 1433 |
* when the format does not support options. |
| 1434 |
*/ |
| 1435 |
|
| 1436 |
int |
| 1437 |
bad_opt(void) |
| 1438 |
{ |
| 1439 |
OPLIST *opt; |
| 1440 |
|
| 1441 |
if (ophead == NULL) |
| 1442 |
return(0); |
| 1443 |
/* |
| 1444 |
* print all we were given |
| 1445 |
*/ |
| 1446 |
paxwarn(1,"These format options are not supported"); |
| 1447 |
while ((opt = opt_next()) != NULL) |
| 1448 |
(void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value); |
| 1449 |
pax_usage(); |
| 1450 |
return(0); |
| 1451 |
} |
| 1452 |
|
| 1453 |
/* |
| 1454 |
* opt_add() |
| 1455 |
* breaks the value supplied to -o into a option name and value. options |
| 1456 |
* are given to -o in the form -o name-value,name=value |
| 1457 |
* multiple -o may be specified. |
| 1458 |
* Return: |
| 1459 |
* 0 if format in name=value format, -1 if -o is passed junk |
| 1460 |
*/ |
| 1461 |
|
| 1462 |
int |
| 1463 |
opt_add(const char *str) |
| 1464 |
{ |
| 1465 |
OPLIST *opt; |
| 1466 |
char *frpt; |
| 1467 |
char *pt; |
| 1468 |
char *endpt; |
| 1469 |
char *dstr; |
| 1470 |
|
| 1471 |
if ((str == NULL) || (*str == '\0')) { |
| 1472 |
paxwarn(0, "Invalid option name"); |
| 1473 |
return(-1); |
| 1474 |
} |
| 1475 |
if ((dstr = strdup(str)) == NULL) { |
| 1476 |
paxwarn(0, "Unable to allocate space for option list"); |
| 1477 |
return(-1); |
| 1478 |
} |
| 1479 |
frpt = endpt = dstr; |
| 1480 |
|
| 1481 |
/* |
| 1482 |
* break into name and values pieces and stuff each one into a |
| 1483 |
* OPLIST structure. When we know the format, the format specific |
| 1484 |
* option function will go through this list |
| 1485 |
*/ |
| 1486 |
while ((frpt != NULL) && (*frpt != '\0')) { |
| 1487 |
if ((endpt = strchr(frpt, ',')) != NULL) |
| 1488 |
*endpt = '\0'; |
| 1489 |
if ((pt = strchr(frpt, '=')) == NULL) { |
| 1490 |
paxwarn(0, "Invalid options format"); |
| 1491 |
free(dstr); |
| 1492 |
return(-1); |
| 1493 |
} |
| 1494 |
if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) { |
| 1495 |
paxwarn(0, "Unable to allocate space for option list"); |
| 1496 |
free(dstr); |
| 1497 |
return(-1); |
| 1498 |
} |
| 1499 |
*pt++ = '\0'; |
| 1500 |
opt->name = frpt; |
| 1501 |
opt->value = pt; |
| 1502 |
opt->fow = NULL; |
| 1503 |
if (endpt != NULL) |
| 1504 |
frpt = endpt + 1; |
| 1505 |
else |
| 1506 |
frpt = NULL; |
| 1507 |
if (ophead == NULL) { |
| 1508 |
optail = ophead = opt; |
| 1509 |
continue; |
| 1510 |
} |
| 1511 |
optail->fow = opt; |
| 1512 |
optail = opt; |
| 1513 |
} |
| 1514 |
return(0); |
| 1515 |
} |
| 1516 |
|
| 1517 |
/* |
| 1518 |
* str_offt() |
| 1519 |
* Convert an expression of the following forms to an off_t > 0. |
| 1520 |
* 1) A positive decimal number. |
| 1521 |
* 2) A positive decimal number followed by a b (mult by 512). |
| 1522 |
* 3) A positive decimal number followed by a k (mult by 1024). |
| 1523 |
* 4) A positive decimal number followed by a m (mult by 512). |
| 1524 |
* 5) A positive decimal number followed by a w (mult by sizeof int) |
| 1525 |
* 6) Two or more positive decimal numbers (with/without k,b or w). |
| 1526 |
* separated by x (also * for backwards compatibility), specifying |
| 1527 |
* the product of the indicated values. |
| 1528 |
* Return: |
| 1529 |
* 0 for an error, a positive value o.w. |
| 1530 |
*/ |
| 1531 |
|
| 1532 |
static off_t |
| 1533 |
str_offt(char *val) |
| 1534 |
{ |
| 1535 |
char *expr; |
| 1536 |
off_t num, t; |
| 1537 |
|
| 1538 |
# ifdef LONG_OFF_T |
| 1539 |
num = strtol(val, &expr, 0); |
| 1540 |
if ((num == LONG_MAX) || (num <= 0) || (expr == val)) |
| 1541 |
# else |
| 1542 |
num = strtoq(val, &expr, 0); |
| 1543 |
if ((num == QUAD_MAX) || (num <= 0) || (expr == val)) |
| 1544 |
# endif |
| 1545 |
return(0); |
| 1546 |
|
| 1547 |
switch (*expr) { |
| 1548 |
case 'b': |
| 1549 |
t = num; |
| 1550 |
num *= 512; |
| 1551 |
if (t > num) |
| 1552 |
return(0); |
| 1553 |
++expr; |
| 1554 |
break; |
| 1555 |
case 'k': |
| 1556 |
t = num; |
| 1557 |
num *= 1024; |
| 1558 |
if (t > num) |
| 1559 |
return(0); |
| 1560 |
++expr; |
| 1561 |
break; |
| 1562 |
case 'm': |
| 1563 |
t = num; |
| 1564 |
num *= 1048576; |
| 1565 |
if (t > num) |
| 1566 |
return(0); |
| 1567 |
++expr; |
| 1568 |
break; |
| 1569 |
case 'w': |
| 1570 |
t = num; |
| 1571 |
num *= sizeof(int); |
| 1572 |
if (t > num) |
| 1573 |
return(0); |
| 1574 |
++expr; |
| 1575 |
break; |
| 1576 |
} |
| 1577 |
|
| 1578 |
switch (*expr) { |
| 1579 |
case '\0': |
| 1580 |
break; |
| 1581 |
case '*': |
| 1582 |
case 'x': |
| 1583 |
t = num; |
| 1584 |
num *= str_offt(expr + 1); |
| 1585 |
if (t > num) |
| 1586 |
return(0); |
| 1587 |
break; |
| 1588 |
default: |
| 1589 |
return(0); |
| 1590 |
} |
| 1591 |
return(num); |
| 1592 |
} |
| 1593 |
|
| 1594 |
char * |
| 1595 |
getline(FILE *f) |
| 1596 |
{ |
| 1597 |
char *name, *temp; |
| 1598 |
size_t len; |
| 1599 |
|
| 1600 |
name = fgetln(f, &len); |
| 1601 |
if (!name) { |
| 1602 |
getline_error = ferror(f) ? GETLINE_FILE_CORRUPT : 0; |
| 1603 |
return(0); |
| 1604 |
} |
| 1605 |
if (name[len-1] != '\n') |
| 1606 |
len++; |
| 1607 |
temp = malloc(len); |
| 1608 |
if (!temp) { |
| 1609 |
getline_error = GETLINE_OUT_OF_MEM; |
| 1610 |
return(0); |
| 1611 |
} |
| 1612 |
memcpy(temp, name, len-1); |
| 1613 |
temp[len-1] = 0; |
| 1614 |
return(temp); |
| 1615 |
} |
| 1616 |
|
| 1617 |
/* |
| 1618 |
* no_op() |
| 1619 |
* for those option functions where the archive format has nothing to do. |
| 1620 |
* Return: |
| 1621 |
* 0 |
| 1622 |
*/ |
| 1623 |
|
| 1624 |
static int |
| 1625 |
no_op(void) |
| 1626 |
{ |
| 1627 |
return(0); |
| 1628 |
} |
| 1629 |
|
| 1630 |
/* |
| 1631 |
* pax_usage() |
| 1632 |
* print the usage summary to the user |
| 1633 |
*/ |
| 1634 |
|
| 1635 |
void |
| 1636 |
pax_usage(void) |
| 1637 |
{ |
| 1638 |
(void)fputs( |
| 1639 |
"usage: pax [-0cdOnRSvz] [-E limit] [-f archive] [-G group] [-s replstr]\n" |
| 1640 |
"\t [-T [from_date][,to_date][/[c][m]]] [-U user] [pattern ...]\n" |
| 1641 |
" pax -r [-0cDdikOnuvzYZz] [-E limit] [-f archive] [-G group]\n" |
| 1642 |
"\t [-o options] [-p string] [-s replstr] [-T [from_date][,to_date]]\n" |
| 1643 |
"\t [-U user] [pattern ...]\n" |
| 1644 |
" pax -w [-0adHiLOPtuvXz] [-B bytes] [-b blocksize] [-f archive]\n" |
| 1645 |
"\t [-G group] [-M value] [-o options] [-s replstr]\n" |
| 1646 |
"\t [-T [from_date][,to_date][/[c][m]]] [-U user] [-x format] [file ...]\n" |
| 1647 |
" pax -r -w [-0DdHikLlnOPtuvXYZ] [-G group] [-p string] [-s replstr]\n" |
| 1648 |
"\t [-T [from_date][,to_date][/[c][m]]] [-U user] [file ...] directory\n", |
| 1649 |
stderr); |
| 1650 |
exit(1); |
| 1651 |
} |
| 1652 |
|
| 1653 |
/* |
| 1654 |
* tar_usage() |
| 1655 |
* print the usage summary to the user |
| 1656 |
*/ |
| 1657 |
|
| 1658 |
void |
| 1659 |
tar_usage(void) |
| 1660 |
{ |
| 1661 |
(void)fputs( |
| 1662 |
"usage: tar {crtux}[014578befHhLmOoPpqsvwXZz]\n" |
| 1663 |
"\t [blocking-factor | archive | replstr] [-C directory] [-I file]\n" |
| 1664 |
"\t [file ...]\n" |
| 1665 |
" tar {-crtux} [-014578eHhLmOoPpqvwXZz] [-b blocking-factor] [-M value]\n" |
| 1666 |
"\t [-C directory] [-f archive] [-I file] [-s replstr] [file ...]\n", |
| 1667 |
stderr); |
| 1668 |
exit(1); |
| 1669 |
} |
| 1670 |
|
| 1671 |
/* |
| 1672 |
* cpio_usage() |
| 1673 |
* print the usage summary to the user |
| 1674 |
*/ |
| 1675 |
|
| 1676 |
void |
| 1677 |
cpio_usage(void) |
| 1678 |
{ |
| 1679 |
(void)fputs("usage: cpio -o [-aABcLvVzZ] [-C bytes] [-H format] [-O archive]\n", stderr); |
| 1680 |
(void)fputs(" [-M flag] [-F archive] <name-list [>archive]\n", stderr); |
| 1681 |
(void)fputs(" cpio -i [-bBcdfmnrsStuvVzZ6] [-C bytes] [-E file] [-H format]\n", stderr); |
| 1682 |
(void)fputs(" [-I archive] [-F archive] [pattern...] [<archive]\n", stderr); |
| 1683 |
(void)fputs(" cpio -p [-adlLmuvV] destination-directory <name-list\n", stderr); |
| 1684 |
exit(1); |
| 1685 |
} |
| 1686 |
|
| 1687 |
void |
| 1688 |
anonarch_init(void) |
| 1689 |
{ |
| 1690 |
if (anonarch & ANON_VERBOSE) { |
| 1691 |
anonarch &= ~ANON_VERBOSE; |
| 1692 |
paxwarn(0, "debug: -M 0x%08X -x %s", anonarch, frmt->name); |
| 1693 |
} |
| 1694 |
} |
| 1695 |
|
| 1696 |
static void |
| 1697 |
process_M(const char *arg, void (*call_usage)(void)) |
| 1698 |
{ |
| 1699 |
int j, k = 0; |
| 1700 |
|
| 1701 |
if ((arg[0] >= '0') && (arg[0] <= '9')) { |
| 1702 |
#ifdef __OpenBSD__ |
| 1703 |
const char *s; |
| 1704 |
int64_t i = strtonum(arg, 0, |
| 1705 |
ANON_MAXVAL, &s); |
| 1706 |
if (s) |
| 1707 |
errx(1, "%s M value: %s", s, |
| 1708 |
arg); |
| 1709 |
#else |
| 1710 |
char *ep; |
| 1711 |
long long i = strtoll(arg, &ep, 0); |
| 1712 |
if ((ep == arg) || (*ep != '\0') || |
| 1713 |
(i < 0) || (i > ANON_MAXVAL)) |
| 1714 |
errx(1, "impossible M value:" |
| 1715 |
" %s", arg); |
| 1716 |
#endif |
| 1717 |
anonarch = i; |
| 1718 |
return; |
| 1719 |
} |
| 1720 |
|
| 1721 |
if (!strncmp(arg, "no-", 3)) { |
| 1722 |
j = 0; |
| 1723 |
arg += 3; |
| 1724 |
} else |
| 1725 |
j = 1; |
| 1726 |
if (!strncmp(arg, "uid", 3) || |
| 1727 |
!strncmp(arg, "gid", 3)) { |
| 1728 |
k = ANON_UIDGID; |
| 1729 |
} else if (!strncmp(arg, "ino", 3)) { |
| 1730 |
k = ANON_INODES; |
| 1731 |
} else if (!strncmp(arg, "mtim", 4)) { |
| 1732 |
k = ANON_MTIME; |
| 1733 |
} else if (!strncmp(arg, "link", 4)) { |
| 1734 |
k = ANON_HARDLINKS; |
| 1735 |
} else if (!strncmp(arg, "norm", 4)) { |
| 1736 |
k = ANON_UIDGID | ANON_INODES |
| 1737 |
| ANON_MTIME | ANON_HARDLINKS; |
| 1738 |
} else if (!strncmp(arg, "root", 4)) { |
| 1739 |
k = ANON_UIDGID | ANON_INODES; |
| 1740 |
} else if (!strncmp(arg, "dist", 4)) { |
| 1741 |
k = ANON_UIDGID | ANON_INODES |
| 1742 |
| ANON_HARDLINKS; |
| 1743 |
} else if (!strncmp(arg, "set", 3)) { |
| 1744 |
k = ANON_INODES | ANON_HARDLINKS; |
| 1745 |
} else if (!strncmp(arg, "v", 1)) { |
| 1746 |
k = ANON_VERBOSE; |
| 1747 |
} else if (!strncmp(arg, "debug", 5)) { |
| 1748 |
k = ANON_DEBUG; |
| 1749 |
} else |
| 1750 |
call_usage(); |
| 1751 |
if (j) |
| 1752 |
anonarch |= k; |
| 1753 |
else |
| 1754 |
anonarch &= ~k; |
| 1755 |
} |