dpkg (1.18.25) stretch; urgency=medium
[dpkg] / lib / dpkg / pkg-spec.c
CommitLineData
1479465f
GJ
1/*
2 * libdpkg - Debian packaging suite library routines
3 * pkg-spec.c - primitives for pkg specifier handling
4 *
5 * Copyright © 2011 Linaro Limited
6 * Copyright © 2011 Raphaël Hertzog <hertzog@debian.org>
7 * Copyright © 2011-2015 Guillem Jover <guillem@debian.org>
8 *
9 * This is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include <config.h>
24#include <compat.h>
25
26#include <stdlib.h>
27#include <fnmatch.h>
28#include <string.h>
29
30#include <dpkg/i18n.h>
31#include <dpkg/dpkg.h>
32#include <dpkg/dpkg-db.h>
33#include <dpkg/arch.h>
34#include <dpkg/pkg-spec.h>
35
36static void
37pkg_spec_blank(struct pkg_spec *ps)
38{
39 ps->name = NULL;
40 ps->arch = NULL;
41
42 ps->name_is_pattern = false;
43 ps->arch_is_pattern = false;
44}
45
46static void
47pkg_spec_iter_blank(struct pkg_spec *ps)
48{
49 ps->pkg_iter = NULL;
50 ps->pkg_next = NULL;
51}
52
53void
54pkg_spec_init(struct pkg_spec *ps, enum pkg_spec_flags flags)
55{
56 ps->flags = flags;
57
58 pkg_spec_blank(ps);
59 pkg_spec_iter_blank(ps);
60}
61
62const char *
63pkg_spec_is_illegal(struct pkg_spec *ps)
64{
65 static char msg[1024];
66 const char *emsg;
67
68 if (!ps->name_is_pattern &&
69 (emsg = pkg_name_is_illegal(ps->name))) {
70 const char *arch_sep;
71
72 /* Only check for DPKG_ARCH_NONE, because for everything else
73 * we want to see the passed package specification, even if
74 * the architecture is empty. */
75 if (ps->arch->type == DPKG_ARCH_NONE)
76 arch_sep = "";
77 else
78 arch_sep = ":";
79
80 snprintf(msg, sizeof(msg),
81 _("illegal package name in specifier '%s%s%s': %s"),
82 ps->name, arch_sep, ps->arch->name, emsg);
83 return msg;
84 }
85
86 if ((!ps->arch_is_pattern && ps->arch->type == DPKG_ARCH_ILLEGAL) ||
87 ps->arch->type == DPKG_ARCH_EMPTY) {
88 emsg = dpkg_arch_name_is_illegal(ps->arch->name);
89 snprintf(msg, sizeof(msg),
90 _("illegal architecture name in specifier '%s:%s': %s"),
91 ps->name, ps->arch->name, emsg);
92 return msg;
93 }
94
95 /* If we have been requested a single instance, check that the
96 * package does not contain other instances. */
97 if (!ps->arch_is_pattern && ps->flags & PKG_SPEC_ARCH_SINGLE) {
98 struct pkgset *set;
99
100 set = pkg_db_find_set(ps->name);
101
102 /* Single instancing only applies with no architecture. */
103 if (ps->arch->type == DPKG_ARCH_NONE &&
104 pkgset_installed_instances(set) > 1) {
105 snprintf(msg, sizeof(msg),
106 _("ambiguous package name '%s' with more "
107 "than one installed instance"), ps->name);
108 return msg;
109 }
110 }
111
112 return NULL;
113}
114
115static const char *
116pkg_spec_prep(struct pkg_spec *ps, char *pkgname, const char *archname)
117{
118 ps->name = pkgname;
119 ps->arch = dpkg_arch_find(archname);
120
121 ps->name_is_pattern = false;
122 ps->arch_is_pattern = false;
123
124 /* Detect if we have patterns and/or illegal names. */
125 if ((ps->flags & PKG_SPEC_PATTERNS) && strpbrk(ps->name, "*[?\\"))
126 ps->name_is_pattern = true;
127
128 if ((ps->flags & PKG_SPEC_PATTERNS) && strpbrk(ps->arch->name, "*[?\\"))
129 ps->arch_is_pattern = true;
130
131 return pkg_spec_is_illegal(ps);
132}
133
134const char *
135pkg_spec_set(struct pkg_spec *ps, const char *pkgname, const char *archname)
136{
137 return pkg_spec_prep(ps, m_strdup(pkgname), archname);
138}
139
140const char *
141pkg_spec_parse(struct pkg_spec *ps, const char *str)
142{
143 char *pkgname, *archname;
144
145 archname = strchr(str, ':');
146 if (archname == NULL) {
147 pkgname = m_strdup(str);
148 } else {
149 pkgname = m_strndup(str, archname - str);
150 archname++;
151 }
152
153 return pkg_spec_prep(ps, pkgname, archname);
154}
155
156static bool
157pkg_spec_match_name(struct pkg_spec *ps, const char *name)
158{
159 if (ps->name_is_pattern)
160 return (fnmatch(ps->name, name, 0) == 0);
161 else
162 return (strcmp(ps->name, name) == 0);
163}
164
165static bool
166pkg_spec_match_arch(struct pkg_spec *ps, struct pkginfo *pkg,
167 const struct dpkg_arch *arch)
168{
169 if (ps->arch_is_pattern)
170 return (fnmatch(ps->arch->name, arch->name, 0) == 0);
171 else if (ps->arch->type != DPKG_ARCH_NONE) /* !arch_is_pattern */
172 return (ps->arch == arch);
173
174 /* No arch specified. */
175 switch (ps->flags & PKG_SPEC_ARCH_MASK) {
176 case PKG_SPEC_ARCH_SINGLE:
177 return pkgset_installed_instances(pkg->set) <= 1;
178 case PKG_SPEC_ARCH_WILDCARD:
179 return true;
180 default:
181 internerr("unknown PKG_SPEC_ARCH_* flags %d in pkg_spec",
182 ps->flags & PKG_SPEC_ARCH_MASK);
183 }
184}
185
186bool
187pkg_spec_match_pkg(struct pkg_spec *ps, struct pkginfo *pkg,
188 struct pkgbin *pkgbin)
189{
190 return (pkg_spec_match_name(ps, pkg->set->name) &&
191 pkg_spec_match_arch(ps, pkg, pkgbin->arch));
192}
193
194static struct pkginfo *
195pkg_spec_get_pkg(struct pkg_spec *ps)
196{
197 if (ps->arch->type == DPKG_ARCH_NONE)
198 return pkg_db_find_singleton(ps->name);
199 else
200 return pkg_db_find_pkg(ps->name, ps->arch);
201}
202
203struct pkginfo *
204pkg_spec_parse_pkg(const char *str, struct dpkg_error *err)
205{
206 struct pkg_spec ps;
207 struct pkginfo *pkg;
208 const char *emsg;
209
210 pkg_spec_init(&ps, PKG_SPEC_ARCH_SINGLE);
211 emsg = pkg_spec_parse(&ps, str);
212 if (emsg) {
213 dpkg_put_error(err, "%s", emsg);
214 pkg = NULL;
215 } else {
216 pkg = pkg_spec_get_pkg(&ps);
217 }
218 pkg_spec_destroy(&ps);
219
220 return pkg;
221}
222
223struct pkginfo *
224pkg_spec_find_pkg(const char *pkgname, const char *archname,
225 struct dpkg_error *err)
226{
227 struct pkg_spec ps;
228 struct pkginfo *pkg;
229 const char *emsg;
230
231 pkg_spec_init(&ps, PKG_SPEC_ARCH_SINGLE);
232 emsg = pkg_spec_set(&ps, pkgname, archname);
233 if (emsg) {
234 dpkg_put_error(err, "%s", emsg);
235 pkg = NULL;
236 } else {
237 pkg = pkg_spec_get_pkg(&ps);
238 }
239 pkg_spec_destroy(&ps);
240
241 return pkg;
242}
243
244void
245pkg_spec_iter_init(struct pkg_spec *ps)
246{
247 if (ps->name_is_pattern)
248 ps->pkg_iter = pkg_db_iter_new();
249 else
250 ps->pkg_next = &pkg_db_find_set(ps->name)->pkg;
251}
252
253static struct pkginfo *
254pkg_spec_iter_next_pkgname(struct pkg_spec *ps)
255{
256 struct pkginfo *pkg;
257
258 while ((pkg = pkg_db_iter_next_pkg(ps->pkg_iter))) {
259 if (pkg_spec_match_pkg(ps, pkg, &pkg->installed))
260 return pkg;
261 }
262
263 return NULL;
264}
265
266static struct pkginfo *
267pkg_spec_iter_next_pkgarch(struct pkg_spec *ps)
268{
269 struct pkginfo *pkg;
270
271 while ((pkg = ps->pkg_next)) {
272 ps->pkg_next = pkg->arch_next;
273
274 if (pkg_spec_match_arch(ps, pkg, pkg->installed.arch))
275 return pkg;
276 }
277
278 return NULL;
279}
280
281struct pkginfo *
282pkg_spec_iter_next_pkg(struct pkg_spec *ps)
283{
284 if (ps->name_is_pattern)
285 return pkg_spec_iter_next_pkgname(ps);
286 else
287 return pkg_spec_iter_next_pkgarch(ps);
288}
289
290void
291pkg_spec_iter_destroy(struct pkg_spec *ps)
292{
293 pkg_db_iter_free(ps->pkg_iter);
294 pkg_spec_iter_blank(ps);
295}
296
297void
298pkg_spec_destroy(struct pkg_spec *ps)
299{
300 free(ps->name);
301 pkg_spec_blank(ps);
302 pkg_spec_iter_destroy(ps);
303}