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