Deleted Added
full compact
ckdist.c (50479) ckdist.c (61019)
1/*
2 * Copyright (c) 1997 Robert Nordier
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
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifndef lint
29static const char rcsid[] =
1/*
2 * Copyright (c) 1997 Robert Nordier
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
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifndef lint
29static const char rcsid[] =
30 "$FreeBSD: head/usr.sbin/ckdist/ckdist.c 50479 1999-08-28 01:35:59Z peter $";
30 "$FreeBSD: head/usr.sbin/ckdist/ckdist.c 61019 2000-05-28 14:57:49Z charnier $";
31#endif /* not lint */
32
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <err.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <fts.h>
39#include <md5.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44
45extern int crc(int fd, u_long * cval, u_long * clen);
46
47#define DISTMD5 1 /* MD5 format */
48#define DISTINF 2 /* .inf format */
49#define DISTTYPES 2 /* types supported */
50
51#define E_UNKNOWN 1 /* Unknown format */
52#define E_BADMD5 2 /* Invalid MD5 format */
53#define E_BADINF 3 /* Invalid .inf format */
54#define E_NAME 4 /* Can't derive component name */
55#define E_LENGTH 5 /* Length mismatch */
56#define E_CHKSUM 6 /* Checksum mismatch */
57#define E_ERRNO 7 /* sys_errlist[errno] */
58
59#define isfatal(err) ((err) && (err) <= E_NAME)
60
61#define NAMESIZE 256 /* filename buffer size */
62#define MDSUMLEN 32 /* length of MD5 message digest */
63
64#define isstdin(path) ((path)[0] == '-' && !(path)[1])
65
66static const char *opt_dir; /* where to look for components */
67static const char *opt_name; /* name for accessing components */
68static int opt_all; /* report on all components */
69static int opt_ignore; /* ignore missing components */
70static int opt_recurse; /* search directories recursively */
71static int opt_silent; /* silent about inaccessible files */
72static int opt_type; /* dist type: md5 or inf */
73static int opt_exist; /* just verify existence */
74
75static int ckdist(const char *path, int type);
76static int chkmd5(FILE * fp, const char *path);
77static int chkinf(FILE * fp, const char *path);
78static int report(const char *path, const char *name, int error);
79static const char *distname(const char *path, const char *name,
80 const char *ext);
81static char *stripath(const char *path);
82static int distfile(const char *path);
83static int disttype(const char *name);
84static int fail(const char *path, const char *msg);
85static void usage(void);
86
87int
88main(int argc, char *argv[])
89{
90 static char *arg[2];
91 struct stat sb;
92 FTS *ftsp;
93 FTSENT *f;
94 int rval, c, type;
95
96 while ((c = getopt(argc, argv, "ad:in:rst:x")) != -1)
97 switch (c) {
98 case 'a':
99 opt_all = 1;
100 break;
101 case 'd':
102 opt_dir = optarg;
103 break;
104 case 'i':
105 opt_ignore = 1;
106 break;
107 case 'n':
108 opt_name = optarg;
109 break;
110 case 'r':
111 opt_recurse = 1;
112 break;
113 case 's':
114 opt_silent = 1;
115 break;
116 case 't':
117 if ((opt_type = disttype(optarg)) == 0) {
118 warnx("illegal argument to -t option");
119 usage();
120 }
121 break;
122 case 'x':
123 opt_exist = 1;
124 break;
125 default:
126 usage();
127 }
128 argc -= optind;
129 argv += optind;
130 if (argc < 1)
131 usage();
132 if (opt_dir) {
133 if (stat(opt_dir, &sb))
31#endif /* not lint */
32
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <err.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <fts.h>
39#include <md5.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44
45extern int crc(int fd, u_long * cval, u_long * clen);
46
47#define DISTMD5 1 /* MD5 format */
48#define DISTINF 2 /* .inf format */
49#define DISTTYPES 2 /* types supported */
50
51#define E_UNKNOWN 1 /* Unknown format */
52#define E_BADMD5 2 /* Invalid MD5 format */
53#define E_BADINF 3 /* Invalid .inf format */
54#define E_NAME 4 /* Can't derive component name */
55#define E_LENGTH 5 /* Length mismatch */
56#define E_CHKSUM 6 /* Checksum mismatch */
57#define E_ERRNO 7 /* sys_errlist[errno] */
58
59#define isfatal(err) ((err) && (err) <= E_NAME)
60
61#define NAMESIZE 256 /* filename buffer size */
62#define MDSUMLEN 32 /* length of MD5 message digest */
63
64#define isstdin(path) ((path)[0] == '-' && !(path)[1])
65
66static const char *opt_dir; /* where to look for components */
67static const char *opt_name; /* name for accessing components */
68static int opt_all; /* report on all components */
69static int opt_ignore; /* ignore missing components */
70static int opt_recurse; /* search directories recursively */
71static int opt_silent; /* silent about inaccessible files */
72static int opt_type; /* dist type: md5 or inf */
73static int opt_exist; /* just verify existence */
74
75static int ckdist(const char *path, int type);
76static int chkmd5(FILE * fp, const char *path);
77static int chkinf(FILE * fp, const char *path);
78static int report(const char *path, const char *name, int error);
79static const char *distname(const char *path, const char *name,
80 const char *ext);
81static char *stripath(const char *path);
82static int distfile(const char *path);
83static int disttype(const char *name);
84static int fail(const char *path, const char *msg);
85static void usage(void);
86
87int
88main(int argc, char *argv[])
89{
90 static char *arg[2];
91 struct stat sb;
92 FTS *ftsp;
93 FTSENT *f;
94 int rval, c, type;
95
96 while ((c = getopt(argc, argv, "ad:in:rst:x")) != -1)
97 switch (c) {
98 case 'a':
99 opt_all = 1;
100 break;
101 case 'd':
102 opt_dir = optarg;
103 break;
104 case 'i':
105 opt_ignore = 1;
106 break;
107 case 'n':
108 opt_name = optarg;
109 break;
110 case 'r':
111 opt_recurse = 1;
112 break;
113 case 's':
114 opt_silent = 1;
115 break;
116 case 't':
117 if ((opt_type = disttype(optarg)) == 0) {
118 warnx("illegal argument to -t option");
119 usage();
120 }
121 break;
122 case 'x':
123 opt_exist = 1;
124 break;
125 default:
126 usage();
127 }
128 argc -= optind;
129 argv += optind;
130 if (argc < 1)
131 usage();
132 if (opt_dir) {
133 if (stat(opt_dir, &sb))
134 err(2, opt_dir);
134 err(2, "%s", opt_dir);
135 if (!S_ISDIR(sb.st_mode))
136 errx(2, "%s: not a directory", opt_dir);
137 }
138 rval = 0;
139 do {
140 if (isstdin(*argv))
141 rval |= ckdist(*argv, opt_type);
142 else if (stat(*argv, &sb))
143 rval |= fail(*argv, NULL);
144 else if (S_ISREG(sb.st_mode))
145 rval |= ckdist(*argv, opt_type);
146 else {
147 arg[0] = *argv;
148 if ((ftsp = fts_open(arg, FTS_LOGICAL, NULL)) == NULL)
149 err(2, "fts_open");
150 while ((f = fts_read(ftsp)) != NULL)
151 switch (f->fts_info) {
152 case FTS_DC:
153 rval = fail(f->fts_path, "Directory causes a cycle");
154 break;
155 case FTS_DNR:
156 case FTS_ERR:
157 case FTS_NS:
158 rval = fail(f->fts_path, sys_errlist[f->fts_errno]);
159 break;
160 case FTS_D:
161 if (!opt_recurse && f->fts_level > FTS_ROOTLEVEL &&
162 fts_set(ftsp, f, FTS_SKIP))
163 err(2, "fts_set");
164 break;
165 case FTS_F:
166 if ((type = distfile(f->fts_name)) != 0 &&
167 (!opt_type || type == opt_type))
168 rval |= ckdist(f->fts_path, type);
169 break;
170 default: ;
171 }
172 if (errno)
173 err(2, "fts_read");
174 if (fts_close(ftsp))
175 err(2, "fts_close");
176 }
177 } while (*++argv);
178 return rval;
179}
180
181static int
182ckdist(const char *path, int type)
183{
184 FILE *fp;
185 int rval, c;
186
187 if (isstdin(path)) {
188 path = "(stdin)";
189 fp = stdin;
190 } else if ((fp = fopen(path, "r")) == NULL)
191 return fail(path, NULL);
192 if (!type) {
193 if (fp != stdin)
194 type = distfile(path);
195 if (!type)
196 if ((c = fgetc(fp)) != EOF) {
197 type = c == 'M' ? DISTMD5 : c == 'P' ? DISTINF : 0;
198 (void)ungetc(c, fp);
199 }
200 }
201 switch (type) {
202 case DISTMD5:
203 rval = chkmd5(fp, path);
204 break;
205 case DISTINF:
206 rval = chkinf(fp, path);
207 break;
208 default:
209 rval = report(path, NULL, E_UNKNOWN);
210 }
211 if (ferror(fp))
135 if (!S_ISDIR(sb.st_mode))
136 errx(2, "%s: not a directory", opt_dir);
137 }
138 rval = 0;
139 do {
140 if (isstdin(*argv))
141 rval |= ckdist(*argv, opt_type);
142 else if (stat(*argv, &sb))
143 rval |= fail(*argv, NULL);
144 else if (S_ISREG(sb.st_mode))
145 rval |= ckdist(*argv, opt_type);
146 else {
147 arg[0] = *argv;
148 if ((ftsp = fts_open(arg, FTS_LOGICAL, NULL)) == NULL)
149 err(2, "fts_open");
150 while ((f = fts_read(ftsp)) != NULL)
151 switch (f->fts_info) {
152 case FTS_DC:
153 rval = fail(f->fts_path, "Directory causes a cycle");
154 break;
155 case FTS_DNR:
156 case FTS_ERR:
157 case FTS_NS:
158 rval = fail(f->fts_path, sys_errlist[f->fts_errno]);
159 break;
160 case FTS_D:
161 if (!opt_recurse && f->fts_level > FTS_ROOTLEVEL &&
162 fts_set(ftsp, f, FTS_SKIP))
163 err(2, "fts_set");
164 break;
165 case FTS_F:
166 if ((type = distfile(f->fts_name)) != 0 &&
167 (!opt_type || type == opt_type))
168 rval |= ckdist(f->fts_path, type);
169 break;
170 default: ;
171 }
172 if (errno)
173 err(2, "fts_read");
174 if (fts_close(ftsp))
175 err(2, "fts_close");
176 }
177 } while (*++argv);
178 return rval;
179}
180
181static int
182ckdist(const char *path, int type)
183{
184 FILE *fp;
185 int rval, c;
186
187 if (isstdin(path)) {
188 path = "(stdin)";
189 fp = stdin;
190 } else if ((fp = fopen(path, "r")) == NULL)
191 return fail(path, NULL);
192 if (!type) {
193 if (fp != stdin)
194 type = distfile(path);
195 if (!type)
196 if ((c = fgetc(fp)) != EOF) {
197 type = c == 'M' ? DISTMD5 : c == 'P' ? DISTINF : 0;
198 (void)ungetc(c, fp);
199 }
200 }
201 switch (type) {
202 case DISTMD5:
203 rval = chkmd5(fp, path);
204 break;
205 case DISTINF:
206 rval = chkinf(fp, path);
207 break;
208 default:
209 rval = report(path, NULL, E_UNKNOWN);
210 }
211 if (ferror(fp))
212 warn(path);
212 warn("%s", path);
213 if (fp != stdin && fclose(fp))
213 if (fp != stdin && fclose(fp))
214 err(2, path);
214 err(2, "%s", path);
215 return rval;
216}
217
218static int
219chkmd5(FILE * fp, const char *path)
220{
221 char buf[298]; /* "MD5 (NAMESIZE = MDSUMLEN" */
222 char name[NAMESIZE + 1];
223 char sum[MDSUMLEN + 1], chk[MDSUMLEN + 1];
224 const char *dname;
225 char *s;
226 int rval, error, c, fd;
227 char ch;
228
229 rval = 0;
230 while (fgets(buf, sizeof(buf), fp)) {
231 dname = NULL;
232 error = 0;
233 if (((c = sscanf(buf, "MD5 (%256s = %32s%c", name, sum,
234 &ch)) != 3 && (!feof(fp) || c != 2)) ||
235 (c == 3 && ch != '\n') ||
236 (s = strrchr(name, ')')) == NULL ||
237 strlen(sum) != MDSUMLEN)
238 error = E_BADMD5;
239 else {
240 *s = 0;
241 if ((dname = distname(path, name, NULL)) == NULL)
242 error = E_NAME;
243 else if (opt_exist) {
244 if ((fd = open(dname, O_RDONLY)) == -1)
245 error = E_ERRNO;
246 else if (close(fd))
215 return rval;
216}
217
218static int
219chkmd5(FILE * fp, const char *path)
220{
221 char buf[298]; /* "MD5 (NAMESIZE = MDSUMLEN" */
222 char name[NAMESIZE + 1];
223 char sum[MDSUMLEN + 1], chk[MDSUMLEN + 1];
224 const char *dname;
225 char *s;
226 int rval, error, c, fd;
227 char ch;
228
229 rval = 0;
230 while (fgets(buf, sizeof(buf), fp)) {
231 dname = NULL;
232 error = 0;
233 if (((c = sscanf(buf, "MD5 (%256s = %32s%c", name, sum,
234 &ch)) != 3 && (!feof(fp) || c != 2)) ||
235 (c == 3 && ch != '\n') ||
236 (s = strrchr(name, ')')) == NULL ||
237 strlen(sum) != MDSUMLEN)
238 error = E_BADMD5;
239 else {
240 *s = 0;
241 if ((dname = distname(path, name, NULL)) == NULL)
242 error = E_NAME;
243 else if (opt_exist) {
244 if ((fd = open(dname, O_RDONLY)) == -1)
245 error = E_ERRNO;
246 else if (close(fd))
247 err(2, dname);
247 err(2, "%s", dname);
248 } else if (!MD5File((char *)dname, chk))
249 error = E_ERRNO;
250 else if (strcmp(chk, sum))
251 error = E_CHKSUM;
252 }
253 if (opt_ignore && error == E_ERRNO && errno == ENOENT)
254 continue;
255 if (error || opt_all)
256 rval |= report(path, dname, error);
257 if (isfatal(error))
258 break;
259 }
260 return rval;
261}
262
263static int
264chkinf(FILE * fp, const char *path)
265{
266 char buf[30]; /* "cksum.2 = 10 6" */
267 char ext[3];
268 struct stat sb;
269 const char *dname;
270 u_long sum, len, chk;
271 int rval, error, c, pieces, cnt, fd;
272 char ch;
273
274 rval = 0;
275 for (cnt = -1; fgets(buf, sizeof(buf), fp); cnt++) {
276 fd = -1;
277 dname = NULL;
278 error = 0;
279 if (cnt == -1) {
280 if ((c = sscanf(buf, "Pieces = %d%c", &pieces, &ch)) != 2 ||
281 ch != '\n' || pieces < 1)
282 error = E_BADINF;
283 } else if (((c = sscanf(buf, "cksum.%2s = %lu %lu%c", ext, &sum,
284 &len, &ch)) != 4 &&
285 (!feof(fp) || c != 3)) || (c == 4 && ch != '\n') ||
286 ext[0] != 'a' + cnt / 26 || ext[1] != 'a' + cnt % 26)
287 error = E_BADINF;
288 else if ((dname = distname(fp == stdin ? NULL : path, NULL,
289 ext)) == NULL)
290 error = E_NAME;
291 else if ((fd = open(dname, O_RDONLY)) == -1)
292 error = E_ERRNO;
293 else if (fstat(fd, &sb))
294 error = E_ERRNO;
295 else if (sb.st_size != (off_t)len)
296 error = E_LENGTH;
297 else if (!opt_exist) {
298 if (crc(fd, &chk, &len))
299 error = E_ERRNO;
300 else if (chk != sum)
301 error = E_CHKSUM;
302 }
303 if (fd != -1 && close(fd))
248 } else if (!MD5File((char *)dname, chk))
249 error = E_ERRNO;
250 else if (strcmp(chk, sum))
251 error = E_CHKSUM;
252 }
253 if (opt_ignore && error == E_ERRNO && errno == ENOENT)
254 continue;
255 if (error || opt_all)
256 rval |= report(path, dname, error);
257 if (isfatal(error))
258 break;
259 }
260 return rval;
261}
262
263static int
264chkinf(FILE * fp, const char *path)
265{
266 char buf[30]; /* "cksum.2 = 10 6" */
267 char ext[3];
268 struct stat sb;
269 const char *dname;
270 u_long sum, len, chk;
271 int rval, error, c, pieces, cnt, fd;
272 char ch;
273
274 rval = 0;
275 for (cnt = -1; fgets(buf, sizeof(buf), fp); cnt++) {
276 fd = -1;
277 dname = NULL;
278 error = 0;
279 if (cnt == -1) {
280 if ((c = sscanf(buf, "Pieces = %d%c", &pieces, &ch)) != 2 ||
281 ch != '\n' || pieces < 1)
282 error = E_BADINF;
283 } else if (((c = sscanf(buf, "cksum.%2s = %lu %lu%c", ext, &sum,
284 &len, &ch)) != 4 &&
285 (!feof(fp) || c != 3)) || (c == 4 && ch != '\n') ||
286 ext[0] != 'a' + cnt / 26 || ext[1] != 'a' + cnt % 26)
287 error = E_BADINF;
288 else if ((dname = distname(fp == stdin ? NULL : path, NULL,
289 ext)) == NULL)
290 error = E_NAME;
291 else if ((fd = open(dname, O_RDONLY)) == -1)
292 error = E_ERRNO;
293 else if (fstat(fd, &sb))
294 error = E_ERRNO;
295 else if (sb.st_size != (off_t)len)
296 error = E_LENGTH;
297 else if (!opt_exist) {
298 if (crc(fd, &chk, &len))
299 error = E_ERRNO;
300 else if (chk != sum)
301 error = E_CHKSUM;
302 }
303 if (fd != -1 && close(fd))
304 err(2, dname);
304 err(2, "%s", dname);
305 if (opt_ignore && error == E_ERRNO && errno == ENOENT)
306 continue;
307 if (error || (opt_all && cnt >= 0))
308 rval |= report(path, dname, error);
309 if (isfatal(error))
310 break;
311 }
312 return rval;
313}
314
315static int
316report(const char *path, const char *name, int error)
317{
318 if (name)
319 name = stripath(name);
320 switch (error) {
321 case E_UNKNOWN:
322 printf("%s: Unknown format\n", path);
323 break;
324 case E_BADMD5:
325 printf("%s: Invalid MD5 format\n", path);
326 break;
327 case E_BADINF:
328 printf("%s: Invalid .inf format\n", path);
329 break;
330 case E_NAME:
331 printf("%s: Can't derive component name\n", path);
332 break;
333 case E_LENGTH:
334 printf("%s: %s: Size mismatch\n", path, name);
335 break;
336 case E_CHKSUM:
337 printf("%s: %s: Checksum mismatch\n", path, name);
338 break;
339 case E_ERRNO:
340 printf("%s: %s: %s\n", path, name, sys_errlist[errno]);
341 break;
342 default:
343 printf("%s: %s: OK\n", path, name);
344 }
345 return error != 0;
346}
347
348static const char *
349distname(const char *path, const char *name, const char *ext)
350{
351 static char buf[NAMESIZE];
352 size_t plen, nlen;
353 char *s;
354
355 if (opt_name)
356 name = opt_name;
357 else if (!name) {
358 if (!path)
359 return NULL;
360 name = stripath(path);
361 }
362 nlen = strlen(name);
363 if (ext && nlen > 4 && name[nlen - 4] == '.' &&
364 disttype(name + nlen - 3) == DISTINF)
365 nlen -= 4;
366 if (opt_dir) {
367 path = opt_dir;
368 plen = strlen(path);
369 } else
370 plen = path && (s = strrchr(path, '/')) != NULL ?
371 (size_t)(s - path) : 0;
372 if (plen + (plen > 0) + nlen + (ext ? 3 : 0) >= sizeof(buf))
373 return NULL;
374 s = buf;
375 if (plen) {
376 memcpy(s, path, plen);
377 s += plen;
378 *s++ = '/';
379 }
380 memcpy(s, name, nlen);
381 s += nlen;
382 if (ext) {
383 *s++ = '.';
384 memcpy(s, ext, 2);
385 s += 2;
386 }
387 *s = 0;
388 return buf;
389}
390
391static char *
392stripath(const char *path)
393{
394 const char *s;
395
396 return (char *)((s = strrchr(path, '/')) != NULL && s[1] ?
397 s + 1 : path);
398}
399
400static int
401distfile(const char *path)
402{
403 const char *s;
404 int type;
405
406 if ((type = disttype(path)) == DISTMD5 ||
407 ((s = strrchr(path, '.')) != NULL && s > path &&
408 (type = disttype(s + 1)) != 0))
409 return type;
410 return 0;
411}
412
413static int
414disttype(const char *name)
415{
416 static const char dname[DISTTYPES][4] = {"md5", "inf"};
417 int i;
418
419 for (i = 0; i < DISTTYPES; i++)
420 if (!strcmp(dname[i], name))
421 return 1 + i;
422 return 0;
423}
424
425static int
426fail(const char *path, const char *msg)
427{
428 if (opt_silent)
429 return 0;
430 warnx("%s: %s", path, msg ? msg : sys_errlist[errno]);
431 return 2;
432}
433
434static void
435usage(void)
436{
437 fprintf(stderr,
438 "usage: ckdist [-airsx] [-d dir] [-n name] [-t type] file ...\n");
439 exit(2);
440}
305 if (opt_ignore && error == E_ERRNO && errno == ENOENT)
306 continue;
307 if (error || (opt_all && cnt >= 0))
308 rval |= report(path, dname, error);
309 if (isfatal(error))
310 break;
311 }
312 return rval;
313}
314
315static int
316report(const char *path, const char *name, int error)
317{
318 if (name)
319 name = stripath(name);
320 switch (error) {
321 case E_UNKNOWN:
322 printf("%s: Unknown format\n", path);
323 break;
324 case E_BADMD5:
325 printf("%s: Invalid MD5 format\n", path);
326 break;
327 case E_BADINF:
328 printf("%s: Invalid .inf format\n", path);
329 break;
330 case E_NAME:
331 printf("%s: Can't derive component name\n", path);
332 break;
333 case E_LENGTH:
334 printf("%s: %s: Size mismatch\n", path, name);
335 break;
336 case E_CHKSUM:
337 printf("%s: %s: Checksum mismatch\n", path, name);
338 break;
339 case E_ERRNO:
340 printf("%s: %s: %s\n", path, name, sys_errlist[errno]);
341 break;
342 default:
343 printf("%s: %s: OK\n", path, name);
344 }
345 return error != 0;
346}
347
348static const char *
349distname(const char *path, const char *name, const char *ext)
350{
351 static char buf[NAMESIZE];
352 size_t plen, nlen;
353 char *s;
354
355 if (opt_name)
356 name = opt_name;
357 else if (!name) {
358 if (!path)
359 return NULL;
360 name = stripath(path);
361 }
362 nlen = strlen(name);
363 if (ext && nlen > 4 && name[nlen - 4] == '.' &&
364 disttype(name + nlen - 3) == DISTINF)
365 nlen -= 4;
366 if (opt_dir) {
367 path = opt_dir;
368 plen = strlen(path);
369 } else
370 plen = path && (s = strrchr(path, '/')) != NULL ?
371 (size_t)(s - path) : 0;
372 if (plen + (plen > 0) + nlen + (ext ? 3 : 0) >= sizeof(buf))
373 return NULL;
374 s = buf;
375 if (plen) {
376 memcpy(s, path, plen);
377 s += plen;
378 *s++ = '/';
379 }
380 memcpy(s, name, nlen);
381 s += nlen;
382 if (ext) {
383 *s++ = '.';
384 memcpy(s, ext, 2);
385 s += 2;
386 }
387 *s = 0;
388 return buf;
389}
390
391static char *
392stripath(const char *path)
393{
394 const char *s;
395
396 return (char *)((s = strrchr(path, '/')) != NULL && s[1] ?
397 s + 1 : path);
398}
399
400static int
401distfile(const char *path)
402{
403 const char *s;
404 int type;
405
406 if ((type = disttype(path)) == DISTMD5 ||
407 ((s = strrchr(path, '.')) != NULL && s > path &&
408 (type = disttype(s + 1)) != 0))
409 return type;
410 return 0;
411}
412
413static int
414disttype(const char *name)
415{
416 static const char dname[DISTTYPES][4] = {"md5", "inf"};
417 int i;
418
419 for (i = 0; i < DISTTYPES; i++)
420 if (!strcmp(dname[i], name))
421 return 1 + i;
422 return 0;
423}
424
425static int
426fail(const char *path, const char *msg)
427{
428 if (opt_silent)
429 return 0;
430 warnx("%s: %s", path, msg ? msg : sys_errlist[errno]);
431 return 2;
432}
433
434static void
435usage(void)
436{
437 fprintf(stderr,
438 "usage: ckdist [-airsx] [-d dir] [-n name] [-t type] file ...\n");
439 exit(2);
440}