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