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