LCOV - code coverage report
Current view: top level - src/main - main.c (source / functions) Hit Total Coverage
Test: dpkg 1.21.11 C code coverage Lines: 37 257 14.4 %
Date: 2022-12-03 00:40:01 Functions: 4 20 20.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 13 133 9.8 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * dpkg - main program for package management
       3                 :            :  * main.c - main program
       4                 :            :  *
       5                 :            :  * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
       6                 :            :  * Copyright © 2006-2016 Guillem Jover <guillem@debian.org>
       7                 :            :  * Copyright © 2010 Canonical Ltd.
       8                 :            :  *   written by Martin Pitt <martin.pitt@canonical.com>
       9                 :            :  *
      10                 :            :  * This is free software; you can redistribute it and/or modify
      11                 :            :  * it under the terms of the GNU General Public License as published by
      12                 :            :  * the Free Software Foundation; either version 2 of the License, or
      13                 :            :  * (at your option) any later version.
      14                 :            :  *
      15                 :            :  * This is distributed in the hope that it will be useful,
      16                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      17                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18                 :            :  * GNU General Public License for more details.
      19                 :            :  *
      20                 :            :  * You should have received a copy of the GNU General Public License
      21                 :            :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      22                 :            :  */
      23                 :            : 
      24                 :            : #include <config.h>
      25                 :            : #include <compat.h>
      26                 :            : 
      27                 :            : #include <sys/types.h>
      28                 :            : #include <sys/wait.h>
      29                 :            : 
      30                 :            : #include <errno.h>
      31                 :            : #include <limits.h>
      32                 :            : #if HAVE_LOCALE_H
      33                 :            : #include <locale.h>
      34                 :            : #endif
      35                 :            : #include <string.h>
      36                 :            : #include <fcntl.h>
      37                 :            : #include <dirent.h>
      38                 :            : #include <unistd.h>
      39                 :            : #include <stdbool.h>
      40                 :            : #include <stdlib.h>
      41                 :            : #include <stdio.h>
      42                 :            : 
      43                 :            : #include <dpkg/macros.h>
      44                 :            : #include <dpkg/i18n.h>
      45                 :            : #include <dpkg/c-ctype.h>
      46                 :            : #include <dpkg/dpkg.h>
      47                 :            : #include <dpkg/dpkg-db.h>
      48                 :            : #include <dpkg/arch.h>
      49                 :            : #include <dpkg/subproc.h>
      50                 :            : #include <dpkg/command.h>
      51                 :            : #include <dpkg/pager.h>
      52                 :            : #include <dpkg/options.h>
      53                 :            : #include <dpkg/db-fsys.h>
      54                 :            : 
      55                 :            : #include "main.h"
      56                 :            : #include "filters.h"
      57                 :            : 
      58                 :            : static int
      59                 :         48 : printversion(const char *const *argv)
      60                 :            : {
      61         [ -  + ]:         48 :   if (f_robot) {
      62                 :          0 :     printf("%s", PACKAGE_VERSION);
      63                 :            :   } else {
      64                 :         48 :     printf(_("Debian '%s' package management program version %s.\n"),
      65                 :            :            DPKG, PACKAGE_RELEASE);
      66                 :         48 :     printf(_(
      67                 :            : "This is free software; see the GNU General Public License version 2 or\n"
      68                 :            : "later for copying conditions. There is NO warranty.\n"));
      69                 :            :   }
      70                 :            : 
      71                 :         48 :   m_output(stdout, _("<standard output>"));
      72                 :            : 
      73                 :         48 :   return 0;
      74                 :            : }
      75                 :            : 
      76                 :            : /*
      77                 :            :  * FIXME: Options that need fixing:
      78                 :            :  * dpkg --command-fd
      79                 :            :  */
      80                 :            : 
      81                 :            : static int
      82                 :          0 : usage(const char *const *argv)
      83                 :            : {
      84                 :          0 :   printf(_(
      85                 :            : "Usage: %s [<option>...] <command>\n"
      86                 :            : "\n"), DPKG);
      87                 :            : 
      88                 :          0 :   printf(_(
      89                 :            : "Commands:\n"
      90                 :            : "  -i|--install       <.deb file name>... | -R|--recursive <directory>...\n"
      91                 :            : "  --unpack           <.deb file name>... | -R|--recursive <directory>...\n"
      92                 :            : "  -A|--record-avail  <.deb file name>... | -R|--recursive <directory>...\n"
      93                 :            : "  --configure        <package>... | -a|--pending\n"
      94                 :            : "  --triggers-only    <package>... | -a|--pending\n"
      95                 :            : "  -r|--remove        <package>... | -a|--pending\n"
      96                 :            : "  -P|--purge         <package>... | -a|--pending\n"
      97                 :            : "  -V|--verify [<package>...]       Verify the integrity of package(s).\n"
      98                 :            : "  --get-selections [<pattern>...]  Get list of selections to stdout.\n"
      99                 :            : "  --set-selections                 Set package selections from stdin.\n"
     100                 :            : "  --clear-selections               Deselect every non-essential package.\n"
     101                 :            : "  --update-avail [<Packages-file>] Replace available packages info.\n"
     102                 :            : "  --merge-avail [<Packages-file>]  Merge with info from file.\n"
     103                 :            : "  --clear-avail                    Erase existing available info.\n"
     104                 :            : "  --forget-old-unavail             Forget uninstalled unavailable pkgs.\n"
     105                 :            : "  -s|--status [<package>...]       Display package status details.\n"
     106                 :            : "  -p|--print-avail [<package>...]  Display available version details.\n"
     107                 :            : "  -L|--listfiles <package>...      List files 'owned' by package(s).\n"
     108                 :            : "  -l|--list [<pattern>...]         List packages concisely.\n"
     109                 :            : "  -S|--search <pattern>...         Find package(s) owning file(s).\n"
     110                 :            : "  -C|--audit [<package>...]        Check for broken package(s).\n"
     111                 :            : "  --yet-to-unpack                  Print packages selected for installation.\n"
     112                 :            : "  --predep-package                 Print pre-dependencies to unpack.\n"
     113                 :            : "  --add-architecture <arch>        Add <arch> to the list of architectures.\n"
     114                 :            : "  --remove-architecture <arch>     Remove <arch> from the list of architectures.\n"
     115                 :            : "  --print-architecture             Print dpkg architecture.\n"
     116                 :            : "  --print-foreign-architectures    Print allowed foreign architectures.\n"
     117                 :            : "  --assert-help                    Show help on assertions.\n"
     118                 :            : "  --assert-<feature>               Assert support for the specified feature.\n"
     119                 :            : "  --validate-<thing> <string>      Validate a <thing>'s <string>.\n"
     120                 :            : "  --compare-versions <a> <op> <b>  Compare version numbers - see below.\n"
     121                 :            : "  --force-help                     Show help on forcing.\n"
     122                 :            : "  -Dh|--debug=help                 Show help on debugging.\n"
     123                 :            : "\n"));
     124                 :            : 
     125                 :          0 :   printf(_(
     126                 :            : "  -?, --help                       Show this help message.\n"
     127                 :            : "      --version                    Show the version.\n"
     128                 :            : "\n"));
     129                 :            : 
     130                 :          0 :   printf(_(
     131                 :            : "Validatable things: pkgname, archname, trigname, version.\n"
     132                 :            : "\n"));
     133                 :            : 
     134                 :          0 :   printf(_(
     135                 :            : "Use dpkg with -b, --build, -c, --contents, -e, --control, -I, --info,\n"
     136                 :            : "  -f, --field, -x, --extract, -X, --vextract, --ctrl-tarfile, --fsys-tarfile\n"
     137                 :            : "on archives (type %s --help).\n"
     138                 :            : "\n"), BACKEND);
     139                 :            : 
     140                 :          0 :   printf(_(
     141                 :            : "Options:\n"
     142                 :            : "  --admindir=<directory>     Use <directory> instead of %s.\n"
     143                 :            : "  --root=<directory>         Install on a different root directory.\n"
     144                 :            : "  --instdir=<directory>      Change installation dir without changing admin dir.\n"
     145                 :            : "  --pre-invoke=<command>     Set a pre-invoke hook.\n"
     146                 :            : "  --post-invoke=<command>    Set a post-invoke hook.\n"
     147                 :            : "  --path-exclude=<pattern>   Do not install paths which match a shell pattern.\n"
     148                 :            : "  --path-include=<pattern>   Re-include a pattern after a previous exclusion.\n"
     149                 :            : "  -O|--selected-only         Skip packages not selected for install/upgrade.\n"
     150                 :            : "  -E|--skip-same-version     Skip packages with same installed version/arch.\n"
     151                 :            : "  -G|--refuse-downgrade      Skip packages with earlier version than installed.\n"
     152                 :            : "  -B|--auto-deconfigure      Install even if it would break some other package.\n"
     153                 :            : "  --[no-]triggers            Skip or force consequential trigger processing.\n"
     154                 :            : "  --verify-format=<format>   Verify output format (supported: 'rpm').\n"
     155                 :            : "  --no-pager                 Disables the use of any pager.\n"
     156                 :            : "  --no-debsig                Do not try to verify package signatures.\n"
     157                 :            : "  --no-act|--dry-run|--simulate\n"
     158                 :            : "                             Just say what we would do - don't do it.\n"
     159                 :            : "  -D|--debug=<octal>         Enable debugging (see -Dhelp or --debug=help).\n"
     160                 :            : "  --status-fd <n>            Send status change updates to file descriptor <n>.\n"
     161                 :            : "  --status-logger=<command>  Send status change updates to <command>'s stdin.\n"
     162                 :            : "  --log=<filename>           Log status changes and actions to <filename>.\n"
     163                 :            : "  --ignore-depends=<package>[,...]\n"
     164                 :            : "                             Ignore dependencies involving <package>.\n"
     165                 :            : "  --force-<thing>[,...]      Override problems (see --force-help).\n"
     166                 :            : "  --no-force-<thing>[,...]   Stop when problems encountered.\n"
     167                 :            : "  --refuse-<thing>[,...]     Ditto.\n"
     168                 :            : "  --abort-after <n>          Abort after encountering <n> errors.\n"
     169                 :            : "  --robot                    Use machine-readable output on some commands.\n"
     170                 :            : "\n"), ADMINDIR);
     171                 :            : 
     172                 :          0 :   printf(_(
     173                 :            : "Comparison operators for --compare-versions are:\n"
     174                 :            : "  lt le eq ne ge gt       (treat empty version as earlier than any version);\n"
     175                 :            : "  lt-nl le-nl ge-nl gt-nl (treat empty version as later than any version);\n"
     176                 :            : "  < << <= = >= >> >       (only for compatibility with control file syntax).\n"
     177                 :            : "\n"));
     178                 :            : 
     179                 :          0 :   printf(_(
     180                 :            : "Use 'apt' or 'aptitude' for user-friendly package management.\n"));
     181                 :            : 
     182                 :          0 :   m_output(stdout, _("<standard output>"));
     183                 :            : 
     184                 :          0 :   return 0;
     185                 :            : }
     186                 :            : 
     187                 :            : static const char printforhelp[] = N_(
     188                 :            : "Type dpkg --help for help about installing and deinstalling packages [*];\n"
     189                 :            : "Use 'apt' or 'aptitude' for user-friendly package management;\n"
     190                 :            : "Type dpkg -Dhelp for a list of dpkg debug flag values;\n"
     191                 :            : "Type dpkg --force-help for a list of forcing options;\n"
     192                 :            : "Type dpkg-deb --help for help about manipulating *.deb files;\n"
     193                 :            : "\n"
     194                 :            : "Options marked [*] produce a lot of output - pipe it through 'less' or 'more' !");
     195                 :            : 
     196                 :            : int f_robot = 0;
     197                 :            : int f_pending=0, f_recursive=0, f_alsoselect=1, f_skipsame=0, f_noact=0;
     198                 :            : int f_autodeconf=0, f_nodebsig=0;
     199                 :            : int f_triggers = 0;
     200                 :            : 
     201                 :            : int errabort = 50;
     202                 :            : struct pkg_list *ignoredependss = NULL;
     203                 :            : 
     204                 :            : #define DBG_DEF(n, d) \
     205                 :            :   { .flag = dbg_##n, .name = #n, .desc = d }
     206                 :            : 
     207                 :            : static const struct debuginfo {
     208                 :            :   int flag;
     209                 :            :   const char *name;
     210                 :            :   const char *desc;
     211                 :            : } debuginfos[] = {
     212                 :            :   DBG_DEF(general,         N_("Generally helpful progress information")),
     213                 :            :   DBG_DEF(scripts,         N_("Invocation and status of maintainer scripts")),
     214                 :            :   DBG_DEF(eachfile,        N_("Output for each file processed")),
     215                 :            :   DBG_DEF(eachfiledetail,  N_("Lots of output for each file processed")),
     216                 :            :   DBG_DEF(conff,           N_("Output for each configuration file")),
     217                 :            :   DBG_DEF(conffdetail,     N_("Lots of output for each configuration file")),
     218                 :            :   DBG_DEF(depcon,          N_("Dependencies and conflicts")),
     219                 :            :   DBG_DEF(depcondetail,    N_("Lots of dependencies/conflicts output")),
     220                 :            :   DBG_DEF(triggers,        N_("Trigger activation and processing")),
     221                 :            :   DBG_DEF(triggersdetail,  N_("Lots of output regarding triggers")),
     222                 :            :   DBG_DEF(triggersstupid,  N_("Silly amounts of output regarding triggers")),
     223                 :            :   DBG_DEF(veryverbose,     N_("Lots of drivel about eg the dpkg/info directory")),
     224                 :            :   DBG_DEF(stupidlyverbose, N_("Insane amounts of drivel")),
     225                 :            :   { 0, NULL, NULL }
     226                 :            : };
     227                 :            : 
     228                 :            : static void
     229                 :          0 : set_debug(const struct cmdinfo *cpi, const char *value)
     230                 :            : {
     231                 :            :   long mask;
     232                 :            :   const struct debuginfo *dip;
     233                 :            : 
     234         [ #  # ]:          0 :   if (*value == 'h') {
     235                 :          0 :     printf(_(
     236                 :            : "%s debugging option, --debug=<octal> or -D<octal>:\n"
     237                 :            : "\n"
     238                 :            : " Number  Ref. in source   Description\n"), DPKG);
     239                 :            : 
     240         [ #  # ]:          0 :     for (dip = debuginfos; dip->name; dip++)
     241                 :          0 :       printf(" %6o  %-16s %s\n", dip->flag, dip->name, gettext(dip->desc));
     242                 :            : 
     243                 :          0 :     printf(_("\n"
     244                 :            : "Debugging options can be mixed using bitwise-or.\n"
     245                 :            : "Note that the meanings and values are subject to change.\n"));
     246                 :          0 :     m_output(stdout, _("<standard output>"));
     247                 :          0 :     exit(0);
     248                 :            :   }
     249                 :            : 
     250                 :          0 :   mask = debug_parse_mask(value);
     251         [ #  # ]:          0 :   if (mask < 0)
     252                 :          0 :     badusage(_("--%s requires a positive octal argument"), cpi->olong);
     253                 :          0 : }
     254                 :            : 
     255                 :            : static void
     256                 :          0 : set_no_pager(const struct cmdinfo *ci, const char *value)
     257                 :            : {
     258                 :          0 :   pager_enable(false);
     259                 :            : 
     260                 :            :   /* Let's communicate this to our backends. */
     261                 :          0 :   setenv("DPKG_PAGER", "cat", 1);
     262                 :          0 : }
     263                 :            : 
     264                 :            : static void
     265                 :          0 : set_filter(const struct cmdinfo *cip, const char *value)
     266                 :            : {
     267                 :          0 :   filter_add(value, cip->arg_int);
     268                 :          0 : }
     269                 :            : 
     270                 :            : static void
     271                 :          0 : set_verify_format(const struct cmdinfo *cip, const char *value)
     272                 :            : {
     273         [ #  # ]:          0 :   if (!verify_set_output(value))
     274                 :          0 :     badusage(_("unknown verify output format '%s'"), value);
     275                 :          0 : }
     276                 :            : 
     277                 :            : static void
     278                 :          0 : set_ignore_depends(const struct cmdinfo *cip, const char *value)
     279                 :            : {
     280                 :            :   char *copy, *p;
     281                 :            : 
     282                 :          0 :   copy= m_malloc(strlen(value)+2);
     283                 :          0 :   strcpy(copy,value);
     284                 :          0 :   copy[strlen(value) + 1] = '\0';
     285         [ #  # ]:          0 :   for (p=copy; *p; p++) {
     286         [ #  # ]:          0 :     if (*p != ',') continue;
     287                 :          0 :     *p++ = '\0';
     288   [ #  #  #  #  :          0 :     if (!*p || *p==',' || p==copy+1)
                   #  # ]
     289                 :          0 :       badusage(_("null package name in --%s comma-separated list '%.250s'"),
     290                 :          0 :                cip->olong, value);
     291                 :            :   }
     292                 :          0 :   p= copy;
     293         [ #  # ]:          0 :   while (*p) {
     294                 :            :     struct pkginfo *pkg;
     295                 :            : 
     296                 :          0 :     pkg = dpkg_options_parse_pkgname(cip, p);
     297                 :          0 :     pkg_list_prepend(&ignoredependss, pkg);
     298                 :            : 
     299                 :          0 :     p+= strlen(p)+1;
     300                 :            :   }
     301                 :            : 
     302                 :          0 :   free(copy);
     303                 :          0 : }
     304                 :            : 
     305                 :            : static void
     306                 :          0 : set_integer(const struct cmdinfo *cip, const char *value)
     307                 :            : {
     308                 :          0 :   *cip->iassignto = dpkg_options_parse_arg_int(cip, value);
     309                 :          0 : }
     310                 :            : 
     311                 :            : static void
     312                 :          0 : set_pipe(const struct cmdinfo *cip, const char *value)
     313                 :            : {
     314                 :            :   long v;
     315                 :            : 
     316                 :          0 :   v = dpkg_options_parse_arg_int(cip, value);
     317                 :            : 
     318                 :          0 :   statusfd_add(v);
     319                 :          0 : }
     320                 :            : 
     321                 :            : static bool
     322                 :         96 : is_invoke_action(enum action action)
     323                 :            : {
     324         [ -  + ]:         96 :   switch (action) {
     325                 :          0 :   case act_unpack:
     326                 :            :   case act_configure:
     327                 :            :   case act_install:
     328                 :            :   case act_triggers:
     329                 :            :   case act_remove:
     330                 :            :   case act_purge:
     331                 :            :   case act_arch_add:
     332                 :            :   case act_arch_remove:
     333                 :          0 :     return true;
     334                 :         96 :   default:
     335                 :         96 :     return false;
     336                 :            :   }
     337                 :            : }
     338                 :            : 
     339                 :            : static struct invoke_list pre_invoke_hooks = {
     340                 :            :   .head = NULL,
     341                 :            :   .tail = &pre_invoke_hooks.head,
     342                 :            : };
     343                 :            : static struct invoke_list post_invoke_hooks = {
     344                 :            :   .head = NULL,
     345                 :            :   .tail = &post_invoke_hooks.head,
     346                 :            : };
     347                 :            : static struct invoke_list status_loggers = {
     348                 :            :   .head = NULL,
     349                 :            :   .tail = &status_loggers.head,
     350                 :            : };
     351                 :            : 
     352                 :            : static void
     353                 :          0 : set_invoke_hook(const struct cmdinfo *cip, const char *value)
     354                 :            : {
     355                 :          0 :   struct invoke_list *hook_list = cip->arg_ptr;
     356                 :            :   struct invoke_hook *hook_new;
     357                 :            : 
     358                 :          0 :   hook_new = m_malloc(sizeof(*hook_new));
     359                 :          0 :   hook_new->command = m_strdup(value);
     360                 :          0 :   hook_new->next = NULL;
     361                 :            : 
     362                 :            :   /* Add the new hook at the tail of the list to preserve the order. */
     363                 :          0 :   *hook_list->tail = hook_new;
     364                 :          0 :   hook_list->tail = &hook_new->next;
     365                 :          0 : }
     366                 :            : 
     367                 :            : static void
     368                 :          0 : run_invoke_hooks(const char *action, struct invoke_list *hook_list)
     369                 :            : {
     370                 :            :   struct invoke_hook *hook;
     371                 :            : 
     372                 :          0 :   setenv("DPKG_HOOK_ACTION", action, 1);
     373                 :            : 
     374         [ #  # ]:          0 :   for (hook = hook_list->head; hook; hook = hook->next) {
     375                 :            :     int status;
     376                 :            : 
     377                 :            :     /* XXX: As an optimization, use exec instead if no shell metachar are
     378                 :            :      * used “!$=&|\\`'"^~;<>{}[]()?*#”. */
     379                 :          0 :     status = system(hook->command);
     380         [ #  # ]:          0 :     if (status != 0)
     381                 :          0 :       ohshit(_("error executing hook '%s', exit code %d"), hook->command,
     382                 :            :              status);
     383                 :            :   }
     384                 :            : 
     385                 :          0 :   unsetenv("DPKG_HOOK_ACTION");
     386                 :          0 : }
     387                 :            : 
     388                 :            : static void
     389                 :         96 : free_invoke_hooks(struct invoke_list *hook_list)
     390                 :            : {
     391                 :            :   struct invoke_hook *hook, *hook_next;
     392                 :            : 
     393         [ -  + ]:         96 :   for (hook = hook_list->head; hook; hook = hook_next) {
     394                 :          0 :     hook_next = hook->next;
     395                 :          0 :     free(hook->command);
     396                 :          0 :     free(hook);
     397                 :            :   }
     398                 :         96 : }
     399                 :            : 
     400                 :            : static int
     401                 :          0 : run_logger(struct invoke_hook *hook, const char *name)
     402                 :            : {
     403                 :            :   pid_t pid;
     404                 :            :   int p[2];
     405                 :            : 
     406                 :          0 :   m_pipe(p);
     407                 :            : 
     408                 :          0 :   pid = subproc_fork();
     409         [ #  # ]:          0 :   if (pid == 0) {
     410                 :            :     /* Setup stdin and stdout. */
     411                 :          0 :     m_dup2(p[0], 0);
     412                 :          0 :     close(1);
     413                 :            : 
     414                 :          0 :     close(p[0]);
     415                 :          0 :     close(p[1]);
     416                 :            : 
     417                 :          0 :     command_shell(hook->command, name);
     418                 :            :   }
     419                 :          0 :   close(p[0]);
     420                 :            : 
     421                 :          0 :   return p[1];
     422                 :            : }
     423                 :            : 
     424                 :            : static void
     425                 :          0 : run_status_loggers(struct invoke_list *hook_list)
     426                 :            : {
     427                 :            :   struct invoke_hook *hook;
     428                 :            : 
     429         [ #  # ]:          0 :   for (hook = hook_list->head; hook; hook = hook->next) {
     430                 :            :     int fd;
     431                 :            : 
     432                 :          0 :     fd = run_logger(hook, _("status logger"));
     433                 :          0 :     statusfd_add(fd);
     434                 :            :   }
     435                 :          0 : }
     436                 :            : 
     437                 :            : static int
     438                 :          0 : arch_add(const char *const *argv)
     439                 :            : {
     440                 :            :   struct dpkg_arch *arch;
     441                 :          0 :   const char *archname = *argv++;
     442                 :            : 
     443   [ #  #  #  # ]:          0 :   if (archname == NULL || *argv)
     444                 :          0 :     badusage(_("--%s takes exactly one argument"), cipaction->olong);
     445                 :            : 
     446                 :          0 :   dpkg_arch_load_list();
     447                 :            : 
     448                 :          0 :   arch = dpkg_arch_add(archname);
     449      [ #  #  # ]:          0 :   switch (arch->type) {
     450                 :          0 :   case DPKG_ARCH_NATIVE:
     451                 :            :   case DPKG_ARCH_FOREIGN:
     452                 :          0 :     break;
     453                 :          0 :   case DPKG_ARCH_ILLEGAL:
     454                 :          0 :     ohshit(_("architecture '%s' is illegal: %s"), archname,
     455                 :            :            dpkg_arch_name_is_illegal(archname));
     456                 :          0 :   default:
     457                 :          0 :     ohshit(_("architecture '%s' is reserved and cannot be added"), archname);
     458                 :            :   }
     459                 :            : 
     460                 :          0 :   dpkg_arch_save_list();
     461                 :            : 
     462                 :          0 :   return 0;
     463                 :            : }
     464                 :            : 
     465                 :            : static int
     466                 :          0 : arch_remove(const char *const *argv)
     467                 :            : {
     468                 :          0 :   const char *archname = *argv++;
     469                 :            :   struct dpkg_arch *arch;
     470                 :            :   struct pkg_hash_iter *iter;
     471                 :            :   struct pkginfo *pkg;
     472                 :            : 
     473   [ #  #  #  # ]:          0 :   if (archname == NULL || *argv)
     474                 :          0 :     badusage(_("--%s takes exactly one argument"), cipaction->olong);
     475                 :            : 
     476                 :          0 :   modstatdb_open(msdbrw_readonly);
     477                 :            : 
     478                 :          0 :   arch = dpkg_arch_find(archname);
     479         [ #  # ]:          0 :   if (arch->type != DPKG_ARCH_FOREIGN) {
     480                 :          0 :     warning(_("cannot remove non-foreign architecture '%s'"), arch->name);
     481                 :          0 :     return 0;
     482                 :            :   }
     483                 :            : 
     484                 :            :   /* Check if it's safe to remove the architecture from the db. */
     485                 :          0 :   iter = pkg_hash_iter_new();
     486         [ #  # ]:          0 :   while ((pkg = pkg_hash_iter_next_pkg(iter))) {
     487         [ #  # ]:          0 :     if (pkg->status < PKG_STAT_HALFINSTALLED)
     488                 :          0 :       continue;
     489         [ #  # ]:          0 :     if (pkg->installed.arch == arch) {
     490         [ #  # ]:          0 :       if (in_force(FORCE_ARCHITECTURE))
     491                 :          0 :         warning(_("removing architecture '%s' currently in use by database"),
     492                 :            :                 arch->name);
     493                 :            :       else
     494                 :          0 :         ohshit(_("cannot remove architecture '%s' currently in use by the database"),
     495                 :            :                arch->name);
     496                 :          0 :       break;
     497                 :            :     }
     498                 :            :   }
     499                 :          0 :   pkg_hash_iter_free(iter);
     500                 :            : 
     501                 :          0 :   dpkg_arch_unmark(arch);
     502                 :          0 :   dpkg_arch_save_list();
     503                 :            : 
     504                 :          0 :   modstatdb_shutdown();
     505                 :            : 
     506                 :          0 :   return 0;
     507                 :            : }
     508                 :            : 
     509                 :            : int execbackend(const char *const *argv) DPKG_ATTR_NORET;
     510                 :            : int commandfd(const char *const *argv);
     511                 :            : 
     512                 :            : /* This table has both the action entries in it and the normal options.
     513                 :            :  * The action entries are made with the ACTION macro, as they all
     514                 :            :  * have a very similar structure. */
     515                 :            : static const struct cmdinfo cmdinfos[]= {
     516                 :            : #define ACTIONBACKEND(longopt, shortopt, backend) \
     517                 :            :  { longopt, shortopt, 0, NULL, NULL, setaction, 0, (void *)backend, execbackend }
     518                 :            : 
     519                 :            :   ACTION( "install",                        'i', act_install,              archivefiles    ),
     520                 :            :   ACTION( "unpack",                          0,  act_unpack,               archivefiles    ),
     521                 :            :   ACTION( "record-avail",                   'A', act_avail,                archivefiles    ),
     522                 :            :   ACTION( "configure",                       0,  act_configure,            packages        ),
     523                 :            :   ACTION( "remove",                         'r', act_remove,               packages        ),
     524                 :            :   ACTION( "purge",                          'P', act_purge,                packages        ),
     525                 :            :   ACTION( "triggers-only",                   0,  act_triggers,             packages        ),
     526                 :            :   ACTION( "verify",                         'V', act_verify,               verify          ),
     527                 :            :   ACTIONBACKEND( "listfiles",               'L', DPKGQUERY),
     528                 :            :   ACTIONBACKEND( "status",                  's', DPKGQUERY),
     529                 :            :   ACTION( "get-selections",                  0,  act_getselections,        getselections   ),
     530                 :            :   ACTION( "set-selections",                  0,  act_setselections,        setselections   ),
     531                 :            :   ACTION( "clear-selections",                0,  act_clearselections,      clearselections ),
     532                 :            :   ACTIONBACKEND( "print-avail",             'p', DPKGQUERY),
     533                 :            :   ACTION( "update-avail",                    0,  act_avreplace,            updateavailable ),
     534                 :            :   ACTION( "merge-avail",                     0,  act_avmerge,              updateavailable ),
     535                 :            :   ACTION( "clear-avail",                     0,  act_avclear,              updateavailable ),
     536                 :            :   ACTION( "forget-old-unavail",              0,  act_forgetold,            forgetold       ),
     537                 :            :   ACTION( "audit",                          'C', act_audit,                audit           ),
     538                 :            :   ACTION( "yet-to-unpack",                   0,  act_unpackchk,            unpackchk       ),
     539                 :            :   ACTIONBACKEND( "list",                    'l', DPKGQUERY),
     540                 :            :   ACTIONBACKEND( "search",                  'S', DPKGQUERY),
     541                 :            :   ACTION_MUX( "assert",                      0,  act_assert_feature,       assert_feature, &assert_feature_name),
     542                 :            :   ACTION( "add-architecture",                0,  act_arch_add,             arch_add        ),
     543                 :            :   ACTION( "remove-architecture",             0,  act_arch_remove,          arch_remove     ),
     544                 :            :   ACTION( "print-architecture",              0,  act_printarch,            printarch   ),
     545                 :            :   ACTION( "print-foreign-architectures",     0,  act_printforeignarches,   print_foreign_arches ),
     546                 :            :   ACTION( "predep-package",                  0,  act_predeppackage,        predeppackage   ),
     547                 :            :   ACTION( "validate-pkgname",                0,  act_validate_pkgname,     validate_pkgname ),
     548                 :            :   ACTION( "validate-trigname",               0,  act_validate_trigname,    validate_trigname ),
     549                 :            :   ACTION( "validate-archname",               0,  act_validate_archname,    validate_archname ),
     550                 :            :   ACTION( "validate-version",                0,  act_validate_version,     validate_version ),
     551                 :            :   ACTION( "compare-versions",                0,  act_cmpversions,          cmpversions     ),
     552                 :            : /*
     553                 :            :   ACTION( "command-fd",                   'c', act_commandfd,   commandfd     ),
     554                 :            : */
     555                 :            :   ACTION( "help",                           '?', act_help,                 usage),
     556                 :            :   ACTION( "version",                         0,  act_version,              printversion),
     557                 :            : 
     558                 :            :   { "pre-invoke",        0,   1, NULL,          NULL,      set_invoke_hook, 0, &pre_invoke_hooks },
     559                 :            :   { "post-invoke",       0,   1, NULL,          NULL,      set_invoke_hook, 0, &post_invoke_hooks },
     560                 :            :   { "path-exclude",      0,   1, NULL,          NULL,      set_filter,     0 },
     561                 :            :   { "path-include",      0,   1, NULL,          NULL,      set_filter,     1 },
     562                 :            :   { "verify-format",     0,   1, NULL,          NULL,      set_verify_format },
     563                 :            :   { "status-logger",     0,   1, NULL,          NULL,      set_invoke_hook, 0, &status_loggers },
     564                 :            :   { "status-fd",         0,   1, NULL,          NULL,      set_pipe, 0 },
     565                 :            :   { "log",               0,   1, NULL,          &log_file, NULL,    0 },
     566                 :            :   { "pending",           'a', 0, &f_pending,    NULL,      NULL,    1 },
     567                 :            :   { "recursive",         'R', 0, &f_recursive,  NULL,      NULL,    1 },
     568                 :            :   { "no-act",            0,   0, &f_noact,      NULL,      NULL,    1 },
     569                 :            :   { "dry-run",           0,   0, &f_noact,      NULL,      NULL,    1 },
     570                 :            :   { "simulate",          0,   0, &f_noact,      NULL,      NULL,    1 },
     571                 :            :   { "no-pager",          0,   0, NULL,          NULL,      set_no_pager,  0 },
     572                 :            :   { "no-debsig",         0,   0, &f_nodebsig,   NULL,      NULL,    1 },
     573                 :            :   /* Alias ('G') for --refuse. */
     574                 :            :   {  NULL,               'G', 0, NULL,          NULL,      reset_force_option, FORCE_DOWNGRADE },
     575                 :            :   { "selected-only",     'O', 0, &f_alsoselect, NULL,      NULL,    0 },
     576                 :            :   { "triggers",           0,  0, &f_triggers,   NULL,      NULL,    1 },
     577                 :            :   { "no-triggers",        0,  0, &f_triggers,   NULL,      NULL,   -1 },
     578                 :            :   /* TODO: Remove ('N') sometime. */
     579                 :            :   { "no-also-select",    'N', 0, &f_alsoselect, NULL,      NULL,    0 },
     580                 :            :   { "skip-same-version", 'E', 0, &f_skipsame,   NULL,      NULL,    1 },
     581                 :            :   { "auto-deconfigure",  'B', 0, &f_autodeconf, NULL,      NULL,    1 },
     582                 :            :   { "robot",             0,   0, &f_robot,      NULL,      NULL,    1 },
     583                 :            :   { "root",              0,   1, NULL,          NULL,      set_root,      0 },
     584                 :            :   { "abort-after",       0,   1, &errabort,     NULL,      set_integer,   0 },
     585                 :            :   { "admindir",          0,   1, NULL,          NULL,      set_admindir,  0 },
     586                 :            :   { "instdir",           0,   1, NULL,          NULL,      set_instdir,   0 },
     587                 :            :   { "ignore-depends",    0,   1, NULL,          NULL,      set_ignore_depends, 0 },
     588                 :            :   { "force",             0,   2, NULL,          NULL,      set_force_option,   1 },
     589                 :            :   { "refuse",            0,   2, NULL,          NULL,      set_force_option,   0 },
     590                 :            :   { "no-force",          0,   2, NULL,          NULL,      set_force_option,   0 },
     591                 :            :   { "debug",             'D', 1, NULL,          NULL,      set_debug,     0 },
     592                 :            :   ACTIONBACKEND( "build",             'b', BACKEND),
     593                 :            :   ACTIONBACKEND( "contents",          'c', BACKEND),
     594                 :            :   ACTIONBACKEND( "control",           'e', BACKEND),
     595                 :            :   ACTIONBACKEND( "info",              'I', BACKEND),
     596                 :            :   ACTIONBACKEND( "field",             'f', BACKEND),
     597                 :            :   ACTIONBACKEND( "extract",           'x', BACKEND),
     598                 :            :   ACTIONBACKEND( "vextract",          'X', BACKEND),
     599                 :            :   ACTIONBACKEND( "ctrl-tarfile",      0,   BACKEND),
     600                 :            :   ACTIONBACKEND( "fsys-tarfile",      0,   BACKEND),
     601                 :            :   { NULL,                0,   0, NULL,          NULL,      NULL,          0 }
     602                 :            : };
     603                 :            : 
     604                 :            : int
     605                 :          0 : execbackend(const char *const *argv)
     606                 :            : {
     607                 :            :   struct command cmd;
     608                 :            : 
     609                 :          0 :   command_init(&cmd, cipaction->arg_ptr, NULL);
     610                 :          0 :   command_add_arg(&cmd, cipaction->arg_ptr);
     611                 :          0 :   command_add_arg(&cmd, str_fmt("--%s", cipaction->olong));
     612                 :            : 
     613                 :            :   /* Explicitly separate arguments from options as any user-supplied
     614                 :            :    * separator got stripped by the option parser */
     615                 :          0 :   command_add_arg(&cmd, "--");
     616                 :          0 :   command_add_argl(&cmd, (const char **)argv);
     617                 :            : 
     618                 :          0 :   command_exec(&cmd);
     619                 :            : }
     620                 :            : 
     621                 :            : int
     622                 :          0 : commandfd(const char *const *argv)
     623                 :            : {
     624                 :          0 :   struct varbuf linevb = VARBUF_INIT;
     625                 :            :   const char * pipein;
     626                 :          0 :   const char **newargs = NULL, **endargs;
     627                 :            :   char *ptr, *endptr;
     628                 :            :   FILE *in;
     629                 :            :   long infd;
     630                 :          0 :   int ret = 0;
     631                 :            :   int c, lno, i;
     632                 :            :   bool skipchar;
     633                 :            : 
     634                 :          0 :   pipein = *argv++;
     635   [ #  #  #  # ]:          0 :   if (pipein == NULL || *argv)
     636                 :          0 :     badusage(_("--%s takes exactly one argument"), cipaction->olong);
     637                 :            : 
     638                 :          0 :   infd = dpkg_options_parse_arg_int(cipaction, pipein);
     639                 :          0 :   in = fdopen(infd, "r");
     640         [ #  # ]:          0 :   if (in == NULL)
     641                 :          0 :     ohshite(_("couldn't open '%i' for stream"), (int)infd);
     642                 :            : 
     643                 :          0 :   for (;;) {
     644                 :          0 :     bool mode = false;
     645                 :          0 :     int argc= 1;
     646                 :          0 :     lno= 0;
     647                 :            : 
     648                 :          0 :     push_error_context();
     649                 :            : 
     650                 :            :     do {
     651                 :          0 :       c = getc(in);
     652         [ #  # ]:          0 :       if (c == '\n')
     653                 :          0 :         lno++;
     654   [ #  #  #  # ]:          0 :     } while (c != EOF && c_isspace(c));
     655         [ #  # ]:          0 :     if (c == EOF) break;
     656         [ #  # ]:          0 :     if (c == '#') {
     657   [ #  #  #  #  :          0 :       do { c= getc(in); if (c == '\n') lno++; } while (c != EOF && c != '\n');
                   #  # ]
     658                 :          0 :       continue;
     659                 :            :     }
     660                 :          0 :     varbuf_reset(&linevb);
     661                 :            :     do {
     662                 :          0 :       varbuf_add_char(&linevb, c);
     663                 :          0 :       c= getc(in);
     664         [ #  # ]:          0 :       if (c == '\n') lno++;
     665                 :            : 
     666                 :            :       /* This isn't fully accurate, but overestimating can't hurt. */
     667         [ #  # ]:          0 :       if (c_isspace(c))
     668                 :          0 :         argc++;
     669   [ #  #  #  # ]:          0 :     } while (c != EOF && c != '\n');
     670         [ #  # ]:          0 :     if (c == EOF)
     671                 :          0 :       ohshit(_("unexpected end of file before end of line %d"), lno);
     672         [ #  # ]:          0 :     if (!argc) continue;
     673                 :          0 :     varbuf_end_str(&linevb);
     674                 :          0 :     newargs = m_realloc(newargs, sizeof(const char *) * (argc + 1));
     675                 :          0 :     argc= 1;
     676                 :          0 :     ptr= linevb.buf;
     677                 :          0 :     endptr = ptr + linevb.used + 1;
     678                 :          0 :     skipchar = false;
     679         [ #  # ]:          0 :     while(ptr < endptr) {
     680         [ #  # ]:          0 :       if (skipchar) {
     681                 :          0 :         skipchar = false;
     682         [ #  # ]:          0 :       } else if (*ptr == '\\') {
     683                 :          0 :         memmove(ptr, (ptr+1), (linevb.used-(linevb.buf - ptr)-1));
     684                 :          0 :         endptr--;
     685                 :          0 :         skipchar = true;
     686                 :          0 :         continue;
     687         [ #  # ]:          0 :       } else if (c_isspace(*ptr)) {
     688         [ #  # ]:          0 :         if (mode == true) {
     689                 :          0 :           *ptr = '\0';
     690                 :          0 :           mode = false;
     691                 :            :         }
     692                 :            :       } else {
     693         [ #  # ]:          0 :         if (mode == false) {
     694                 :          0 :           newargs[argc]= ptr;
     695                 :          0 :           argc++;
     696                 :          0 :           mode = true;
     697                 :            :         }
     698                 :            :       }
     699                 :          0 :       ptr++;
     700                 :            :     }
     701                 :          0 :     *ptr = '\0';
     702                 :          0 :     newargs[argc++] = NULL;
     703                 :            : 
     704                 :            :     /* We strdup() each argument, but never free it, because the
     705                 :            :      * error messages contain references back to these strings.
     706                 :            :      * Freeing them, and reusing the memory, would make those
     707                 :            :      * error messages confusing, to say the least. */
     708         [ #  # ]:          0 :     for(i=1;i<argc;i++)
     709         [ #  # ]:          0 :       if (newargs[i])
     710                 :          0 :         newargs[i] = m_strdup(newargs[i]);
     711                 :          0 :     endargs = newargs;
     712                 :            : 
     713                 :          0 :     setaction(NULL, NULL);
     714                 :          0 :     dpkg_options_parse((const char *const **)&endargs, cmdinfos, printforhelp);
     715         [ #  # ]:          0 :     if (!cipaction) badusage(_("need an action option"));
     716                 :            : 
     717                 :          0 :     ret |= cipaction->action(endargs);
     718                 :            : 
     719                 :          0 :     fsys_hash_reset();
     720                 :            : 
     721                 :          0 :     pop_error_context(ehflag_normaltidy);
     722                 :            :   }
     723                 :            : 
     724                 :          0 :   fclose(in);
     725                 :            : 
     726                 :          0 :   return ret;
     727                 :            : }
     728                 :            : 
     729                 :         48 : int main(int argc, const char *const *argv) {
     730                 :            :   char *force_string;
     731                 :            :   int ret;
     732                 :            : 
     733                 :         48 :   dpkg_locales_init(PACKAGE);
     734                 :         48 :   dpkg_program_init("dpkg");
     735                 :         48 :   set_force_default(FORCE_ALL);
     736                 :         48 :   dpkg_options_load(DPKG, cmdinfos);
     737                 :         48 :   dpkg_options_parse(&argv, cmdinfos, printforhelp);
     738                 :            : 
     739                 :         48 :   debug(dbg_general, "root=%s admindir=%s", dpkg_fsys_get_dir(), dpkg_db_get_dir());
     740                 :            : 
     741                 :            :   /* When running as root, make sure our primary group is also root, so
     742                 :            :    * that files created by maintainer scripts have correct ownership. */
     743   [ +  -  -  +  :         48 :   if (!in_force(FORCE_NON_ROOT) && getuid() == 0 && getgid() != 0)
                   -  - ]
     744         [ #  # ]:          0 :     if (setgid(0) < 0)
     745                 :          0 :       ohshite(_("cannot set primary group ID to root"));
     746                 :            : 
     747         [ -  + ]:         48 :   if (!cipaction) badusage(_("need an action option"));
     748                 :            : 
     749                 :            :   /* Always set environment, to avoid possible security risks. */
     750         [ -  + ]:         48 :   if (setenv("DPKG_ADMINDIR", dpkg_db_get_dir(), 1) < 0)
     751                 :          0 :     ohshite(_("unable to setenv for subprocesses"));
     752         [ -  + ]:         48 :   if (setenv("DPKG_ROOT", dpkg_fsys_get_dir(), 1) < 0)
     753                 :          0 :     ohshite(_("unable to setenv for subprocesses"));
     754                 :         48 :   force_string = get_force_string();
     755         [ -  + ]:         48 :   if (setenv("DPKG_FORCE", force_string, 1) < 0)
     756                 :          0 :     ohshite(_("unable to setenv for subprocesses"));
     757                 :         48 :   free(force_string);
     758                 :            : 
     759         [ +  - ]:         48 :   if (!f_triggers)
     760   [ -  +  -  - ]:         48 :     f_triggers = (cipaction->arg_int == act_triggers && *argv) ? -1 : 1;
     761                 :            : 
     762         [ -  + ]:         48 :   if (is_invoke_action(cipaction->arg_int)) {
     763                 :          0 :     run_invoke_hooks(cipaction->olong, &pre_invoke_hooks);
     764                 :          0 :     run_status_loggers(&status_loggers);
     765                 :            :   }
     766                 :            : 
     767                 :         48 :   ret = cipaction->action(argv);
     768                 :            : 
     769         [ -  + ]:         48 :   if (is_invoke_action(cipaction->arg_int))
     770                 :          0 :     run_invoke_hooks(cipaction->olong, &post_invoke_hooks);
     771                 :            : 
     772                 :         48 :   free_invoke_hooks(&pre_invoke_hooks);
     773                 :         48 :   free_invoke_hooks(&post_invoke_hooks);
     774                 :            : 
     775                 :         48 :   dpkg_program_done();
     776                 :         48 :   dpkg_locales_done();
     777                 :            : 
     778                 :         48 :   return reportbroken_retexitstatus(ret);
     779                 :            : }

Generated by: LCOV version 1.16