LCOV - code coverage report
Current view: top level - lib/dpkg - pkg-spec.c (source / functions) Hit Total Coverage
Test: dpkg 1.21.11 C code coverage Lines: 0 129 0.0 %
Date: 2022-12-03 00:40:01 Functions: 0 19 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 61 0.0 %

           Branch data     Line data    Source code
       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
      37                 :          0 : pkg_spec_blank(struct pkg_spec *ps)
      38                 :            : {
      39                 :          0 :         ps->name = NULL;
      40                 :          0 :         ps->arch = NULL;
      41                 :            : 
      42                 :          0 :         ps->name_is_pattern = false;
      43                 :          0 :         ps->arch_is_pattern = false;
      44                 :          0 : }
      45                 :            : 
      46                 :            : static void
      47                 :          0 : pkg_spec_iter_blank(struct pkg_spec *ps)
      48                 :            : {
      49                 :          0 :         ps->pkg_iter = NULL;
      50                 :          0 :         ps->pkg_next = NULL;
      51                 :          0 : }
      52                 :            : 
      53                 :            : void
      54                 :          0 : pkg_spec_init(struct pkg_spec *ps, enum pkg_spec_flags flags)
      55                 :            : {
      56                 :          0 :         ps->flags = flags;
      57                 :            : 
      58                 :          0 :         pkg_spec_blank(ps);
      59                 :          0 :         pkg_spec_iter_blank(ps);
      60                 :          0 : }
      61                 :            : 
      62                 :            : const char *
      63                 :          0 : pkg_spec_is_illegal(struct pkg_spec *ps)
      64                 :            : {
      65                 :            :         static char msg[1024];
      66                 :            :         const char *emsg;
      67                 :            : 
      68   [ #  #  #  # ]:          0 :         if (!ps->name_is_pattern &&
      69                 :          0 :             (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         [ #  # ]:          0 :                 if (ps->arch->type == DPKG_ARCH_NONE)
      76                 :          0 :                         arch_sep = "";
      77                 :            :                 else
      78                 :          0 :                         arch_sep = ":";
      79                 :            : 
      80                 :          0 :                 snprintf(msg, sizeof(msg),
      81                 :          0 :                          _("illegal package name in specifier '%s%s%s': %s"),
      82                 :          0 :                          ps->name, arch_sep, ps->arch->name, emsg);
      83                 :          0 :                 return msg;
      84                 :            :         }
      85                 :            : 
      86   [ #  #  #  # ]:          0 :         if ((!ps->arch_is_pattern && ps->arch->type == DPKG_ARCH_ILLEGAL) ||
      87         [ #  # ]:          0 :             ps->arch->type == DPKG_ARCH_EMPTY) {
      88                 :          0 :                 emsg = dpkg_arch_name_is_illegal(ps->arch->name);
      89                 :          0 :                 snprintf(msg, sizeof(msg),
      90                 :          0 :                          _("illegal architecture name in specifier '%s:%s': %s"),
      91                 :          0 :                          ps->name, ps->arch->name, emsg);
      92                 :          0 :                 return msg;
      93                 :            :         }
      94                 :            : 
      95                 :            :         /* If we have been requested a single instance, check that the
      96                 :            :          * package does not contain other instances. */
      97   [ #  #  #  # ]:          0 :         if (!ps->arch_is_pattern && ps->flags & PKG_SPEC_ARCH_SINGLE) {
      98                 :            :                 struct pkgset *set;
      99                 :            : 
     100                 :          0 :                 set = pkg_hash_find_set(ps->name);
     101                 :            : 
     102                 :            :                 /* Single instancing only applies with no architecture. */
     103   [ #  #  #  # ]:          0 :                 if (ps->arch->type == DPKG_ARCH_NONE &&
     104                 :          0 :                     pkgset_installed_instances(set) > 1) {
     105                 :          0 :                         snprintf(msg, sizeof(msg),
     106                 :          0 :                                  _("ambiguous package name '%s' with more "
     107                 :            :                                    "than one installed instance"), ps->name);
     108                 :          0 :                         return msg;
     109                 :            :                 }
     110                 :            :         }
     111                 :            : 
     112                 :          0 :         return NULL;
     113                 :            : }
     114                 :            : 
     115                 :            : static const char *
     116                 :          0 : pkg_spec_prep(struct pkg_spec *ps, char *pkgname, const char *archname)
     117                 :            : {
     118                 :          0 :         ps->name = pkgname;
     119                 :          0 :         ps->arch = dpkg_arch_find(archname);
     120                 :            : 
     121                 :          0 :         ps->name_is_pattern = false;
     122                 :          0 :         ps->arch_is_pattern = false;
     123                 :            : 
     124                 :            :         /* Detect if we have patterns and/or illegal names. */
     125   [ #  #  #  # ]:          0 :         if ((ps->flags & PKG_SPEC_PATTERNS) && strpbrk(ps->name, "*[?\\"))
     126                 :          0 :                 ps->name_is_pattern = true;
     127                 :            : 
     128   [ #  #  #  # ]:          0 :         if ((ps->flags & PKG_SPEC_PATTERNS) && strpbrk(ps->arch->name, "*[?\\"))
     129                 :          0 :                 ps->arch_is_pattern = true;
     130                 :            : 
     131                 :          0 :         return pkg_spec_is_illegal(ps);
     132                 :            : }
     133                 :            : 
     134                 :            : const char *
     135                 :          0 : pkg_spec_set(struct pkg_spec *ps, const char *pkgname, const char *archname)
     136                 :            : {
     137                 :          0 :         return pkg_spec_prep(ps, m_strdup(pkgname), archname);
     138                 :            : }
     139                 :            : 
     140                 :            : const char *
     141                 :          0 : pkg_spec_parse(struct pkg_spec *ps, const char *str)
     142                 :            : {
     143                 :            :         char *pkgname, *archname;
     144                 :            : 
     145                 :          0 :         archname = strchr(str, ':');
     146         [ #  # ]:          0 :         if (archname == NULL) {
     147                 :          0 :                 pkgname = m_strdup(str);
     148                 :            :         } else {
     149                 :          0 :                 pkgname = m_strndup(str, archname - str);
     150                 :          0 :                 archname++;
     151                 :            :         }
     152                 :            : 
     153                 :          0 :         return pkg_spec_prep(ps, pkgname, archname);
     154                 :            : }
     155                 :            : 
     156                 :            : static bool
     157                 :          0 : pkg_spec_match_name(struct pkg_spec *ps, const char *name)
     158                 :            : {
     159         [ #  # ]:          0 :         if (ps->name_is_pattern)
     160                 :          0 :                 return (fnmatch(ps->name, name, 0) == 0);
     161                 :            :         else
     162                 :          0 :                 return (strcmp(ps->name, name) == 0);
     163                 :            : }
     164                 :            : 
     165                 :            : static bool
     166                 :          0 : pkg_spec_match_arch(struct pkg_spec *ps, struct pkginfo *pkg,
     167                 :            :                     const struct dpkg_arch *arch)
     168                 :            : {
     169         [ #  # ]:          0 :         if (ps->arch_is_pattern)
     170                 :          0 :                 return (fnmatch(ps->arch->name, arch->name, 0) == 0);
     171         [ #  # ]:          0 :         else if (ps->arch->type != DPKG_ARCH_NONE) /* !arch_is_pattern */
     172                 :          0 :                 return (ps->arch == arch);
     173                 :            : 
     174                 :            :         /* No arch specified. */
     175      [ #  #  # ]:          0 :         switch (ps->flags & PKG_SPEC_ARCH_MASK) {
     176                 :          0 :         case PKG_SPEC_ARCH_SINGLE:
     177                 :          0 :                 return pkgset_installed_instances(pkg->set) <= 1;
     178                 :          0 :         case PKG_SPEC_ARCH_WILDCARD:
     179                 :          0 :                 return true;
     180                 :          0 :         default:
     181                 :          0 :                 internerr("unknown PKG_SPEC_ARCH_* flags %d in pkg_spec",
     182                 :            :                           ps->flags & PKG_SPEC_ARCH_MASK);
     183                 :            :         }
     184                 :            : }
     185                 :            : 
     186                 :            : bool
     187                 :          0 : pkg_spec_match_pkg(struct pkg_spec *ps, struct pkginfo *pkg,
     188                 :            :                    struct pkgbin *pkgbin)
     189                 :            : {
     190   [ #  #  #  # ]:          0 :         return (pkg_spec_match_name(ps, pkg->set->name) &&
     191                 :          0 :                 pkg_spec_match_arch(ps, pkg, pkgbin->arch));
     192                 :            : }
     193                 :            : 
     194                 :            : static struct pkginfo *
     195                 :          0 : pkg_spec_get_pkg(struct pkg_spec *ps)
     196                 :            : {
     197         [ #  # ]:          0 :         if (ps->arch->type == DPKG_ARCH_NONE)
     198                 :          0 :                 return pkg_hash_find_singleton(ps->name);
     199                 :            :         else
     200                 :          0 :                 return pkg_hash_find_pkg(ps->name, ps->arch);
     201                 :            : }
     202                 :            : 
     203                 :            : struct pkginfo *
     204                 :          0 : 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                 :          0 :         pkg_spec_init(&ps, PKG_SPEC_ARCH_SINGLE);
     211                 :          0 :         emsg = pkg_spec_parse(&ps, str);
     212         [ #  # ]:          0 :         if (emsg) {
     213                 :          0 :                 dpkg_put_error(err, "%s", emsg);
     214                 :          0 :                 pkg = NULL;
     215                 :            :         } else {
     216                 :          0 :                 pkg = pkg_spec_get_pkg(&ps);
     217                 :            :         }
     218                 :          0 :         pkg_spec_destroy(&ps);
     219                 :            : 
     220                 :          0 :         return pkg;
     221                 :            : }
     222                 :            : 
     223                 :            : struct pkginfo *
     224                 :          0 : 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                 :          0 :         pkg_spec_init(&ps, PKG_SPEC_ARCH_SINGLE);
     232                 :          0 :         emsg = pkg_spec_set(&ps, pkgname, archname);
     233         [ #  # ]:          0 :         if (emsg) {
     234                 :          0 :                 dpkg_put_error(err, "%s", emsg);
     235                 :          0 :                 pkg = NULL;
     236                 :            :         } else {
     237                 :          0 :                 pkg = pkg_spec_get_pkg(&ps);
     238                 :            :         }
     239                 :          0 :         pkg_spec_destroy(&ps);
     240                 :            : 
     241                 :          0 :         return pkg;
     242                 :            : }
     243                 :            : 
     244                 :            : void
     245                 :          0 : pkg_spec_iter_init(struct pkg_spec *ps)
     246                 :            : {
     247         [ #  # ]:          0 :         if (ps->name_is_pattern)
     248                 :          0 :                 ps->pkg_iter = pkg_hash_iter_new();
     249                 :            :         else
     250                 :          0 :                 ps->pkg_next = &pkg_hash_find_set(ps->name)->pkg;
     251                 :          0 : }
     252                 :            : 
     253                 :            : static struct pkginfo *
     254                 :          0 : pkg_spec_iter_next_pkgname(struct pkg_spec *ps)
     255                 :            : {
     256                 :            :         struct pkginfo *pkg;
     257                 :            : 
     258         [ #  # ]:          0 :         while ((pkg = pkg_hash_iter_next_pkg(ps->pkg_iter))) {
     259         [ #  # ]:          0 :                 if (pkg_spec_match_pkg(ps, pkg, &pkg->installed))
     260                 :          0 :                         return pkg;
     261                 :            :         }
     262                 :            : 
     263                 :          0 :         return NULL;
     264                 :            : }
     265                 :            : 
     266                 :            : static struct pkginfo *
     267                 :          0 : pkg_spec_iter_next_pkgarch(struct pkg_spec *ps)
     268                 :            : {
     269                 :            :         struct pkginfo *pkg;
     270                 :            : 
     271         [ #  # ]:          0 :         while ((pkg = ps->pkg_next)) {
     272                 :          0 :                 ps->pkg_next = pkg->arch_next;
     273                 :            : 
     274         [ #  # ]:          0 :                 if (pkg_spec_match_arch(ps, pkg, pkg->installed.arch))
     275                 :          0 :                         return pkg;
     276                 :            :         }
     277                 :            : 
     278                 :          0 :         return NULL;
     279                 :            : }
     280                 :            : 
     281                 :            : struct pkginfo *
     282                 :          0 : pkg_spec_iter_next_pkg(struct pkg_spec *ps)
     283                 :            : {
     284         [ #  # ]:          0 :         if (ps->name_is_pattern)
     285                 :          0 :                 return pkg_spec_iter_next_pkgname(ps);
     286                 :            :         else
     287                 :          0 :                 return pkg_spec_iter_next_pkgarch(ps);
     288                 :            : }
     289                 :            : 
     290                 :            : void
     291                 :          0 : pkg_spec_iter_destroy(struct pkg_spec *ps)
     292                 :            : {
     293                 :          0 :         pkg_hash_iter_free(ps->pkg_iter);
     294                 :          0 :         pkg_spec_iter_blank(ps);
     295                 :          0 : }
     296                 :            : 
     297                 :            : void
     298                 :          0 : pkg_spec_destroy(struct pkg_spec *ps)
     299                 :            : {
     300                 :          0 :         free(ps->name);
     301                 :          0 :         pkg_spec_blank(ps);
     302                 :          0 :         pkg_spec_iter_destroy(ps);
     303                 :          0 : }

Generated by: LCOV version 1.16