1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2011-2014, Mike Kazantsev 5 * All rights reserved. 6 */ 7 8 #include "bsdcat_platform.h" 9 10 #ifdef HAVE_SIGNAL_H 11 #include <signal.h> 12 #endif 13 #include <stdio.h> 14 #ifdef HAVE_STDLIB_H 15 #include <stdlib.h> 16 #endif 17 #ifdef HAVE_UNISTD_H 18 #include <unistd.h> 19 #endif 20 #ifdef HAVE_STRING_H 21 #include <string.h> 22 #endif 23 24 #include <archive.h> 25 #include <archive_entry.h> 26 27 #include "bsdcat.h" 28 #include "lafe_err.h" 29 30 #define BYTES_PER_BLOCK (20*512) 31 32 static struct archive *a; 33 static struct archive_entry *ae; 34 static const char *bsdcat_current_path; 35 static int exit_status = 0; 36 37 38 static __LA_NORETURN void 39 usage(FILE *stream, int eval) 40 { 41 const char *p; 42 p = lafe_getprogname(); 43 fprintf(stream, 44 "Usage: %s [-h] [--help] [--version] [--] [filenames...]\n", p); 45 exit(eval); 46 } 47 48 static __LA_NORETURN void 49 version(void) 50 { 51 printf("bsdcat %s - %s \n", 52 BSDCAT_VERSION_STRING, 53 archive_version_details()); 54 exit(0); 55 } 56 57 static void 58 bsdcat_print_error(void) 59 { 60 lafe_warnc(0, "%s: %s", 61 bsdcat_current_path, archive_error_string(a)); 62 exit_status = 1; 63 } 64 65 static void 66 bsdcat_next(void) 67 { 68 if (a != NULL) { 69 if (archive_read_close(a) != ARCHIVE_OK) 70 bsdcat_print_error(); 71 archive_read_free(a); 72 } 73 74 a = archive_read_new(); 75 archive_read_support_filter_all(a); 76 archive_read_support_format_empty(a); 77 archive_read_support_format_raw(a); 78 } 79 80 static void 81 bsdcat_read_to_stdout(const char* filename) 82 { 83 int r; 84 85 if (archive_read_open_filename(a, filename, BYTES_PER_BLOCK) 86 != ARCHIVE_OK) 87 bsdcat_print_error(); 88 else if (r = archive_read_next_header(a, &ae), 89 r != ARCHIVE_OK && r != ARCHIVE_EOF) 90 bsdcat_print_error(); 91 else if (r == ARCHIVE_EOF) 92 /* for empty payloads don't try and read data */ 93 ; 94 else if (archive_read_data_into_fd(a, 1) != ARCHIVE_OK) 95 bsdcat_print_error(); 96 if (archive_read_close(a) != ARCHIVE_OK) 97 bsdcat_print_error(); 98 archive_read_free(a); 99 a = NULL; 100 } 101 102 int 103 main(int argc, char **argv) 104 { 105 struct bsdcat *bsdcat, bsdcat_storage; 106 int c; 107 108 bsdcat = &bsdcat_storage; 109 memset(bsdcat, 0, sizeof(*bsdcat)); 110 111 #if defined(HAVE_SIGACTION) && defined(SIGCHLD) 112 { /* Do not ignore SIGCHLD. */ 113 struct sigaction sa; 114 sa.sa_handler = SIG_DFL; 115 sigemptyset(&sa.sa_mask); 116 sa.sa_flags = 0; 117 sigaction(SIGCHLD, &sa, NULL); 118 } 119 #endif 120 121 lafe_setprogname(*argv, "bsdcat"); 122 123 bsdcat->argv = argv; 124 bsdcat->argc = argc; 125 126 while ((c = bsdcat_getopt(bsdcat)) != -1) { 127 switch (c) { 128 case 'h': 129 usage(stdout, 0); 130 /* NOTREACHED */ 131 /* Fallthrough */ 132 case OPTION_VERSION: 133 version(); 134 /* NOTREACHED */ 135 /* Fallthrough */ 136 default: 137 usage(stderr, 1); 138 /* Fallthrough */ 139 /* NOTREACHED */ 140 } 141 } 142 143 bsdcat_next(); 144 if (*bsdcat->argv == NULL) { 145 bsdcat_current_path = "<stdin>"; 146 bsdcat_read_to_stdout(NULL); 147 } else { 148 while (*bsdcat->argv) { 149 bsdcat_current_path = *bsdcat->argv++; 150 bsdcat_read_to_stdout(bsdcat_current_path); 151 bsdcat_next(); 152 } 153 archive_read_free(a); /* Help valgrind & friends */ 154 } 155 156 exit(exit_status); 157 } 158