1 1.21 alnsn /* $NetBSD: veriexecgen.c,v 1.21 2019/08/01 08:51:52 alnsn Exp $ */ 2 1.1 elad 3 1.1 elad /*- 4 1.1 elad * Copyright (c) 2006 The NetBSD Foundation, Inc. 5 1.1 elad * All rights reserved. 6 1.1 elad * 7 1.1 elad * This code is derived from software contributed to The NetBSD Foundation 8 1.1 elad * by Matt Fleming. 9 1.1 elad * 10 1.1 elad * Redistribution and use in source and binary forms, with or without 11 1.1 elad * modification, are permitted provided that the following conditions 12 1.1 elad * are met: 13 1.1 elad * 1. Redistributions of source code must retain the above copyright 14 1.1 elad * notice, this list of conditions and the following disclaimer. 15 1.1 elad * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 elad * notice, this list of conditions and the following disclaimer in the 17 1.1 elad * documentation and/or other materials provided with the distribution. 18 1.1 elad * 19 1.1 elad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 elad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 elad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 elad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 elad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 elad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 elad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 elad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 elad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 elad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 elad * POSSIBILITY OF SUCH DAMAGE. 30 1.1 elad */ 31 1.11 agc #if HAVE_NBTOOL_CONFIG_H 32 1.11 agc #include "nbtool_config.h" 33 1.11 agc #endif 34 1.11 agc 35 1.11 agc #include <sys/cdefs.h> 36 1.11 agc 37 1.11 agc #ifndef lint 38 1.11 agc #ifdef __RCSID 39 1.21 alnsn __RCSID("$NetBSD: veriexecgen.c,v 1.21 2019/08/01 08:51:52 alnsn Exp $"); 40 1.11 agc #endif 41 1.11 agc #endif /* not lint */ 42 1.11 agc 43 1.1 elad #include <sys/param.h> 44 1.1 elad #include <sys/types.h> 45 1.1 elad #include <sys/queue.h> 46 1.1 elad #include <sys/stat.h> 47 1.1 elad #include <sys/dirent.h> 48 1.1 elad #include <sys/verified_exec.h> 49 1.1 elad 50 1.1 elad #include <err.h> 51 1.1 elad #include <errno.h> 52 1.1 elad #include <fts.h> 53 1.1 elad #include <stdio.h> 54 1.1 elad #include <stdlib.h> 55 1.1 elad #include <string.h> 56 1.1 elad #include <time.h> 57 1.1 elad #include <unistd.h> 58 1.1 elad #include <util.h> 59 1.1 elad 60 1.8 christos #include <sha2.h> 61 1.1 elad 62 1.1 elad #define IS_EXEC(mode) ((mode) & (S_IXUSR | S_IXGRP | S_IXOTH)) 63 1.1 elad 64 1.1 elad #define DEFAULT_DBFILE "/etc/signatures" 65 1.1 elad #define DEFAULT_HASH "sha256" 66 1.1 elad #define DEFAULT_SYSPATHS { "/bin", "/sbin", "/usr/bin", "/usr/sbin", \ 67 1.6 elad "/lib", "/usr/lib", "/libexec", "/usr/libexec", \ 68 1.6 elad NULL } 69 1.1 elad 70 1.11 agc /* this struct defines a hash algorithm */ 71 1.11 agc typedef struct hash_t { 72 1.11 agc const char *hashname; /* algorithm name */ 73 1.11 agc char *(*filefunc)(const char *, char *); /* function */ 74 1.11 agc } hash_t; 75 1.11 agc 76 1.11 agc /* this struct encapsulates various diverse options and arguments */ 77 1.11 agc typedef struct veriexecgen_t { 78 1.11 agc int all_files; /* scan also for non-executable files */ 79 1.11 agc int append_output; /* append output to existing sigs file */ 80 1.11 agc char *dbfile; /* name of signatures database file */ 81 1.11 agc int exit_on_error; /* exit if we can't create a hash */ 82 1.11 agc char *prefix; /* any prefix to be discarded on output */ 83 1.11 agc int recursive_scan;/* perform scan for files recursively */ 84 1.11 agc int scan_system_dirs; /* just scan system directories */ 85 1.11 agc int verbose; /* verbosity level */ 86 1.15 elad int stamp; /* put a timestamp */ 87 1.20 alnsn FILE *from_file; /* read from a file or stdin */ 88 1.20 alnsn char *from_filename; 89 1.11 agc } veriexecgen_t; 90 1.11 agc 91 1.10 agc /* this struct describes a directory entry to generate a hash for */ 92 1.1 elad struct fentry { 93 1.10 agc char filename[MAXPATHLEN]; /* name of entry */ 94 1.10 agc char *hash_val; /* its associated hash value */ 95 1.10 agc int flags; /* any associated flags */ 96 1.10 agc TAILQ_ENTRY(fentry) f; /* its place in the queue */ 97 1.1 elad }; 98 1.1 elad TAILQ_HEAD(, fentry) fehead; 99 1.1 elad 100 1.11 agc /* define the possible hash algorithms */ 101 1.11 agc static hash_t hashes[] = { 102 1.1 elad { "SHA256", SHA256_File }, 103 1.1 elad { "SHA384", SHA384_File }, 104 1.1 elad { "SHA512", SHA512_File }, 105 1.1 elad { NULL, NULL }, 106 1.1 elad }; 107 1.1 elad 108 1.10 agc static int Fflag; 109 1.9 agc 110 1.10 agc static int make_immutable; /* set immutable flag on signatures file */ 111 1.9 agc 112 1.9 agc /* warn about a problem - exit if exit_on_error is set */ 113 1.9 agc static void 114 1.11 agc gripe(veriexecgen_t *vp, const char *fmt, const char *filename) 115 1.9 agc { 116 1.9 agc warn(fmt, filename); 117 1.11 agc if (vp->exit_on_error) { 118 1.9 agc /* error out on problematic files */ 119 1.9 agc exit(EXIT_FAILURE); 120 1.9 agc } 121 1.9 agc } 122 1.1 elad 123 1.10 agc /* print usage message */ 124 1.1 elad static void 125 1.1 elad usage(void) 126 1.1 elad { 127 1.1 elad (void)fprintf(stderr, 128 1.20 alnsn "usage: %s [-AaDrSTvW] [-d dir] [-f file] [-o fingerprintdb] [-p prefix]\n" 129 1.12 wiz "\t\t [-t algorithm]\n" 130 1.12 wiz "\t%s [-h]\n", getprogname(), getprogname()); 131 1.1 elad } 132 1.1 elad 133 1.10 agc /* tell people what we're doing - scan dirs, fingerprint etc */ 134 1.1 elad static void 135 1.11 agc banner(veriexecgen_t *vp, hash_t *hash_type, char **search_path) 136 1.1 elad { 137 1.1 elad int j; 138 1.1 elad 139 1.1 elad (void)printf("Fingerprinting "); 140 1.1 elad 141 1.20 alnsn if (search_path) { 142 1.20 alnsn for (j = 0; search_path[j] != NULL; j++) 143 1.20 alnsn (void)printf("%s ", search_path[j]); 144 1.20 alnsn } else if (vp->from_file == stdin) { 145 1.20 alnsn (void)printf("files from stdin "); 146 1.20 alnsn } else { 147 1.20 alnsn (void)printf("files from %s ", 148 1.20 alnsn vp->from_filename ? vp->from_filename : "???"); 149 1.20 alnsn } 150 1.1 elad 151 1.1 elad (void)printf("(%s) (%s) using %s\n", 152 1.11 agc vp->all_files ? "all files" : "executables only", 153 1.11 agc vp->recursive_scan ? "recursive" : "non-recursive", 154 1.1 elad hash_type->hashname); 155 1.1 elad } 156 1.1 elad 157 1.10 agc /* find a hash algorithm, given its name */ 158 1.11 agc static hash_t * 159 1.1 elad find_hash(char *hash_type) 160 1.1 elad { 161 1.11 agc hash_t *hash; 162 1.1 elad 163 1.1 elad for (hash = hashes; hash->hashname != NULL; hash++) 164 1.1 elad if (strcasecmp(hash_type, hash->hashname) == 0) 165 1.1 elad return hash; 166 1.1 elad return NULL; 167 1.1 elad } 168 1.1 elad 169 1.10 agc /* perform the hashing operation on `filename' */ 170 1.1 elad static char * 171 1.11 agc do_hash(char *filename, hash_t * h) 172 1.1 elad { 173 1.1 elad return h->filefunc(filename, NULL); 174 1.1 elad } 175 1.1 elad 176 1.10 agc /* return flags for `path' */ 177 1.1 elad static int 178 1.1 elad figure_flags(char *path, mode_t mode) 179 1.1 elad { 180 1.1 elad #ifdef notyet 181 1.1 elad if (Fflag) { 182 1.1 elad /* Try to figure out right flag(s). */ 183 1.1 elad return VERIEXEC_DIRECT; 184 1.10 agc } 185 1.1 elad #endif /* notyet */ 186 1.1 elad 187 1.10 agc return (IS_EXEC(mode)) ? 0 : VERIEXEC_FILE; 188 1.1 elad } 189 1.1 elad 190 1.10 agc /* check to see that we don't have a duplicate entry */ 191 1.1 elad static int 192 1.1 elad check_dup(char *filename) 193 1.1 elad { 194 1.1 elad struct fentry *lwalk; 195 1.1 elad 196 1.1 elad TAILQ_FOREACH(lwalk, &fehead, f) { 197 1.15 elad if (strcmp(lwalk->filename, filename) == 0) 198 1.1 elad return 1; 199 1.1 elad } 200 1.1 elad 201 1.1 elad return 0; 202 1.1 elad } 203 1.1 elad 204 1.10 agc /* add a new entry to the list for `file' */ 205 1.1 elad static void 206 1.20 alnsn add_new_path_entry(veriexecgen_t *vp, const char *file, hash_t *hash) 207 1.20 alnsn { 208 1.20 alnsn struct stat sb; 209 1.20 alnsn struct fentry *e; 210 1.20 alnsn 211 1.20 alnsn if (stat(file, &sb) == -1) { 212 1.20 alnsn gripe(vp, "Cannot stat file `%s'", file); 213 1.20 alnsn return; 214 1.20 alnsn } 215 1.20 alnsn 216 1.20 alnsn if (!vp->all_files && !IS_EXEC(sb.st_mode)) 217 1.20 alnsn return; 218 1.20 alnsn 219 1.20 alnsn e = ecalloc(1UL, sizeof(*e)); 220 1.20 alnsn 221 1.20 alnsn if (realpath(file, e->filename) == NULL) { 222 1.20 alnsn gripe(vp, "Cannot find absolute path `%s'", file); 223 1.20 alnsn return; 224 1.20 alnsn } 225 1.20 alnsn if (check_dup(e->filename)) { 226 1.20 alnsn free(e); 227 1.20 alnsn return; 228 1.20 alnsn } 229 1.20 alnsn if ((e->hash_val = do_hash(e->filename, hash)) == NULL) { 230 1.20 alnsn gripe(vp, "Cannot calculate hash `%s'", e->filename); 231 1.20 alnsn return; 232 1.20 alnsn } 233 1.20 alnsn e->flags = figure_flags(e->filename, sb.st_mode); 234 1.20 alnsn 235 1.20 alnsn TAILQ_INSERT_TAIL(&fehead, e, f); 236 1.20 alnsn } 237 1.20 alnsn 238 1.20 alnsn /* add a new entry to the list for `file' */ 239 1.20 alnsn static void 240 1.20 alnsn add_new_ftsent_entry(veriexecgen_t *vp, FTSENT *file, hash_t *hash) 241 1.1 elad { 242 1.1 elad struct fentry *e; 243 1.1 elad struct stat sb; 244 1.1 elad 245 1.1 elad if (file->fts_info == FTS_SL) { 246 1.10 agc /* we have a symbolic link */ 247 1.9 agc if (stat(file->fts_path, &sb) == -1) { 248 1.11 agc gripe(vp, "Cannot stat symlink `%s'", file->fts_path); 249 1.9 agc return; 250 1.9 agc } 251 1.1 elad } else 252 1.1 elad sb = *file->fts_statp; 253 1.1 elad 254 1.19 sevan if (!vp->all_files && !IS_EXEC(sb.st_mode)) 255 1.1 elad return; 256 1.1 elad 257 1.1 elad e = ecalloc(1UL, sizeof(*e)); 258 1.1 elad 259 1.9 agc if (realpath(file->fts_accpath, e->filename) == NULL) { 260 1.11 agc gripe(vp, "Cannot find absolute path `%s'", file->fts_accpath); 261 1.9 agc return; 262 1.9 agc } 263 1.1 elad if (check_dup(e->filename)) { 264 1.1 elad free(e); 265 1.1 elad return; 266 1.1 elad } 267 1.9 agc if ((e->hash_val = do_hash(e->filename, hash)) == NULL) { 268 1.11 agc gripe(vp, "Cannot calculate hash `%s'", e->filename); 269 1.9 agc return; 270 1.9 agc } 271 1.1 elad e->flags = figure_flags(e->filename, sb.st_mode); 272 1.1 elad 273 1.1 elad TAILQ_INSERT_TAIL(&fehead, e, f); 274 1.1 elad } 275 1.1 elad 276 1.10 agc /* walk through a directory */ 277 1.1 elad static void 278 1.11 agc walk_dir(veriexecgen_t *vp, char **search_path, hash_t *hash) 279 1.1 elad { 280 1.1 elad FTS *fh; 281 1.1 elad FTSENT *file; 282 1.1 elad 283 1.9 agc if ((fh = fts_open(search_path, FTS_PHYSICAL, NULL)) == NULL) { 284 1.11 agc gripe(vp, "fts_open `%s'", (const char *)search_path); 285 1.9 agc return; 286 1.9 agc } 287 1.1 elad 288 1.1 elad while ((file = fts_read(fh)) != NULL) { 289 1.11 agc if (!vp->recursive_scan && file->fts_level > 1) { 290 1.1 elad fts_set(fh, file, FTS_SKIP); 291 1.1 elad continue; 292 1.1 elad } 293 1.1 elad 294 1.1 elad switch (file->fts_info) { 295 1.1 elad case FTS_D: 296 1.1 elad case FTS_DC: 297 1.1 elad case FTS_DP: 298 1.1 elad continue; 299 1.1 elad default: 300 1.1 elad break; 301 1.1 elad } 302 1.1 elad 303 1.1 elad if (file->fts_errno) { 304 1.11 agc if (vp->exit_on_error) { 305 1.10 agc errx(EXIT_FAILURE, "%s: %s", file->fts_path, 306 1.10 agc strerror(file->fts_errno)); 307 1.10 agc } 308 1.10 agc } else { 309 1.20 alnsn add_new_ftsent_entry(vp, file, hash); 310 1.1 elad } 311 1.1 elad } 312 1.1 elad 313 1.1 elad fts_close(fh); 314 1.1 elad } 315 1.1 elad 316 1.20 alnsn /* read files from `file' */ 317 1.20 alnsn static void 318 1.20 alnsn read_from_file(veriexecgen_t *vp, hash_t *hash, FILE *file) 319 1.20 alnsn { 320 1.20 alnsn char *line = NULL; 321 1.20 alnsn size_t linesize = 0; 322 1.20 alnsn ssize_t linelen; 323 1.20 alnsn 324 1.20 alnsn while ((linelen = getline(&line, &linesize, file)) != -1) { 325 1.20 alnsn if (linelen > 0 && line[linelen - 1] == '\n') 326 1.20 alnsn line[linelen - 1] = '\0'; 327 1.20 alnsn add_new_path_entry(vp, line, hash); 328 1.20 alnsn } 329 1.20 alnsn 330 1.20 alnsn if (ferror(stdin)) { 331 1.20 alnsn gripe(vp, "Error reading from stdin `%s'", strerror(errno)); 332 1.20 alnsn return; 333 1.20 alnsn } 334 1.20 alnsn } 335 1.20 alnsn 336 1.10 agc /* return a string representation of the flags */ 337 1.1 elad static char * 338 1.1 elad flags2str(int flags) 339 1.1 elad { 340 1.15 elad return (flags == 0) ? "" : "file, indirect"; 341 1.15 elad } 342 1.15 elad 343 1.15 elad static char * 344 1.15 elad escape(const char *s) 345 1.15 elad { 346 1.15 elad char *q, *p; 347 1.15 elad size_t len; 348 1.15 elad 349 1.15 elad len = strlen(s); 350 1.15 elad if (len >= MAXPATHLEN) 351 1.15 elad return (NULL); 352 1.15 elad 353 1.15 elad len *= 2; 354 1.15 elad q = p = calloc(1, len + 1); 355 1.15 elad 356 1.15 elad while (*s) { 357 1.15 elad if (*s == ' ' || *s == '\t') 358 1.15 elad *p++ = '\\'; 359 1.15 elad 360 1.15 elad *p++ = *s++; 361 1.15 elad } 362 1.15 elad 363 1.15 elad return (q); 364 1.1 elad } 365 1.1 elad 366 1.10 agc /* store the list in the signatures file */ 367 1.1 elad static void 368 1.11 agc store_entries(veriexecgen_t *vp, hash_t *hash) 369 1.1 elad { 370 1.1 elad FILE *fp; 371 1.1 elad int move = 1; 372 1.1 elad char old_dbfile[MAXPATHLEN]; 373 1.1 elad time_t ct; 374 1.1 elad struct stat sb; 375 1.1 elad struct fentry *e; 376 1.11 agc int prefixc; 377 1.1 elad 378 1.11 agc if (stat(vp->dbfile, &sb) != 0) { 379 1.1 elad if (errno == ENOENT) 380 1.1 elad move = 0; 381 1.1 elad else 382 1.11 agc err(EXIT_FAILURE, "could not stat %s", vp->dbfile); 383 1.1 elad } 384 1.11 agc if (move && !vp->append_output) { 385 1.11 agc if (vp->verbose) 386 1.1 elad (void)printf("\nBacking up existing fingerprint file " 387 1.11 agc "to \"%s.old\"\n\n", vp->dbfile); 388 1.1 elad 389 1.15 elad if (snprintf(old_dbfile, sizeof(old_dbfile), "%s.old", 390 1.15 elad vp->dbfile) < strlen(vp->dbfile) + 4) { 391 1.10 agc err(EXIT_FAILURE, "%s", old_dbfile); 392 1.1 elad } 393 1.11 agc if (rename(vp->dbfile, old_dbfile) == -1) 394 1.10 agc err(EXIT_FAILURE, "could not rename file"); 395 1.1 elad } 396 1.1 elad 397 1.11 agc prefixc = (vp->prefix == NULL) ? -1 : strlen(vp->prefix); 398 1.11 agc 399 1.11 agc fp = efopen(vp->dbfile, vp->append_output ? "a" : "w+"); 400 1.1 elad 401 1.15 elad if (vp->stamp) { 402 1.15 elad time(&ct); 403 1.15 elad (void)fprintf(fp, "# Generated by %s, %.24s\n", 404 1.15 elad getlogin(), ctime(&ct)); 405 1.15 elad } 406 1.1 elad 407 1.1 elad TAILQ_FOREACH(e, &fehead, f) { 408 1.15 elad char *file; 409 1.15 elad 410 1.11 agc if (vp->verbose) 411 1.1 elad (void)printf("Adding %s.\n", e->filename); 412 1.1 elad 413 1.15 elad file = (prefixc < 0) ? e->filename : &e->filename[prefixc]; 414 1.15 elad file = escape(file); 415 1.15 elad 416 1.15 elad (void)fprintf(fp, "%s %s %s %s\n", file, hash->hashname, 417 1.15 elad e->hash_val, flags2str(e->flags)); 418 1.11 agc 419 1.15 elad free(file); 420 1.1 elad } 421 1.1 elad 422 1.1 elad (void)fclose(fp); 423 1.1 elad 424 1.11 agc if (vp->verbose) { 425 1.10 agc (void)printf("\n\n" 426 1.10 agc "#############################################################\n" 427 1.10 agc " PLEASE VERIFY CONTENTS OF %s AND FINE-TUNE THE\n" 428 1.10 agc " FLAGS WHERE APPROPRIATE AFTER READING veriexecctl(8)\n" 429 1.10 agc "#############################################################\n", 430 1.11 agc vp->dbfile); 431 1.10 agc } 432 1.1 elad } 433 1.1 elad 434 1.1 elad int 435 1.1 elad main(int argc, char **argv) 436 1.1 elad { 437 1.1 elad int ch, total = 0; 438 1.1 elad char **search_path = NULL; 439 1.11 agc hash_t *hash = NULL; 440 1.11 agc veriexecgen_t v; 441 1.1 elad 442 1.11 agc (void) memset(&v, 0x0, sizeof(v)); 443 1.10 agc make_immutable = 0; 444 1.10 agc Fflag = 0; 445 1.1 elad 446 1.9 agc /* error out if we have a dangling symlink or other fs problem */ 447 1.11 agc v.exit_on_error = 1; 448 1.9 agc 449 1.20 alnsn while ((ch = getopt(argc, argv, "AaDd:f:ho:p:rSTt:vW")) != -1) { 450 1.1 elad switch (ch) { 451 1.1 elad case 'A': 452 1.11 agc v.append_output = 1; 453 1.1 elad break; 454 1.1 elad case 'a': 455 1.11 agc v.all_files = 1; 456 1.1 elad break; 457 1.1 elad case 'D': 458 1.11 agc v.scan_system_dirs = 1; 459 1.1 elad break; 460 1.1 elad case 'd': 461 1.1 elad search_path = erealloc(search_path, sizeof(char *) * 462 1.1 elad (total + 1)); 463 1.1 elad search_path[total] = optarg; 464 1.1 elad search_path[++total] = NULL; 465 1.1 elad break; 466 1.1 elad #ifdef notyet 467 1.1 elad case 'F': 468 1.1 elad Fflag = 1; 469 1.1 elad break; 470 1.1 elad #endif /* notyet */ 471 1.20 alnsn case 'f': 472 1.20 alnsn if (strcmp(optarg, "-") == 0) { 473 1.20 alnsn v.from_file = stdin; 474 1.20 alnsn v.from_filename = NULL; 475 1.20 alnsn } else { 476 1.20 alnsn v.from_file = fopen(optarg, "r"); 477 1.20 alnsn if (v.from_file == NULL) { 478 1.20 alnsn errx(EXIT_FAILURE, 479 1.20 alnsn "Error opening file %s", 480 1.20 alnsn optarg); 481 1.20 alnsn } 482 1.20 alnsn v.from_filename = strdup(optarg); 483 1.20 alnsn } 484 1.20 alnsn break; 485 1.21 alnsn case 'h': 486 1.21 alnsn usage(); 487 1.21 alnsn return EXIT_SUCCESS; 488 1.1 elad case 'o': 489 1.11 agc v.dbfile = optarg; 490 1.11 agc break; 491 1.11 agc case 'p': 492 1.11 agc v.prefix = optarg; 493 1.1 elad break; 494 1.1 elad case 'r': 495 1.11 agc v.recursive_scan = 1; 496 1.1 elad break; 497 1.3 elad case 'S': 498 1.10 agc make_immutable = 1; 499 1.3 elad break; 500 1.15 elad case 'T': 501 1.15 elad v.stamp = 1; 502 1.15 elad break; 503 1.1 elad case 't': 504 1.10 agc if ((hash = find_hash(optarg)) == NULL) { 505 1.10 agc errx(EXIT_FAILURE, 506 1.10 agc "No such hash algorithm (%s)", 507 1.10 agc optarg); 508 1.10 agc } 509 1.1 elad break; 510 1.1 elad case 'v': 511 1.11 agc v.verbose = 1; 512 1.1 elad break; 513 1.9 agc case 'W': 514 1.11 agc v.exit_on_error = 0; 515 1.9 agc break; 516 1.1 elad default: 517 1.1 elad usage(); 518 1.10 agc return EXIT_FAILURE; 519 1.1 elad } 520 1.1 elad } 521 1.1 elad 522 1.11 agc if (v.dbfile == NULL) 523 1.11 agc v.dbfile = DEFAULT_DBFILE; 524 1.1 elad 525 1.1 elad if (hash == NULL) { 526 1.1 elad if ((hash = find_hash(DEFAULT_HASH)) == NULL) 527 1.10 agc errx(EXIT_FAILURE, "No hash algorithm"); 528 1.1 elad } 529 1.1 elad 530 1.1 elad TAILQ_INIT(&fehead); 531 1.1 elad 532 1.20 alnsn if (search_path == NULL && !v.from_file) 533 1.11 agc v.scan_system_dirs = 1; 534 1.1 elad 535 1.11 agc if (v.scan_system_dirs) { 536 1.1 elad char *sys_paths[] = DEFAULT_SYSPATHS; 537 1.1 elad 538 1.11 agc if (v.verbose) 539 1.11 agc banner(&v, hash, sys_paths); 540 1.11 agc walk_dir(&v, sys_paths, hash); 541 1.1 elad } 542 1.1 elad 543 1.1 elad if (search_path != NULL) { 544 1.11 agc if (v.verbose) 545 1.11 agc banner(&v, hash, search_path); 546 1.11 agc walk_dir(&v, search_path, hash); 547 1.1 elad } 548 1.1 elad 549 1.20 alnsn if (v.from_file) { 550 1.20 alnsn if (v.verbose) 551 1.20 alnsn banner(&v, hash, NULL); 552 1.20 alnsn read_from_file(&v, hash, v.from_file); 553 1.20 alnsn } 554 1.20 alnsn 555 1.11 agc store_entries(&v, hash); 556 1.1 elad 557 1.11 agc if (make_immutable && chflags(v.dbfile, SF_IMMUTABLE) != 0) 558 1.10 agc err(EXIT_FAILURE, "Can't set immutable flag"); 559 1.3 elad 560 1.20 alnsn if (v.from_file && v.from_file != stdin) { 561 1.20 alnsn fclose(v.from_file); 562 1.20 alnsn free(v.from_filename); 563 1.20 alnsn } 564 1.20 alnsn 565 1.10 agc return EXIT_SUCCESS; 566 1.1 elad } 567