"Fossies" - the Fresh Open Source Software Archive

Member "dpkg-1.19.7/src/main.c" (16 May 2019, 27336 Bytes) of package /linux/misc/dpkg_1.19.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "main.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.19.6_vs_1.19.7.

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