summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGuillem Jover <guillem@debian.org>2019-02-23 04:55:59 +0100
committerGuillem Jover <guillem@debian.org>2019-02-23 17:57:18 +0100
commit80b9ae537f0d1d1c1f4dbb7f046c434618ee6363 (patch)
tree8790c65917f580cb9f20e708e9269dbc25174884 /lib
parent4dfa2cb392e442938a7a4fcb90a46826f90abb2e (diff)
downloaddpkg-80b9ae537f0d1d1c1f4dbb7f046c434618ee6363.tar.gz
libdpkg: Optimize error handling
Move the error reporting outside the involved functions so that we do not need to call gettext if there is no error, which has a significant performance cost.
Diffstat (limited to 'lib')
-rw-r--r--lib/dpkg/fields.c63
-rw-r--r--lib/dpkg/parse.c1
-rw-r--r--lib/dpkg/parsedump.h14
-rw-r--r--lib/dpkg/parsehelp.c47
4 files changed, 80 insertions, 45 deletions
diff --git a/lib/dpkg/fields.c b/lib/dpkg/fields.c
index 63f9441bd..a2e5ef81c 100644
--- a/lib/dpkg/fields.c
+++ b/lib/dpkg/fields.c
@@ -62,20 +62,22 @@ enum parse_nv_flags {
*/
static int
parse_nv(struct parsedb_state *ps, enum parse_nv_flags flags,
- const char **strp, const struct namevalue *nv_head, const char *what)
+ const char **strp, const struct namevalue *nv_head)
{
const char *str_start = *strp, *str_end;
const struct namevalue *nv;
int value;
+ dpkg_error_destroy(&ps->err);
+
if (str_start[0] == '\0')
- parse_error(ps, _("%s is missing"), what);
+ return dpkg_put_error(&ps->err, _("is missing a value"));
nv = namevalue_find_by_name(nv_head, str_start);
if (nv == NULL) {
/* We got no match, skip further string validation. */
if (!(flags & PARSE_NV_FALLBACK))
- parse_error(ps, _("'%.50s' is not allowed for %s"), str_start, what);
+ return dpkg_put_error(&ps->err, _("has invalid value '%.50s'"), str_start);
str_end = NULL;
value = -1;
@@ -87,7 +89,7 @@ parse_nv(struct parsedb_state *ps, enum parse_nv_flags flags,
}
if (!(flags & PARSE_NV_NEXT) && str_is_set(str_end))
- parse_error(ps, _("junk after %s"), what);
+ return dpkg_put_error(&ps->err, _("has trailing junk"));
*strp = str_end;
@@ -174,8 +176,11 @@ f_boolean(struct pkginfo *pkg, struct pkgbin *pkgbin,
if (!*value)
return;
- boolean = parse_nv(ps, PARSE_NV_LAST, &value, booleaninfos,
- _("yes/no in boolean field"));
+ boolean = parse_nv(ps, PARSE_NV_LAST, &value, booleaninfos);
+ if (dpkg_has_error(&ps->err))
+ parse_error(ps, _("boolean (yes/no) '%s' field: %s"),
+ fip->name, ps->err.str);
+
STRUCTFIELD(pkgbin, fip->integer, bool) = boolean;
}
@@ -189,8 +194,10 @@ f_multiarch(struct pkginfo *pkg, struct pkgbin *pkgbin,
if (!*value)
return;
- multiarch = parse_nv(ps, PARSE_NV_LAST, &value, multiarchinfos,
- _("foreign/allowed/same/no in quadstate field"));
+ multiarch = parse_nv(ps, PARSE_NV_LAST, &value, multiarchinfos);
+ if (dpkg_has_error(&ps->err))
+ parse_error(ps, _("quadstate (foreign/allowed/same/no) '%s' field: %s"),
+ fip->name, ps->err.str);
STRUCTFIELD(pkgbin, fip->integer, int) = multiarch;
}
@@ -225,7 +232,9 @@ f_priority(struct pkginfo *pkg, struct pkgbin *pkgbin,
if (!*value) return;
priority = parse_nv(ps, PARSE_NV_LAST | PARSE_NV_FALLBACK, &str,
- priorityinfos, _("word in 'Priority' field"));
+ priorityinfos);
+ if (dpkg_has_error(&ps->err))
+ parse_error(ps, _("word in '%s' field: %s"), fip->name, ps->err.str);
if (str == NULL) {
pkg->priority = PKG_PRIO_OTHER;
@@ -247,12 +256,18 @@ f_status(struct pkginfo *pkg, struct pkgbin *pkgbin,
if (ps->flags & pdb_recordavailable)
return;
- pkg->want = parse_nv(ps, PARSE_NV_NEXT, &value, wantinfos,
- _("first (want) word in 'Status' field"));
- pkg->eflag = parse_nv(ps, PARSE_NV_NEXT, &value, eflaginfos,
- _("second (error) word in 'Status' field"));
- pkg->status = parse_nv(ps, PARSE_NV_LAST, &value, statusinfos,
- _("third (status) word in 'Status' field"));
+ pkg->want = parse_nv(ps, PARSE_NV_NEXT, &value, wantinfos);
+ if (dpkg_has_error(&ps->err))
+ parse_error(ps, _("first (want) word in '%s' field: %s"),
+ fip->name, ps->err.str);
+ pkg->eflag = parse_nv(ps, PARSE_NV_NEXT, &value, eflaginfos);
+ if (dpkg_has_error(&ps->err))
+ parse_error(ps, _("second (error) word in '%s' field: %s"),
+ fip->name, ps->err.str);
+ pkg->status = parse_nv(ps, PARSE_NV_LAST, &value, statusinfos);
+ if (dpkg_has_error(&ps->err))
+ parse_error(ps, _("third (status) word in '%s' field: %s"),
+ fip->name, ps->err.str);
}
void
@@ -260,9 +275,8 @@ f_version(struct pkginfo *pkg, struct pkgbin *pkgbin,
struct parsedb_state *ps,
const char *value, const struct fieldinfo *fip)
{
- parse_db_version(ps, &pkgbin->version, value,
- _("'%s' field value '%.250s'"),
- fip->name, value);
+ if (parse_db_version(ps, &pkgbin->version, value) < 0)
+ parse_problem(ps, _("'%s' field value '%.250s'"), fip->name, value);
}
void
@@ -298,10 +312,8 @@ f_configversion(struct pkginfo *pkg, struct pkgbin *pkgbin,
if (ps->flags & pdb_recordavailable)
return;
- parse_db_version(ps, &pkg->configversion, value,
- _("'%s' field value '%.250s'"),
- fip->name, value);
-
+ if (parse_db_version(ps, &pkg->configversion, value) < 0)
+ parse_problem(ps, _("'%s' field value '%.250s'"), fip->name, value);
}
/*
@@ -578,9 +590,10 @@ f_dependency(struct pkginfo *pkg, struct pkgbin *pkgbin,
varbuf_reset(&version);
varbuf_add_buf(&version, versionstart, versionlength);
varbuf_end_str(&version);
- parse_db_version(ps, &dop->version, version.buf,
- _("'%s' field, reference to '%.255s': "
- "error in version"), fip->name, depname.buf);
+ if (parse_db_version(ps, &dop->version, version.buf) < 0)
+ parse_problem(ps,
+ _("'%s' field, reference to '%.255s': version '%s'"),
+ fip->name, depname.buf, version.buf);
p++;
while (c_isspace(*p))
p++;
diff --git a/lib/dpkg/parse.c b/lib/dpkg/parse.c
index a2663cf5f..2a96e7e46 100644
--- a/lib/dpkg/parse.c
+++ b/lib/dpkg/parse.c
@@ -529,6 +529,7 @@ parsedb_new(const char *filename, int fd, enum parsedbflags flags)
struct parsedb_state *ps;
ps = m_malloc(sizeof(*ps));
+ ps->err = DPKG_ERROR_OBJECT;
ps->filename = filename;
ps->type = parse_get_type(ps, flags);
ps->flags = flags;
diff --git a/lib/dpkg/parsedump.h b/lib/dpkg/parsedump.h
index 2a857c47d..8e9a71056 100644
--- a/lib/dpkg/parsedump.h
+++ b/lib/dpkg/parsedump.h
@@ -25,6 +25,8 @@
#include <stdint.h>
+#include <dpkg/error.h>
+
/**
* @defgroup parsedump In-core package database parsing and reading
* @ingroup dpkg-public
@@ -46,6 +48,7 @@ enum parsedbtype {
struct parsedb_state {
enum parsedbtype type;
enum parsedbflags flags;
+ struct dpkg_error err;
struct pkginfo *pkg;
struct pkgbin *pkgbin;
char *data;
@@ -135,14 +138,19 @@ struct fieldinfo {
size_t integer;
};
-void parse_db_version(struct parsedb_state *ps,
- struct dpkg_version *version, const char *value,
- const char *fmt, ...) DPKG_ATTR_PRINTF(4);
+int
+parse_db_version(struct parsedb_state *ps,
+ struct dpkg_version *version, const char *value)
+ DPKG_ATTR_REQRET;
void parse_error(struct parsedb_state *ps, const char *fmt, ...)
DPKG_ATTR_NORET DPKG_ATTR_PRINTF(2);
void parse_warn(struct parsedb_state *ps, const char *fmt, ...)
DPKG_ATTR_PRINTF(2);
+void
+parse_problem(struct parsedb_state *ps, const char *fmt, ...)
+ DPKG_ATTR_PRINTF(2);
+
void parse_must_have_field(struct parsedb_state *ps,
const char *value, const char *what);
void parse_ensure_have_field(struct parsedb_state *ps,
diff --git a/lib/dpkg/parsehelp.c b/lib/dpkg/parsehelp.c
index caba83afb..a9095f1f4 100644
--- a/lib/dpkg/parsehelp.c
+++ b/lib/dpkg/parsehelp.c
@@ -77,6 +77,24 @@ parse_warn(struct parsedb_state *ps, const char *fmt, ...)
va_end(args);
}
+void
+parse_problem(struct parsedb_state *ps, const char *fmt, ...)
+{
+ va_list args;
+ char *str;
+
+ va_start(args, fmt);
+ m_vasprintf(&str, parse_error_msg(ps, fmt), args);
+ va_end(args);
+
+ if (ps->err.type == DPKG_MSG_WARN)
+ warning("%s: %s", str, ps->err.str);
+ else
+ ohshit("%s: %s", str, ps->err.str);
+
+ free(str);
+}
+
const struct fieldinfo *
find_field_info(const struct fieldinfo *fields, const char *fieldname)
{
@@ -266,29 +284,24 @@ parseversion(struct dpkg_version *rversion, const char *string,
* @param ps The parsedb state.
* @param version The version to parse into.
* @param value The version string to parse from.
- * @param fmt The error format string.
+ *
+ * @retval 0 On success, and err is reset.
+ * @retval -1 On failure, and err is set accordingly.
*/
-void
+int
parse_db_version(struct parsedb_state *ps, struct dpkg_version *version,
- const char *value, const char *fmt, ...)
+ const char *value)
{
- struct dpkg_error err;
- va_list args;
- char buf[1000];
+ dpkg_error_destroy(&ps->err);
- if (parseversion(version, value, &err) == 0)
- return;
+ if (parseversion(version, value, &ps->err) == 0)
+ return 0;
- va_start(args, fmt);
- vsnprintf(buf, sizeof(buf), fmt, args);
- va_end(args);
-
- if (err.type == DPKG_MSG_WARN && (ps->flags & pdb_lax_version_parser))
- parse_warn(ps, "%s: %.250s", buf, err.str);
- else
- parse_error(ps, "%s: %.250s", buf, err.str);
+ /* If not in lax mode, turn everything into an error. */
+ if (!(ps->flags & pdb_lax_version_parser))
+ ps->err.type = DPKG_MSG_ERROR;
- dpkg_error_destroy(&err);
+ return -1;
}
void