1/* $NetBSD: check.c,v 1.5 2021/04/10 19:49:59 nia Exp $ */ 2 3#ifdef HAVE_NBTOOL_CONFIG_H 4#include "nbtool_config.h" 5#else 6#if HAVE_CONFIG_H 7#include "config.h" 8#endif 9#include <nbcompat.h> 10#if HAVE_SYS_CDEFS_H 11#include <sys/cdefs.h> 12#endif 13#endif 14__RCSID("$NetBSD: check.c,v 1.5 2021/04/10 19:49:59 nia Exp $"); 15 16/*- 17 * Copyright (c) 1999-2008 The NetBSD Foundation, Inc. 18 * All rights reserved. 19 * 20 * This code is derived from software contributed to The NetBSD Foundation 21 * by Hubert Feyrer <hubert@feyrer.de>. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 33 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 34 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 35 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 36 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 37 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 38 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 39 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 40 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 41 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 * POSSIBILITY OF SUCH DAMAGE. 43 */ 44 45#if HAVE_SYS_TYPES_H 46#include <sys/types.h> 47#endif 48#if HAVE_SYS_STAT_H 49#include <sys/stat.h> 50#endif 51#if HAVE_DIRENT_H 52#include <dirent.h> 53#endif 54#if HAVE_ERR_H 55#include <err.h> 56#endif 57#if HAVE_ERRNO_H 58#include <errno.h> 59#endif 60#if HAVE_FCNTL_H 61#include <fcntl.h> 62#endif 63#ifndef NETBSD 64#include <nbcompat/md5.h> 65#else 66#include <md5.h> 67#endif 68#if HAVE_LIMITS_H 69#include <limits.h> 70#endif 71#if HAVE_STDIO_H 72#include <stdio.h> 73#endif 74#if HAVE_STRING_H 75#include <string.h> 76#endif 77 78#include "admin.h" 79#include "lib.h" 80 81static int checkpattern_fn(const char *, void *); 82 83/* 84 * Assumes CWD is in the database directory ($PREFIX/pkgdb/<pkg>)! 85 */ 86static void 87check1pkg(const char *pkgdir, int *filecnt, int *pkgcnt) 88{ 89 FILE *f; 90 plist_t *p; 91 package_t Plist; 92 char *PkgName, *dirp = NULL, *md5file; 93 char file[MaxPathSize]; 94 char *content; 95 96 content = pkgdb_pkg_file(pkgdir, CONTENTS_FNAME); 97 f = fopen(content, "r"); 98 if (f == NULL) 99 err(EXIT_FAILURE, "can't open %s", content); 100 free(content); 101 102 read_plist(&Plist, f); 103 p = find_plist(&Plist, PLIST_NAME); 104 if (p == NULL) 105 errx(EXIT_FAILURE, "Package %s has no @name, aborting.", 106 pkgdir); 107 PkgName = p->name; 108 for (p = Plist.head; p; p = p->next) { 109 switch (p->type) { 110 case PLIST_FILE: 111 if (dirp == NULL) { 112 warnx("dirp not initialized, please send-pr!"); 113 abort(); 114 } 115 116 (void) snprintf(file, sizeof(file), "%s/%s", dirp, p->name); 117 118 if (isfile(file) || islinktodir(file)) { 119 if (p->next && p->next->type == PLIST_COMMENT) { 120 if (strncmp(p->next->name, CHECKSUM_HEADER, ChecksumHeaderLen) == 0) { 121 if ((md5file = MD5File(file, NULL)) != NULL) { 122 /* Mismatch? */ 123 if (strcmp(md5file, p->next->name + ChecksumHeaderLen) != 0) 124 printf("%s fails MD5 checksum\n", file); 125 126 free(md5file); 127 } 128 } else if (strncmp(p->next->name, SYMLINK_HEADER, SymlinkHeaderLen) == 0) { 129 char buf[MaxPathSize + SymlinkHeaderLen]; 130 int cc; 131 132 (void) strlcpy(buf, SYMLINK_HEADER, sizeof(buf)); 133 if ((cc = readlink(file, &buf[SymlinkHeaderLen], 134 sizeof(buf) - SymlinkHeaderLen - 1)) < 0) { 135 warnx("can't readlink `%s'", file); 136 } else { 137 buf[SymlinkHeaderLen + cc] = 0x0; 138 if (strcmp(buf, p->next->name) != 0) { 139 printf("symlink (%s) is not same as recorded value, %s: %s\n", 140 file, buf, p->next->name); 141 } 142 } 143 } 144 } 145 146 (*filecnt)++; 147 } else if (isbrokenlink(file)) { 148 warnx("%s: Symlink `%s' exists and is in %s but target does not exist!", PkgName, file, CONTENTS_FNAME); 149 } else { 150 warnx("%s: File `%s' is in %s but not on filesystem!", PkgName, file, CONTENTS_FNAME); 151 } 152 break; 153 case PLIST_CWD: 154 if (strcmp(p->name, ".") != 0) 155 dirp = p->name; 156 else 157 dirp = pkgdb_pkg_dir(pkgdir); 158 break; 159 case PLIST_IGNORE: 160 p = p->next; 161 break; 162 case PLIST_SHOW_ALL: 163 case PLIST_SRC: 164 case PLIST_CMD: 165 case PLIST_CHMOD: 166 case PLIST_CHOWN: 167 case PLIST_CHGRP: 168 case PLIST_COMMENT: 169 case PLIST_NAME: 170 case PLIST_UNEXEC: 171 case PLIST_DISPLAY: 172 case PLIST_PKGDEP: 173 case PLIST_DIR_RM: 174 case PLIST_OPTION: 175 case PLIST_PKGCFL: 176 case PLIST_BLDDEP: 177 case PLIST_PKGDIR: 178 break; 179 } 180 } 181 free_plist(&Plist); 182 fclose(f); 183 (*pkgcnt)++; 184} 185 186struct checkpattern_arg { 187 int filecnt; 188 int pkgcnt; 189 int got_match; 190}; 191 192static int 193checkpattern_fn(const char *pkg, void *vp) 194{ 195 struct checkpattern_arg *arg = vp; 196 197 check1pkg(pkg, &arg->filecnt, &arg->pkgcnt); 198 if (!quiet) 199 printf("."); 200 201 arg->got_match = 1; 202 203 return 0; 204} 205 206static void 207check_pkg(const char *pkg, int *filecnt, int *pkgcnt, int allow_unmatched) 208{ 209 struct checkpattern_arg arg; 210 char *pattern; 211 212 arg.filecnt = *filecnt; 213 arg.pkgcnt = *pkgcnt; 214 arg.got_match = 0; 215 216 if (match_installed_pkgs(pkg, checkpattern_fn, &arg) == -1) 217 errx(EXIT_FAILURE, "Cannot process pkdbdb"); 218 if (arg.got_match != 0) { 219 *filecnt = arg.filecnt; 220 *pkgcnt = arg.pkgcnt; 221 return; 222 } 223 224 if (ispkgpattern(pkg)) { 225 if (allow_unmatched) 226 return; 227 errx(EXIT_FAILURE, "No matching pkg for %s.", pkg); 228 } 229 230 pattern = xasprintf("%s-[0-9]*", pkg); 231 232 if (match_installed_pkgs(pattern, checkpattern_fn, &arg) == -1) 233 errx(EXIT_FAILURE, "Cannot process pkdbdb"); 234 235 if (arg.got_match == 0) 236 errx(EXIT_FAILURE, "cannot find package %s", pkg); 237 free(pattern); 238 239 *filecnt = arg.filecnt; 240 *pkgcnt = arg.pkgcnt; 241} 242 243void 244check(char **argv) 245{ 246 int filecnt, pkgcnt; 247 248 filecnt = 0; 249 pkgcnt = 0; 250 setbuf(stdout, NULL); 251 252 if (*argv == NULL) { 253 check_pkg("*", &filecnt, &pkgcnt, 1); 254 } else { 255 for (; *argv != NULL; ++argv) 256 check_pkg(*argv, &filecnt, &pkgcnt, 0); 257 } 258 259 printf("\n"); 260 printf("Checked %d file%s from %d package%s.\n", 261 filecnt, (filecnt == 1) ? "" : "s", 262 pkgcnt, (pkgcnt == 1) ? "" : "s"); 263} 264