Annotation of src/usr.bin/compress/main.c, Revision 1.35
1.35 ! millert 1: /* $OpenBSD: main.c,v 1.34 2003/07/14 18:42:20 mickey Exp $ */
1.1 mickey 2:
1.18 mickey 3: static const char copyright[] =
4: "@(#) Copyright (c) 1992, 1993\n\
5: The Regents of the University of California. All rights reserved.\n"
6: "Copyright (c) 1997-2002 Michael Shalayeff\n";
1.1 mickey 7:
1.18 mickey 8: static const char license[] =
9: "\n"
10: " Redistribution and use in source and binary forms, with or without\n"
11: " modification, are permitted provided that the following conditions\n"
12: " are met:\n"
13: " 1. Redistributions of source code must retain the above copyright\n"
14: " notice, this list of conditions and the following disclaimer.\n"
15: " 2. Redistributions in binary form must reproduce the above copyright\n"
16: " notice, this list of conditions and the following disclaimer in the\n"
17: " documentation and/or other materials provided with the distribution.\n"
1.23 deraadt 18: " 3. Neither the name of the University nor the names of its contributors\n"
19: " may be used to endorse or promote products derived from this software\n"
20: " without specific prior written permission.\n"
1.18 mickey 21: "\n"
22: " THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
23: " IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n"
24: " OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n"
25: " IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,\n"
26: " INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n"
27: " (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n"
28: " SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"
29: " HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n"
30: " STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n"
31: " IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n"
32: " THE POSSIBILITY OF SUCH DAMAGE.\n";
1.1 mickey 33:
34: #ifndef lint
35: #if 0
36: static char sccsid[] = "@(#)compress.c 8.2 (Berkeley) 1/7/94";
37: #else
1.35 ! millert 38: static const char main_rcsid[] = "$OpenBSD: main.c,v 1.34 2003/07/14 18:42:20 mickey Exp $";
1.1 mickey 39: #endif
40: #endif /* not lint */
41:
42: #include <sys/param.h>
43: #include <sys/time.h>
44: #include <sys/stat.h>
45:
1.18 mickey 46: #include <getopt.h>
1.1 mickey 47: #include <err.h>
48: #include <errno.h>
1.19 millert 49: #include <fts.h>
1.1 mickey 50: #include <stdio.h>
51: #include <stdlib.h>
52: #include <string.h>
53: #include <unistd.h>
54: #include <fcntl.h>
55: #include <paths.h>
56: #include "compress.h"
57:
58: #define min(a,b) ((a) < (b)? (a) : (b))
59:
1.18 mickey 60: int pipin, force, verbose, testmode, list, nosave;
61: int savename, recurse;
62: int bits, cat, decomp;
1.1 mickey 63: extern char *__progname;
64:
1.18 mickey 65: const struct compressor {
1.1 mickey 66: char *name;
67: char *suffix;
1.33 millert 68: u_char *magic;
69: void *(*open)(int, const char *, int, int);
1.17 millert 70: int (*read)(void *, char *, int);
71: int (*write)(void *, const char *, int);
72: int (*close)(void *);
1.1 mickey 73: } c_table[] = {
74: #define M_COMPRESS (&c_table[0])
1.33 millert 75: { "compress", ".Z", "\037\235", z_open, zread, zwrite, zclose },
1.1 mickey 76: #define M_DEFLATE (&c_table[1])
1.33 millert 77: { "deflate", ".gz", "\037\213", gz_open, gz_read, gz_write, gz_close },
1.18 mickey 78: #if 0
79: #define M_LZH (&c_table[2])
1.33 millert 80: { "lzh", ".lzh", "\037\240", lzh_open, lzh_read, lzh_write, lzh_close },
1.18 mickey 81: #define M_ZIP (&c_table[3])
1.33 millert 82: { "zip", ".zip", "PK", zip_open, zip_read, zip_write, zip_close },
1.18 mickey 83: #define M_PACK (&c_table[4])
1.33 millert 84: { "pack", ".pak", "\037\036", pak_open, pak_read, pak_write, pak_close },
1.18 mickey 85: #endif
1.1 mickey 86: { NULL }
87: };
88:
1.18 mickey 89: int permission(const char *);
90: void setfile(const char *, struct stat *);
1.31 millert 91: __dead void usage(int);
1.25 deraadt 92: int compress(const char *, const char *, const struct compressor *,
93: int, struct stat *);
94: int decompress(const char *, const char *, const struct compressor *,
95: int, struct stat *);
1.18 mickey 96: const struct compressor *check_method(int, struct stat *, const char *);
1.35 ! millert 97: char *set_outfile(char *, char *, size_t);
1.18 mickey 98:
1.19 millert 99: #define OPTSTRING "123456789ab:cdfghlLnNOo:qrS:tvV"
1.18 mickey 100: const struct option longopts[] = {
101: { "ascii", no_argument, 0, 'a' },
102: { "stdout", no_argument, 0, 'c' },
103: { "to-stdout", no_argument, 0, 'c' },
104: { "decompress", no_argument, 0, 'd' },
105: { "uncompress", no_argument, 0, 'd' },
106: { "force", no_argument, 0, 'f' },
107: { "help", no_argument, 0, 'h' },
108: { "list", no_argument, 0, 'l' },
109: { "license", no_argument, 0, 'L' },
110: { "no-name", no_argument, 0, 'n' },
111: { "name", no_argument, 0, 'N' },
112: { "quiet", no_argument, 0, 'q' },
113: { "recursive", no_argument, 0, 'r' },
114: { "suffix", required_argument, 0, 'S' },
115: { "test", no_argument, 0, 't' },
116: { "verbose", no_argument, 0, 'v' },
117: { "version", no_argument, 0, 'V' },
118: { "fast", no_argument, 0, '1' },
119: { "best", no_argument, 0, '9' },
120: { NULL }
121: };
1.1 mickey 122:
123: int
1.24 deraadt 124: main(int argc, char *argv[])
1.1 mickey 125: {
1.19 millert 126: FTS *ftsp;
127: FTSENT *entry;
128: struct stat osb;
1.18 mickey 129: const struct compressor *method;
1.19 millert 130: char *p, *s, *infile;
131: char outfile[MAXPATHLEN], _infile[MAXPATHLEN], suffix[16];
1.18 mickey 132: char *nargv[512]; /* some estimate based on ARG_MAX */
1.19 millert 133: int exists, oreg, ch, error, i, rc, oflag;
1.1 mickey 134:
1.19 millert 135: bits = cat = oflag = decomp = 0;
1.1 mickey 136: p = __progname;
137: if (p[0] == 'g') {
138: method = M_DEFLATE;
1.18 mickey 139: bits = 6;
1.1 mickey 140: p++;
141: } else
142: method = M_COMPRESS;
143:
144: decomp = 0;
145: if (!strcmp(p, "zcat")) {
146: decomp++;
1.20 mickey 147: cat = 1;
1.1 mickey 148: } else {
149: if (p[0] == 'u' && p[1] == 'n') {
150: p += 2;
151: decomp++;
152: }
153:
1.2 mickey 154: if (strcmp(p, "zip") &&
155: strcmp(p, "compress"))
1.1 mickey 156: errx(1, "unknown program name");
157: }
158:
1.18 mickey 159: strlcpy(suffix, method->suffix, sizeof(suffix));
160:
1.19 millert 161: nargv[0] = NULL;
1.18 mickey 162: if ((s = getenv("GZIP")) != NULL) {
163: char *last;
164:
165: nargv[0] = *argv++;
166: for (i = 1, (p = strtok_r(s, " ", &last)); p;
167: (p = strtok_r(NULL, " ", &last)), i++)
168: if (i < sizeof(nargv)/sizeof(nargv[1]) - argc - 1)
169: nargv[i] = p;
170: else {
171: errx(1, "GZIP is too long");
172: }
173: argc += i - 1;
174: while ((nargv[i++] = *argv++))
175: ;
176: argv = nargv;
177: }
178:
179: while ((ch = getopt_long(argc, argv, OPTSTRING, longopts, NULL)) != -1)
1.1 mickey 180: switch(ch) {
181: case '1':
182: case '2':
183: case '3':
184: case '4':
185: case '5':
186: case '6':
187: case '7':
188: case '8':
189: case '9':
190: method = M_DEFLATE;
1.18 mickey 191: strlcpy(suffix, method->suffix, sizeof(suffix));
1.1 mickey 192: bits = ch - '0';
193: break;
1.18 mickey 194: case 'a':
195: warnx("option -a is ignored on this system");
196: break;
1.1 mickey 197: case 'b':
198: bits = strtol(optarg, &p, 10);
1.7 denny 199: /*
200: * POSIX 1002.3 says 9 <= bits <= 14 for portable
201: * apps, but says the implementation may allow
202: * greater.
203: */
1.1 mickey 204: if (*p)
205: errx(1, "illegal bit count -- %s", optarg);
206: break;
207: case 'c':
1.20 mickey 208: cat = 1;
1.1 mickey 209: break;
210: case 'd': /* Backward compatible. */
211: decomp++;
212: break;
213: case 'f':
214: force++;
215: break;
216: case 'g':
217: method = M_DEFLATE;
1.18 mickey 218: strlcpy(suffix, method->suffix, sizeof(suffix));
219: bits = 6;
1.1 mickey 220: break;
221: case 'l':
222: list++;
223: break;
224: case 'n':
225: nosave++;
226: break;
227: case 'N':
1.18 mickey 228: nosave = 0; /* XXX not yet */
1.1 mickey 229: break;
230: case 'O':
231: method = M_COMPRESS;
1.18 mickey 232: strlcpy(suffix, method->suffix, sizeof(suffix));
1.1 mickey 233: break;
234: case 'o':
1.18 mickey 235: if (strlcpy(outfile, optarg,
236: sizeof(outfile)) >= sizeof(outfile))
237: errx(1, "-o argument is too long");
1.20 mickey 238: oflag = 1;
1.1 mickey 239: break;
240: case 'q':
241: verbose = -1;
242: break;
243: case 'S':
244: p = suffix;
245: if (optarg[0] != '.')
246: *p++ = '.';
1.18 mickey 247: strlcpy(p, optarg, sizeof(suffix) - (p - suffix));
248: p = optarg;
1.1 mickey 249: break;
250: case 't':
1.20 mickey 251: testmode = 1;
1.29 millert 252: decomp++;
1.1 mickey 253: break;
1.18 mickey 254: case 'V':
255: printf("%s\n%s\n%s\n", main_rcsid,
256: z_rcsid, gz_rcsid);
1.19 millert 257: exit (0);
1.1 mickey 258: case 'v':
259: verbose++;
260: break;
1.18 mickey 261: case 'L':
262: fputs(copyright, stderr);
263: fputs(license, stderr);
1.19 millert 264: exit (0);
1.18 mickey 265: case 'r':
1.19 millert 266: recurse++;
1.18 mickey 267: break;
268:
1.1 mickey 269: case 'h':
1.31 millert 270: usage(0);
271: break;
1.1 mickey 272: default:
1.31 millert 273: usage(1);
1.1 mickey 274: }
275: argc -= optind;
276: argv += optind;
277:
1.19 millert 278: if (argc == 0) {
279: if (nargv[0] == NULL)
280: argv = nargv;
281: /* XXX - make sure we don't oflow nargv in $GZIP case (millert) */
282: argv[0] = "/dev/stdin";
283: argv[1] = NULL;
284: pipin++;
1.20 mickey 285: cat = 1;
1.28 millert 286: } else {
287: for (i = 0; i < argc; i++) {
288: if (argv[i][0] == '-' && argv[i][1] == '\0') {
289: argv[i] = "/dev/stdin";
290: pipin++;
291: cat = 1;
292: }
293: }
1.19 millert 294: }
295: if (oflag && (recurse || argc > 1))
296: errx(1, "-o option may only be used with a single input file");
1.20 mickey 297:
1.34 mickey 298: if ((cat && argc) + testmode + oflag > 1)
1.19 millert 299: errx(1, "may not mix -o, -c, or -t options");
300:
301: if ((ftsp = fts_open(argv, FTS_PHYSICAL|FTS_NOCHDIR, 0)) == NULL)
302: err(1, NULL);
303: /* XXX - set rc in cases where we "continue" below? */
304: for (rc = 0; (entry = fts_read(ftsp)) != NULL;) {
305: infile = entry->fts_path;
306: switch (entry->fts_info) {
307: case FTS_D:
308: if (!recurse) {
309: warnx("%s is a directory: ignored",
310: infile);
311: fts_set(ftsp, entry, FTS_SKIP);
312: }
313: continue;
314: case FTS_DP:
315: continue;
316: case FTS_NS:
317: /*
318: * If file does not exist and has no suffix,
319: * tack on the default suffix and try that.
320: */
321: /* XXX - is overwriting fts_statp legal? (millert) */
322: if (entry->fts_errno == ENOENT &&
323: strchr(entry->fts_accpath, '.') == NULL &&
324: snprintf(_infile, sizeof(_infile), "%s%s", infile,
325: suffix) < sizeof(_infile) &&
326: stat(_infile, entry->fts_statp) == 0 &&
327: S_ISREG(entry->fts_statp->st_mode)) {
328: infile = _infile;
329: break;
330: }
331: case FTS_ERR:
332: case FTS_DNR:
333: warnx("%s: %s", infile, strerror(entry->fts_errno));
334: error = 1;
335: continue;
336: default:
1.20 mickey 337: if (!S_ISREG(entry->fts_statp->st_mode) && !pipin) {
1.27 millert 338: warnx("%s not a regular file%s",
1.28 millert 339: infile, cat ? "" : ": unchanged");
1.19 millert 340: continue;
1.18 mickey 341: }
1.19 millert 342: break;
1.9 mickey 343: }
1.1 mickey 344:
345: if (testmode)
1.22 deraadt 346: strlcpy(outfile, _PATH_DEVNULL, sizeof outfile);
1.19 millert 347: else if (cat)
1.22 deraadt 348: strlcpy(outfile, "/dev/stdout", sizeof outfile);
1.19 millert 349: else if (!oflag) {
350: if (decomp) {
1.35 ! millert 351: if (set_outfile(infile, outfile,
! 352: sizeof outfile) == NULL) {
1.19 millert 353: if (!recurse)
354: warnx("%s: unknown suffix: "
355: "ignored", infile);
356: continue;
357: }
358: } else {
359: if (snprintf(outfile, sizeof(outfile),
360: "%s%s", infile, suffix) >= sizeof(outfile)) {
361: warnx("%s%s: name too long",
362: infile, suffix);
363: continue;
364: }
365: }
1.1 mickey 366: }
367:
1.19 millert 368: exists = !stat(outfile, &osb);
369: if (!force && exists && S_ISREG(osb.st_mode) &&
370: !permission(outfile))
1.1 mickey 371: continue;
372:
1.19 millert 373: oreg = !exists || S_ISREG(osb.st_mode);
1.1 mickey 374:
375: if (verbose > 0)
376: fprintf(stderr, "%s:\t", infile);
377:
1.19 millert 378: error = (decomp ? decompress : compress)
379: (infile, outfile, method, bits, entry->fts_statp);
1.1 mickey 380:
1.19 millert 381: if (!error && !cat && !testmode && stat(outfile, &osb) == 0) {
382: if (!force && !decomp &&
383: osb.st_size >= entry->fts_statp->st_size) {
1.1 mickey 384: if (verbose > 0)
385: fprintf(stderr, "file would grow; "
1.25 deraadt 386: "left unmodified\n");
1.1 mickey 387: error = 1;
1.19 millert 388: rc = rc ? rc : 2;
1.1 mickey 389: } else {
1.19 millert 390: setfile(outfile, entry->fts_statp);
1.1 mickey 391:
392: if (unlink(infile) && verbose >= 0)
1.18 mickey 393: warn("input: %s", infile);
1.1 mickey 394:
395: if (verbose > 0) {
396: u_int ratio;
1.19 millert 397: ratio = (1000 * osb.st_size)
398: / entry->fts_statp->st_size;
1.1 mickey 399: fprintf(stderr, "%u", ratio / 10);
400: if (ratio % 10)
401: fprintf(stderr, ".%u",
1.25 deraadt 402: ratio % 10);
1.1 mickey 403: fputc('%', stderr);
404: fputc(' ', stderr);
405: }
406: }
407: }
408:
1.21 millert 409: if (error > 0 && oreg && unlink(outfile) && errno != ENOENT &&
1.18 mickey 410: verbose >= 0) {
411: if (force) {
412: warn("output: %s", outfile);
413: rc = 1;
414: } else
415: err(1, "output: %s", outfile);
416: } else if (!error && verbose > 0)
1.1 mickey 417: fputs("OK\n", stderr);
1.19 millert 418: }
1.1 mickey 419:
1.18 mickey 420: exit(rc);
1.1 mickey 421: }
422:
423: int
1.24 deraadt 424: compress(const char *in, const char *out, const struct compressor *method,
425: int bits, struct stat *sb)
1.1 mickey 426: {
1.18 mickey 427: u_char buf[Z_BUFSIZE];
428: int error, ifd, ofd;
1.16 mpech 429: void *cookie;
430: ssize_t nr;
1.1 mickey 431:
432: error = 0;
433: cookie = NULL;
1.3 mickey 434:
1.21 millert 435: if ((ifd = open(in, O_RDONLY)) < 0) {
436: if (verbose >= 0)
437: warn("%s", out);
438: return (-1);
439: }
440:
1.3 mickey 441: if ((ofd = open(out, O_WRONLY|O_CREAT, S_IWUSR)) < 0) {
442: if (verbose >= 0)
443: warn("%s", out);
1.32 mickey 444: (void) close(ifd);
1.19 millert 445: return (-1);
1.3 mickey 446: }
447:
1.4 mickey 448: if (method != M_COMPRESS && !force && isatty(ofd)) {
1.3 mickey 449: if (verbose >= 0)
450: warnx("%s: won't write compressed data to terminal",
1.25 deraadt 451: out);
1.32 mickey 452: (void) close(ofd);
453: (void) close(ifd);
1.19 millert 454: return (-1);
1.3 mickey 455: }
1.1 mickey 456:
1.33 millert 457: if ((cookie = (*method->open)(ofd, "w", bits, 0)) == NULL) {
1.32 mickey 458: if (verbose >= 0)
459: warn("%s", in);
460: (void) close(ofd);
461: (void) close(ifd);
462: return (-1);
463: }
1.1 mickey 464:
1.32 mickey 465: while ((nr = read(ifd, buf, sizeof(buf))) > 0)
466: if ((method->write)(cookie, buf, nr) != nr) {
467: if (verbose >= 0)
468: warn("%s", out);
469: error++;
470: break;
471: }
1.1 mickey 472:
1.32 mickey 473: if (!error && nr < 0) {
474: if (verbose >= 0)
1.1 mickey 475: warn("%s", in);
476: error++;
477: }
478:
1.32 mickey 479: if ((method->close)(cookie)) {
1.1 mickey 480: if (!error && verbose >= 0)
481: warn("%s", out);
482: error++;
483: }
484:
1.18 mickey 485: if (close(ifd)) {
486: if (!error && verbose >= 0)
1.32 mickey 487: warn("%s", in);
1.18 mickey 488: error++;
489: }
1.32 mickey 490:
1.21 millert 491: return (error);
1.1 mickey 492: }
493:
1.18 mickey 494: const struct compressor *
1.24 deraadt 495: check_method(int fd, struct stat *sb, const char *out)
1.1 mickey 496: {
1.18 mickey 497: const struct compressor *method;
1.33 millert 498: u_char magic[2];
1.1 mickey 499:
1.33 millert 500: if (read(fd, magic, sizeof(magic)) != 2)
501: return (NULL);
502: for (method = &c_table[0]; method->name != NULL; method++) {
503: if (magic[0] == method->magic[0] &&
504: magic[1] == method->magic[1])
505: return (method);
506: }
507: return (NULL);
1.1 mickey 508: }
509:
510: int
1.24 deraadt 511: decompress(const char *in, const char *out, const struct compressor *method,
512: int bits, struct stat *sb)
1.1 mickey 513: {
1.18 mickey 514: u_char buf[Z_BUFSIZE];
515: int error, ifd, ofd;
1.16 mpech 516: void *cookie;
517: ssize_t nr;
1.1 mickey 518:
519: error = 0;
520: cookie = NULL;
521:
1.3 mickey 522: if ((ifd = open(in, O_RDONLY)) < 0) {
523: if (verbose >= 0)
524: warn("%s", in);
525: return -1;
526: }
527:
528: if (!force && isatty(ifd)) {
529: if (verbose >= 0)
530: warnx("%s: won't read compressed data from terminal",
1.25 deraadt 531: in);
1.3 mickey 532: close (ifd);
533: return -1;
534: }
535:
1.33 millert 536: if ((method = check_method(ifd, sb, out)) == NULL) {
1.3 mickey 537: if (verbose >= 0)
538: warnx("%s: unrecognized file format", in);
1.13 d 539: close (ifd);
1.3 mickey 540: return -1;
541: }
542:
1.33 millert 543: if ((cookie = (*method->open)(ifd, "r", bits, 1)) == NULL) {
1.32 mickey 544: if (verbose >= 0)
545: warn("%s", in);
546: error++;
547: close (ifd);
548: return -1;
549: }
550:
551: if ((ofd = open(out, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR)) < 0) {
552: if (verbose >= 0)
553: warn("%s", in);
554: (method->close)(cookie);
555: return -1;
556: }
557:
558: while ((nr = (method->read)(cookie, buf, sizeof(buf))) > 0)
559: if (write(ofd, buf, nr) != nr) {
1.21 millert 560: if (verbose >= 0)
1.32 mickey 561: warn("%s", out);
562: error++;
563: break;
1.21 millert 564: }
1.1 mickey 565:
1.32 mickey 566: if (!error && nr < 0) {
567: if (verbose >= 0)
568: warnx("%s: %s", in,
569: errno == EINVAL ? "crc error" : strerror(errno));
570: error++;
1.1 mickey 571: }
572:
1.32 mickey 573: if ((method->close)(cookie)) {
1.1 mickey 574: if (!error && verbose >= 0)
1.32 mickey 575: warnx("%s", in);
1.1 mickey 576: error++;
577: }
578:
1.18 mickey 579: if (close(ofd)) {
1.1 mickey 580: if (!error && verbose >= 0)
1.18 mickey 581: warn("%s", out);
1.1 mickey 582: error++;
583: }
584:
1.21 millert 585: return (error);
1.1 mickey 586: }
587:
588: void
1.24 deraadt 589: setfile(const char *name, struct stat *fs)
1.1 mickey 590: {
1.18 mickey 591: struct timeval tv[2];
1.1 mickey 592:
593: fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
594:
595: TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
596: TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
597: if (utimes(name, tv))
598: warn("utimes: %s", name);
599:
600: /*
601: * Changing the ownership probably won't succeed, unless we're root
602: * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting
603: * the mode; current BSD behavior is to remove all setuid bits on
604: * chown. If chown fails, lose setuid/setgid bits.
605: */
606: if (chown(name, fs->st_uid, fs->st_gid)) {
607: if (errno != EPERM)
608: warn("chown: %s", name);
609: fs->st_mode &= ~(S_ISUID|S_ISGID);
610: }
611: if (chmod(name, fs->st_mode))
612: warn("chown: %s", name);
613:
1.8 millert 614: if (fs->st_flags && chflags(name, fs->st_flags))
1.1 mickey 615: warn("chflags: %s", name);
616: }
617:
618: int
1.24 deraadt 619: permission(const char *fname)
1.1 mickey 620: {
621: int ch, first;
622:
623: if (!isatty(fileno(stderr)))
624: return (0);
625: (void)fprintf(stderr, "overwrite %s? ", fname);
626: first = ch = getchar();
627: while (ch != '\n' && ch != EOF)
628: ch = getchar();
629: return (first == 'y');
1.35 ! millert 630: }
! 631:
! 632: /*
! 633: * Set outfile based on the suffix. In most cases we just strip
! 634: * off the suffix but things like .tgz and .taz are special.
! 635: */
! 636: char *
! 637: set_outfile(char *infile, char *outfile, size_t osize)
! 638: {
! 639: int i;
! 640: char *s;
! 641: static char *suffixes[] = { ".Z", ".gz", ".z", ".tgz", ".taz",
! 642: "-Z", "-gz", "-z", "_Z", "_gz", "_z",
! 643: NULL };
! 644:
! 645: if ((s = strrchr(infile, '.')) == NULL &&
! 646: (s = strrchr(infile, '-')) == NULL &&
! 647: (s = strrchr(infile, '_')) == NULL)
! 648: return (NULL);
! 649:
! 650: for (i = 0; suffixes[i] != NULL; i++) {
! 651: if (strcmp(s, suffixes[i]) == 0) {
! 652: (void)strlcpy(outfile, infile, osize);
! 653: s = outfile + (s - infile);
! 654: /*
! 655: * Convert .tgz and .taz -> .tar,
! 656: * else drop the suffix.
! 657: */
! 658: if (strcmp(s, ".tgz") == 0) {
! 659: s[2] = 'a';
! 660: s[3] = 'r';
! 661: } else if (strcmp(s, ".taz") == 0)
! 662: s[3] = 'r';
! 663: else
! 664: s[0] = '\0';
! 665: return (outfile);
! 666: }
! 667: }
! 668: return (NULL);
1.1 mickey 669: }
670:
1.31 millert 671: __dead void
672: usage(int status)
1.1 mickey 673: {
674: fprintf(stderr,
1.31 millert 675: "usage: %s [-cdfghOqrtvV] [-b bits] [-S suffix] [-[1-9]] [file ...]\n",
1.18 mickey 676: __progname);
1.31 millert 677: exit(status);
1.1 mickey 678: }