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 : : }
|