Dpkg::OpenPGP::Backend::GnuPG: Fallback to use «gpg dearmor» if present
[dpkg.git] / src / main / main.c
blob6f0633e6f8edf84268f5f958ab70fcfe9192aaa1
1 /*
2 * dpkg - main program for package management
3 * main.c - main program
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>
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.
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.
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/>.
24 #include <config.h>
25 #include <compat.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
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>
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>
55 #include "main.h"
56 #include "filters.h"
58 static int
59 printversion(const char *const *argv)
61 if (f_robot) {
62 printf("%s", PACKAGE_VERSION);
63 } else {
64 printf(_("Debian '%s' package management program version %s.\n"),
65 DPKG, PACKAGE_RELEASE);
66 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"));
71 m_output(stdout, _("<standard output>"));
73 return 0;
77 * FIXME: Options that need fixing:
78 * dpkg --command-fd
81 static int
82 usage(const char *const *argv)
84 printf(_(
85 "Usage: %s [<option>...] <command>\n"
86 "\n"), DPKG);
88 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"));
125 printf(_(
126 " -?, --help Show this help message.\n"
127 " --version Show the version.\n"
128 "\n"));
130 printf(_(
131 "Validatable things: pkgname, archname, trigname, version.\n"
132 "\n"));
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);
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 " --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);
172 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"));
179 printf(_(
180 "Use 'apt' or 'aptitude' for user-friendly package management.\n"));
182 m_output(stdout, _("<standard output>"));
184 return 0;
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' !");
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;
201 int errabort = 50;
202 struct pkg_list *ignoredependss = NULL;
204 #define DBG_DEF(n, d) \
205 { .flag = dbg_##n, .name = #n, .desc = d }
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 }
228 static void
229 set_debug(const struct cmdinfo *cpi, const char *value)
231 long mask;
232 const struct debuginfo *dip;
234 if (*value == 'h') {
235 printf(_(
236 "%s debugging option, --debug=<octal> or -D<octal>:\n"
237 "\n"
238 " Number Ref. in source Description\n"), DPKG);
240 for (dip = debuginfos; dip->name; dip++)
241 printf(" %6o %-16s %s\n", dip->flag, dip->name, gettext(dip->desc));
243 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 m_output(stdout, _("<standard output>"));
247 exit(0);
250 mask = debug_parse_mask(value);
251 if (mask < 0)
252 badusage(_("--%s requires a positive octal argument"), cpi->olong);
255 static void
256 set_no_pager(const struct cmdinfo *ci, const char *value)
258 pager_enable(false);
260 /* Let's communicate this to our backends. */
261 setenv("DPKG_PAGER", "cat", 1);
264 static void
265 set_filter(const struct cmdinfo *cip, const char *value)
267 filter_add(value, cip->arg_int);
270 static void
271 set_verify_format(const struct cmdinfo *cip, const char *value)
273 if (!verify_set_output(value))
274 badusage(_("unknown verify output format '%s'"), value);
277 static void
278 set_ignore_depends(const struct cmdinfo *cip, const char *value)
280 char *copy, *p;
282 copy= m_malloc(strlen(value)+2);
283 strcpy(copy,value);
284 copy[strlen(value) + 1] = '\0';
285 for (p=copy; *p; p++) {
286 if (*p != ',') continue;
287 *p++ = '\0';
288 if (!*p || *p==',' || p==copy+1)
289 badusage(_("null package name in --%s comma-separated list '%.250s'"),
290 cip->olong, value);
292 p= copy;
293 while (*p) {
294 struct pkginfo *pkg;
296 pkg = dpkg_options_parse_pkgname(cip, p);
297 pkg_list_prepend(&ignoredependss, pkg);
299 p+= strlen(p)+1;
302 free(copy);
305 static void
306 set_integer(const struct cmdinfo *cip, const char *value)
308 *cip->iassignto = dpkg_options_parse_arg_int(cip, value);
311 static void
312 set_pipe(const struct cmdinfo *cip, const char *value)
314 long v;
316 v = dpkg_options_parse_arg_int(cip, value);
318 statusfd_add(v);
321 static bool
322 is_invoke_action(enum action action)
324 switch (action) {
325 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 return true;
334 default:
335 return false;
339 static struct invoke_list pre_invoke_hooks = {
340 .head = NULL,
341 .tail = &pre_invoke_hooks.head,
343 static struct invoke_list post_invoke_hooks = {
344 .head = NULL,
345 .tail = &post_invoke_hooks.head,
347 static struct invoke_list status_loggers = {
348 .head = NULL,
349 .tail = &status_loggers.head,
352 static void
353 set_invoke_hook(const struct cmdinfo *cip, const char *value)
355 struct invoke_list *hook_list = cip->arg_ptr;
356 struct invoke_hook *hook_new;
358 hook_new = m_malloc(sizeof(*hook_new));
359 hook_new->command = m_strdup(value);
360 hook_new->next = NULL;
362 /* Add the new hook at the tail of the list to preserve the order. */
363 *hook_list->tail = hook_new;
364 hook_list->tail = &hook_new->next;
367 static void
368 run_invoke_hooks(const char *action, struct invoke_list *hook_list)
370 struct invoke_hook *hook;
372 setenv("DPKG_HOOK_ACTION", action, 1);
374 for (hook = hook_list->head; hook; hook = hook->next) {
375 int status;
377 /* XXX: As an optimization, use exec instead if no shell metachar are
378 * used “!$=&|\\`'"^~;<>{}[]()?*#”. */
379 status = system(hook->command);
380 if (status != 0)
381 ohshit(_("error executing hook '%s', exit code %d"), hook->command,
382 status);
385 unsetenv("DPKG_HOOK_ACTION");
388 static void
389 free_invoke_hooks(struct invoke_list *hook_list)
391 struct invoke_hook *hook, *hook_next;
393 for (hook = hook_list->head; hook; hook = hook_next) {
394 hook_next = hook->next;
395 free(hook->command);
396 free(hook);
400 static int
401 run_logger(struct invoke_hook *hook, const char *name)
403 pid_t pid;
404 int p[2];
406 m_pipe(p);
408 pid = subproc_fork();
409 if (pid == 0) {
410 /* Setup stdin and stdout. */
411 m_dup2(p[0], 0);
412 close(1);
414 close(p[0]);
415 close(p[1]);
417 command_shell(hook->command, name);
419 close(p[0]);
421 return p[1];
424 static void
425 run_status_loggers(struct invoke_list *hook_list)
427 struct invoke_hook *hook;
429 for (hook = hook_list->head; hook; hook = hook->next) {
430 int fd;
432 fd = run_logger(hook, _("status logger"));
433 statusfd_add(fd);
437 static int
438 arch_add(const char *const *argv)
440 struct dpkg_arch *arch;
441 const char *archname = *argv++;
443 if (archname == NULL || *argv)
444 badusage(_("--%s takes exactly one argument"), cipaction->olong);
446 dpkg_arch_load_list();
448 arch = dpkg_arch_add(archname);
449 switch (arch->type) {
450 case DPKG_ARCH_NATIVE:
451 case DPKG_ARCH_FOREIGN:
452 break;
453 case DPKG_ARCH_ILLEGAL:
454 ohshit(_("architecture '%s' is illegal: %s"), archname,
455 dpkg_arch_name_is_illegal(archname));
456 default:
457 ohshit(_("architecture '%s' is reserved and cannot be added"), archname);
460 dpkg_arch_save_list();
462 return 0;
465 static int
466 arch_remove(const char *const *argv)
468 const char *archname = *argv++;
469 struct dpkg_arch *arch;
470 struct pkg_hash_iter *iter;
471 struct pkginfo *pkg;
473 if (archname == NULL || *argv)
474 badusage(_("--%s takes exactly one argument"), cipaction->olong);
476 modstatdb_open(msdbrw_readonly);
478 arch = dpkg_arch_find(archname);
479 if (arch->type != DPKG_ARCH_FOREIGN) {
480 warning(_("cannot remove non-foreign architecture '%s'"), arch->name);
481 return 0;
484 /* Check if it's safe to remove the architecture from the db. */
485 iter = pkg_hash_iter_new();
486 while ((pkg = pkg_hash_iter_next_pkg(iter))) {
487 if (pkg->status < PKG_STAT_HALFINSTALLED)
488 continue;
489 if (pkg->installed.arch == arch) {
490 if (in_force(FORCE_ARCHITECTURE))
491 warning(_("removing architecture '%s' currently in use by database"),
492 arch->name);
493 else
494 ohshit(_("cannot remove architecture '%s' currently in use by the database"),
495 arch->name);
496 break;
499 pkg_hash_iter_free(iter);
501 dpkg_arch_unmark(arch);
502 dpkg_arch_save_list();
504 modstatdb_shutdown();
506 return 0;
509 int execbackend(const char *const *argv) DPKG_ATTR_NORET;
510 int commandfd(const char *const *argv);
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 }
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 ),
553 ACTION( "command-fd", 'c', act_commandfd, commandfd ),
555 ACTION( "help", '?', act_help, usage),
556 ACTION( "version", 0, act_version, printversion),
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 }
605 execbackend(const char *const *argv)
607 struct command cmd;
609 command_init(&cmd, cipaction->arg_ptr, NULL);
610 command_add_arg(&cmd, cipaction->arg_ptr);
611 command_add_arg(&cmd, str_fmt("--%s", cipaction->olong));
613 /* Explicitly separate arguments from options as any user-supplied
614 * separator got stripped by the option parser */
615 command_add_arg(&cmd, "--");
616 command_add_argl(&cmd, (const char **)argv);
618 command_exec(&cmd);
622 commandfd(const char *const *argv)
624 struct varbuf linevb = VARBUF_INIT;
625 const char * pipein;
626 const char **newargs = NULL, **endargs;
627 char *ptr, *endptr;
628 FILE *in;
629 long infd;
630 int ret = 0;
631 int c, lno, i;
632 bool skipchar;
634 pipein = *argv++;
635 if (pipein == NULL || *argv)
636 badusage(_("--%s takes exactly one argument"), cipaction->olong);
638 infd = dpkg_options_parse_arg_int(cipaction, pipein);
639 in = fdopen(infd, "r");
640 if (in == NULL)
641 ohshite(_("couldn't open '%i' for stream"), (int)infd);
643 for (;;) {
644 bool mode = false;
645 int argc= 1;
646 lno= 0;
648 push_error_context();
650 do {
651 c = getc(in);
652 if (c == '\n')
653 lno++;
654 } while (c != EOF && c_isspace(c));
655 if (c == EOF) break;
656 if (c == '#') {
657 do { c= getc(in); if (c == '\n') lno++; } while (c != EOF && c != '\n');
658 continue;
660 varbuf_reset(&linevb);
661 do {
662 varbuf_add_char(&linevb, c);
663 c= getc(in);
664 if (c == '\n') lno++;
666 /* This isn't fully accurate, but overestimating can't hurt. */
667 if (c_isspace(c))
668 argc++;
669 } while (c != EOF && c != '\n');
670 if (c == EOF)
671 ohshit(_("unexpected end of file before end of line %d"), lno);
672 if (!argc) continue;
673 varbuf_end_str(&linevb);
674 newargs = m_realloc(newargs, sizeof(const char *) * (argc + 1));
675 argc= 1;
676 ptr= linevb.buf;
677 endptr = ptr + linevb.used + 1;
678 skipchar = false;
679 while(ptr < endptr) {
680 if (skipchar) {
681 skipchar = false;
682 } else if (*ptr == '\\') {
683 memmove(ptr, (ptr+1), (linevb.used-(linevb.buf - ptr)-1));
684 endptr--;
685 skipchar = true;
686 continue;
687 } else if (c_isspace(*ptr)) {
688 if (mode == true) {
689 *ptr = '\0';
690 mode = false;
692 } else {
693 if (mode == false) {
694 newargs[argc]= ptr;
695 argc++;
696 mode = true;
699 ptr++;
701 *ptr = '\0';
702 newargs[argc++] = NULL;
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 for(i=1;i<argc;i++)
709 if (newargs[i])
710 newargs[i] = m_strdup(newargs[i]);
711 endargs = newargs;
713 setaction(NULL, NULL);
714 dpkg_options_parse((const char *const **)&endargs, cmdinfos, printforhelp);
715 if (!cipaction) badusage(_("need an action option"));
717 ret |= cipaction->action(endargs);
719 fsys_hash_reset();
721 pop_error_context(ehflag_normaltidy);
724 fclose(in);
726 return ret;
729 int main(int argc, const char *const *argv) {
730 char *force_string;
731 int ret;
733 dpkg_locales_init(PACKAGE);
734 dpkg_program_init("dpkg");
735 set_force_default(FORCE_ALL);
736 dpkg_options_load(DPKG, cmdinfos);
737 dpkg_options_parse(&argv, cmdinfos, printforhelp);
739 debug(dbg_general, "root=%s admindir=%s", dpkg_fsys_get_dir(), dpkg_db_get_dir());
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 if (!in_force(FORCE_NON_ROOT) && getuid() == 0 && getgid() != 0)
744 if (setgid(0) < 0)
745 ohshite(_("cannot set primary group ID to root"));
747 if (!cipaction) badusage(_("need an action option"));
749 /* Always set environment, to avoid possible security risks. */
750 if (setenv("DPKG_ADMINDIR", dpkg_db_get_dir(), 1) < 0)
751 ohshite(_("unable to setenv for subprocesses"));
752 if (setenv("DPKG_ROOT", dpkg_fsys_get_dir(), 1) < 0)
753 ohshite(_("unable to setenv for subprocesses"));
754 force_string = get_force_string();
755 if (setenv("DPKG_FORCE", force_string, 1) < 0)
756 ohshite(_("unable to setenv for subprocesses"));
757 free(force_string);
759 if (!f_triggers)
760 f_triggers = (cipaction->arg_int == act_triggers && *argv) ? -1 : 1;
762 if (is_invoke_action(cipaction->arg_int)) {
763 run_invoke_hooks(cipaction->olong, &pre_invoke_hooks);
764 run_status_loggers(&status_loggers);
767 ret = cipaction->action(argv);
769 if (is_invoke_action(cipaction->arg_int))
770 run_invoke_hooks(cipaction->olong, &post_invoke_hooks);
772 free_invoke_hooks(&pre_invoke_hooks);
773 free_invoke_hooks(&post_invoke_hooks);
775 dpkg_program_done();
776 dpkg_locales_done();
778 return reportbroken_retexitstatus(ret);