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