1 /*
2 * Copyright 2018 Jonathan Dieter <jdieter@gmail.com>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <stdbool.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <argp.h>
36 #include <zck.h>
37
38 #include "util_common.h"
39
40 static char doc[] = "zck_read_header - Read header from a zchunk file";
41
42 static char args_doc[] = "<file>";
43
44 static struct argp_option options[] = {
45 {"verbose", 'v', 0, 0,
46 "Increase verbosity (can be specified more than once for debugging)"},
47 {"show-chunks", 'c', 0, 0, "Show chunk information"},
48 {"quiet", 'q', 0, 0, "Only show errors"},
49 {"version", 'V', 0, 0, "Show program version"},
50 {"verify", 'f', 0, 0, "Verify full zchunk file"},
51 { 0 }
52 };
53
54 struct arguments {
55 char *args[1];
56 bool verify;
57 bool quiet;
58 bool show_chunks;
59 zck_log_type log_level;
60 bool exit;
61 };
62
parse_opt(int key,char * arg,struct argp_state * state)63 static error_t parse_opt (int key, char *arg, struct argp_state *state) {
64 struct arguments *arguments = state->input;
65
66 if(arguments->exit)
67 return 0;
68
69 switch (key) {
70 case 'v':
71 arguments->log_level--;
72 if(arguments->log_level < ZCK_LOG_DDEBUG)
73 arguments->log_level = ZCK_LOG_DDEBUG;
74 break;
75 case 'c':
76 arguments->show_chunks = true;
77 break;
78 case 'q':
79 arguments->quiet = true;
80 break;
81 case 'V':
82 version();
83 arguments->exit = true;
84 break;
85 case 'f':
86 arguments->verify = true;
87 break;
88
89 case ARGP_KEY_ARG:
90 if (state->arg_num >= 1) {
91 argp_usage (state);
92 return EINVAL;
93 }
94 arguments->args[state->arg_num] = arg;
95
96 break;
97
98 case ARGP_KEY_END:
99 if (state->arg_num < 1) {
100 argp_usage (state);
101 return EINVAL;
102 }
103 break;
104
105 default:
106 return ARGP_ERR_UNKNOWN;
107 }
108 return 0;
109 }
110
111 static struct argp argp = {options, parse_opt, args_doc, doc};
112
main(int argc,char * argv[])113 int main (int argc, char *argv[]) {
114 struct arguments arguments = {0};
115
116 /* Defaults */
117 arguments.log_level = ZCK_LOG_ERROR;
118
119 int retval = argp_parse (&argp, argc, argv, 0, 0, &arguments);
120 if(retval || arguments.exit)
121 exit(retval);
122
123 zck_set_log_level(arguments.log_level);
124
125 int src_fd = open(arguments.args[0], O_RDONLY);
126 if(src_fd < 0) {
127 printf("Unable to open %s\n", arguments.args[0]);
128 perror("");
129 exit(1);
130 }
131
132 zckCtx *zck = zck_create();
133 if(zck == NULL) {
134 dprintf(STDERR_FILENO, "%s", zck_get_error(NULL));
135 zck_clear_error(NULL);
136 exit(1);
137 }
138 if(!zck_init_read(zck, src_fd)) {
139 dprintf(STDERR_FILENO, "Error reading zchunk header: %s",
140 zck_get_error(zck));
141 zck_free(&zck);
142 exit(1);
143 }
144
145 int valid_cks = 1;
146 if(arguments.verify) {
147 valid_cks = zck_validate_checksums(zck);
148 if(!valid_cks)
149 exit(1);
150 }
151 close(src_fd);
152
153 if(!arguments.quiet) {
154 printf("Overall checksum type: %s\n",
155 zck_hash_name_from_type(zck_get_full_hash_type(zck)));
156 printf("Header size: %lu\n", zck_get_header_length(zck));
157 char *digest = zck_get_header_digest(zck);
158 printf("Header checksum: %s\n", digest);
159 free(digest);
160 printf("Data size: %lu\n", zck_get_data_length(zck));
161 digest = zck_get_data_digest(zck);
162 printf("Data checksum: %s\n", digest);
163 free(digest);
164 printf("Chunk count: %lu\n", (long unsigned)zck_get_chunk_count(zck));
165 printf("Chunk checksum type: %s\n", zck_hash_name_from_type(zck_get_chunk_hash_type(zck)));
166 }
167 if(!arguments.quiet && arguments.show_chunks)
168 printf("\n");
169 if(arguments.show_chunks) {
170 printf(" Chunk Checksum %*c Start Comp size Size\n",
171 (((int)zck_get_chunk_digest_size(zck)*2)-9), ' ');
172 for(zckChunk *chk=zck_get_first_chunk(zck); chk;
173 chk=zck_get_next_chunk(chk)) {
174 char *digest = zck_get_chunk_digest(chk);
175 if(digest == NULL) {
176 dprintf(STDERR_FILENO, "%s", zck_get_error(zck));
177 exit(1);
178 }
179 printf("%12lu %s %12lu %12lu %12lu",
180 (long unsigned)zck_get_chunk_number(chk),
181 digest,
182 (long unsigned)zck_get_chunk_start(chk),
183 (long unsigned)zck_get_chunk_comp_size(chk),
184 (long unsigned)zck_get_chunk_size(chk));
185 if(arguments.verify) {
186 if(zck_get_chunk_valid(chk) == 1)
187 printf(" +");
188 else
189 printf(" !");
190 }
191 printf("\n");
192 free(digest);
193 }
194 }
195 if(arguments.verify) {
196 if(valid_cks == 1 && arguments.log_level <= ZCK_LOG_WARNING)
197 printf("All checksums are valid\n");
198 else if(valid_cks == -1)
199 printf("Some checksums failed\n");
200 }
201 zck_free(&zck);
202 return 1-valid_cks;
203 }
204