dpkg (1.18.25) stretch; urgency=medium
[dpkg] / lib / dpkg / parsehelp.c
CommitLineData
1479465f
GJ
1/*
2 * libdpkg - Debian packaging suite library routines
3 * parsehelp.c - helpful routines for parsing and writing
4 *
5 * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2006-2012 Guillem Jover <guillem@debian.org>
7 *
8 * This is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <config.h>
23#include <compat.h>
24
25#include <errno.h>
26#include <limits.h>
27#include <string.h>
28#include <stdlib.h>
29#include <stdio.h>
30
31#include <dpkg/i18n.h>
32#include <dpkg/c-ctype.h>
33#include <dpkg/dpkg.h>
34#include <dpkg/dpkg-db.h>
35#include <dpkg/string.h>
36#include <dpkg/error.h>
37#include <dpkg/parsedump.h>
38
39static const char *
40parse_error_msg(struct parsedb_state *ps, const char *fmt)
41{
42 static char msg[1024];
43 char filename[256];
44
45 str_escape_fmt(filename, ps->filename, sizeof(filename));
46
47 if (ps->pkg && ps->pkg->set->name) {
48 char pkgname[256];
49
50 str_escape_fmt(pkgname, pkgbin_name(ps->pkg, ps->pkgbin, pnaw_nonambig),
51 sizeof(pkgname));
52 sprintf(msg, _("parsing file '%.255s' near line %d package '%.255s':\n"
53 " %.255s"), filename, ps->lno, pkgname, fmt);
54 } else
55 sprintf(msg, _("parsing file '%.255s' near line %d:\n"
56 " %.255s"), filename, ps->lno, fmt);
57
58 return msg;
59}
60
61void
62parse_error(struct parsedb_state *ps, const char *fmt, ...)
63{
64 va_list args;
65
66 va_start(args, fmt);
67 ohshitv(parse_error_msg(ps, fmt), args);
68}
69
70void
71parse_warn(struct parsedb_state *ps, const char *fmt, ...)
72{
73 va_list args;
74
75 va_start(args, fmt);
76 warningv(parse_error_msg(ps, fmt), args);
77 va_end(args);
78}
79
80const struct fieldinfo *
81find_field_info(const struct fieldinfo *fields, const char *fieldname)
82{
83 const struct fieldinfo *field;
84
85 for (field = fields; field->name; field++)
86 if (strcasecmp(field->name, fieldname) == 0)
87 return field;
88
89 return NULL;
90}
91
92const struct arbitraryfield *
93find_arbfield_info(const struct arbitraryfield *arbs, const char *fieldname)
94{
95 const struct arbitraryfield *arbfield;
96
97 for (arbfield = arbs; arbfield; arbfield = arbfield->next)
98 if (strcasecmp(arbfield->name, fieldname) == 0)
99 return arbfield;
100
101 return NULL;
102}
103
104const char *
105pkg_name_is_illegal(const char *p)
106{
107 /* FIXME: _ is deprecated, remove sometime. */
108 static const char alsoallowed[] = "-+._";
109 static char buf[150];
110 int c;
111
112 if (!*p) return _("may not be empty string");
113 if (!c_isalnum(*p))
114 return _("must start with an alphanumeric character");
115 while ((c = *p++) != '\0')
116 if (!c_isalnum(c) && !strchr(alsoallowed, c))
117 break;
118 if (!c) return NULL;
119
120 snprintf(buf, sizeof(buf), _(
121 "character '%c' not allowed (only letters, digits and characters '%s')"),
122 c, alsoallowed);
123 return buf;
124}
125
126void varbufversion
127(struct varbuf *vb,
128 const struct dpkg_version *version,
129 enum versiondisplayepochwhen vdew)
130{
131 switch (vdew) {
132 case vdew_never:
133 break;
134 case vdew_nonambig:
135 if (!version->epoch &&
136 (!version->version || !strchr(version->version,':')) &&
137 (!version->revision || !strchr(version->revision,':'))) break;
138 /* Fall through. */
139 case vdew_always:
140 varbuf_printf(vb, "%u:", version->epoch);
141 break;
142 default:
143 internerr("unknown versiondisplayepochwhen '%d'", vdew);
144 }
145 if (version->version)
146 varbuf_add_str(vb, version->version);
147 if (str_is_set(version->revision)) {
148 varbuf_add_char(vb, '-');
149 varbuf_add_str(vb, version->revision);
150 }
151}
152
153const char *versiondescribe
154(const struct dpkg_version *version,
155 enum versiondisplayepochwhen vdew)
156{
157 static struct varbuf bufs[10];
158 static int bufnum=0;
159
160 struct varbuf *vb;
161
162 if (!dpkg_version_is_informative(version))
163 return C_("version", "<none>");
164
165 vb= &bufs[bufnum]; bufnum++; if (bufnum == 10) bufnum= 0;
166 varbuf_reset(vb);
167 varbufversion(vb,version,vdew);
168 varbuf_end_str(vb);
169
170 return vb->buf;
171}
172
173/**
174 * Parse a version string and check for invalid syntax.
175 *
176 * Distinguish between lax (warnings) and strict (error) parsing.
177 *
178 * @param rversion The parsed version.
179 * @param string The version string to parse.
180 * @param err The warning or error message if any.
181 *
182 * @retval 0 On success.
183 * @retval -1 On failure, and err is set accordingly.
184 */
185int
186parseversion(struct dpkg_version *rversion, const char *string,
187 struct dpkg_error *err)
188{
189 char *hyphen, *colon, *eepochcolon;
190 const char *end, *ptr;
191
192 /* Trim leading and trailing space. */
193 while (*string && c_isblank(*string))
194 string++;
195
196 if (!*string)
197 return dpkg_put_error(err, _("version string is empty"));
198
199 /* String now points to the first non-whitespace char. */
200 end = string;
201 /* Find either the end of the string, or a whitespace char. */
202 while (*end && !c_isblank(*end))
203 end++;
204 /* Check for extra chars after trailing space. */
205 ptr = end;
206 while (*ptr && c_isblank(*ptr))
207 ptr++;
208 if (*ptr)
209 return dpkg_put_error(err, _("version string has embedded spaces"));
210
211 colon= strchr(string,':');
212 if (colon) {
213 long epoch;
214
215 errno = 0;
216 epoch = strtol(string, &eepochcolon, 10);
217 if (string == eepochcolon)
218 return dpkg_put_error(err, _("epoch in version is empty"));
219 if (colon != eepochcolon)
220 return dpkg_put_error(err, _("epoch in version is not number"));
221 if (epoch < 0)
222 return dpkg_put_error(err, _("epoch in version is negative"));
223 if (epoch > INT_MAX || errno == ERANGE)
224 return dpkg_put_error(err, _("epoch in version is too big"));
225 if (!*++colon)
226 return dpkg_put_error(err, _("nothing after colon in version number"));
227 string= colon;
228 rversion->epoch= epoch;
229 } else {
230 rversion->epoch= 0;
231 }
232 rversion->version= nfstrnsave(string,end-string);
233 hyphen= strrchr(rversion->version,'-');
234 if (hyphen) {
235 *hyphen++ = '\0';
236
237 if (*hyphen == '\0')
238 return dpkg_put_error(err, _("revision number is empty"));
239 }
240 rversion->revision= hyphen ? hyphen : "";
241
242 /* XXX: Would be faster to use something like cisversion and cisrevision. */
243 ptr = rversion->version;
244 if (!*ptr)
245 return dpkg_put_error(err, _("version number is empty"));
246 if (*ptr && !c_isdigit(*ptr++))
247 return dpkg_put_warn(err, _("version number does not start with digit"));
248 for (; *ptr; ptr++) {
249 if (!c_isdigit(*ptr) && !c_isalpha(*ptr) && strchr(".-+~:", *ptr) == NULL)
250 return dpkg_put_warn(err, _("invalid character in version number"));
251 }
252 for (ptr = rversion->revision; *ptr; ptr++) {
253 if (!c_isdigit(*ptr) && !c_isalpha(*ptr) && strchr(".+~", *ptr) == NULL)
254 return dpkg_put_warn(err, _("invalid character in revision number"));
255 }
256
257 return 0;
258}
259
260/**
261 * Parse a version string coming from a database file.
262 *
263 * It parses a version string, and prints a warning or an error depending
264 * on the parse options.
265 *
266 * @param ps The parsedb state.
267 * @param version The version to parse into.
268 * @param value The version string to parse from.
269 * @param fmt The error format string.
270 */
271void
272parse_db_version(struct parsedb_state *ps, struct dpkg_version *version,
273 const char *value, const char *fmt, ...)
274{
275 struct dpkg_error err;
276 va_list args;
277 char buf[1000];
278
279 if (parseversion(version, value, &err) == 0)
280 return;
281
282 va_start(args, fmt);
283 vsnprintf(buf, sizeof(buf), fmt, args);
284 va_end(args);
285
286 if (err.type == DPKG_MSG_WARN && (ps->flags & pdb_lax_version_parser))
287 parse_warn(ps, "%s: %.250s", buf, err.str);
288 else
289 parse_error(ps, "%s: %.250s", buf, err.str);
290
291 dpkg_error_destroy(&err);
292}
293
294void
295parse_must_have_field(struct parsedb_state *ps,
296 const char *value, const char *what)
297{
298 if (!value)
299 parse_error(ps, _("missing %s"), what);
300 else if (!*value)
301 parse_error(ps, _("empty value for %s"), what);
302}
303
304void
305parse_ensure_have_field(struct parsedb_state *ps,
306 const char **value, const char *what)
307{
308 static const char empty[] = "";
309
310 if (!*value) {
311 parse_warn(ps, _("missing %s"), what);
312 *value = empty;
313 } else if (!**value) {
314 parse_warn(ps, _("empty value for %s"), what);
315 }
316}