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