1 /*
2 * cpio - copy file archives in and out
3 *
4 * Gunnar Ritter, Freiburg i. Br., Germany, April 2003.
5 */
6 /*
7 * Copyright (c) 2003 Gunnar Ritter
8 *
9 * This software is provided 'as-is', without any express or implied
10 * warranty. In no event will the authors be held liable for any damages
11 * arising from the use of this software.
12 *
13 * Permission is granted to anyone to use this software for any purpose,
14 * including commercial applications, and to alter it and redistribute
15 * it freely, subject to the following restrictions:
16 *
17 * 1. The origin of this software must not be misrepresented; you must not
18 * claim that you wrote the original software. If you use this software
19 * in a product, an acknowledgment in the product documentation would be
20 * appreciated but is not required.
21 *
22 * 2. Altered source versions must be plainly marked as such, and must not be
23 * misrepresented as being the original software.
24 *
25 * 3. This notice may not be removed or altered from any source distribution.
26 */
27
28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
29 #define USED __attribute__ ((used))
30 #elif defined __GNUC__
31 #define USED __attribute__ ((unused))
32 #else
33 #define USED
34 #endif
35 #if defined (SU3)
36 static const char sccsid[] USED = "@(#)pax_su3.sl 1.26 (gritter) 6/26/05";
37 #else
38 static const char sccsid[] USED = "@(#)pax.sl 1.26 (gritter) 6/26/05";
39 #endif
40 /* Sccsid @(#)pax.c 1.26 (gritter) 6/26/05 */
41
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <unistd.h>
46 #include <stdio.h>
47 #include <stdarg.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <fnmatch.h>
51 #include <dirent.h>
52 #include <regex.h>
53 #include <wchar.h>
54 #include <time.h>
55 #include <inttypes.h>
56
57 #include "iblok.h"
58 #include "cpio.h"
59
60 static char **files;
61 static int filec;
62 static struct iblok *filinp;
63 static char *path;
64 static size_t pathsz;
65 static int pax_Hflag;
66
67 static void setpres(const char *);
68 static size_t ofiles_pax(char **, size_t *);
69 static void prtime_pax(time_t);
70 static void parsesub(char *);
71
72 void
flags(int ac,char ** av)73 flags(int ac, char **av)
74 {
75 const char optstring[] = "rwab:cdf:HikKlLno:p:s:tuvx:X";
76 int i;
77 int illegal = 0;
78 char *x;
79
80 #if defined (SU3)
81 pax = PAX_TYPE_PAX2001;
82 #else
83 pax = PAX_TYPE_PAX1992;
84 #endif
85 dflag = 1;
86 uflag = 1;
87 ofiles = ofiles_pax;
88 prtime = prtime_pax;
89 while ((i = getopt(ac, av, optstring)) != EOF) {
90 switch (i) {
91 case 'r':
92 if (action && action != 'i')
93 action = 'p';
94 else
95 action = 'i';
96 break;
97 case 'w':
98 if (action && action != 'o')
99 action = 'p';
100 else
101 action = 'o';
102 break;
103 case 'a':
104 Aflag = 1;
105 break;
106 case 'b':
107 blksiz = strtol(optarg, &x, 10);
108 switch (*x) {
109 case 'b':
110 blksiz *= 512;
111 break;
112 case 'k':
113 blksiz *= 1024;
114 break;
115 case 'm':
116 blksiz *= 1048576;
117 break;
118 case 'w':
119 blksiz *= 2;
120 break;
121 }
122 if (blksiz <= 0)
123 msg(4, -2,
124 "Illegal size given for -b option.\n");
125 Cflag = 1;
126 break;
127 case 'c':
128 fflag = 1;
129 break;
130 case 'd':
131 pax_dflag = 1;
132 break;
133 case 'f':
134 Oflag = Iflag = optarg;
135 break;
136 case 'H':
137 pax_Hflag = 1;
138 break;
139 case 'i':
140 rflag = 1;
141 break;
142 case 'k':
143 pax_kflag = 1;
144 break;
145 case 'K':
146 kflag = 1;
147 break;
148 case 'l':
149 lflag = 1;
150 break;
151 case 'L':
152 Lflag = 1;
153 break;
154 case 'n':
155 pax_nflag = 1;
156 break;
157 case 'o':
158 pax_options(optarg, 1);
159 break;
160 case 'p':
161 setpres(optarg);
162 break;
163 case 's':
164 pax_sflag = 1;
165 parsesub(optarg);
166 break;
167 case 't':
168 aflag = 1;
169 break;
170 case 'u':
171 uflag = 0;
172 pax_uflag = 1;
173 break;
174 case 'v':
175 vflag = 1;
176 break;
177 case 'x':
178 if (strcmp(optarg, "cpio") == 0)
179 fmttype = FMT_ODC;
180 else {
181 if (setfmt(optarg) < 0)
182 illegal = 1;
183 }
184 break;
185 case 'X':
186 pax_Xflag = 1;
187 break;
188 default:
189 illegal = 1;
190 }
191 }
192 switch (action) {
193 case 0:
194 if (rflag || pax_kflag || pax_uflag || pax_preserve)
195 illegal = 1;
196 action = 'i';
197 tflag = 1;
198 setvbuf(stdout, NULL, _IOLBF, 0);
199 /*FALLTHRU*/
200 case 'i':
201 if (aflag || pax_Xflag || lflag)
202 illegal = 1;
203 for (i = optind; i < ac; i++) {
204 addg(av[i], 0);
205 if (pax_dflag == 0) {
206 char *da;
207 int j;
208
209 da = smalloc(strlen(av[i]) + 2);
210 for (j = 0; av[i][j]; j++)
211 da[j] = av[i][j];
212 da[j++] = '/';
213 da[j++] = '*';
214 da[j] = 0;
215 addg(da, 1);
216 free(da);
217 }
218 }
219 break;
220 case 'o':
221 if (fflag || pax_kflag || pax_nflag || kflag)
222 illegal = 1;
223 if (Aflag && Oflag == NULL) {
224 msg(3, 0, "-a requires the -f option\n");
225 illegal = 1;
226 }
227 if (optind != ac) {
228 files = &av[optind];
229 filec = ac - optind;
230 } else
231 filinp = ib_alloc(0, 0);
232 if (pax_uflag)
233 Aflag = 1;
234 if (Aflag == 0 && fmttype == FMT_NONE)
235 fmttype = FMT_ODC;
236 break;
237 case 'p':
238 if (fflag || blksiz || Oflag || Iflag || fmttype != FMT_NONE ||
239 kflag)
240 illegal = 1;
241 if (optind == ac)
242 illegal = 1;
243 else if (optind+1 != ac) {
244 files = &av[optind];
245 filec = ac - optind - 1;
246 optind = ac - 1;
247 } else
248 filinp = ib_alloc(0, 0);
249 break;
250 }
251 if (illegal)
252 usage();
253 }
254
255 void
usage(void)256 usage(void)
257 {
258 fprintf(stderr, "USAGE:\n\
259 \t%s [-cdnvK] [-b size] [-f file] [-s replstr] [-x hdr] [patterns]\n\
260 \t%s -r[cdiknuvK] [-b size] [-f file] [-p priv] [-s replstr] [-x hdr] [patterns]\n\
261 \t%s -w[adituvLX] [-b size] [-f file] [-s replstr] [-x hdr] [files]\n\
262 \t%s -rw[diklntuvLX] [-p priv] [-s replstr] [files] directory\n",
263 progname, progname, progname, progname);
264 exit(1);
265 }
266
267 static void
setpres(const char * s)268 setpres(const char *s)
269 {
270 s--;
271 while (*++s) {
272 pax_preserve &= ~PAX_P_EVERY;
273 switch (*s) {
274 case 'a':
275 pax_preserve |= PAX_P_ATIME;
276 break;
277 case 'e':
278 pax_preserve |= PAX_P_EVERY;
279 break;
280 case 'm':
281 pax_preserve |= PAX_P_MTIME;
282 break;
283 case 'o':
284 pax_preserve |= PAX_P_OWNER;
285 break;
286 case 'p':
287 pax_preserve |= PAX_P_MODE;
288 break;
289 default:
290 msg(2, 0, "ignoring unknown option \"-p%c\"\n",
291 *s&0377);
292 }
293 }
294 if (pax_preserve & PAX_P_EVERY)
295 pax_preserve |= PAX_P_OWNER|PAX_P_MODE;
296 }
297
298 int
gmatch(const char * s,const char * p)299 gmatch(const char *s, const char *p)
300 {
301 int val;
302 #ifdef __GLIBC__
303 /* avoid glibc's broken [^...] */
304 extern char **environ;
305 char **savenv = environ;
306 char *newenv[] = { "POSIXLY_CORRECT=", NULL };
307 environ = newenv;
308 #endif /* __GLIBC__ */
309 val = fnmatch(p, s, 0) == 0;
310 #ifdef __GLIBC__
311 environ = savenv;
312 #endif /* __GLIBC__ */
313 return val;
314 }
315
316 static const char *
nextfile(void)317 nextfile(void)
318 {
319 char *line = NULL;
320 size_t linsiz = 0, linlen;
321
322 if (filinp) {
323 pax_Hflag = 0;
324 if ((linlen=ib_getlin(filinp, &line, &linsiz, srealloc)) == 0) {
325 filinp = NULL;
326 return NULL;
327 }
328 if (line[linlen-1] == '\n')
329 line[--linlen] = '\0';
330 return line;
331 } else if (filec > 0) {
332 filec--;
333 return *files++;
334 } else
335 return NULL;
336 }
337
338 static size_t
catpath(size_t pend,const char * base)339 catpath(size_t pend, const char *base)
340 {
341 size_t blen = strlen(base);
342
343 if (pend + blen + 2 >= pathsz)
344 path = srealloc(path, pathsz = pend + blen + 16);
345 if (pend == 0 || path[pend-1] != '/')
346 path[pend++] = '/';
347 strcpy(&path[pend], base);
348 return pend + blen;
349 }
350
351 /*
352 * Descend the directory hierarchies given using stdin or arguments
353 * and return file names one per one.
354 */
355 static size_t
ofiles_pax(char ** name,size_t * namsiz)356 ofiles_pax(char **name, size_t *namsiz)
357 {
358 static DIR **dt;
359 static int dti, dts;
360 static int *pend;
361 static dev_t *curdev;
362 static ino_t *curino;
363 struct stat st;
364 struct dirent *dp;
365 const char *nf;
366 int i;
367
368 if (dt == NULL) {
369 dt = scalloc(dts = 1, sizeof *dt);
370 pend = scalloc(dts, sizeof *pend);
371 curdev = scalloc(dts, sizeof *curdev);
372 curino = scalloc(dts, sizeof *curino);
373 }
374 for (;;) {
375 if (dti >= 0 && dt[dti] != NULL) {
376 if ((dp = readdir(dt[dti])) != NULL) {
377 if (dp->d_name[0] == '.' &&
378 (dp->d_name[1] == '\0' ||
379 dp->d_name[1] == '.' &&
380 dp->d_name[2] == '\0'))
381 continue;
382 if (dti+1 <= dts) {
383 dt = srealloc(dt, sizeof *dt * ++dts);
384 pend = srealloc(pend, sizeof *pend*dts);
385 curdev = srealloc(curdev, sizeof *curdev
386 * dts);
387 curino = srealloc(curino, sizeof *curino
388 * dts);
389 }
390 pend[dti+1] = catpath(pend[dti], dp->d_name);
391 if (pax_Hflag)
392 Lflag = dti < 0;
393 if ((Lflag ? stat : lstat)(path, &st) < 0) {
394 emsg(2, "Error with %s of \"%s\"",
395 lflag? "stat" : "lstat",
396 path);
397 errcnt++;
398 } else if ((st.st_mode&S_IFMT) == S_IFDIR &&
399 (pax_Xflag == 0 ||
400 curdev[0] == st.st_dev)) {
401 if (Lflag) {
402 for (i = 0; i <= dti; i++)
403 if (st.st_dev ==
404 curdev[i] &&
405 st.st_ino ==
406 curino[i]) {
407 if (pax ==
408 PAX_TYPE_PAX2001)
409 msg(4, 1,
410 "Symbolic link "
411 "loop at "
412 "\"%s\"\n",
413 path);
414 break;
415 }
416 if (i <= dti)
417 break;
418 }
419 if ((dt[dti+1]=opendir(path)) == NULL) {
420 emsg(2, "Cannot open directory "
421 "\"%s\"", path);
422 errcnt++;
423 } else {
424 dti++;
425 curdev[dti] = st.st_dev;
426 curino[dti] = st.st_ino;
427 continue;
428 }
429 } else
430 break;
431 } else {
432 path[pend[dti]] = '\0';
433 closedir(dt[dti]);
434 dt[dti--] = NULL;
435 if (pax_Hflag)
436 Lflag = dti < 0;
437 break;
438 }
439 } else {
440 if (pax_Hflag)
441 Lflag = 1;
442 while ((nf = nextfile()) != NULL &&
443 (Lflag ? stat : lstat)(nf, &st) < 0) {
444 emsg(2, "Error with stat of \"%s\"", nf);
445 errcnt++;
446 }
447 if (nf == NULL)
448 return 0;
449 dti = 0;
450 if (path)
451 free(path);
452 pend[dti] = strlen(nf);
453 strcpy(path = smalloc(pathsz = pend[dti]+1), nf);
454 if (pax_dflag || (st.st_mode&S_IFMT) != S_IFDIR) {
455 dti = -1;
456 break;
457 }
458 curdev[dti] = st.st_dev;
459 curino[dti] = st.st_ino;
460 if ((dt[dti] = opendir(path)) == NULL) {
461 emsg(2, "Cannot open directory \"%s\"", path);
462 errcnt++;
463 }
464 }
465 }
466 if (*name == NULL || *namsiz < pathsz) {
467 free(*name);
468 *name = smalloc(*namsiz=pathsz);
469 }
470 strcpy(*name, path);
471 return pend[dti+1];
472 }
473
474 struct pax_had {
475 struct pax_had *p_next;
476 const char *p_name;
477 time_t p_mtime;
478 };
479
480 static int pprime = 7919;
481
482 static int
phash(const char * s)483 phash(const char *s)
484 {
485 uint32_t h = 0, g;
486
487 s--;
488 while (*++s) {
489 h = (h << 4) + (*s & 0377);
490 if (g = h & 0xf0000000) {
491 h = h ^ (g >> 24);
492 h = h ^ g;
493 }
494 }
495 return h % pprime;
496 }
497
498 static int
plook(const char * name,struct pax_had ** pp)499 plook(const char *name, struct pax_had **pp)
500 {
501 static struct pax_had **pt;
502 uint32_t h, had;
503
504 if (pt == NULL)
505 pt = scalloc(pprime, sizeof *pt);
506 (*pp) = pt[h = phash(name)];
507 while (*pp != NULL) {
508 if (strcmp((*pp)->p_name, name) == 0)
509 break;
510 *pp = (*pp)->p_next;
511 }
512 had = *pp != NULL;
513 if (*pp == NULL) {
514 *pp = scalloc(1, sizeof **pp);
515 (*pp)->p_name = sstrdup(name);
516 (*pp)->p_next = pt[h];
517 pt[h] = *pp;
518 }
519 return had;
520 }
521
522 int
pax_track(const char * name,time_t mtime)523 pax_track(const char *name, time_t mtime)
524 {
525 struct pax_had *pp;
526 struct stat st;
527
528 if (pax_uflag == 0 && (pax_nflag == 0 || patterns))
529 return 1;
530 if (action == 'i' && pax_uflag) {
531 if (lstat(name, &st) == 0 && mtime < st.st_mtime)
532 return 0;
533 }
534 if (action != 'i' || pax_nflag) {
535 if (plook(name, &pp) != 0) {
536 if (action != 'i' && pax_uflag == 0)
537 return 0;
538 if (mtime > pp->p_mtime) {
539 pp->p_mtime = mtime;
540 return 1;
541 }
542 return 0;
543 } else
544 pp->p_mtime = mtime;
545 }
546 return 1;
547 }
548
549 static void
prtime_pax(time_t t)550 prtime_pax(time_t t)
551 {
552 char b[30];
553 time_t now;
554
555 time(&now);
556 if (t > now || t < now - (6*30*86400))
557 strftime(b, sizeof b, "%b %e %Y", localtime(&t));
558 else
559 strftime(b, sizeof b, "%b %e %H:%M", localtime(&t));
560 printf(" %s ", b);
561 }
562
563 struct replacement {
564 regex_t r_re;
565 const char *r_rhs;
566 int r_nbra;
567 enum {
568 REPL_0 = 0,
569 REPL_G = 1,
570 REPL_P = 2
571 } r_flags;
572 } *rep;
573
574 #define NBRA 9
575 static int ren, res;
576 static int mb_cur_max;
577
578 static wchar_t
nextc(char ** sc,int * np)579 nextc(char **sc, int *np)
580 {
581 char *p = *sc;
582 wchar_t wcbuf;
583 int len;
584
585 if (**sc == '\0') {
586 *np = 0;
587 return 0;
588 }
589 if (mb_cur_max == 1 || (**sc&0200) == 0) {
590 *np = 1;
591 return *(*sc)++ & 0377;
592 }
593 if ((len = mbtowc(&wcbuf, p, mb_cur_max)) < 0)
594 msg(3, -2, "Invalid multibyte character for \"-s\" option\n");
595 *np = len;
596 *sc += len;
597 return wcbuf;
598 }
599
600 static void
parsesub(char * s)601 parsesub(char *s)
602 {
603 int len;
604 char *ps = NULL;
605 wchar_t seof = nextc(&s, &len);
606 wint_t c, d;
607 int nbra = 0;
608 int reflags;
609
610 if (seof == 0)
611 goto unt;
612 mb_cur_max = MB_CUR_MAX;
613 ps = s;
614 do {
615 if ((c = nextc(&s, &len)) == seof)
616 break;
617 if (c == '\\') {
618 if ((c = nextc(&s, &len)) == '(')
619 nbra++;
620 continue;
621 } else if (c == '[') {
622 d = WEOF;
623 do {
624 if ((c = nextc(&s, &len)) == '\0')
625 continue;
626 if (d == '[' && (c == ':' || c == '.' ||
627 c == '=')) {
628 d = c;
629 do {
630 if ((c=nextc(&s, &len)) == '\0')
631 continue;
632 } while (c != d || *s != ']');
633 nextc(&s, &len);
634 c = WEOF; /* reset d and continue */
635 }
636 d = c;
637 } while (c != ']');
638 }
639 } while (*s != '\0');
640 if (c != seof)
641 unt: msg(3, -2, "Unterminated argument for \"-s\" option.\n");
642 s[-len] = '\0';
643 if (ren <= res)
644 rep = srealloc(rep, ++res * sizeof *rep);
645 reflags = REG_ANGLES;
646 if (pax >= PAX_TYPE_PAX2001)
647 reflags |= REG_AVOIDNULL;
648 if (regcomp(&rep[ren].r_re, ps, reflags) != 0)
649 msg(3, -2, "Regular expression error in \"-s\" option\n");
650 rep[ren].r_rhs = s;
651 rep[ren].r_nbra = nbra;
652 while ((c = nextc(&s, &len)) != 0) {
653 if (c == '\\')
654 c = nextc(&s, &len);
655 else if (c == seof)
656 break;
657 }
658 rep[ren].r_flags = 0;
659 if (c == seof) {
660 s[-len] = '\0';
661 while ((c = nextc(&s, &len)) != '\0') {
662 switch (c) {
663 case 'g':
664 rep[ren].r_flags |= REPL_G;
665 break;
666 case 'p':
667 rep[ren].r_flags |= REPL_P;
668 break;
669 default:
670 msg(2, 0, "Ignoring unknown -s flag \"%c\"\n",
671 c);
672 }
673 }
674 }
675 ren++;
676 }
677
678 #define put(c) ((new = innew+1>=newsize ? srealloc(new, newsize+=32) : new), \
679 new[innew++] = (c))
680
681 int
pax_sname(char ** oldp,size_t * olds)682 pax_sname(char **oldp, size_t *olds)
683 {
684 char *new = NULL;
685 size_t newsize = 0;
686 regmatch_t bralist[NBRA+1];
687 int c, i, k, l, y, z;
688 int innew = 0, ef = 0;
689 char *inp = *oldp;
690
691 for (z = 0; z < ren; z++) {
692 in: if (regexec(&rep[z].r_re, inp, NBRA+1, bralist, ef) != 0) {
693 if (ef == 0)
694 continue;
695 goto out;
696 }
697 for (i = 0; i < bralist[0].rm_so; i++)
698 put(inp[i]);
699 k = 0;
700 while (c = rep[z].r_rhs[k++] & 0377) {
701 y = -1;
702 if (c == '&')
703 y = 0;
704 else if (c == '\\') {
705 c = rep[z].r_rhs[k++] & 0377;
706 if (c >= '1' && c < rep[z].r_nbra+'1')
707 y = c - '0';
708 }
709 if (y >= 0)
710 for (l = bralist[y].rm_so; l < bralist[y].rm_eo;
711 l++)
712 put(inp[l]);
713 else
714 put(c);
715 }
716 k = innew;
717 for (i = bralist[0].rm_eo; inp[i]; i++)
718 put(inp[i]);
719 put('\0');
720 if (rep[z].r_flags & REPL_G) {
721 ef = REG_NOTBOL;
722 inp = &inp[bralist[0].rm_eo];
723 innew = k;
724 if (bralist[0].rm_so == bralist[0].rm_eo) {
725 if (inp[0] && (nextc(&inp, &l), inp[0]))
726 innew++;
727 else
728 goto out;
729 }
730 goto in;
731 }
732 out: if (rep[z].r_flags & REPL_P)
733 fprintf(stderr, "%s >> %s\n", *oldp, new);
734 free(*oldp);
735 *oldp = new;
736 *olds = newsize;
737 return *new != '\0';
738 }
739 return 1;
740 }
741
742 void
pax_onexit(void)743 pax_onexit(void)
744 {
745 struct glist *gp;
746
747 for (gp = patterns; gp; gp = gp->g_nxt) {
748 if (gp->g_art)
749 continue;
750 if (gp->g_gotcha == 0 && (gp->g_nxt == NULL ||
751 gp->g_nxt->g_art == 0 ||
752 gp->g_gotcha == 0)) {
753 msg(3, 0, "Pattern not matched: \"%s\"\n", gp->g_pat);
754 errcnt++;
755 }
756 }
757 }
758