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
36 static void
pkg_spec_blank(struct pkg_spec * ps)37 pkg_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
46 static void
pkg_spec_iter_blank(struct pkg_spec * ps)47 pkg_spec_iter_blank(struct pkg_spec *ps)
48 {
49 ps->pkg_iter = NULL;
50 ps->pkg_next = NULL;
51 }
52
53 void
pkg_spec_init(struct pkg_spec * ps,enum pkg_spec_flags flags)54 pkg_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
62 const char *
pkg_spec_is_illegal(struct pkg_spec * ps)63 pkg_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_hash_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
115 static const char *
pkg_spec_prep(struct pkg_spec * ps,char * pkgname,const char * archname)116 pkg_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
134 const char *
pkg_spec_set(struct pkg_spec * ps,const char * pkgname,const char * archname)135 pkg_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
140 const char *
pkg_spec_parse(struct pkg_spec * ps,const char * str)141 pkg_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
156 static bool
pkg_spec_match_name(struct pkg_spec * ps,const char * name)157 pkg_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
165 static bool
pkg_spec_match_arch(struct pkg_spec * ps,struct pkginfo * pkg,const struct dpkg_arch * arch)166 pkg_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
186 bool
pkg_spec_match_pkg(struct pkg_spec * ps,struct pkginfo * pkg,struct pkgbin * pkgbin)187 pkg_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
194 static struct pkginfo *
pkg_spec_get_pkg(struct pkg_spec * ps)195 pkg_spec_get_pkg(struct pkg_spec *ps)
196 {
197 if (ps->arch->type == DPKG_ARCH_NONE)
198 return pkg_hash_find_singleton(ps->name);
199 else
200 return pkg_hash_find_pkg(ps->name, ps->arch);
201 }
202
203 struct pkginfo *
pkg_spec_parse_pkg(const char * str,struct dpkg_error * err)204 pkg_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
223 struct pkginfo *
pkg_spec_find_pkg(const char * pkgname,const char * archname,struct dpkg_error * err)224 pkg_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
244 void
pkg_spec_iter_init(struct pkg_spec * ps)245 pkg_spec_iter_init(struct pkg_spec *ps)
246 {
247 if (ps->name_is_pattern)
248 ps->pkg_iter = pkg_hash_iter_new();
249 else
250 ps->pkg_next = &pkg_hash_find_set(ps->name)->pkg;
251 }
252
253 static struct pkginfo *
pkg_spec_iter_next_pkgname(struct pkg_spec * ps)254 pkg_spec_iter_next_pkgname(struct pkg_spec *ps)
255 {
256 struct pkginfo *pkg;
257
258 while ((pkg = pkg_hash_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
266 static struct pkginfo *
pkg_spec_iter_next_pkgarch(struct pkg_spec * ps)267 pkg_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
281 struct pkginfo *
pkg_spec_iter_next_pkg(struct pkg_spec * ps)282 pkg_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
290 void
pkg_spec_iter_destroy(struct pkg_spec * ps)291 pkg_spec_iter_destroy(struct pkg_spec *ps)
292 {
293 pkg_hash_iter_free(ps->pkg_iter);
294 pkg_spec_iter_blank(ps);
295 }
296
297 void
pkg_spec_destroy(struct pkg_spec * ps)298 pkg_spec_destroy(struct pkg_spec *ps)
299 {
300 free(ps->name);
301 pkg_spec_blank(ps);
302 pkg_spec_iter_destroy(ps);
303 }
304