1/*-
2 * Copyright (c) 2011-2014, Mike Kazantsev
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "bsdcat_platform.h"
27
28#include <stdio.h>
29#ifdef HAVE_STDLIB_H
30#include <stdlib.h>
31#endif
32#ifdef HAVE_UNISTD_H
33#include <unistd.h>
34#endif
35#ifdef HAVE_STRING_H
36#include <string.h>
37#endif
38
39#include <archive.h>
40#include <archive_entry.h>
41
42#include "bsdcat.h"
43#include "err.h"
44
45#define	BYTES_PER_BLOCK	(20*512)
46
47static struct archive *a;
48static struct archive_entry *ae;
49static const char *bsdcat_current_path;
50static int exit_status = 0;
51
52
53static __LA_NORETURN void
54usage(FILE *stream, int eval)
55{
56	const char *p;
57	p = lafe_getprogname();
58	fprintf(stream,
59	    "Usage: %s [-h] [--help] [--version] [--] [filenames...]\n", p);
60	exit(eval);
61}
62
63static __LA_NORETURN void
64version(void)
65{
66	printf("bsdcat %s - %s \n",
67	    BSDCAT_VERSION_STRING,
68	    archive_version_details());
69	exit(0);
70}
71
72static void
73bsdcat_print_error(void)
74{
75	lafe_warnc(0, "%s: %s",
76	    bsdcat_current_path, archive_error_string(a));
77	exit_status = 1;
78}
79
80static void
81bsdcat_next(void)
82{
83	if (a != NULL) {
84		if (archive_read_close(a) != ARCHIVE_OK)
85			bsdcat_print_error();
86		archive_read_free(a);
87	}
88
89	a = archive_read_new();
90	archive_read_support_filter_all(a);
91	archive_read_support_format_empty(a);
92	archive_read_support_format_raw(a);
93}
94
95static void
96bsdcat_read_to_stdout(const char* filename)
97{
98	int r;
99
100	if (archive_read_open_filename(a, filename, BYTES_PER_BLOCK)
101	    != ARCHIVE_OK)
102		bsdcat_print_error();
103	else if (r = archive_read_next_header(a, &ae),
104		 r != ARCHIVE_OK && r != ARCHIVE_EOF)
105		bsdcat_print_error();
106	else if (r == ARCHIVE_EOF)
107		/* for empty payloads don't try and read data */
108		;
109	else if (archive_read_data_into_fd(a, 1) != ARCHIVE_OK)
110		bsdcat_print_error();
111	if (archive_read_close(a) != ARCHIVE_OK)
112		bsdcat_print_error();
113	archive_read_free(a);
114	a = NULL;
115}
116
117int
118main(int argc, char **argv)
119{
120	struct bsdcat *bsdcat, bsdcat_storage;
121	int c;
122
123	bsdcat = &bsdcat_storage;
124	memset(bsdcat, 0, sizeof(*bsdcat));
125
126	lafe_setprogname(*argv, "bsdcat");
127
128	bsdcat->argv = argv;
129	bsdcat->argc = argc;
130
131	while ((c = bsdcat_getopt(bsdcat)) != -1) {
132		switch (c) {
133		case 'h':
134			usage(stdout, 0);
135			/* NOTREACHED */
136			/* Fallthrough */
137		case OPTION_VERSION:
138			version();
139			/* NOTREACHED */
140			/* Fallthrough */
141		default:
142			usage(stderr, 1);
143			/* Fallthrough */
144			/* NOTREACHED */
145		}
146	}
147
148	bsdcat_next();
149	if (*bsdcat->argv == NULL) {
150		bsdcat_current_path = "<stdin>";
151		bsdcat_read_to_stdout(NULL);
152	} else {
153		while (*bsdcat->argv) {
154			bsdcat_current_path = *bsdcat->argv++;
155			bsdcat_read_to_stdout(bsdcat_current_path);
156			bsdcat_next();
157		}
158		archive_read_free(a); /* Help valgrind & friends */
159	}
160
161	exit(exit_status);
162}
163