1*f46918caSnia /* $NetBSD: conflicts.c,v 1.3 2021/04/10 19:49:59 nia Exp $ */
2d66ee6c3Sjoerg
3d66ee6c3Sjoerg /*-
4d66ee6c3Sjoerg * Copyright (c) 2007 Roland Illig <rillig@NetBSD.org>.
5d66ee6c3Sjoerg * All rights reserved.
6d66ee6c3Sjoerg *
7d66ee6c3Sjoerg * Redistribution and use in source and binary forms, with or without
8d66ee6c3Sjoerg * modification, are permitted provided that the following conditions
9d66ee6c3Sjoerg * are met:
10d66ee6c3Sjoerg *
11d66ee6c3Sjoerg * 1. Redistributions of source code must retain the above copyright
12d66ee6c3Sjoerg * notice, this list of conditions and the following disclaimer.
13d66ee6c3Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
14d66ee6c3Sjoerg * notice, this list of conditions and the following disclaimer in
15d66ee6c3Sjoerg * the documentation and/or other materials provided with the
16d66ee6c3Sjoerg * distribution.
17d66ee6c3Sjoerg *
18d66ee6c3Sjoerg * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19d66ee6c3Sjoerg * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20d66ee6c3Sjoerg * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21d66ee6c3Sjoerg * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22d66ee6c3Sjoerg * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23d66ee6c3Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24d66ee6c3Sjoerg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25d66ee6c3Sjoerg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26d66ee6c3Sjoerg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27d66ee6c3Sjoerg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28d66ee6c3Sjoerg * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29d66ee6c3Sjoerg * SUCH DAMAGE.
30d66ee6c3Sjoerg */
31d66ee6c3Sjoerg
32af21abb5Sjoerg /*
33af21abb5Sjoerg * XXX: Reading the +CONTENTS files of all installed packages is
34af21abb5Sjoerg * rather slow. Since this check is necessary to avoid conflicting
35af21abb5Sjoerg * packages, it should not be removed.
36af21abb5Sjoerg *
37af21abb5Sjoerg * TODO: Put all the information that is currently in the +CONTENTS
38af21abb5Sjoerg * files into one large file or another database.
39af21abb5Sjoerg */
40af21abb5Sjoerg
41af21abb5Sjoerg #if HAVE_CONFIG_H
42af21abb5Sjoerg #include "config.h"
43af21abb5Sjoerg #endif
44af21abb5Sjoerg
45af21abb5Sjoerg #include <nbcompat.h>
46af21abb5Sjoerg
47d66ee6c3Sjoerg #if HAVE_SYS_CDEFS_H
48d66ee6c3Sjoerg #include <sys/cdefs.h>
49d66ee6c3Sjoerg #endif
50d66ee6c3Sjoerg
51*f46918caSnia __RCSID("$NetBSD: conflicts.c,v 1.3 2021/04/10 19:49:59 nia Exp $");
52d66ee6c3Sjoerg
53af21abb5Sjoerg #if HAVE_ERR_H
54af21abb5Sjoerg #include <err.h>
55af21abb5Sjoerg #endif
56af21abb5Sjoerg
57af21abb5Sjoerg #include "dewey.h"
58af21abb5Sjoerg #include "lib.h"
59af21abb5Sjoerg
60af21abb5Sjoerg /**
61af21abb5Sjoerg * Data structure to keep the intermediate result of the conflict
62af21abb5Sjoerg * search. ''pkgname'' is the package in question. The first
63af21abb5Sjoerg * installed package that conflicts is filled into
64af21abb5Sjoerg * ''conflicting_pkgname''. The pattern that leads to the conflict is
65af21abb5Sjoerg * also filled in to help the user in deciding what to do with the
66af21abb5Sjoerg * conflict.
67af21abb5Sjoerg */
68af21abb5Sjoerg struct package_conflict {
69af21abb5Sjoerg const char *pkgname;
70d66ee6c3Sjoerg const char *skip_pkgname;
71af21abb5Sjoerg char **conflicting_pkgname;
72af21abb5Sjoerg char **conflicting_pattern;
73af21abb5Sjoerg };
74af21abb5Sjoerg
75af21abb5Sjoerg static FILE *
fopen_contents(const char * pkgname,const char * mode)76af21abb5Sjoerg fopen_contents(const char *pkgname, const char *mode)
77af21abb5Sjoerg {
785ac0fc9cSjoerg char *fname;
79af21abb5Sjoerg FILE *f;
80af21abb5Sjoerg
815ac0fc9cSjoerg fname = pkgdb_pkg_file(pkgname, CONTENTS_FNAME);
82af21abb5Sjoerg f = fopen(fname, mode);
83af21abb5Sjoerg if (f == NULL) {
84af21abb5Sjoerg err(EXIT_FAILURE, "%s", fname);
85af21abb5Sjoerg /* NOTREACHED */
86af21abb5Sjoerg }
875ac0fc9cSjoerg free(fname);
88af21abb5Sjoerg return f;
89af21abb5Sjoerg }
90af21abb5Sjoerg
91af21abb5Sjoerg
92af21abb5Sjoerg static int
check_package_conflict(const char * pkgname,void * v)93af21abb5Sjoerg check_package_conflict(const char *pkgname, void *v)
94af21abb5Sjoerg {
95af21abb5Sjoerg struct package_conflict *conflict = v;
96af21abb5Sjoerg package_t pkg;
97af21abb5Sjoerg plist_t *p;
98af21abb5Sjoerg FILE *f;
99af21abb5Sjoerg int rv;
100af21abb5Sjoerg
101d66ee6c3Sjoerg if (conflict->skip_pkgname != NULL &&
102d66ee6c3Sjoerg strcmp(conflict->skip_pkgname, pkgname) == 0)
103d66ee6c3Sjoerg return 0;
104d66ee6c3Sjoerg
105af21abb5Sjoerg rv = 0;
106af21abb5Sjoerg
107af21abb5Sjoerg f = fopen_contents(pkgname, "r");
108af21abb5Sjoerg read_plist(&pkg, f);
109af21abb5Sjoerg (void)fclose(f);
110af21abb5Sjoerg
111af21abb5Sjoerg for (p = pkg.head; p; p = p->next) {
112af21abb5Sjoerg if (p->type != PLIST_PKGCFL)
113af21abb5Sjoerg continue;
114af21abb5Sjoerg
115af21abb5Sjoerg if (pkg_match(p->name, conflict->pkgname) == 1) {
116d66ee6c3Sjoerg *(conflict->conflicting_pkgname) = xstrdup(pkgname);
117d66ee6c3Sjoerg *(conflict->conflicting_pattern) = xstrdup(p->name);
118af21abb5Sjoerg rv = 1 /* nonzero, stop iterating */;
119af21abb5Sjoerg break;
120af21abb5Sjoerg }
121af21abb5Sjoerg }
122af21abb5Sjoerg
123af21abb5Sjoerg free_plist(&pkg);
124af21abb5Sjoerg return rv;
125af21abb5Sjoerg }
126af21abb5Sjoerg
127af21abb5Sjoerg /**
128af21abb5Sjoerg * Checks if some installed package has a pkgcfl entry that matches
129af21abb5Sjoerg * PkgName. If such an entry is found, the package name is returned in
130af21abb5Sjoerg * inst_pkgname, the matching pattern in inst_pattern, and the function
131af21abb5Sjoerg * returns a non-zero value. Otherwise, zero is returned and the result
132af21abb5Sjoerg * variables are set to NULL.
133af21abb5Sjoerg */
134af21abb5Sjoerg int
some_installed_package_conflicts_with(const char * pkgname,const char * skip_pkgname,char ** inst_pkgname,char ** inst_pattern)135d66ee6c3Sjoerg some_installed_package_conflicts_with(const char *pkgname,
136d66ee6c3Sjoerg const char *skip_pkgname, char **inst_pkgname, char **inst_pattern)
137af21abb5Sjoerg {
138af21abb5Sjoerg struct package_conflict cfl;
139af21abb5Sjoerg int rv;
140af21abb5Sjoerg
141af21abb5Sjoerg cfl.pkgname = pkgname;
142d66ee6c3Sjoerg cfl.skip_pkgname = skip_pkgname;
143af21abb5Sjoerg *inst_pkgname = NULL;
144af21abb5Sjoerg *inst_pattern = NULL;
145af21abb5Sjoerg cfl.conflicting_pkgname = inst_pkgname;
146af21abb5Sjoerg cfl.conflicting_pattern = inst_pattern;
147af21abb5Sjoerg rv = iterate_pkg_db(check_package_conflict, &cfl);
148af21abb5Sjoerg if (rv == -1) {
149af21abb5Sjoerg errx(EXIT_FAILURE, "Couldn't read list of installed packages.");
150af21abb5Sjoerg /* NOTREACHED */
151af21abb5Sjoerg }
152af21abb5Sjoerg return *inst_pkgname != NULL;
153af21abb5Sjoerg }
154af21abb5Sjoerg
155af21abb5Sjoerg #if 0
156af21abb5Sjoerg int main(int argc, char **argv)
157af21abb5Sjoerg {
158af21abb5Sjoerg char *pkg, *patt;
159af21abb5Sjoerg
160af21abb5Sjoerg if (some_installed_package_conflicts_with(argv[1], &pkg, &patt))
161af21abb5Sjoerg printf("yes: package %s conflicts with %s, pattern %s\n", pkg, argv[1], patt);
162af21abb5Sjoerg else
163af21abb5Sjoerg printf("no\n");
164af21abb5Sjoerg return 0;
165af21abb5Sjoerg }
166af21abb5Sjoerg #endif
167