LCOV - code coverage report
Current view: top level - lib/dpkg - parsehelp.c (source / functions) Coverage Total Hit
Test: dpkg 1.22.7-3-g89f48 C code coverage Lines: 70.6 % 153 108
Test Date: 2024-07-17 02:53:43 Functions: 73.3 % 15 11
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 77.1 % 118 91

             Branch data     Line data    Source code
       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                 :             : 
      39                 :             : static DPKG_ATTR_VPRINTF(2) const char *
      40                 :           8 : parse_error_msg(struct parsedb_state *ps, const char *fmt, va_list args)
      41                 :             : {
      42                 :           8 :   struct varbuf *vb = &ps->errmsg;
      43                 :             : 
      44                 :           8 :   varbuf_reset(vb);
      45                 :             : 
      46   [ +  -  +  - ]:           8 :   if (ps->pkg && ps->pkg->set->name)
      47                 :           8 :     varbuf_printf(vb, _("parsing file '%s' near line %d package '%s':\n "),
      48                 :             :                   ps->filename, ps->lno,
      49                 :             :                   pkgbin_name(ps->pkg, ps->pkgbin, pnaw_nonambig));
      50                 :             :   else
      51                 :           0 :     varbuf_printf(vb, _("parsing file '%.255s' near line %d:\n "),
      52                 :             :                   ps->filename, ps->lno);
      53                 :             : 
      54                 :           8 :   varbuf_vprintf(vb, fmt, args);
      55                 :             : 
      56                 :           8 :   return vb->buf;
      57                 :             : }
      58                 :             : 
      59                 :             : void
      60                 :           0 : parse_error(struct parsedb_state *ps, const char *fmt, ...)
      61                 :             : {
      62                 :             :   va_list args;
      63                 :             :   const char *str;
      64                 :             : 
      65                 :           0 :   va_start(args, fmt);
      66                 :           0 :   str = parse_error_msg(ps, fmt, args);
      67                 :           0 :   va_end(args);
      68                 :             : 
      69                 :           0 :   ohshit("%s", str);
      70                 :             : }
      71                 :             : 
      72                 :             : void
      73                 :           8 : parse_warn(struct parsedb_state *ps, const char *fmt, ...)
      74                 :             : {
      75                 :             :   va_list args;
      76                 :             : 
      77                 :           8 :   va_start(args, fmt);
      78                 :           8 :   warning("%s", parse_error_msg(ps, fmt, args));
      79                 :           8 :   va_end(args);
      80                 :           8 : }
      81                 :             : 
      82                 :             : void
      83                 :           0 : parse_lax_problem(struct parsedb_state *ps, enum parsedbflags flags_lax,
      84                 :             :                   const char *fmt, ...)
      85                 :             : {
      86                 :             :   va_list args;
      87                 :             :   const char *str;
      88                 :             : 
      89                 :           0 :   va_start(args, fmt);
      90                 :           0 :   str = parse_error_msg(ps, fmt, args);
      91                 :           0 :   va_end(args);
      92                 :             : 
      93         [ #  # ]:           0 :   if (ps->flags & flags_lax)
      94                 :           0 :     warning("%s", str);
      95                 :             :   else
      96                 :           0 :     ohshit("%s", str);
      97                 :           0 : }
      98                 :             : 
      99                 :             : void
     100                 :           0 : parse_problem(struct parsedb_state *ps, const char *fmt, ...)
     101                 :             : {
     102                 :             :   va_list args;
     103                 :             :   const char *str;
     104                 :             : 
     105                 :           0 :   va_start(args, fmt);
     106                 :           0 :   str = parse_error_msg(ps, fmt, args);
     107                 :           0 :   va_end(args);
     108                 :             : 
     109         [ #  # ]:           0 :   if (ps->err.type == DPKG_MSG_WARN)
     110                 :           0 :     warning("%s: %s", str, ps->err.str);
     111                 :             :   else
     112                 :           0 :     ohshit("%s: %s", str, ps->err.str);
     113                 :           0 : }
     114                 :             : 
     115                 :             : const struct fieldinfo *
     116                 :          35 : find_field_info(const struct fieldinfo *fields, const char *fieldname)
     117                 :             : {
     118                 :             :   const struct fieldinfo *field;
     119                 :             : 
     120         [ +  + ]:         796 :   for (field = fields; field->name; field++)
     121         [ +  + ]:         781 :     if (strcasecmp(field->name, fieldname) == 0)
     122                 :          20 :       return field;
     123                 :             : 
     124                 :          15 :   return NULL;
     125                 :             : }
     126                 :             : 
     127                 :             : const struct arbitraryfield *
     128                 :           2 : find_arbfield_info(const struct arbitraryfield *arbs, const char *fieldname)
     129                 :             : {
     130                 :             :   const struct arbitraryfield *arbfield;
     131                 :             : 
     132         [ +  + ]:           2 :   for (arbfield = arbs; arbfield; arbfield = arbfield->next)
     133         [ +  - ]:           1 :     if (strcasecmp(arbfield->name, fieldname) == 0)
     134                 :           1 :       return arbfield;
     135                 :             : 
     136                 :           1 :   return NULL;
     137                 :             : }
     138                 :             : 
     139                 :             : const char *
     140                 :          36 : pkg_name_is_illegal(const char *p)
     141                 :             : {
     142                 :             :   /* TODO: _ is deprecated, remove sometime. */
     143                 :             :   static const char alsoallowed[] = "-+._";
     144                 :             :   static char buf[150];
     145                 :             :   int c;
     146                 :             : 
     147         [ -  + ]:          36 :   if (!*p) return _("may not be empty string");
     148         [ -  + ]:          36 :   if (!c_isalnum(*p))
     149                 :           0 :     return _("must start with an alphanumeric character");
     150         [ +  + ]:         627 :   while ((c = *p++) != '\0')
     151   [ +  +  -  + ]:         591 :     if (!c_isalnum(c) && !strchr(alsoallowed, c))
     152                 :           0 :       break;
     153         [ +  - ]:          36 :   if (!c) return NULL;
     154                 :             : 
     155                 :           0 :   snprintf(buf, sizeof(buf), _(
     156                 :             :            "character '%c' not allowed (only letters, digits and characters '%s')"),
     157                 :             :            c, alsoallowed);
     158                 :           0 :   return buf;
     159                 :             : }
     160                 :             : 
     161                 :           7 : void varbufversion
     162                 :             : (struct varbuf *vb,
     163                 :             :  const struct dpkg_version *version,
     164                 :             :  enum versiondisplayepochwhen vdew)
     165                 :             : {
     166   [ -  +  -  - ]:           7 :   switch (vdew) {
     167                 :           0 :   case vdew_never:
     168                 :           0 :     break;
     169                 :           7 :   case vdew_nonambig:
     170         [ +  + ]:           7 :     if (!version->epoch &&
     171   [ +  +  +  - ]:           6 :         (!version->version || !strchr(version->version,':')) &&
     172   [ +  +  -  + ]:           6 :         (!version->revision || !strchr(version->revision,':'))) break;
     173                 :             :     /* Fall through. */
     174                 :             :   case vdew_always:
     175                 :           1 :     varbuf_printf(vb, "%u:", version->epoch);
     176                 :           1 :     break;
     177                 :           0 :   default:
     178                 :           0 :     internerr("unknown versiondisplayepochwhen '%d'", vdew);
     179                 :             :   }
     180         [ +  + ]:           7 :   if (version->version)
     181                 :           6 :     varbuf_add_str(vb, version->version);
     182         [ +  + ]:           7 :   if (str_is_set(version->revision)) {
     183                 :           6 :     varbuf_add_char(vb, '-');
     184                 :           6 :     varbuf_add_str(vb, version->revision);
     185                 :             :   }
     186                 :           7 : }
     187                 :             : 
     188                 :           1 : const char *versiondescribe
     189                 :             : (const struct dpkg_version *version,
     190                 :             :  enum versiondisplayepochwhen vdew)
     191                 :             : {
     192                 :             :   static struct varbuf bufs[10];
     193                 :             :   static int bufnum=0;
     194                 :             : 
     195                 :             :   struct varbuf *vb;
     196                 :             : 
     197         [ -  + ]:           1 :   if (!dpkg_version_is_informative(version))
     198                 :           0 :     return C_("version", "<none>");
     199                 :             : 
     200         [ -  + ]:           1 :   vb= &bufs[bufnum]; bufnum++; if (bufnum == 10) bufnum= 0;
     201                 :           1 :   varbuf_reset(vb);
     202                 :           1 :   varbufversion(vb,version,vdew);
     203                 :             : 
     204                 :           1 :   return vb->buf;
     205                 :             : }
     206                 :             : 
     207                 :             : const char *
     208                 :           0 : versiondescribe_c(const struct dpkg_version *version,
     209                 :             :                   enum versiondisplayepochwhen vdew)
     210                 :             : {
     211                 :             :   struct dpkg_locale oldloc;
     212                 :             :   const char *str;
     213                 :             : 
     214                 :           0 :   oldloc = dpkg_locale_switch_C();
     215                 :           0 :   str = versiondescribe(version, vdew);
     216                 :           0 :   dpkg_locale_switch_back(oldloc);
     217                 :             : 
     218                 :           0 :   return str;
     219                 :             : }
     220                 :             : 
     221                 :             : /**
     222                 :             :  * Parse a version string and check for invalid syntax.
     223                 :             :  *
     224                 :             :  * Distinguish between lax (warnings) and strict (error) parsing.
     225                 :             :  *
     226                 :             :  * @param rversion The parsed version.
     227                 :             :  * @param string The version string to parse.
     228                 :             :  * @param err The warning or error message if any.
     229                 :             :  *
     230                 :             :  * @retval  0 On success.
     231                 :             :  * @retval -1 On failure, and err is set accordingly.
     232                 :             :  */
     233                 :             : int
     234                 :         114 : parseversion(struct dpkg_version *rversion, const char *string,
     235                 :             :              struct dpkg_error *err)
     236                 :             : {
     237                 :             :   char *hyphen, *colon, *eepochcolon;
     238                 :             :   const char *end, *ptr;
     239                 :             : 
     240                 :             :   /* Trim leading and trailing space. */
     241   [ +  +  +  + ]:         122 :   while (*string && c_isblank(*string))
     242                 :           8 :     string++;
     243                 :             : 
     244         [ +  + ]:         114 :   if (!*string)
     245                 :           2 :     return dpkg_put_error(err, _("version string is empty"));
     246                 :             : 
     247                 :             :   /* String now points to the first non-whitespace char. */
     248                 :         112 :   end = string;
     249                 :             :   /* Find either the end of the string, or a whitespace char. */
     250   [ +  +  +  + ]:         742 :   while (*end && !c_isblank(*end))
     251                 :         630 :     end++;
     252                 :             :   /* Check for extra chars after trailing space. */
     253                 :         112 :   ptr = end;
     254   [ +  +  +  + ]:         119 :   while (*ptr && c_isblank(*ptr))
     255                 :           7 :     ptr++;
     256         [ +  + ]:         112 :   if (*ptr)
     257                 :           1 :     return dpkg_put_error(err, _("version string has embedded spaces"));
     258                 :             : 
     259                 :         111 :   colon= strchr(string,':');
     260         [ +  + ]:         111 :   if (colon) {
     261                 :             :     long epoch;
     262                 :             : 
     263                 :          76 :     errno = 0;
     264                 :          76 :     epoch = strtol(string, &eepochcolon, 10);
     265         [ +  + ]:          76 :     if (string == eepochcolon)
     266                 :           3 :       return dpkg_put_error(err, _("epoch in version is empty"));
     267         [ -  + ]:          73 :     if (colon != eepochcolon)
     268                 :           0 :       return dpkg_put_error(err, _("epoch in version is not number"));
     269         [ +  + ]:          73 :     if (epoch < 0)
     270                 :           1 :       return dpkg_put_error(err, _("epoch in version is negative"));
     271   [ +  +  -  + ]:          72 :     if (epoch > INT_MAX || errno == ERANGE)
     272                 :           1 :       return dpkg_put_error(err, _("epoch in version is too big"));
     273         [ +  + ]:          71 :     if (!*++colon)
     274                 :           1 :       return dpkg_put_error(err, _("nothing after colon in version number"));
     275                 :          70 :     string= colon;
     276                 :          70 :     rversion->epoch= epoch;
     277                 :             :   } else {
     278                 :          35 :     rversion->epoch= 0;
     279                 :             :   }
     280                 :         105 :   rversion->version= nfstrnsave(string,end-string);
     281                 :         105 :   hyphen= strrchr(rversion->version,'-');
     282         [ +  + ]:         105 :   if (hyphen) {
     283                 :          98 :     *hyphen++ = '\0';
     284                 :             : 
     285         [ +  + ]:          98 :     if (*hyphen == '\0')
     286                 :           1 :       return dpkg_put_error(err, _("revision number is empty"));
     287                 :             :   }
     288         [ +  + ]:         104 :   rversion->revision= hyphen ? hyphen : "";
     289                 :             : 
     290                 :             :   /* XXX: Would be faster to use something like cisversion and cisrevision. */
     291                 :         104 :   ptr = rversion->version;
     292         [ +  + ]:         104 :   if (!*ptr)
     293                 :           2 :     return dpkg_put_error(err, _("version number is empty"));
     294         [ +  + ]:         102 :   if (!c_isdigit(*ptr++))
     295                 :           1 :     return dpkg_put_warn(err, _("version number does not start with digit"));
     296         [ +  + ]:         199 :   for (; *ptr; ptr++) {
     297   [ +  +  +  +  :         122 :     if (!c_isdigit(*ptr) && !c_isalpha(*ptr) && strchr(".-+~:", *ptr) == NULL)
                   +  + ]
     298                 :          24 :       return dpkg_put_warn(err, _("invalid character in version number"));
     299                 :             :   }
     300         [ +  + ]:         132 :   for (ptr = rversion->revision; *ptr; ptr++) {
     301   [ +  +  +  +  :          81 :     if (!c_isdigit(*ptr) && !c_isalpha(*ptr) && strchr(".+~", *ptr) == NULL)
                   +  + ]
     302                 :          26 :       return dpkg_put_warn(err, _("invalid character in revision number"));
     303                 :             :   }
     304                 :             : 
     305                 :          51 :   return 0;
     306                 :             : }
     307                 :             : 
     308                 :             : /**
     309                 :             :  * Parse a version string coming from a database file.
     310                 :             :  *
     311                 :             :  * It parses a version string, and prints a warning or an error depending
     312                 :             :  * on the parse options.
     313                 :             :  *
     314                 :             :  * @param ps The parsedb state.
     315                 :             :  * @param version The version to parse into.
     316                 :             :  * @param value The version string to parse from.
     317                 :             :  *
     318                 :             :  * @retval  0 On success, and err is reset.
     319                 :             :  * @retval -1 On failure, and err is set accordingly.
     320                 :             :  */
     321                 :             : int
     322                 :          32 : parse_db_version(struct parsedb_state *ps, struct dpkg_version *version,
     323                 :             :                  const char *value)
     324                 :             : {
     325                 :          32 :   dpkg_error_destroy(&ps->err);
     326                 :             : 
     327         [ +  - ]:          32 :   if (parseversion(version, value, &ps->err) == 0)
     328                 :          32 :     return 0;
     329                 :             : 
     330                 :             :   /* If not in lax mode, turn everything into an error. */
     331         [ #  # ]:           0 :   if (!(ps->flags & pdb_lax_version_parser))
     332                 :           0 :     ps->err.type = DPKG_MSG_ERROR;
     333                 :             : 
     334                 :           0 :   return -1;
     335                 :             : }
     336                 :             : 
     337                 :             : void
     338                 :          64 : parse_must_have_field(struct parsedb_state *ps,
     339                 :             :                       const char *value, const char *what)
     340                 :             : {
     341         [ -  + ]:          64 :   if (!value)
     342                 :           0 :     parse_error(ps, _("missing '%s' field"), what);
     343         [ -  + ]:          64 :   else if (!*value)
     344                 :           0 :     parse_error(ps, _("empty value for '%s' field"), what);
     345                 :          64 : }
     346                 :             : 
     347                 :             : void
     348                 :          64 : parse_ensure_have_field(struct parsedb_state *ps,
     349                 :             :                         const char **value, const char *what)
     350                 :             : {
     351                 :             :   static const char empty[] = "";
     352                 :             : 
     353         [ -  + ]:          64 :   if (!*value) {
     354                 :           0 :     parse_warn(ps, _("missing '%s' field"), what);
     355                 :           0 :     *value = empty;
     356         [ -  + ]:          64 :   } else if (!**value) {
     357                 :           0 :     parse_warn(ps, _("empty value for '%s' field"), what);
     358                 :             :   }
     359                 :          64 : }
        

Generated by: LCOV version 2.0-1