11de7b4b8SPedro F. Giffuni /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
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
30dcf118f1SJordan K. Hubbard #include <sys/types.h>
31dcf118f1SJordan K. Hubbard #include <sys/stat.h>
32fadcf8aeSRobert Drehmel
33dcf118f1SJordan K. Hubbard #include <err.h>
34dcf118f1SJordan K. Hubbard #include <errno.h>
3555c5024eSPhilippe Charnier #include <fcntl.h>
3655c5024eSPhilippe Charnier #include <fts.h>
3755c5024eSPhilippe Charnier #include <md5.h>
3855c5024eSPhilippe Charnier #include <stdio.h>
39fadcf8aeSRobert Drehmel #include <stdint.h>
40dcf118f1SJordan K. Hubbard #include <stdlib.h>
41dcf118f1SJordan K. Hubbard #include <string.h>
4255c5024eSPhilippe Charnier #include <unistd.h>
43dcf118f1SJordan K. Hubbard
44fadcf8aeSRobert Drehmel extern int crc(int fd, uint32_t *cval, off_t *clen);
45dcf118f1SJordan K. Hubbard
46dcf118f1SJordan K. Hubbard #define DISTMD5 1 /* MD5 format */
47dcf118f1SJordan K. Hubbard #define DISTINF 2 /* .inf format */
48dcf118f1SJordan K. Hubbard #define DISTTYPES 2 /* types supported */
49dcf118f1SJordan K. Hubbard
50dcf118f1SJordan K. Hubbard #define E_UNKNOWN 1 /* Unknown format */
51dcf118f1SJordan K. Hubbard #define E_BADMD5 2 /* Invalid MD5 format */
52dcf118f1SJordan K. Hubbard #define E_BADINF 3 /* Invalid .inf format */
53dcf118f1SJordan K. Hubbard #define E_NAME 4 /* Can't derive component name */
54dcf118f1SJordan K. Hubbard #define E_LENGTH 5 /* Length mismatch */
55dcf118f1SJordan K. Hubbard #define E_CHKSUM 6 /* Checksum mismatch */
56dcf118f1SJordan K. Hubbard #define E_ERRNO 7 /* sys_errlist[errno] */
57dcf118f1SJordan K. Hubbard
58dcf118f1SJordan K. Hubbard #define isfatal(err) ((err) && (err) <= E_NAME)
59dcf118f1SJordan K. Hubbard
60dcf118f1SJordan K. Hubbard #define NAMESIZE 256 /* filename buffer size */
61dcf118f1SJordan K. Hubbard #define MDSUMLEN 32 /* length of MD5 message digest */
62dcf118f1SJordan K. Hubbard
63dcf118f1SJordan K. Hubbard #define isstdin(path) ((path)[0] == '-' && !(path)[1])
64dcf118f1SJordan K. Hubbard
65dcf118f1SJordan K. Hubbard static const char *opt_dir; /* where to look for components */
66dcf118f1SJordan K. Hubbard static const char *opt_name; /* name for accessing components */
67dcf118f1SJordan K. Hubbard static int opt_all; /* report on all components */
68dcf118f1SJordan K. Hubbard static int opt_ignore; /* ignore missing components */
69dcf118f1SJordan K. Hubbard static int opt_recurse; /* search directories recursively */
70dcf118f1SJordan K. Hubbard static int opt_silent; /* silent about inaccessible files */
71dcf118f1SJordan K. Hubbard static int opt_type; /* dist type: md5 or inf */
72dcf118f1SJordan K. Hubbard static int opt_exist; /* just verify existence */
73dcf118f1SJordan K. Hubbard
74dcf118f1SJordan K. Hubbard static int ckdist(const char *path, int type);
75dcf118f1SJordan K. Hubbard static int chkmd5(FILE * fp, const char *path);
76dcf118f1SJordan K. Hubbard static int chkinf(FILE * fp, const char *path);
77dcf118f1SJordan K. Hubbard static int report(const char *path, const char *name, int error);
78dcf118f1SJordan K. Hubbard static const char *distname(const char *path, const char *name,
79dcf118f1SJordan K. Hubbard const char *ext);
809d21c94eSXin LI static const char *stripath(const char *path);
81dcf118f1SJordan K. Hubbard static int distfile(const char *path);
82dcf118f1SJordan K. Hubbard static int disttype(const char *name);
83dcf118f1SJordan K. Hubbard static int fail(const char *path, const char *msg);
84*72e1ea2fSAlfonso Gregory static void usage(void) __dead2;
85dcf118f1SJordan K. Hubbard
86dcf118f1SJordan K. Hubbard int
main(int argc,char * argv[])87dcf118f1SJordan K. Hubbard main(int argc, char *argv[])
88dcf118f1SJordan K. Hubbard {
89dcf118f1SJordan K. Hubbard static char *arg[2];
90dcf118f1SJordan K. Hubbard struct stat sb;
91dcf118f1SJordan K. Hubbard FTS *ftsp;
92dcf118f1SJordan K. Hubbard FTSENT *f;
93dcf118f1SJordan K. Hubbard int rval, c, type;
94dcf118f1SJordan K. Hubbard
95dcf118f1SJordan K. Hubbard while ((c = getopt(argc, argv, "ad:in:rst:x")) != -1)
96dcf118f1SJordan K. Hubbard switch (c) {
97dcf118f1SJordan K. Hubbard case 'a':
98dcf118f1SJordan K. Hubbard opt_all = 1;
99dcf118f1SJordan K. Hubbard break;
100dcf118f1SJordan K. Hubbard case 'd':
101dcf118f1SJordan K. Hubbard opt_dir = optarg;
102dcf118f1SJordan K. Hubbard break;
103dcf118f1SJordan K. Hubbard case 'i':
104dcf118f1SJordan K. Hubbard opt_ignore = 1;
105dcf118f1SJordan K. Hubbard break;
106dcf118f1SJordan K. Hubbard case 'n':
107dcf118f1SJordan K. Hubbard opt_name = optarg;
108dcf118f1SJordan K. Hubbard break;
109dcf118f1SJordan K. Hubbard case 'r':
110dcf118f1SJordan K. Hubbard opt_recurse = 1;
111dcf118f1SJordan K. Hubbard break;
112dcf118f1SJordan K. Hubbard case 's':
113dcf118f1SJordan K. Hubbard opt_silent = 1;
114dcf118f1SJordan K. Hubbard break;
115dcf118f1SJordan K. Hubbard case 't':
116dcf118f1SJordan K. Hubbard if ((opt_type = disttype(optarg)) == 0) {
117dcf118f1SJordan K. Hubbard warnx("illegal argument to -t option");
118dcf118f1SJordan K. Hubbard usage();
119dcf118f1SJordan K. Hubbard }
120dcf118f1SJordan K. Hubbard break;
121dcf118f1SJordan K. Hubbard case 'x':
122dcf118f1SJordan K. Hubbard opt_exist = 1;
123dcf118f1SJordan K. Hubbard break;
124dcf118f1SJordan K. Hubbard default:
125dcf118f1SJordan K. Hubbard usage();
126dcf118f1SJordan K. Hubbard }
127dcf118f1SJordan K. Hubbard argc -= optind;
128dcf118f1SJordan K. Hubbard argv += optind;
129dcf118f1SJordan K. Hubbard if (argc < 1)
130dcf118f1SJordan K. Hubbard usage();
131dcf118f1SJordan K. Hubbard if (opt_dir) {
132dcf118f1SJordan K. Hubbard if (stat(opt_dir, &sb))
1337f69f4fdSPhilippe Charnier err(2, "%s", opt_dir);
134dcf118f1SJordan K. Hubbard if (!S_ISDIR(sb.st_mode))
13555c5024eSPhilippe Charnier errx(2, "%s: not a directory", opt_dir);
136dcf118f1SJordan K. Hubbard }
137dcf118f1SJordan K. Hubbard rval = 0;
138dcf118f1SJordan K. Hubbard do {
139dcf118f1SJordan K. Hubbard if (isstdin(*argv))
140dcf118f1SJordan K. Hubbard rval |= ckdist(*argv, opt_type);
141dcf118f1SJordan K. Hubbard else if (stat(*argv, &sb))
142dcf118f1SJordan K. Hubbard rval |= fail(*argv, NULL);
143dcf118f1SJordan K. Hubbard else if (S_ISREG(sb.st_mode))
144dcf118f1SJordan K. Hubbard rval |= ckdist(*argv, opt_type);
145dcf118f1SJordan K. Hubbard else {
146dcf118f1SJordan K. Hubbard arg[0] = *argv;
147dcf118f1SJordan K. Hubbard if ((ftsp = fts_open(arg, FTS_LOGICAL, NULL)) == NULL)
148dcf118f1SJordan K. Hubbard err(2, "fts_open");
1492dfa4b66SBryan Drewery while (errno = 0, (f = fts_read(ftsp)) != NULL)
150dcf118f1SJordan K. Hubbard switch (f->fts_info) {
151dcf118f1SJordan K. Hubbard case FTS_DC:
152dcf118f1SJordan K. Hubbard rval = fail(f->fts_path, "Directory causes a cycle");
153dcf118f1SJordan K. Hubbard break;
154dcf118f1SJordan K. Hubbard case FTS_DNR:
155dcf118f1SJordan K. Hubbard case FTS_ERR:
156dcf118f1SJordan K. Hubbard case FTS_NS:
157dcf118f1SJordan K. Hubbard rval = fail(f->fts_path, sys_errlist[f->fts_errno]);
158dcf118f1SJordan K. Hubbard break;
159dcf118f1SJordan K. Hubbard case FTS_D:
160dcf118f1SJordan K. Hubbard if (!opt_recurse && f->fts_level > FTS_ROOTLEVEL &&
161dcf118f1SJordan K. Hubbard fts_set(ftsp, f, FTS_SKIP))
162dcf118f1SJordan K. Hubbard err(2, "fts_set");
163dcf118f1SJordan K. Hubbard break;
164dcf118f1SJordan K. Hubbard case FTS_F:
165dcf118f1SJordan K. Hubbard if ((type = distfile(f->fts_name)) != 0 &&
166dcf118f1SJordan K. Hubbard (!opt_type || type == opt_type))
167dcf118f1SJordan K. Hubbard rval |= ckdist(f->fts_path, type);
168dcf118f1SJordan K. Hubbard break;
169dcf118f1SJordan K. Hubbard default: ;
170dcf118f1SJordan K. Hubbard }
171dcf118f1SJordan K. Hubbard if (errno)
172dcf118f1SJordan K. Hubbard err(2, "fts_read");
173dcf118f1SJordan K. Hubbard if (fts_close(ftsp))
174dcf118f1SJordan K. Hubbard err(2, "fts_close");
175dcf118f1SJordan K. Hubbard }
176dcf118f1SJordan K. Hubbard } while (*++argv);
177dcf118f1SJordan K. Hubbard return rval;
178dcf118f1SJordan K. Hubbard }
179dcf118f1SJordan K. Hubbard
180dcf118f1SJordan K. Hubbard static int
ckdist(const char * path,int type)181dcf118f1SJordan K. Hubbard ckdist(const char *path, int type)
182dcf118f1SJordan K. Hubbard {
183dcf118f1SJordan K. Hubbard FILE *fp;
184dcf118f1SJordan K. Hubbard int rval, c;
185dcf118f1SJordan K. Hubbard
186dcf118f1SJordan K. Hubbard if (isstdin(path)) {
187dcf118f1SJordan K. Hubbard path = "(stdin)";
188dcf118f1SJordan K. Hubbard fp = stdin;
189dcf118f1SJordan K. Hubbard } else if ((fp = fopen(path, "r")) == NULL)
190dcf118f1SJordan K. Hubbard return fail(path, NULL);
191dcf118f1SJordan K. Hubbard if (!type) {
192dcf118f1SJordan K. Hubbard if (fp != stdin)
193dcf118f1SJordan K. Hubbard type = distfile(path);
194dcf118f1SJordan K. Hubbard if (!type)
195dcf118f1SJordan K. Hubbard if ((c = fgetc(fp)) != EOF) {
196dcf118f1SJordan K. Hubbard type = c == 'M' ? DISTMD5 : c == 'P' ? DISTINF : 0;
197dcf118f1SJordan K. Hubbard (void)ungetc(c, fp);
198dcf118f1SJordan K. Hubbard }
199dcf118f1SJordan K. Hubbard }
200dcf118f1SJordan K. Hubbard switch (type) {
201dcf118f1SJordan K. Hubbard case DISTMD5:
202dcf118f1SJordan K. Hubbard rval = chkmd5(fp, path);
203dcf118f1SJordan K. Hubbard break;
204dcf118f1SJordan K. Hubbard case DISTINF:
205dcf118f1SJordan K. Hubbard rval = chkinf(fp, path);
206dcf118f1SJordan K. Hubbard break;
207dcf118f1SJordan K. Hubbard default:
208dcf118f1SJordan K. Hubbard rval = report(path, NULL, E_UNKNOWN);
209dcf118f1SJordan K. Hubbard }
210dcf118f1SJordan K. Hubbard if (ferror(fp))
2117f69f4fdSPhilippe Charnier warn("%s", path);
212dcf118f1SJordan K. Hubbard if (fp != stdin && fclose(fp))
2137f69f4fdSPhilippe Charnier err(2, "%s", path);
214dcf118f1SJordan K. Hubbard return rval;
215dcf118f1SJordan K. Hubbard }
216dcf118f1SJordan K. Hubbard
217dcf118f1SJordan K. Hubbard static int
chkmd5(FILE * fp,const char * path)218dcf118f1SJordan K. Hubbard chkmd5(FILE * fp, const char *path)
219dcf118f1SJordan K. Hubbard {
220dcf118f1SJordan K. Hubbard char buf[298]; /* "MD5 (NAMESIZE = MDSUMLEN" */
221dcf118f1SJordan K. Hubbard char name[NAMESIZE + 1];
222dcf118f1SJordan K. Hubbard char sum[MDSUMLEN + 1], chk[MDSUMLEN + 1];
223dcf118f1SJordan K. Hubbard const char *dname;
224dcf118f1SJordan K. Hubbard char *s;
225dcf118f1SJordan K. Hubbard int rval, error, c, fd;
226dcf118f1SJordan K. Hubbard char ch;
227dcf118f1SJordan K. Hubbard
228dcf118f1SJordan K. Hubbard rval = 0;
229dcf118f1SJordan K. Hubbard while (fgets(buf, sizeof(buf), fp)) {
230dcf118f1SJordan K. Hubbard dname = NULL;
231dcf118f1SJordan K. Hubbard error = 0;
232dcf118f1SJordan K. Hubbard if (((c = sscanf(buf, "MD5 (%256s = %32s%c", name, sum,
233dcf118f1SJordan K. Hubbard &ch)) != 3 && (!feof(fp) || c != 2)) ||
234dcf118f1SJordan K. Hubbard (c == 3 && ch != '\n') ||
235dcf118f1SJordan K. Hubbard (s = strrchr(name, ')')) == NULL ||
236dcf118f1SJordan K. Hubbard strlen(sum) != MDSUMLEN)
237dcf118f1SJordan K. Hubbard error = E_BADMD5;
238dcf118f1SJordan K. Hubbard else {
239dcf118f1SJordan K. Hubbard *s = 0;
240dcf118f1SJordan K. Hubbard if ((dname = distname(path, name, NULL)) == NULL)
241dcf118f1SJordan K. Hubbard error = E_NAME;
242dcf118f1SJordan K. Hubbard else if (opt_exist) {
243dcf118f1SJordan K. Hubbard if ((fd = open(dname, O_RDONLY)) == -1)
244dcf118f1SJordan K. Hubbard error = E_ERRNO;
245dcf118f1SJordan K. Hubbard else if (close(fd))
2467f69f4fdSPhilippe Charnier err(2, "%s", dname);
2479d21c94eSXin LI } else if (!MD5File(dname, chk))
248dcf118f1SJordan K. Hubbard error = E_ERRNO;
249dcf118f1SJordan K. Hubbard else if (strcmp(chk, sum))
250dcf118f1SJordan K. Hubbard error = E_CHKSUM;
251dcf118f1SJordan K. Hubbard }
252dcf118f1SJordan K. Hubbard if (opt_ignore && error == E_ERRNO && errno == ENOENT)
253dcf118f1SJordan K. Hubbard continue;
254dcf118f1SJordan K. Hubbard if (error || opt_all)
255dcf118f1SJordan K. Hubbard rval |= report(path, dname, error);
256dcf118f1SJordan K. Hubbard if (isfatal(error))
257dcf118f1SJordan K. Hubbard break;
258dcf118f1SJordan K. Hubbard }
259dcf118f1SJordan K. Hubbard return rval;
260dcf118f1SJordan K. Hubbard }
261dcf118f1SJordan K. Hubbard
262dcf118f1SJordan K. Hubbard static int
chkinf(FILE * fp,const char * path)263dcf118f1SJordan K. Hubbard chkinf(FILE * fp, const char *path)
264dcf118f1SJordan K. Hubbard {
265dcf118f1SJordan K. Hubbard char buf[30]; /* "cksum.2 = 10 6" */
266dcf118f1SJordan K. Hubbard char ext[3];
267dcf118f1SJordan K. Hubbard struct stat sb;
268dcf118f1SJordan K. Hubbard const char *dname;
269fadcf8aeSRobert Drehmel off_t len;
270fadcf8aeSRobert Drehmel u_long sum;
271fadcf8aeSRobert Drehmel intmax_t sumlen;
272fadcf8aeSRobert Drehmel uint32_t chk;
273dcf118f1SJordan K. Hubbard int rval, error, c, pieces, cnt, fd;
274dcf118f1SJordan K. Hubbard char ch;
275dcf118f1SJordan K. Hubbard
276dcf118f1SJordan K. Hubbard rval = 0;
277dcf118f1SJordan K. Hubbard for (cnt = -1; fgets(buf, sizeof(buf), fp); cnt++) {
278dcf118f1SJordan K. Hubbard fd = -1;
279dcf118f1SJordan K. Hubbard dname = NULL;
280dcf118f1SJordan K. Hubbard error = 0;
281dcf118f1SJordan K. Hubbard if (cnt == -1) {
282dcf118f1SJordan K. Hubbard if ((c = sscanf(buf, "Pieces = %d%c", &pieces, &ch)) != 2 ||
283dcf118f1SJordan K. Hubbard ch != '\n' || pieces < 1)
284dcf118f1SJordan K. Hubbard error = E_BADINF;
285fadcf8aeSRobert Drehmel } else if (((c = sscanf(buf, "cksum.%2s = %lu %jd%c", ext, &sum,
286fadcf8aeSRobert Drehmel &sumlen, &ch)) != 4 &&
287dcf118f1SJordan K. Hubbard (!feof(fp) || c != 3)) || (c == 4 && ch != '\n') ||
288dcf118f1SJordan K. Hubbard ext[0] != 'a' + cnt / 26 || ext[1] != 'a' + cnt % 26)
289dcf118f1SJordan K. Hubbard error = E_BADINF;
290dcf118f1SJordan K. Hubbard else if ((dname = distname(fp == stdin ? NULL : path, NULL,
291dcf118f1SJordan K. Hubbard ext)) == NULL)
292dcf118f1SJordan K. Hubbard error = E_NAME;
293dcf118f1SJordan K. Hubbard else if ((fd = open(dname, O_RDONLY)) == -1)
294dcf118f1SJordan K. Hubbard error = E_ERRNO;
295dcf118f1SJordan K. Hubbard else if (fstat(fd, &sb))
296dcf118f1SJordan K. Hubbard error = E_ERRNO;
297fadcf8aeSRobert Drehmel else if (sb.st_size != (off_t)sumlen)
298dcf118f1SJordan K. Hubbard error = E_LENGTH;
299dcf118f1SJordan K. Hubbard else if (!opt_exist) {
300dcf118f1SJordan K. Hubbard if (crc(fd, &chk, &len))
301dcf118f1SJordan K. Hubbard error = E_ERRNO;
302dcf118f1SJordan K. Hubbard else if (chk != sum)
303dcf118f1SJordan K. Hubbard error = E_CHKSUM;
304dcf118f1SJordan K. Hubbard }
305dcf118f1SJordan K. Hubbard if (fd != -1 && close(fd))
3067f69f4fdSPhilippe Charnier err(2, "%s", dname);
307dcf118f1SJordan K. Hubbard if (opt_ignore && error == E_ERRNO && errno == ENOENT)
308dcf118f1SJordan K. Hubbard continue;
309dcf118f1SJordan K. Hubbard if (error || (opt_all && cnt >= 0))
310dcf118f1SJordan K. Hubbard rval |= report(path, dname, error);
311dcf118f1SJordan K. Hubbard if (isfatal(error))
312dcf118f1SJordan K. Hubbard break;
313dcf118f1SJordan K. Hubbard }
314dcf118f1SJordan K. Hubbard return rval;
315dcf118f1SJordan K. Hubbard }
316dcf118f1SJordan K. Hubbard
317dcf118f1SJordan K. Hubbard static int
report(const char * path,const char * name,int error)318dcf118f1SJordan K. Hubbard report(const char *path, const char *name, int error)
319dcf118f1SJordan K. Hubbard {
320dcf118f1SJordan K. Hubbard if (name)
321dcf118f1SJordan K. Hubbard name = stripath(name);
322dcf118f1SJordan K. Hubbard switch (error) {
323dcf118f1SJordan K. Hubbard case E_UNKNOWN:
324dcf118f1SJordan K. Hubbard printf("%s: Unknown format\n", path);
325dcf118f1SJordan K. Hubbard break;
326dcf118f1SJordan K. Hubbard case E_BADMD5:
327dcf118f1SJordan K. Hubbard printf("%s: Invalid MD5 format\n", path);
328dcf118f1SJordan K. Hubbard break;
329dcf118f1SJordan K. Hubbard case E_BADINF:
330dcf118f1SJordan K. Hubbard printf("%s: Invalid .inf format\n", path);
331dcf118f1SJordan K. Hubbard break;
332dcf118f1SJordan K. Hubbard case E_NAME:
333dcf118f1SJordan K. Hubbard printf("%s: Can't derive component name\n", path);
334dcf118f1SJordan K. Hubbard break;
335dcf118f1SJordan K. Hubbard case E_LENGTH:
336dcf118f1SJordan K. Hubbard printf("%s: %s: Size mismatch\n", path, name);
337dcf118f1SJordan K. Hubbard break;
338dcf118f1SJordan K. Hubbard case E_CHKSUM:
339dcf118f1SJordan K. Hubbard printf("%s: %s: Checksum mismatch\n", path, name);
340dcf118f1SJordan K. Hubbard break;
341dcf118f1SJordan K. Hubbard case E_ERRNO:
342dcf118f1SJordan K. Hubbard printf("%s: %s: %s\n", path, name, sys_errlist[errno]);
343dcf118f1SJordan K. Hubbard break;
344dcf118f1SJordan K. Hubbard default:
345dcf118f1SJordan K. Hubbard printf("%s: %s: OK\n", path, name);
346dcf118f1SJordan K. Hubbard }
347dcf118f1SJordan K. Hubbard return error != 0;
348dcf118f1SJordan K. Hubbard }
349dcf118f1SJordan K. Hubbard
350dcf118f1SJordan K. Hubbard static const char *
distname(const char * path,const char * name,const char * ext)351dcf118f1SJordan K. Hubbard distname(const char *path, const char *name, const char *ext)
352dcf118f1SJordan K. Hubbard {
353dcf118f1SJordan K. Hubbard static char buf[NAMESIZE];
354dcf118f1SJordan K. Hubbard size_t plen, nlen;
355dcf118f1SJordan K. Hubbard char *s;
356dcf118f1SJordan K. Hubbard
357dcf118f1SJordan K. Hubbard if (opt_name)
358dcf118f1SJordan K. Hubbard name = opt_name;
359dcf118f1SJordan K. Hubbard else if (!name) {
360dcf118f1SJordan K. Hubbard if (!path)
361dcf118f1SJordan K. Hubbard return NULL;
362dcf118f1SJordan K. Hubbard name = stripath(path);
363dcf118f1SJordan K. Hubbard }
364dcf118f1SJordan K. Hubbard nlen = strlen(name);
365dcf118f1SJordan K. Hubbard if (ext && nlen > 4 && name[nlen - 4] == '.' &&
366dcf118f1SJordan K. Hubbard disttype(name + nlen - 3) == DISTINF)
367dcf118f1SJordan K. Hubbard nlen -= 4;
368dcf118f1SJordan K. Hubbard if (opt_dir) {
369dcf118f1SJordan K. Hubbard path = opt_dir;
370dcf118f1SJordan K. Hubbard plen = strlen(path);
371dcf118f1SJordan K. Hubbard } else
372dcf118f1SJordan K. Hubbard plen = path && (s = strrchr(path, '/')) != NULL ?
373dcf118f1SJordan K. Hubbard (size_t)(s - path) : 0;
374dcf118f1SJordan K. Hubbard if (plen + (plen > 0) + nlen + (ext ? 3 : 0) >= sizeof(buf))
375dcf118f1SJordan K. Hubbard return NULL;
376dcf118f1SJordan K. Hubbard s = buf;
377dcf118f1SJordan K. Hubbard if (plen) {
378dcf118f1SJordan K. Hubbard memcpy(s, path, plen);
379dcf118f1SJordan K. Hubbard s += plen;
380dcf118f1SJordan K. Hubbard *s++ = '/';
381dcf118f1SJordan K. Hubbard }
382dcf118f1SJordan K. Hubbard memcpy(s, name, nlen);
383dcf118f1SJordan K. Hubbard s += nlen;
384dcf118f1SJordan K. Hubbard if (ext) {
385dcf118f1SJordan K. Hubbard *s++ = '.';
386dcf118f1SJordan K. Hubbard memcpy(s, ext, 2);
387dcf118f1SJordan K. Hubbard s += 2;
388dcf118f1SJordan K. Hubbard }
389dcf118f1SJordan K. Hubbard *s = 0;
390dcf118f1SJordan K. Hubbard return buf;
391dcf118f1SJordan K. Hubbard }
392dcf118f1SJordan K. Hubbard
3939d21c94eSXin LI static const char *
stripath(const char * path)394dcf118f1SJordan K. Hubbard stripath(const char *path)
395dcf118f1SJordan K. Hubbard {
396dcf118f1SJordan K. Hubbard const char *s;
397dcf118f1SJordan K. Hubbard
3989d21c94eSXin LI return ((s = strrchr(path, '/')) != NULL && s[1] ?
399dcf118f1SJordan K. Hubbard s + 1 : path);
400dcf118f1SJordan K. Hubbard }
401dcf118f1SJordan K. Hubbard
402dcf118f1SJordan K. Hubbard static int
distfile(const char * path)403dcf118f1SJordan K. Hubbard distfile(const char *path)
404dcf118f1SJordan K. Hubbard {
405dcf118f1SJordan K. Hubbard const char *s;
406dcf118f1SJordan K. Hubbard int type;
407dcf118f1SJordan K. Hubbard
408dcf118f1SJordan K. Hubbard if ((type = disttype(path)) == DISTMD5 ||
409dcf118f1SJordan K. Hubbard ((s = strrchr(path, '.')) != NULL && s > path &&
410dcf118f1SJordan K. Hubbard (type = disttype(s + 1)) != 0))
411dcf118f1SJordan K. Hubbard return type;
412dcf118f1SJordan K. Hubbard return 0;
413dcf118f1SJordan K. Hubbard }
414dcf118f1SJordan K. Hubbard
415dcf118f1SJordan K. Hubbard static int
disttype(const char * name)416dcf118f1SJordan K. Hubbard disttype(const char *name)
417dcf118f1SJordan K. Hubbard {
418dcf118f1SJordan K. Hubbard static const char dname[DISTTYPES][4] = {"md5", "inf"};
419dcf118f1SJordan K. Hubbard int i;
420dcf118f1SJordan K. Hubbard
421dcf118f1SJordan K. Hubbard for (i = 0; i < DISTTYPES; i++)
422dcf118f1SJordan K. Hubbard if (!strcmp(dname[i], name))
423dcf118f1SJordan K. Hubbard return 1 + i;
424dcf118f1SJordan K. Hubbard return 0;
425dcf118f1SJordan K. Hubbard }
426dcf118f1SJordan K. Hubbard
427dcf118f1SJordan K. Hubbard static int
fail(const char * path,const char * msg)428dcf118f1SJordan K. Hubbard fail(const char *path, const char *msg)
429dcf118f1SJordan K. Hubbard {
430dcf118f1SJordan K. Hubbard if (opt_silent)
431dcf118f1SJordan K. Hubbard return 0;
432dcf118f1SJordan K. Hubbard warnx("%s: %s", path, msg ? msg : sys_errlist[errno]);
433dcf118f1SJordan K. Hubbard return 2;
434dcf118f1SJordan K. Hubbard }
435dcf118f1SJordan K. Hubbard
436dcf118f1SJordan K. Hubbard static void
usage(void)437dcf118f1SJordan K. Hubbard usage(void)
438dcf118f1SJordan K. Hubbard {
439dcf118f1SJordan K. Hubbard fprintf(stderr,
44055c5024eSPhilippe Charnier "usage: ckdist [-airsx] [-d dir] [-n name] [-t type] file ...\n");
441dcf118f1SJordan K. Hubbard exit(2);
442dcf118f1SJordan K. Hubbard }
443