Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/pax/pax.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1987-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* pax -- portable archive interchange
26
*
27
* test registry:
28
*
29
* 0000010 dump option table
30
* 0000020 force DELTA_TEMP to file
31
* 0000040 pretend io device is char special
32
* 0000100 don't copy in holes
33
* 0000200 sleep(1) between meter displays
34
*/
35
36
static const char usage[] =
37
"[-?\n@(#)$Id: pax (AT&T Research) 2012-05-25 $\n]"
38
USAGE_LICENSE
39
"[+NAME?pax - read, write, and list file archives]"
40
"[+DESCRIPTION?The pax command reads, writes, and lists archive files in"
41
" various formats. There are four operation modes controlled by"
42
" combinations of the -\br\b and -\bw\b options.]"
43
"[+?\bpax -w\b writes the files and directories named by the \apathname\a"
44
" arguments to the standard output together with pathname and status"
45
" information. A directory \apathname\a argument refers to the files and"
46
" (recursively) subdirectories of that directory. If no \apathname\a"
47
" arguments are given then the standard input is read to get a list of"
48
" pathnames to copy, one pathname per line. In this case only those"
49
" pathnames appearing on the standard input are copied.]"
50
"[+?\bpax -r\b reads the standard input that is assumed to be the result of a"
51
" previous \bpax -w\b command. Only member files with names"
52
" that match any of the \apattern\a arguments are selected. Matching"
53
" is done before any \b-i\b or \b-s\b options are applied. A"
54
" \apattern\a is given in the name-generating notation of \bsh\b(1),"
55
" except that the \b/\b character is also matched. The default if no"
56
" \apattern\a is given is \b*\b which selects all files. The selected"
57
" files are conditionally created and copied relative to the current"
58
" directory tree, subject to the options described below. By default the"
59
" owner and group of selected files will be that of the current user, and"
60
" the permissions and modify times will be the same as those in the"
61
" archive.]"
62
"[+?\bpax -rw\b reads the files and directories named in the \apathname\a"
63
" arguments and copies them to the destination \adirectory\a."
64
" A directory \apathname\a argument refers to the files and (recursively)"
65
" subdirectories of that directory. If no \apathname\a arguments are"
66
" given then the standard input is read to get a list of pathnames to"
67
" copy, one pathname per l, lineine. In this case only those pathnames"
68
" appearing on the standard input are copied. \adirectory\a must exist"
69
" before the copy.]"
70
"[+?\bpax\b (\b-r\b and \b-w\b omitted) reads the standard input that is"
71
" assumed to be the result of a previous \bpax -w\b command and lists"
72
" table of contents of the selected member files on the standard output.]"
73
"[+?The standard archive formats are automatically detected on input."
74
" The default output archive format is \b\fdefault\f\b, but may be"
75
" overridden by the \b-x\b option described below. \bpax\b archives may"
76
" be concatenated to combine multiple volumes on a single tape or file."
77
" This is accomplished by forcing any format prescribed pad data to be"
78
" null bytes. Hard links are not maintained between volumes, and delta"
79
" and base archives cannot be multi-volume.]"
80
"[+?A single archive may span many files/devices. The second and"
81
" subsequent file names are prompted for on the terminal input. The"
82
" response may be:]{"
83
" [+!command?Execute \acommand\a via \bsystem\b(3) and prompt"
84
" again for file name.]"
85
" [+EOF?Terminate processing and exit.]"
86
" [+CR?An empty input line retains the previous file name.]"
87
" [+pathname?The file name for the next archive part.]"
88
"}"
89
"[+?\bgetconf PATH_RESOLVE\b determines how symbolic links are handled. This"
90
" can be explicitly overridden by the \b--logical\b, \b--metaphysical\b,"
91
" and \b--physical\b options below. \bPATH_RESOLVE\b can be one of:]{"
92
" [+logical?Follow all symbolic links.]"
93
" [+metaphysical?Follow command argument symbolic links,"
94
" otherwise don't follow.]"
95
" [+physical?Don't follow symbolic links.]"
96
"}"
97
;
98
99
/* state.usage is generated at runtime from usage+options+usage2 */
100
101
static const char usage2[] =
102
"\n"
103
"[ pathname ... ]\n"
104
"[ pattern ... ]\n"
105
"[ pathname ... directory ]\n"
106
"\n"
107
"[+DIAGNOSTICS?The number of files, blocks, and optionally the number"
108
" of volumes and media parts are listed on the standard error."
109
" For -\bv\b the input archive formats are also listed on the"
110
" standard error.]"
111
"[+EXAMPLES]{"
112
" [+pax -w -t 1m .?Copies the contents of the current directory to"
113
" tape drive 1, medium density.]"
114
" [+mkdir newdir; cd olddir; pax -rw . newdir?Copies the"
115
" \aolddir\a directory hierarchy to \anewdir\a.]"
116
"}"
117
"[+SEE ALSO?\bar\b(1), \bcpio\b(1), \bfind\b(1), \bgetconf\b(1), \bgzip\b(1),"
118
" \bksh\b(1), \bratz\b(1), \bstar\b(1), \btar\b(1), \btw\b(1),"
119
" \bfsync\b(2), \blibdelta\b(3), \bcpio\b(5), \btar\b(5)]"
120
"[+BUGS?Special privileges may be required to copy special files."
121
" Some archive formats have hard upper limits on member string, numeric"
122
" and data sizes. Attribute values larger than the standard min-max"
123
" values may cause additional header or embedded data records to be"
124
" output for some formats; these records are ignored by old versions"
125
" of \bcpio\b(1) and \btar\b(1). \b--format=pax\b avoids size and"
126
" portability limitations \abut\a requires a working reader on the"
127
" receiving side.]"
128
;
129
130
#include "pax.h"
131
132
#include <ardir.h>
133
#include <iconv.h>
134
#include <tm.h>
135
136
char* definput = "/dev/stdin";
137
char* defoutput = "/dev/stdout";
138
char* eomprompt = "Change to part %d and hit RETURN: ";
139
140
State_t state;
141
142
static int signals[] = /* signals caught by interrupt() */
143
{
144
SIGHUP,
145
SIGINT,
146
#if !DEBUG
147
SIGQUIT,
148
#endif
149
SIGALRM,
150
SIGTERM,
151
};
152
153
static struct
154
{
155
char* arg0;
156
Sfio_t* ignore_all;
157
Sfio_t* ignore_ext;
158
Map_t* lastmap;
159
Sfio_t* listformat;
160
char* owner;
161
} opt;
162
163
/*
164
* clean up dir info before exit
165
*/
166
167
static void
168
interrupt(int sig)
169
{
170
signal(sig, SIG_IGN);
171
switch (sig)
172
{
173
case SIGINT:
174
case SIGQUIT:
175
sfprintf(sfstderr, "\n");
176
break;
177
}
178
state.interrupt = sig;
179
finish(1);
180
}
181
182
/*
183
* enter new substitute expression(s)
184
*/
185
186
static void
187
substitute(Map_t** lastmap, register char* s)
188
{
189
register Map_t* mp;
190
int c;
191
192
for (;;)
193
{
194
while (isspace(*s))
195
s++;
196
if (!*s)
197
break;
198
if (!(mp = newof(0, Map_t, 1, 0)))
199
error(3, "no space [substitution]");
200
if (!(c = regcomp(&mp->re, s, REG_DELIMITED|REG_LENIENT|REG_NULL)))
201
{
202
s += mp->re.re_npat;
203
if (!(c = regsubcomp(&mp->re, s, NiL, 0, 0)))
204
s += mp->re.re_npat;
205
}
206
if (c)
207
regfatal(&mp->re, 4, c);
208
for (;;)
209
{
210
switch (*s++)
211
{
212
case 'i':
213
mp->flags |= MAP_INDEX;
214
continue;
215
}
216
s--;
217
break;
218
}
219
if (*s && !isspace(*s))
220
error(1, "invalid character after substitution: %s", s);
221
if (*lastmap)
222
*lastmap = (*lastmap)->next = mp;
223
else
224
state.maps = *lastmap = mp;
225
}
226
}
227
228
/*
229
* clear meter line for each error message
230
*/
231
232
static ssize_t
233
meterror(int fd, const void* buf, size_t n)
234
{
235
if (state.meter.last)
236
{
237
sfprintf(sfstderr, "%*s\r", state.meter.last, "");
238
state.meter.last = 0;
239
}
240
return write(fd, buf, n);
241
}
242
243
/*
244
* construct an action from command
245
*/
246
247
static Filter_t*
248
action(const char* command, int pattern)
249
{
250
register Filter_t* fp;
251
register char* s;
252
register char* t;
253
register int c;
254
register int q;
255
register int n;
256
regex_t* re;
257
258
s = (char*)command;
259
if (pattern && *s && *s == *(s + 1))
260
{
261
s += 2;
262
pattern = 0;
263
}
264
if (pattern)
265
{
266
if (!(re = newof(0, regex_t, 1, 0)))
267
nospace();
268
if (c = regcomp(re, s, REG_SHELL|REG_AUGMENTED|REG_DELIMITED|REG_LENIENT|REG_NULL|REG_LEFT|REG_RIGHT))
269
regfatal(re, 4, c);
270
s += re->re_npat;
271
}
272
else
273
re = 0;
274
command = (const char*)s;
275
q = 0;
276
n = 3;
277
while (c = *s++)
278
if (c == '"' || c == '\'')
279
{
280
if (!q)
281
q = c;
282
else if (q == c)
283
q = 0;
284
}
285
else if (c == '\\')
286
{
287
if (q != '\'' && *s)
288
s++;
289
}
290
else if (!q && isspace(c))
291
{
292
n++;
293
while (isspace(*s))
294
s++;
295
}
296
if (!(fp = newof(0, Filter_t, 1, n * sizeof(char**) + 2 * (s - (char*)command))))
297
nospace();
298
fp->re = re;
299
fp->argv = (char**)(fp + 1);
300
fp->command = (char*)(fp->argv + n);
301
s = strcopy(fp->command, command) + 1;
302
strcpy(s, command);
303
fp->argv[0] = s;
304
q = 0;
305
n = 1;
306
t = s;
307
while (c = *s++)
308
if (c == '"' || c == '\'')
309
{
310
if (!q)
311
q = c;
312
else if (q == c)
313
q = 0;
314
else
315
*t++ = c;
316
}
317
else if (c == '\\')
318
{
319
if (q == '\'')
320
*t++ = c;
321
else if (*s)
322
*t++ = *s++;
323
}
324
else if (q || !isspace(c))
325
*t++ = c;
326
else
327
{
328
*t++ = 0;
329
while (isspace(*s))
330
s++;
331
if (*(t = s))
332
fp->argv[n++] = s;
333
}
334
*t = 0;
335
fp->patharg = fp->argv + n;
336
return fp;
337
}
338
339
/*
340
* return action for f, 0 if no match
341
*/
342
343
Filter_t*
344
filter(Archive_t* ap, File_t* f)
345
{
346
register Filter_t* fp;
347
348
if (f->st->st_size && (fp = state.filter.list))
349
do
350
{
351
if (!fp->re || !regexec(fp->re, f->name, NiL, 0, 0))
352
return fp;
353
} while (fp = fp->next);
354
return 0;
355
}
356
357
/*
358
* set options from line if != 0 or argv according to usage
359
* type: 0:command EXTTYPE:extended GLBTYPE:global
360
*/
361
362
void
363
setoptions(char* line, size_t hdr, char** argv, char* usage, Archive_t* ap, int type)
364
{
365
intmax_t n;
366
int c;
367
int y;
368
int assignment;
369
int cvt;
370
int index;
371
int offset;
372
int from;
373
int to;
374
char* e;
375
char* s;
376
char* v;
377
char* o;
378
char* end;
379
Filter_t* xp;
380
Format_t* fp;
381
Option_t* op;
382
Sfio_t* sp;
383
Value_t* vp;
384
char tmp1[PATH_MAX];
385
char tmp2[PATH_MAX];
386
387
cvt = 0;
388
index = opt_info.index;
389
offset = opt_info.offset;
390
if (line && hdr)
391
end = line + hdr;
392
for (;;)
393
{
394
if (hdr)
395
{
396
if (!*line)
397
break;
398
while (isspace(*line))
399
line++;
400
s = line;
401
y = 0;
402
while ((c = *line++) >= '0' && c <= '9')
403
y = y * 10 + (c - '0');
404
if ((e = (s + y - 1)) > end)
405
e = end;
406
else
407
*e++ = 0;
408
while (isspace(*line))
409
line++;
410
o = line;
411
assignment = 0;
412
for (;;)
413
{
414
switch (*line++)
415
{
416
case 0:
417
line--;
418
break;
419
case '=':
420
*(line - 1) = 0;
421
break;
422
case ':':
423
if (*line == '=')
424
{
425
*(line - 1) = 0;
426
line++;
427
assignment = 1;
428
break;
429
}
430
continue;
431
default:
432
continue;
433
}
434
break;
435
}
436
v = line;
437
line = e;
438
y = 1;
439
if (!(op = (Option_t*)hashget(state.options, o)))
440
{
441
s = o;
442
if (strneq(o, VENDOR ".", sizeof(VENDOR)))
443
{
444
o += sizeof(VENDOR);
445
op = (Option_t*)hashget(state.options, o);
446
}
447
if (!op && *o == 'n' && *(o + 1) == 'o')
448
{
449
o += 2;
450
y = 0;
451
op = (Option_t*)hashget(state.options, o);
452
}
453
if (!op)
454
{
455
if (islower(*s) && !strchr(s, '.'))
456
error(2, "%s: unknown option", s);
457
continue;
458
}
459
}
460
if (!y)
461
n = 0;
462
else if (!(op->flags & OPT_NUMBER))
463
n = 1;
464
else
465
{
466
n = strtonll(v, &e, NiL, 0);
467
if (*e)
468
error(2, "%s: %s: invalid numeric option value", op->name, v);
469
}
470
}
471
else if (!(c = line ? optstr(line, usage) : optget(argv, usage)))
472
break;
473
else if (c > 0)
474
{
475
if (c == '?')
476
error(ERROR_USAGE|4, "%s", opt_info.arg);
477
if (c == ':' && (!type || islower(*opt_info.name) && !strchr(opt_info.name, '.')))
478
error(2, "%s", opt_info.arg);
479
continue;
480
}
481
else
482
{
483
assignment = opt_info.assignment == ':';
484
y = (n = opt_info.number) != 0;
485
if (!(v = opt_info.arg))
486
v = "";
487
else if (!n)
488
y = 1;
489
op = options - c;
490
}
491
492
/*
493
* option precedence levels
494
*
495
* 8 ignore all
496
* 7 command:=
497
* 6 ignore extended
498
* 5 extended:=
499
* 4 extended=
500
* 3 command=
501
* 2 global:=
502
* 1 global=
503
*/
504
505
switch (type)
506
{
507
case EXTTYPE:
508
c = 4;
509
vp = &op->temp;
510
break;
511
case GLBTYPE:
512
c = 1;
513
vp = &op->perm;
514
break;
515
default:
516
c = 3;
517
vp = &op->perm;
518
break;
519
}
520
c += assignment;
521
message((-5, "option: %c %s level=%d:%d", type ? type : '-', op->name, op->level, c));
522
if (op->level > c)
523
continue;
524
if (y && (op->flags & (OPT_HEADER|OPT_READONLY)) == OPT_HEADER)
525
{
526
if (vp == &op->temp)
527
op->entry = ap->entry;
528
else
529
op->level = c;
530
if (*v)
531
{
532
op->flags |= OPT_SET;
533
if (op->flags & OPT_NUMBER)
534
vp->number = n;
535
stash(vp, v, 0);
536
}
537
else
538
vp = 0;
539
}
540
else
541
vp = 0;
542
message((-4, "option: %c %s%s%s=%s entry=%d:%d level=%d:%d number=%I*u", type ? type : '-', y ? "" : "no", op->name, assignment ? ":" : "", v, op->entry, ap ? ap->entry : 0, op->level, c, sizeof(n), n));
543
switch (op->index)
544
{
545
case OPT_action:
546
if (*v)
547
{
548
xp = action(v, 1);
549
if (!xp->re)
550
state.filter.all = xp;
551
else
552
{
553
if (state.filter.last)
554
state.filter.last->next = xp;
555
else
556
state.filter.list = xp;
557
state.filter.last = xp;
558
}
559
}
560
break;
561
case OPT_append:
562
state.append = y;
563
break;
564
case OPT_atime:
565
if (vp)
566
{
567
settime:
568
vp->number = strtoul(vp->string, &e, 10);
569
vp->fraction = 0;
570
if (*e)
571
{
572
if (*e != '.')
573
vp->number = tmdate(vp->string, &e, NiL);
574
if (*e == '.')
575
vp->fraction = strtoul(s = e + 1, &e, 10);
576
if (*e)
577
error(2, "%s: invalid %s date string", vp->string, options[op->index].name);
578
else if (vp->fraction)
579
{
580
y = e - s;
581
for (y = e - s; y < 9; y++)
582
vp->fraction *= 10;
583
for (; y > 9; y--)
584
vp->fraction /= 10;
585
}
586
}
587
}
588
break;
589
case OPT_base:
590
ap = getarchive(state.operation);
591
if (ap->delta)
592
error(3, "base archive already specified");
593
if (y)
594
{
595
initdelta(ap, NiL);
596
if (!*v || streq(v, "-"))
597
{
598
state.delta2delta++;
599
if (!(state.operation & OUT))
600
{
601
ap->delta->format = getformat(FMT_IGNORE, 1);
602
break;
603
}
604
v = "/dev/null";
605
}
606
ap->delta->base = initarchive(strdup(v), O_RDONLY);
607
}
608
break;
609
case OPT_blocksize:
610
if (y)
611
{
612
state.blocksize = n;
613
if (state.blocksize < MINBLOCK)
614
error(3, "block size must be at least %d", MINBLOCK);
615
if (state.blocksize & (BLOCKSIZE - 1))
616
error(1, "block size should probably be a multiple of %d", BLOCKSIZE);
617
}
618
else
619
state.blocksize = DEFBLOCKS * BLOCKSIZE;
620
break;
621
case OPT_blok:
622
if (!*v)
623
getarchive(IN)->io->blok = getarchive(OUT)->io->blok = n;
624
else
625
while (*v) switch (*v++)
626
{
627
case 'i':
628
getarchive(IN)->io->blok = 1;
629
break;
630
case 'o':
631
getarchive(OUT)->io->blok = 1;
632
break;
633
default:
634
error(3, "%s: [io] expected", op->name);
635
break;
636
}
637
break;
638
case OPT_checksum:
639
if (y)
640
{
641
if (e = strchr(v, ':'))
642
*e++ = 0;
643
else
644
{
645
e = v;
646
v = "md5";
647
}
648
state.checksum.name = strdup(e);
649
if (!(state.checksum.sum = sumopen(v)))
650
error(3, "%s: %s: unknown checksum algorithm", e, v);
651
}
652
else
653
state.checksum.name = 0;
654
break;
655
case OPT_chmod:
656
if (y && *v)
657
{
658
strperm(v, &e, 0);
659
if (*e)
660
error(3, "%s: invalid file mode expression", v);
661
state.mode = strdup(v);
662
}
663
else
664
state.mode = 0;
665
break;
666
case OPT_clobber:
667
state.clobber = y;
668
break;
669
case OPT_comment:
670
state.header.comment = y ? strdup(v) : (char*)0;
671
break;
672
case OPT_complete:
673
state.complete = y;
674
break;
675
case OPT_crossdevice:
676
if (!y)
677
state.ftwflags |= FTW_MOUNT;
678
else
679
state.ftwflags &= ~FTW_MOUNT;
680
break;
681
case OPT_ctime:
682
if (vp)
683
goto settime;
684
break;
685
case OPT_debug:
686
if (y)
687
{
688
y = error_info.trace;
689
error_info.trace = -(int)n;
690
if (!y)
691
message((-10, "usage %s", usage));
692
}
693
else
694
error_info.trace = 0;
695
break;
696
case OPT_delete:
697
if (y && *v)
698
sfprintf(opt.ignore_all, "%s(%s)", sfstrtell(opt.ignore_all) ? "|" : "", v);
699
break;
700
case OPT_delta_base_checksum:
701
if (ap && ap->delta)
702
ap->delta->checksum = n;
703
break;
704
case OPT_delta_base_size:
705
if (ap && ap->delta)
706
ap->delta->size = n;
707
break;
708
case OPT_delta_checksum:
709
if (ap)
710
ap->file.delta.checksum = n;
711
break;
712
case OPT_delta_compress:
713
if (ap && ap->delta)
714
ap->delta->compress = 1;
715
break;
716
case OPT_delta_index:
717
if (ap)
718
{
719
if (type == GLBTYPE)
720
{
721
if (ap->delta && (c = n - ap->delta->index - 1))
722
{
723
if (c > 0)
724
error(2, "%s: corrupt archive: %d missing file%s", ap->name, c, c == 1 ? "" : "s");
725
else
726
error(2, "%s: corrupt archive: %d extra file%s", ap->name, -c, -c == 1 ? "" : "s");
727
}
728
}
729
else
730
ap->file.delta.index = n;
731
}
732
break;
733
case OPT_delta_method:
734
if (ap)
735
{
736
if (!(fp = getformat(v, 0)) || !(fp->flags & DELTA))
737
error(3, "%s: %s: delta method not supported", ap->name, v);
738
initdelta(ap, fp);
739
}
740
break;
741
case OPT_delta_op:
742
if (ap && ap->delta)
743
ap->file.delta.op = line ? *v : n;
744
break;
745
case OPT_delta_ordered:
746
if (ap && ap->delta)
747
ap->delta->ordered = n;
748
break;
749
case OPT_delta_update:
750
state.delta.update = y;
751
break;
752
case OPT_delta_version:
753
break;
754
case OPT_descend:
755
state.descend = y;
756
break;
757
case OPT_different:
758
case OPT_newer:
759
case OPT_update:
760
state.update = y ? op->index : 0;
761
break;
762
case OPT_dots:
763
state.drop = y;
764
break;
765
case OPT_edit:
766
substitute(&opt.lastmap, (char*)v);
767
break;
768
case OPT_eom:
769
eomprompt = y ? strdup(v) : (char*)0;
770
break;
771
case OPT_exact:
772
state.exact = y;
773
break;
774
case OPT_extended_name:
775
state.header.extended = y ? strdup(v) : (char*)0;
776
break;
777
case OPT_file:
778
ap = getarchive(state.operation);
779
if (ap->name)
780
error(3, "%s: %s: archive name already specified", v, ap->name);
781
ap->name = strdup(v);
782
break;
783
case OPT_filter:
784
if (y && *v)
785
{
786
state.filter.command = v;
787
state.descend = 0;
788
}
789
else
790
state.filter.command = 0;
791
break;
792
case OPT_format:
793
ap = getarchive(state.operation);
794
if (!y)
795
ap->format = 0;
796
else if (s = strdup(v))
797
{
798
v = s;
799
do
800
{
801
for (e = s, o = 0;;)
802
{
803
switch (*e++)
804
{
805
case 0:
806
e = 0;
807
break;
808
case ' ':
809
case '\t':
810
case '\n':
811
case ':':
812
case ',':
813
case '.':
814
*(e - 1) = 0;
815
if (*s)
816
break;
817
s = e;
818
continue;
819
case '=':
820
if (!o)
821
{
822
*(e - 1) = 0;
823
o = e;
824
}
825
continue;
826
default:
827
continue;
828
}
829
break;
830
}
831
if (!(fp = getformat(s, 0)) && s == v && s[0] == 't' && !strchr(s, ':') && (fp = getformat(s + 1, 0)))
832
{
833
if (ap->format = getformat("tar", 0))
834
s++;
835
else
836
fp = 0;
837
}
838
if (!fp)
839
{
840
if (!pathpath("lib/pax", opt.arg0, PATH_EXECUTE, tmp1, sizeof(tmp1)) || sfsprintf(tmp2, sizeof(tmp2) - 1, "%s/%s.fmt", tmp1, s) <= 0 || !(sp = sfopen(NiL, tmp2, "r")))
841
error(3, "%s: unknown archive format", s);
842
while (e = sfgetr(sp, '\n', 1))
843
if (*e != '#')
844
{
845
setoptions(e, sfvalue(sp), NiL, state.usage, ap, type);
846
if (line && !hdr)
847
line += opt_info.offset;
848
}
849
sfclose(sp);
850
}
851
else
852
{
853
fp->details = o;
854
switch (fp->flags & (ARCHIVE|COMPRESS|DELTA))
855
{
856
case ARCHIVE:
857
ap->format = fp;
858
break;
859
case COMPRESS:
860
ap->compress = fp;
861
break;
862
case DELTA:
863
initdelta(ap, fp);
864
break;
865
}
866
}
867
} while (s = e);
868
}
869
ap->expected = ap->format;
870
if (!state.operation)
871
state.format = ap->format;
872
break;
873
case OPT_from:
874
case OPT_to:
875
if (!cvt)
876
{
877
cvt = 1;
878
from = to = CC_NATIVE;
879
}
880
ap = getarchive(state.operation);
881
if ((y = ccmapid(v)) < 0)
882
error(3, "%s: unknown character code set", v);
883
switch (op->index)
884
{
885
case OPT_from:
886
from = y;
887
break;
888
case OPT_to:
889
to = y;
890
break;
891
}
892
break;
893
case OPT_global_name:
894
state.header.global = y ? strdup(v) : (char*)0;
895
break;
896
case OPT_header:
897
v = y ? strdup(v) : (char*)0;
898
if (assignment)
899
state.header.extended = v;
900
else
901
state.header.global = v;
902
break;
903
case OPT_ignore:
904
if (y && *v)
905
{
906
if (assignment)
907
sfprintf(opt.ignore_ext, "%s(%s)", sfstrtell(opt.ignore_ext) ? "|" : "", v);
908
else
909
sfprintf(opt.ignore_all, "%s(%s)", sfstrtell(opt.ignore_all) ? "|" : "", v);
910
}
911
break;
912
case OPT_install:
913
state.install.name = y ? strdup(v) : (char*)0;
914
break;
915
case OPT_intermediate:
916
state.intermediate = y;
917
break;
918
case OPT_invalid:
919
if (line)
920
{
921
n = 0;
922
y = strlen(v);
923
s = op->details;
924
while (s = strchr(s, '['))
925
{
926
c = *++s;
927
o = ++s;
928
for (;;)
929
{
930
if (strneq(v, o, y))
931
{
932
s = "";
933
n = c;
934
break;
935
}
936
if (!(o = strchr(o, '|')))
937
break;
938
o++;
939
}
940
}
941
}
942
switch ((int)n)
943
{
944
case 'b':
945
state.header.invalid = INVALID_binary;
946
break;
947
case 'i':
948
state.header.invalid = INVALID_ignore;
949
break;
950
case 'p':
951
state.header.invalid = INVALID_prompt;
952
break;
953
case 't':
954
state.header.invalid = INVALID_translate;
955
break;
956
case 'u':
957
state.header.invalid = INVALID_UTF8;
958
break;
959
default:
960
error(2, "%s: %s: unknown option value", op->name, v);
961
break;
962
}
963
break;
964
case OPT_invert:
965
state.matchsense = !y;
966
break;
967
case OPT_keepgoing:
968
state.keepgoing = y;
969
break;
970
case OPT_label:
971
if (*state.volume)
972
{
973
if (assignment)
974
sfsprintf(tmp1, sizeof(tmp1), "%s %s", v, state.volume);
975
else
976
sfsprintf(tmp1, sizeof(tmp1), "%s %s", state.volume, v);
977
v = tmp1;
978
}
979
strncpy(state.volume, v, sizeof(state.volume) - 2);
980
break;
981
case OPT_link:
982
if (y)
983
state.linkf = link;
984
else
985
state.linkf = 0;
986
break;
987
case OPT_linkdata:
988
state.header.linkdata = y;
989
break;
990
case OPT_listformat:
991
if (y && *v)
992
sfputr(opt.listformat, v, ' ');
993
break;
994
case OPT_listmacro:
995
if (y && *v)
996
{
997
if (s = strchr(v, '='))
998
*s++ = 0;
999
if (!(op = (Option_t*)hashget(state.options, v)))
1000
{
1001
if (!s)
1002
break;
1003
if (!(op = newof(0, Option_t, 1, 0)))
1004
nospace();
1005
op->name = hashput(state.options, 0, op);
1006
}
1007
if (s)
1008
{
1009
op->macro = strdup(s);
1010
*(s - 1) = 0;
1011
}
1012
else
1013
op->macro = 0;
1014
}
1015
break;
1016
case OPT_local:
1017
state.local = 1;
1018
break;
1019
case OPT_logical:
1020
if (y)
1021
state.ftwflags &= ~FTW_PHYSICAL;
1022
else
1023
state.ftwflags |= FTW_PHYSICAL;
1024
break;
1025
case OPT_maxout:
1026
state.maxout = n;
1027
break;
1028
case OPT_metaphysical:
1029
if (y)
1030
state.ftwflags |= FTW_META|FTW_PHYSICAL;
1031
else
1032
state.ftwflags &= ~(FTW_META|FTW_PHYSICAL);
1033
break;
1034
case OPT_meter:
1035
if (state.meter.on = y)
1036
{
1037
if (!(state.meter.tmp = sfstropen()))
1038
nospace();
1039
if (state.meter.fancy = isatty(sffileno(sfstderr)))
1040
{
1041
error_info.write = meterror;
1042
astwinsize(1, NiL, &state.meter.width);
1043
if (state.meter.width < 2 * (METER_width + 1))
1044
state.meter.width = 2 * (METER_width + 1);
1045
}
1046
}
1047
break;
1048
case OPT_mkdir:
1049
state.mkdir = y;
1050
break;
1051
case OPT_mtime:
1052
if (vp)
1053
goto settime;
1054
break;
1055
case OPT_options:
1056
if (v)
1057
{
1058
setoptions(v, 0, NiL, usage, ap, type);
1059
if (line && !hdr)
1060
line += opt_info.offset;
1061
}
1062
break;
1063
case OPT_ordered:
1064
state.ordered = y;
1065
break;
1066
case OPT_owner:
1067
if (!(state.owner = y))
1068
opt.owner = 0;
1069
else if (*v)
1070
opt.owner = strdup(v);
1071
break;
1072
case OPT_passphrase:
1073
state.passphrase = y ? strdup(v) : (char*)0;
1074
break;
1075
case OPT_physical:
1076
if (y)
1077
{
1078
state.ftwflags &= ~FTW_META;
1079
state.ftwflags |= FTW_PHYSICAL;
1080
}
1081
else
1082
state.ftwflags &= ~FTW_PHYSICAL;
1083
break;
1084
case OPT_preserve:
1085
for (;;)
1086
{
1087
switch (*v++)
1088
{
1089
case 0:
1090
break;
1091
case 'a':
1092
state.acctime = 0;
1093
continue;
1094
case 'e':
1095
state.acctime = 1;
1096
state.modtime = 1;
1097
state.owner = 1;
1098
state.modemask = 0;
1099
state.chmod = 1;
1100
continue;
1101
case 'm':
1102
state.modtime = 0;
1103
continue;
1104
case 'o':
1105
state.owner = 1;
1106
continue;
1107
case 'p':
1108
state.modemask &= (S_ISUID|S_ISGID);
1109
state.chmod = 1;
1110
continue;
1111
case 's':
1112
state.modemask &= ~(S_ISUID|S_ISGID);
1113
continue;
1114
default:
1115
error(1, "%s=%c: unknown flag", op->name, *(v - 1));
1116
continue;
1117
}
1118
break;
1119
}
1120
break;
1121
case OPT_read:
1122
if (y)
1123
state.operation |= IN;
1124
else
1125
state.operation &= ~IN;
1126
break;
1127
case OPT_record_charset:
1128
state.record.charset = y;
1129
break;
1130
case OPT_record_delimiter:
1131
if (!y)
1132
state.record.delimiter = 0;
1133
else
1134
state.record.delimiter = *v;
1135
break;
1136
case OPT_record_format:
1137
state.record.format = y ? *v : 0;
1138
break;
1139
case OPT_record_header:
1140
if (!y)
1141
{
1142
state.record.header = 0;
1143
state.record.headerlen = 0;
1144
}
1145
else if (!(state.record.headerlen = stresc(state.record.header = strdup(v))))
1146
state.record.headerlen = 1;
1147
break;
1148
case OPT_record_line:
1149
state.record.line = y;
1150
break;
1151
case OPT_record_match:
1152
state.record.pattern = y ? strdup(v) : (char*)0;
1153
break;
1154
case OPT_record_pad:
1155
state.record.pad = y;
1156
break;
1157
case OPT_record_size:
1158
state.record.size = n;
1159
break;
1160
case OPT_record_trailer:
1161
if (!y)
1162
{
1163
state.record.trailer = 0;
1164
state.record.trailerlen = 0;
1165
}
1166
else if (!(state.record.trailerlen = stresc(state.record.trailer = strdup(v))))
1167
state.record.trailerlen = 1;
1168
break;
1169
case OPT_reset_atime:
1170
state.resetacctime = y;
1171
break;
1172
case OPT_size:
1173
break;
1174
case OPT_strict:
1175
state.strict = y;
1176
break;
1177
case OPT_summary:
1178
state.summary = y;
1179
break;
1180
case OPT_symlink:
1181
if (y)
1182
state.linkf = pathsetlink;
1183
else
1184
state.linkf = 0;
1185
break;
1186
case OPT_sync:
1187
#if _lib_fsync
1188
state.sync = y;
1189
#else
1190
error(1, "%s not implemented on this system", op->name);
1191
#endif
1192
break;
1193
case OPT_tape:
1194
ap = getarchive(state.operation);
1195
if (ap->name)
1196
error(3, "%s: %s: archive name already specified", v, ap->name);
1197
s = strtape(v, &e);
1198
if (*s)
1199
ap->name = s;
1200
for (;;)
1201
{
1202
switch (*e++)
1203
{
1204
case 'k':
1205
if (!(n = strtonll(e, &e, 0, 1)))
1206
n = -1;
1207
ap->io->keep = n;
1208
ap->io->mode = O_RDWR;
1209
continue;
1210
case 's':
1211
if (!(n = strtonll(e, &e, 0, 1)))
1212
n = -1;
1213
ap->io->skip = n;
1214
ap->io->mode = O_RDWR;
1215
continue;
1216
}
1217
e--;
1218
break;
1219
}
1220
if (*e)
1221
error(3, "%s: invalid tape unit specification [%s]", v, e);
1222
break;
1223
case OPT_test:
1224
if (y)
1225
state.test |= (unsigned long)n;
1226
else
1227
state.test = 0;
1228
break;
1229
case OPT_testdate:
1230
if (y)
1231
{
1232
state.testdate = tmdate(v, &e, NiL);
1233
if (*e)
1234
error(3, "%s: invalid %s date string", v, options[op->index].name);
1235
}
1236
else
1237
state.testdate = ~0;
1238
break;
1239
case OPT_times:
1240
if (y)
1241
{
1242
setoptions("atime:= ctime:= mtime:=", 0, NiL, usage, ap, type);
1243
if (line && !hdr)
1244
line += opt_info.offset;
1245
}
1246
break;
1247
case OPT_unblocked:
1248
if (!*v)
1249
getarchive(IN)->io->unblocked = getarchive(OUT)->io->unblocked = y;
1250
else
1251
while (*v) switch (*v++)
1252
{
1253
case 'i':
1254
getarchive(IN)->io->unblocked = 1;
1255
break;
1256
case 'o':
1257
getarchive(OUT)->io->unblocked = 1;
1258
break;
1259
default:
1260
error(3, "%s: [io] expected", op->name);
1261
break;
1262
}
1263
break;
1264
case OPT_uncompressed:
1265
ap->file.uncompressed = n;
1266
break;
1267
case OPT_verbose:
1268
state.verbose = y;
1269
break;
1270
case OPT_verify:
1271
state.verify = y;
1272
break;
1273
case OPT_warn:
1274
state.warn = y;
1275
break;
1276
case OPT_write:
1277
if (y)
1278
state.operation |= OUT;
1279
else
1280
state.operation &= ~OUT;
1281
if (!(state.operation & IN) && state.in && !state.out)
1282
{
1283
state.out = state.in;
1284
state.in = 0;
1285
state.out->io->mode = O_CREAT|O_TRUNC|O_WRONLY;
1286
}
1287
break;
1288
case OPT_yes:
1289
state.verify = state.yesno = y;
1290
break;
1291
default:
1292
if (!type && !(op->flags & OPT_HEADER) || !(op->flags & (OPT_IGNORE|OPT_SET)))
1293
error(1, "%s: option ignored [index=%d]", op->name, op->index);
1294
break;
1295
}
1296
}
1297
if (line && !hdr)
1298
{
1299
opt_info.index = index;
1300
opt_info.offset = offset;
1301
}
1302
if (cvt)
1303
{
1304
ap->convert[0].on = 1;
1305
convert(ap, SECTION_DATA, from, to);
1306
}
1307
}
1308
1309
/*
1310
* option match with VENDOR check
1311
*/
1312
1313
static int
1314
matchopt(const char* name, const char* pattern, Option_t* op)
1315
{
1316
return strmatch(name, pattern) || (op->flags & OPT_VENDOR) && strmatch(sfprints("%s.%s", VENDOR, name), pattern);
1317
}
1318
1319
/*
1320
* mark ignored header keywords
1321
*/
1322
1323
static void
1324
ignore(void)
1325
{
1326
register Option_t* op;
1327
Hash_position_t* pos;
1328
char* all;
1329
char* ext;
1330
int lev;
1331
1332
if (!sfstrtell(opt.ignore_all))
1333
all = 0;
1334
else if (!(all = sfstruse(opt.ignore_all)))
1335
nospace();
1336
if (!sfstrtell(opt.ignore_ext))
1337
ext = 0;
1338
else if (!(ext = sfstruse(opt.ignore_ext)))
1339
nospace();
1340
if ((all || ext) && (pos = hashscan(state.options, 0)))
1341
{
1342
while (hashnext(pos))
1343
{
1344
op = (Option_t*)pos->bucket->value;
1345
if (!(op->flags & OPT_READONLY) && (all && matchopt(pos->bucket->name, all, op) && (lev = 8) || ext && matchopt(pos->bucket->name, ext, op) && (lev = 6)) && op->level < lev)
1346
op->level = lev;
1347
}
1348
hashdone(pos);
1349
}
1350
sfstrclose(opt.ignore_all);
1351
sfstrclose(opt.ignore_ext);
1352
}
1353
1354
/*
1355
* list fp for optinfo()
1356
*/
1357
1358
static void
1359
listformat(register Sfio_t* sp, register Format_t* fp)
1360
{
1361
register const char* p;
1362
register int c;
1363
1364
sfprintf(sp, "[+%s", fp->name);
1365
if (p = fp->match)
1366
{
1367
sfputc(sp, '|');
1368
if (*p == '(')
1369
p++;
1370
while (c = *p++)
1371
{
1372
if (c == ')' && !*p)
1373
break;
1374
if (c == '?' || c == ']')
1375
sfputc(sp, c);
1376
sfputc(sp, c);
1377
}
1378
}
1379
sfputc(sp, '?');
1380
p = fp->desc;
1381
while (c = *p++)
1382
{
1383
if (c == ']')
1384
sfputc(sp, c);
1385
sfputc(sp, c);
1386
}
1387
switch (fp->flags & (IN|OUT))
1388
{
1389
case 0:
1390
sfputr(sp, "; for listing only", -1);
1391
break;
1392
case IN:
1393
sfputr(sp, "; for input only", -1);
1394
break;
1395
case OUT:
1396
sfputr(sp, "; for output only", -1);
1397
break;
1398
}
1399
sfputc(sp, ']');
1400
}
1401
1402
/*
1403
* optget() info discipline function
1404
*/
1405
1406
static int
1407
optinfo(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
1408
{
1409
register Format_t* fp;
1410
register iconv_list_t* ic;
1411
register const char* p;
1412
register int i;
1413
register int c;
1414
Ardirmeth_t* ar;
1415
1416
switch (*s)
1417
{
1418
case 'c':
1419
for (ic = iconv_list(NiL); ic; ic = iconv_list(ic))
1420
{
1421
sfputc(sp, '[');
1422
sfputc(sp, '+');
1423
sfputc(sp, '\b');
1424
p = ic->match;
1425
if (*p == '(')
1426
p++;
1427
while (c = *p++)
1428
{
1429
if (c == ')' && !*p)
1430
break;
1431
if (c == '?' || c == ']')
1432
sfputc(sp, c);
1433
sfputc(sp, c);
1434
}
1435
sfputc(sp, '?');
1436
p = ic->desc;
1437
while (c = *p++)
1438
{
1439
if (c == ']')
1440
sfputc(sp, c);
1441
sfputc(sp, c);
1442
}
1443
sfputc(sp, ']');
1444
}
1445
break;
1446
case 'd':
1447
sfputr(sp, FMT_DEFAULT, -1);
1448
break;
1449
case 'D':
1450
fp = 0;
1451
while (fp = nextformat(fp))
1452
if (fp->flags & DELTA)
1453
{
1454
sfprintf(sp, "[+%s", fp->name);
1455
sfputc(sp, '?');
1456
p = fp->desc;
1457
while (c = *p++)
1458
{
1459
if (c == ']')
1460
sfputc(sp, c);
1461
sfputc(sp, c);
1462
}
1463
sfputc(sp, ']');
1464
}
1465
break;
1466
case 'f':
1467
fp = 0;
1468
while (fp = nextformat(fp))
1469
if (fp->flags & ARCHIVE)
1470
listformat(sp, fp);
1471
ar = 0;
1472
while (ar = ardirlist(ar))
1473
sfprintf(sp, "[+%s?%s; for input only]", ar->name, ar->description);
1474
sfprintf(sp, "[+----?compression methods ----]");
1475
fp = 0;
1476
while (fp = nextformat(fp))
1477
if (fp->flags & COMPRESS)
1478
listformat(sp, fp);
1479
sfprintf(sp, "[+----?delta methods ----]");
1480
fp = 0;
1481
while (fp = nextformat(fp))
1482
if (fp->flags & DELTA)
1483
listformat(sp, fp);
1484
break;
1485
break;
1486
case 'l':
1487
for (i = 1; options[i].name; i++)
1488
if ((options[i].flags & (OPT_GLOBAL|OPT_READONLY)) == OPT_READONLY)
1489
{
1490
sfprintf(sp, "[+%s?%s]\n", options[i].name, options[i].description);
1491
if (options[i].details)
1492
sfprintf(sp, "{\n%s\n}", options[i].details);
1493
}
1494
sfprintf(sp, "%s",
1495
" [+----?subformats ----]"
1496
" [+case\b::\bp\b\a1\a::\bs\b\a1\a::...::\bp\b\an\a::\bs\b\an\a?Expands"
1497
" to \bs\b\ai\a if the value of \aid\a matches the shell"
1498
" pattern \bp\b\ai\a, or the empty string if there is no"
1499
" match.]"
1500
" [+mode?The integral value as a \bfmtmode\b(3) string.]"
1501
" [+perm?The integral value as a \bfmtperm\b(3) string.]"
1502
" [+time[=\aformat\a]]?The integral value as a \bstrftime\b(3)"
1503
" string. For example,"
1504
" \b--format=\"%8(mtime)u %(ctime:time=%H:%M:%S)s\"\b"
1505
" lists the mtime in seconds since the epoch and the"
1506
" ctime as hours:minutes:seconds.]");
1507
break;
1508
}
1509
return 0;
1510
}
1511
1512
int
1513
main(int argc, char** argv)
1514
{
1515
register int i;
1516
register char* s;
1517
register Archive_t* ap;
1518
char* p;
1519
Hash_position_t* pos;
1520
Option_t* op;
1521
int n;
1522
int pass = 0;
1523
unsigned long blocksize;
1524
struct stat st;
1525
Optdisc_t optdisc;
1526
1527
static Format_t rw = { "rw", 0, 0, 0, IN|OUT };
1528
1529
setlocale(LC_ALL, "");
1530
paxinit(&state, error_info.id = "pax");
1531
optinit(&optdisc, optinfo);
1532
state.strict = !!conformance(0, 0);
1533
state.gid = getegid();
1534
state.uid = geteuid();
1535
state.pid = getpid();
1536
umask(state.modemask = umask(0));
1537
state.modemask |= S_ISUID|S_ISGID;
1538
state.ftwflags = ftwflags()|FTW_DOT;
1539
state.acctime = 1;
1540
state.buffersize = DEFBUFFER * DEFBLOCKS;
1541
state.clobber = 1;
1542
state.delta.buffersize = DELTA_WINDOW >> 1;
1543
state.descend = RESETABLE;
1544
state.format = getformat(FMT_DEFAULT, 1);
1545
state.header.extended = state.strict ? HEADER_EXTENDED_STD : HEADER_EXTENDED;
1546
state.header.global = state.strict ? HEADER_GLOBAL_STD : HEADER_GLOBAL;
1547
state.map.a2n = ccmap(CC_ASCII, CC_NATIVE);
1548
state.map.e2n = ccmap(CC_EBCDIC, CC_NATIVE);
1549
state.map.n2e = ccmap(CC_NATIVE, CC_EBCDIC);
1550
if (!(opt.ignore_all = sfstropen()) || !(opt.ignore_ext = sfstropen()))
1551
nospace();
1552
if (!(opt.listformat = sfstropen()))
1553
nospace();
1554
state.matchsense = 1;
1555
state.mkdir = 1;
1556
state.modtime = 1;
1557
if (!(state.tmp.fmt = sfstropen()) || !(state.tmp.lst = sfstropen()) || !(state.tmp.str = sfstropen()))
1558
nospace();
1559
stash(&options[OPT_release].perm, release(), 0);
1560
options[OPT_release].flags |= OPT_SET;
1561
if (!(state.options = hashalloc(NiL, HASH_name, "options", 0)))
1562
nospace();
1563
for (i = 1; options[i].name; i++)
1564
{
1565
p = options[i].name;
1566
if (strchr(p, '|'))
1567
p = strdup(p);
1568
do
1569
{
1570
if (s = strchr(p, '|'))
1571
*s++ = 0;
1572
hashput(state.options, p, &options[options[i].index]);
1573
} while (p = s);
1574
}
1575
hashset(state.options, HASH_ALLOCATE);
1576
state.record.charset = 1;
1577
state.record.line = 1;
1578
state.summary = 1;
1579
state.testdate = ~0;
1580
if (!(state.tmp.file = pathtemp(NiL, 0, NiL, error_info.id, NiL)))
1581
nospace();
1582
sfputr(state.tmp.str, usage, -1);
1583
for (i = 1; options[i].name; i++)
1584
if ((options[i].flags & (OPT_GLOBAL|OPT_READONLY)) != OPT_READONLY)
1585
{
1586
sfputc(state.tmp.str, '[');
1587
if (options[i].flag)
1588
{
1589
sfputc(state.tmp.str, options[i].flag);
1590
if (options[i].flags & OPT_INVERT)
1591
sfputc(state.tmp.str, '!');
1592
}
1593
sfprintf(state.tmp.str, "=%d:%s", options[i].index, options[i].name);
1594
if (options[i].flags & OPT_VENDOR)
1595
{
1596
for (s = (char*)options[i].name; p = strchr(s, '|'); s = p + 1)
1597
sfprintf(state.tmp.str, "|%s.%-.*s", VENDOR, p - s, s);
1598
sfprintf(state.tmp.str, "|%s.%s", VENDOR, s);
1599
}
1600
sfprintf(state.tmp.str, "?%s]", options[i].description);
1601
if (options[i].argument)
1602
{
1603
sfputc(state.tmp.str, (options[i].flags & OPT_NUMBER) ? '#' : ':');
1604
if (options[i].flags & OPT_OPTIONAL)
1605
sfputc(state.tmp.str, '?');
1606
sfprintf(state.tmp.str, "[%s]", options[i].argument);
1607
}
1608
if (options[i].details)
1609
sfprintf(state.tmp.str, "\n{%s}", options[i].details);
1610
sfputc(state.tmp.str, '\n');
1611
}
1612
sfputr(state.tmp.str, usage2, -1);
1613
if (!(state.usage = sfstruse(state.tmp.str)))
1614
nospace();
1615
opt.arg0 = argv[0];
1616
setoptions(NiL, 0, argv, state.usage, NiL, 0);
1617
argv += opt_info.index;
1618
argc -= opt_info.index;
1619
if (error_info.errors)
1620
error(ERROR_USAGE|4, "%s", optusage(NiL));
1621
if (!state.operation)
1622
{
1623
state.operation = IN;
1624
state.list = 1;
1625
}
1626
if (!sfstrtell(opt.listformat))
1627
sfputr(opt.listformat, (state.list && state.verbose) ? "%(mode)s %2(nlink)d %-8(uname)s %-8(gname)s%8(device:case::%(size)llu:*:%(device)s)s %(mtime)s %(delta.op:case:?*:%(delta.op)s )s%(path)s%(linkop:case:?*: %(linkop)s %(linkpath)s)s" : "%(delta.op:case:?*:%(delta.op)s )s%(path)s%(linkop:case:?*: %(linkop)s %(linkpath)s)s", ' ');
1628
sfstrseek(opt.listformat, -1, SEEK_CUR);
1629
if (!state.meter.on)
1630
sfputc(opt.listformat, '\n');
1631
if (!(state.listformat = strdup(sfstruse(opt.listformat))))
1632
nospace();
1633
sfstrclose(opt.listformat);
1634
ignore();
1635
if (s = state.filter.command)
1636
{
1637
if (streq(s, "-"))
1638
{
1639
state.filter.line = -1;
1640
s = "sh -c";
1641
}
1642
state.filter.all = action(s, 0);
1643
}
1644
if (state.filter.last)
1645
state.filter.last->next = state.filter.all;
1646
else
1647
state.filter.list = state.filter.all;
1648
state.statf = (state.ftwflags & FTW_PHYSICAL) ? lstat : pathstat;
1649
1650
/*
1651
* determine the buffer sizes
1652
*/
1653
1654
switch (state.operation)
1655
{
1656
case IN|OUT:
1657
if (!state.in)
1658
break;
1659
/*FALLTHROUGH*/
1660
case IN:
1661
case OUT:
1662
getarchive(state.operation);
1663
break;
1664
}
1665
blocksize = state.blocksize;
1666
if (ap = state.out)
1667
{
1668
if (!ap->format)
1669
ap->format = state.format;
1670
else if (state.operation == (IN|OUT))
1671
pass = 1;
1672
if (state.operation == OUT)
1673
{
1674
if (state.files)
1675
state.ftwflags |= FTW_POST;
1676
}
1677
if (state.append || state.update)
1678
ap->io->mode = O_RDWR|O_CREAT;
1679
ap->io->fd = 1;
1680
if (!ap->name || streq(ap->name, "-"))
1681
ap->name = defoutput;
1682
else
1683
{
1684
close(1);
1685
if (open(ap->name, ap->io->mode|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1)
1686
error(ERROR_SYSTEM|3, "%s: cannot write", ap->name);
1687
}
1688
if (fstat(ap->io->fd, &st))
1689
error(ERROR_SYSTEM|3, "%s: cannot stat", ap->name);
1690
if (S_ISREG(st.st_mode))
1691
{
1692
ap->io->seekable = 1;
1693
ap->io->size = st.st_size;
1694
}
1695
if (!state.blocksize)
1696
{
1697
st.st_mode = modex(st.st_mode);
1698
if (state.test & 0000040)
1699
st.st_mode = X_IFCHR;
1700
if (X_ITYPE(st.st_mode) == X_IFREG)
1701
{
1702
state.blocksize = ap->format->regular;
1703
ap->io->unblocked = 1;
1704
}
1705
else
1706
state.blocksize = ap->format->special;
1707
state.buffersize = state.blocksize *= BLOCKSIZE;
1708
}
1709
}
1710
else
1711
{
1712
if (state.blocksize)
1713
state.buffersize = state.blocksize;
1714
else
1715
state.blocksize = (state.operation == (IN|OUT) ? FILBLOCKS : DEFBLOCKS) * BLOCKSIZE;
1716
if (state.record.size)
1717
error(1, "record size automatically determined on archive read");
1718
}
1719
if (ap = state.in)
1720
{
1721
if (!ap->name || streq(ap->name, "-"))
1722
ap->name = definput;
1723
else
1724
{
1725
close(0);
1726
if (open(ap->name, ap->io->mode|O_BINARY))
1727
error(ERROR_SYSTEM|3, "%s: cannot read", ap->name);
1728
}
1729
if (fstat(ap->io->fd, &st))
1730
error(ERROR_SYSTEM|3, "%s: cannot stat", ap->name);
1731
if (S_ISREG(st.st_mode))
1732
{
1733
ap->io->seekable = 1;
1734
ap->io->size = st.st_size;
1735
}
1736
if (state.meter.on && !(state.meter.size = ap->io->size))
1737
state.meter.on = 0;
1738
}
1739
if (!blocksize && (blocksize = bblock(!state.in)))
1740
state.blocksize = blocksize;
1741
if (state.buffersize < state.blocksize)
1742
state.buffersize = state.blocksize;
1743
state.tmp.buffersize = state.buffersize;
1744
if (!(state.tmp.buffer = newof(0, char, state.tmp.buffersize, 0)))
1745
nospace();
1746
if (state.maxout && state.maxout <= state.blocksize)
1747
error(3, "--maxout=%#i must be greater than --blocksize=%#i", state.maxout, state.blocksize);
1748
message((-1, "blocksize=%d buffersize=%d recordsize=%d", state.blocksize, state.buffersize, state.record.size));
1749
1750
/*
1751
* initialize the main io
1752
*/
1753
1754
switch (state.operation)
1755
{
1756
case IN:
1757
case OUT:
1758
getarchive(state.operation);
1759
break;
1760
}
1761
if (ap = state.in)
1762
{
1763
binit(ap);
1764
if (state.append && !state.out)
1765
{
1766
error(1, "append ignored for archive read");
1767
state.append = 0;
1768
}
1769
}
1770
if (ap = state.out)
1771
{
1772
if (!ap->format)
1773
ap->format = state.format;
1774
if (state.append || state.update)
1775
{
1776
if (ap->delta)
1777
{
1778
error(1, "append/update ignored for archive delta");
1779
state.update = 0;
1780
}
1781
if (state.append && state.update)
1782
{
1783
error(1, "append ignored for archive update");
1784
state.append = 0;
1785
}
1786
if (!ap->io->seekable)
1787
error(3, "%s: append/update requires seekable archive", ap->name);
1788
else if (!ap->io->size)
1789
state.append = state.update = 0;
1790
else
1791
{
1792
initdelta(ap, NiL);
1793
ap->delta->base = ap;
1794
}
1795
}
1796
binit(ap);
1797
if (ap->compress)
1798
{
1799
Proc_t* proc;
1800
List_t* p;
1801
char* cmd[4];
1802
1803
cmd[0] = ap->compress->name;
1804
i = 1;
1805
if (cmd[i] = ((Compress_format_t*)ap->compress->data)->variant)
1806
i++;
1807
if (cmd[i] = ap->compress->details)
1808
i++;
1809
cmd[i] = 0;
1810
if (!(proc = procopen(*cmd, cmd, NiL, NiL, PROC_WRITE)))
1811
error(3, "%s: cannot execute %s filter", ap->name, ap->compress->name);
1812
n = proc->wfd;
1813
proc->wfd = 1;
1814
close(1);
1815
if (dup(n) != 1)
1816
error(3, "%s: cannot redirect %s filter output", ap->name, ap->compress->name);
1817
close(n);
1818
if (!(p = newof(0, List_t, 1, 0)))
1819
nospace();
1820
p->item = (void*)proc;
1821
p->next = state.proc;
1822
state.proc = p;
1823
}
1824
if (state.checksum.name)
1825
{
1826
if (!(state.checksum.path = pathtemp(NiL, 0, NiL, error_info.id, NiL)))
1827
nospace();
1828
if (!(state.checksum.sp = sfopen(NiL, state.checksum.path, "w")))
1829
error(3, "%s: cannot write checksum temporary", state.checksum.path);
1830
sfprintf(state.checksum.sp, "method=%s\n", state.checksum.sum->name);
1831
sfprintf(state.checksum.sp, "permissions\n");
1832
}
1833
if (state.install.name)
1834
{
1835
if (!(state.install.path = pathtemp(NiL, 0, NiL, error_info.id, NiL)))
1836
nospace();
1837
if (!(state.install.sp = sfopen(NiL, state.install.path, "w")))
1838
error(3, "%s: cannot write install temporary", state.install.path);
1839
}
1840
}
1841
if (!(state.linktab = hashalloc(NiL, HASH_set, HASH_ALLOCATE, HASH_namesize, sizeof(Fileid_t), HASH_name, "links", 0)))
1842
error(3, "cannot allocate hard link table");
1843
if ((state.operation & IN) && !state.list && !(state.restore = hashalloc(NiL, HASH_set, HASH_ALLOCATE, HASH_name, "restore", 0)))
1844
error(3, "cannot allocate directory table");
1845
if (state.owner)
1846
{
1847
if (state.operation & IN)
1848
{
1849
state.modemask = 0;
1850
if (opt.owner)
1851
{
1852
if ((state.setuid = struid(opt.owner)) < 0 || (state.setgid = strgid(opt.owner)) < 0)
1853
error(3, "%s: invalid user name", opt.owner);
1854
state.flags |= SETIDS;
1855
}
1856
}
1857
else
1858
error(1, "ownership assignment ignored on archive write");
1859
}
1860
if (state.verify)
1861
interactive();
1862
if (!(state.modemask &= (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)))
1863
umask(0);
1864
state.modemask = ~state.modemask;
1865
#if DEBUG
1866
if ((state.test & 0000010) && (pos = hashscan(state.options, 0)))
1867
{
1868
while (hashnext(pos))
1869
{
1870
op = (Option_t*)pos->bucket->value;
1871
if (op->name == pos->bucket->name)
1872
sfprintf(sfstderr, "%-16s %c %2d %d perm=%ld:%s temp=%ld:%s%s%s\n", op->name, op->flag ? op->flag : '-', op->index, op->level, op->perm.number, op->perm.string, op->temp.number, op->temp.string, (op->flags & OPT_HEADER) ? " HEADER" : "", (op->flags & OPT_READONLY) ? " READONLY" : "");
1873
}
1874
hashdone(pos);
1875
}
1876
#endif
1877
for (i = 0; i < elementsof(signals); i++)
1878
if (signal(signals[i], interrupt) == SIG_IGN)
1879
signal(signals[i], SIG_IGN);
1880
switch (state.operation)
1881
{
1882
case IN:
1883
if (*argv)
1884
{
1885
initmatch(argv);
1886
if (state.exact)
1887
state.matchsense = 1;
1888
}
1889
else if (state.exact)
1890
error(3, "file arguments expected");
1891
getcwd(state.pwd, PATH_MAX);
1892
state.pwdlen = strlen(state.pwd);
1893
if (state.pwdlen > 1)
1894
state.pwd[state.pwdlen++] = '/';
1895
copyin(state.in);
1896
if (state.exact)
1897
for (state.pattern = state.patterns; state.pattern->pattern; state.pattern++)
1898
if (!state.pattern->matched)
1899
error(2, "%s: %s: file not found in archive", state.in->name, state.pattern->pattern);
1900
break;
1901
1902
case OUT:
1903
if (*argv)
1904
state.files = argv;
1905
if (!state.maxout && state.complete)
1906
error(3, "maximum block count required");
1907
copy(state.out, copyout);
1908
break;
1909
1910
case (IN|OUT):
1911
if (pass || state.in || state.out)
1912
{
1913
state.pass = 1;
1914
if (*argv)
1915
initmatch(argv);
1916
deltapass(getarchive(IN), getarchive(OUT));
1917
}
1918
else
1919
{
1920
if (--argc < 0)
1921
{
1922
error(2, "destination directory required for pass mode");
1923
error(ERROR_USAGE|4, "%s", optusage(NiL));
1924
}
1925
state.destination = argv[argc];
1926
argv[argc] = 0;
1927
if (*argv)
1928
state.files = argv;
1929
if (state.record.size)
1930
error(1, "record size ignored in pass mode");
1931
1932
/*
1933
* initialize destination dir
1934
*/
1935
1936
pathcanon(state.destination, 0, 0);
1937
if (stat(state.destination, &st) || !S_ISDIR(st.st_mode))
1938
error(3, "%s: destination must be a directory", state.destination);
1939
state.dev = st.st_dev;
1940
strcpy(state.pwd, state.destination);
1941
if (state.pwdlen = strlen(state.pwd))
1942
state.pwd[state.pwdlen++] = '/';
1943
if (state.update < 0)
1944
state.update = OPT_newer;
1945
getarchive(OUT);
1946
state.out->format = &rw;
1947
copy(NiL, copyinout);
1948
}
1949
break;
1950
}
1951
finish(0);
1952
}
1953
1954
/*
1955
* print number of blocks actually copied and exit
1956
*/
1957
1958
void
1959
finish(int code)
1960
{
1961
register Archive_t* ap;
1962
size_t x = state.buffersize / 4;
1963
register char* x1 = &state.tmp.buffer[0];
1964
register char* x2 = x1 + x;
1965
register char* x3 = x2 + x;
1966
register char* x4 = x3 + x;
1967
register off_t n;
1968
1969
while (state.proc)
1970
{
1971
procclose((Proc_t*)state.proc->item);
1972
state.proc = state.proc->next;
1973
}
1974
remove(state.tmp.file);
1975
if (state.checksum.path)
1976
remove(state.checksum.path);
1977
if (state.install.path)
1978
remove(state.install.path);
1979
if (state.restore)
1980
hashwalk(state.restore, 0, restore, NiL);
1981
sfsync(sfstdout);
1982
if (state.meter.last)
1983
{
1984
sfprintf(sfstderr, "%*s\r", state.meter.last, "");
1985
state.meter.last = 0;
1986
}
1987
else if (state.dropcount)
1988
{
1989
sfprintf(sfstderr, "\n");
1990
sfsync(sfstderr);
1991
}
1992
if (state.summary)
1993
{
1994
ap = getarchive(state.operation);
1995
n = ap->io->count + ap->io->expand + ap->io->offset;
1996
message((-1, "%s totals entries=%d count=%I*d expand=%I*d offset=%I*d BLOCKSIZE=%I*d n=%I*d blocks=%I*d", ap->name, ap->entries, sizeof(ap->io->count), ap->io->count, sizeof(ap->io->expand), ap->io->expand, sizeof(ap->io->offset), ap->io->offset, sizeof(BLOCKSIZE), BLOCKSIZE, sizeof(n), n, sizeof(n), (n + BLOCKSIZE - 1) / BLOCKSIZE));
1997
if (ap->entries)
1998
{
1999
if (ap->volume > 1)
2000
sfsprintf(x1, x, ", %d volumes", ap->volume);
2001
else
2002
*x1 = 0;
2003
if (ap->volume > 0 && ap->part > ap->volume)
2004
sfsprintf(x2, x, ", %d parts", ap->part - ap->volume + 1);
2005
else
2006
*x2 = 0;
2007
n = (n + BLOCKSIZE - 1) / BLOCKSIZE;
2008
if (state.verbose || state.meter.on)
2009
{
2010
sfsprintf(x3, x, "%I*u file%s, ", sizeof(ap->selected), ap->selected, ap->selected == 1 ? "" : "s");
2011
if (state.update)
2012
sfsprintf(x4, x, "%I*u updated, ", sizeof(ap->updated), ap->updated);
2013
else
2014
*x4 = 0;
2015
}
2016
else
2017
*x3 = *x4 = 0;
2018
sfprintf(sfstderr, "%s%s%I*d block%s%s%s\n", x3, x4, sizeof(n), n, n == 1 ? "" : "s", x1, x2);
2019
}
2020
}
2021
sfsync(sfstderr);
2022
if (state.interrupt)
2023
{
2024
signal(state.interrupt, SIG_DFL);
2025
kill(getpid(), state.interrupt);
2026
pause();
2027
}
2028
exit(code ? code : error_info.errors != 0);
2029
}
2030
2031
/*
2032
* return release stamp
2033
*/
2034
2035
char*
2036
release(void)
2037
{
2038
register char* b;
2039
register char* s;
2040
register char* t;
2041
2042
if ((s = strchr(usage, '@')) && (t = strchr(s, '\n')) && (b = fmtbuf(t - s + 1)))
2043
{
2044
memcpy(b, s, t - s);
2045
b[t - s] = 0;
2046
}
2047
else
2048
b = fmtident(usage);
2049
return b;
2050
}
2051
2052