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 : : #ifdef 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 : :
233 [ # # ]: 0 : if (*value == 'h') {
234 : : const struct debuginfo *dip;
235 : :
236 : 0 : printf(_(
237 : : "%s debugging option, --debug=<octal> or -D<octal>:\n"
238 : : "\n"
239 : : " Number Ref. in source Description\n"), DPKG);
240 : :
241 [ # # ]: 0 : for (dip = debuginfos; dip->name; dip++)
242 : 0 : printf(" %6o %-16s %s\n", dip->flag, dip->name, gettext(dip->desc));
243 : :
244 : 0 : printf(_("\n"
245 : : "Debugging options can be mixed using bitwise-or.\n"
246 : : "Note that the meanings and values are subject to change.\n"));
247 : 0 : m_output(stdout, _("<standard output>"));
248 : 0 : exit(0);
249 : : }
250 : :
251 : 0 : mask = debug_parse_mask(value);
252 [ # # ]: 0 : if (mask < 0)
253 : 0 : badusage(_("--%s requires a positive octal argument"), cpi->olong);
254 : 0 : }
255 : :
256 : : static void
257 : 0 : set_no_pager(const struct cmdinfo *ci, const char *value)
258 : : {
259 : 0 : pager_enable(false);
260 : :
261 : : /* Let's communicate this to our backends. */
262 : 0 : setenv("DPKG_PAGER", "cat", 1);
263 : 0 : }
264 : :
265 : : static void
266 : 0 : set_filter(const struct cmdinfo *cip, const char *value)
267 : : {
268 : 0 : filter_add(value, cip->arg_int);
269 : 0 : }
270 : :
271 : : static void
272 : 0 : set_verify_format(const struct cmdinfo *cip, const char *value)
273 : : {
274 [ # # ]: 0 : if (!verify_set_output(value))
275 : 0 : badusage(_("unknown verify output format '%s'"), value);
276 : 0 : }
277 : :
278 : : static void
279 : 0 : set_ignore_depends(const struct cmdinfo *cip, const char *value)
280 : : {
281 : : char *copy, *p;
282 : :
283 : 0 : copy= m_malloc(strlen(value)+2);
284 : 0 : strcpy(copy,value);
285 : 0 : copy[strlen(value) + 1] = '\0';
286 [ # # ]: 0 : for (p=copy; *p; p++) {
287 [ # # ]: 0 : if (*p != ',') continue;
288 : 0 : *p++ = '\0';
289 [ # # # # : 0 : if (!*p || *p==',' || p==copy+1)
# # ]
290 : 0 : badusage(_("null package name in --%s comma-separated list '%.250s'"),
291 : 0 : cip->olong, value);
292 : : }
293 : 0 : p= copy;
294 [ # # ]: 0 : while (*p) {
295 : : struct pkginfo *pkg;
296 : :
297 : 0 : pkg = dpkg_options_parse_pkgname(cip, p);
298 : 0 : pkg_list_prepend(&ignoredependss, pkg);
299 : :
300 : 0 : p+= strlen(p)+1;
301 : : }
302 : :
303 : 0 : free(copy);
304 : 0 : }
305 : :
306 : : static void
307 : 0 : set_integer(const struct cmdinfo *cip, const char *value)
308 : : {
309 : 0 : *cip->iassignto = dpkg_options_parse_arg_int(cip, value);
310 : 0 : }
311 : :
312 : : static void
313 : 0 : set_pipe(const struct cmdinfo *cip, const char *value)
314 : : {
315 : : long v;
316 : :
317 : 0 : v = dpkg_options_parse_arg_int(cip, value);
318 : :
319 : 0 : statusfd_add(v);
320 : 0 : }
321 : :
322 : : static bool
323 : 96 : is_invoke_action(enum action action)
324 : : {
325 [ - + ]: 96 : switch (action) {
326 : 0 : case act_unpack:
327 : : case act_configure:
328 : : case act_install:
329 : : case act_triggers:
330 : : case act_remove:
331 : : case act_purge:
332 : : case act_arch_add:
333 : : case act_arch_remove:
334 : 0 : return true;
335 : 96 : default:
336 : 96 : return false;
337 : : }
338 : : }
339 : :
340 : : static bool
341 : 96 : can_invoke_hooks(enum action action)
342 : : {
343 [ + - ]: 96 : if (!is_invoke_action(action))
344 : 96 : return false;
345 : :
346 [ # # ]: 0 : if (f_noact)
347 : 0 : return false;
348 : :
349 [ # # ]: 0 : if (in_force(FORCE_NON_ROOT))
350 : 0 : return true;
351 : :
352 [ # # # # ]: 0 : if (getuid() || geteuid())
353 : 0 : return false;
354 : :
355 : 0 : return true;
356 : : }
357 : :
358 : : static struct invoke_list pre_invoke_hooks = {
359 : : .head = NULL,
360 : : .tail = &pre_invoke_hooks.head,
361 : : };
362 : : static struct invoke_list post_invoke_hooks = {
363 : : .head = NULL,
364 : : .tail = &post_invoke_hooks.head,
365 : : };
366 : : static struct invoke_list status_loggers = {
367 : : .head = NULL,
368 : : .tail = &status_loggers.head,
369 : : };
370 : :
371 : : static void
372 : 0 : set_invoke_hook(const struct cmdinfo *cip, const char *value)
373 : : {
374 : 0 : struct invoke_list *hook_list = cip->arg_ptr;
375 : : struct invoke_hook *hook_new;
376 : :
377 : 0 : hook_new = m_malloc(sizeof(*hook_new));
378 : 0 : hook_new->command = m_strdup(value);
379 : 0 : hook_new->next = NULL;
380 : :
381 : : /* Add the new hook at the tail of the list to preserve the order. */
382 : 0 : *hook_list->tail = hook_new;
383 : 0 : hook_list->tail = &hook_new->next;
384 : 0 : }
385 : :
386 : : static void
387 : 0 : run_invoke_hooks(const char *action, struct invoke_list *hook_list)
388 : : {
389 : : struct invoke_hook *hook;
390 : :
391 : 0 : setenv("DPKG_HOOK_ACTION", action, 1);
392 : :
393 [ # # ]: 0 : for (hook = hook_list->head; hook; hook = hook->next) {
394 : : int status;
395 : :
396 : : /* XXX: As an optimization, use exec instead if no shell metachar are
397 : : * used “!$=&|\\`'"^~;<>{}[]()?*#”. */
398 : 0 : status = system(hook->command);
399 [ # # ]: 0 : if (status != 0)
400 : 0 : ohshit(_("error executing hook '%s', exit code %d"), hook->command,
401 : : status);
402 : : }
403 : :
404 : 0 : unsetenv("DPKG_HOOK_ACTION");
405 : 0 : }
406 : :
407 : : static void
408 : 96 : free_invoke_hooks(struct invoke_list *hook_list)
409 : : {
410 : : struct invoke_hook *hook, *hook_next;
411 : :
412 [ - + ]: 96 : for (hook = hook_list->head; hook; hook = hook_next) {
413 : 0 : hook_next = hook->next;
414 : 0 : free(hook->command);
415 : 0 : free(hook);
416 : : }
417 : 96 : }
418 : :
419 : : static int
420 : 0 : run_logger(struct invoke_hook *hook, const char *name)
421 : : {
422 : : pid_t pid;
423 : : int p[2];
424 : :
425 : 0 : m_pipe(p);
426 : :
427 : 0 : pid = subproc_fork();
428 [ # # ]: 0 : if (pid == 0) {
429 : : /* Setup stdin and stdout. */
430 : 0 : m_dup2(p[0], 0);
431 : 0 : close(1);
432 : :
433 : 0 : close(p[0]);
434 : 0 : close(p[1]);
435 : :
436 : 0 : command_shell(hook->command, name);
437 : : }
438 : 0 : close(p[0]);
439 : :
440 : 0 : return p[1];
441 : : }
442 : :
443 : : static void
444 : 0 : run_status_loggers(struct invoke_list *hook_list)
445 : : {
446 : : struct invoke_hook *hook;
447 : :
448 [ # # ]: 0 : for (hook = hook_list->head; hook; hook = hook->next) {
449 : : int fd;
450 : :
451 : 0 : fd = run_logger(hook, _("status logger"));
452 : 0 : statusfd_add(fd);
453 : : }
454 : 0 : }
455 : :
456 : : static int
457 : 0 : arch_add(const char *const *argv)
458 : : {
459 : : struct dpkg_arch *arch;
460 : 0 : const char *archname = *argv++;
461 : :
462 [ # # # # ]: 0 : if (archname == NULL || *argv)
463 : 0 : badusage(_("--%s takes exactly one argument"), cipaction->olong);
464 : :
465 : 0 : dpkg_arch_load_list();
466 : :
467 : 0 : arch = dpkg_arch_add(archname);
468 [ # # # ]: 0 : switch (arch->type) {
469 : 0 : case DPKG_ARCH_NATIVE:
470 : : case DPKG_ARCH_FOREIGN:
471 : 0 : break;
472 : 0 : case DPKG_ARCH_ILLEGAL:
473 : 0 : ohshit(_("architecture '%s' is illegal: %s"), archname,
474 : : dpkg_arch_name_is_illegal(archname));
475 : 0 : default:
476 : 0 : ohshit(_("architecture '%s' is reserved and cannot be added"), archname);
477 : : }
478 : :
479 : 0 : dpkg_arch_save_list();
480 : :
481 : 0 : return 0;
482 : : }
483 : :
484 : : static int
485 : 0 : arch_remove(const char *const *argv)
486 : : {
487 : 0 : const char *archname = *argv++;
488 : : struct dpkg_arch *arch;
489 : : struct pkg_hash_iter *iter;
490 : : struct pkginfo *pkg;
491 : :
492 [ # # # # ]: 0 : if (archname == NULL || *argv)
493 : 0 : badusage(_("--%s takes exactly one argument"), cipaction->olong);
494 : :
495 : 0 : modstatdb_open(msdbrw_readonly);
496 : :
497 : 0 : arch = dpkg_arch_find(archname);
498 [ # # ]: 0 : if (arch->type != DPKG_ARCH_FOREIGN) {
499 : 0 : warning(_("cannot remove non-foreign architecture '%s'"), arch->name);
500 : 0 : return 0;
501 : : }
502 : :
503 : : /* Check if it's safe to remove the architecture from the db. */
504 : 0 : iter = pkg_hash_iter_new();
505 [ # # ]: 0 : while ((pkg = pkg_hash_iter_next_pkg(iter))) {
506 [ # # ]: 0 : if (pkg->status < PKG_STAT_HALFINSTALLED)
507 : 0 : continue;
508 [ # # ]: 0 : if (pkg->installed.arch == arch) {
509 [ # # ]: 0 : if (in_force(FORCE_ARCHITECTURE))
510 : 0 : warning(_("removing architecture '%s' currently in use by database"),
511 : : arch->name);
512 : : else
513 : 0 : ohshit(_("cannot remove architecture '%s' currently in use by the database"),
514 : : arch->name);
515 : 0 : break;
516 : : }
517 : : }
518 : 0 : pkg_hash_iter_free(iter);
519 : :
520 : 0 : dpkg_arch_unmark(arch);
521 : 0 : dpkg_arch_save_list();
522 : :
523 : 0 : modstatdb_shutdown();
524 : :
525 : 0 : return 0;
526 : : }
527 : :
528 : : int execbackend(const char *const *argv) DPKG_ATTR_NORET;
529 : : int commandfd(const char *const *argv);
530 : :
531 : : /* This table has both the action entries in it and the normal options.
532 : : * The action entries are made with the ACTION macro, as they all
533 : : * have a very similar structure. */
534 : : static const struct cmdinfo cmdinfos[]= {
535 : : #define ACTIONBACKEND(longopt, shortopt, backend) \
536 : : { longopt, shortopt, 0, NULL, NULL, setaction, 0, (void *)backend, execbackend }
537 : :
538 : : ACTION( "install", 'i', act_install, archivefiles ),
539 : : ACTION( "unpack", 0, act_unpack, archivefiles ),
540 : : ACTION( "record-avail", 'A', act_avail, archivefiles ),
541 : : ACTION( "configure", 0, act_configure, packages ),
542 : : ACTION( "remove", 'r', act_remove, packages ),
543 : : ACTION( "purge", 'P', act_purge, packages ),
544 : : ACTION( "triggers-only", 0, act_triggers, packages ),
545 : : ACTION( "verify", 'V', act_verify, verify ),
546 : : ACTIONBACKEND( "listfiles", 'L', DPKGQUERY),
547 : : ACTIONBACKEND( "status", 's', DPKGQUERY),
548 : : ACTION( "get-selections", 0, act_getselections, getselections ),
549 : : ACTION( "set-selections", 0, act_setselections, setselections ),
550 : : ACTION( "clear-selections", 0, act_clearselections, clearselections ),
551 : : ACTIONBACKEND( "print-avail", 'p', DPKGQUERY),
552 : : ACTION( "update-avail", 0, act_avreplace, updateavailable ),
553 : : ACTION( "merge-avail", 0, act_avmerge, updateavailable ),
554 : : ACTION( "clear-avail", 0, act_avclear, updateavailable ),
555 : : ACTION( "forget-old-unavail", 0, act_forgetold, forgetold ),
556 : : ACTION( "audit", 'C', act_audit, audit ),
557 : : ACTION( "yet-to-unpack", 0, act_unpackchk, unpackchk ),
558 : : ACTIONBACKEND( "list", 'l', DPKGQUERY),
559 : : ACTIONBACKEND( "search", 'S', DPKGQUERY),
560 : : ACTION_MUX( "assert", 0, act_assert_feature, assert_feature, &assert_feature_name),
561 : : ACTION( "add-architecture", 0, act_arch_add, arch_add ),
562 : : ACTION( "remove-architecture", 0, act_arch_remove, arch_remove ),
563 : : ACTION( "print-architecture", 0, act_printarch, printarch ),
564 : : ACTION( "print-foreign-architectures", 0, act_printforeignarches, print_foreign_arches ),
565 : : ACTION( "predep-package", 0, act_predeppackage, predeppackage ),
566 : : ACTION( "validate-pkgname", 0, act_validate_pkgname, validate_pkgname ),
567 : : ACTION( "validate-trigname", 0, act_validate_trigname, validate_trigname ),
568 : : ACTION( "validate-archname", 0, act_validate_archname, validate_archname ),
569 : : ACTION( "validate-version", 0, act_validate_version, validate_version ),
570 : : ACTION( "compare-versions", 0, act_cmpversions, cmpversions ),
571 : : /*
572 : : ACTION( "command-fd", 'c', act_commandfd, commandfd ),
573 : : */
574 : : ACTION( "help", '?', act_help, usage),
575 : : ACTION( "version", 0, act_version, printversion),
576 : :
577 : : { "pre-invoke", 0, 1, NULL, NULL, set_invoke_hook, 0, &pre_invoke_hooks },
578 : : { "post-invoke", 0, 1, NULL, NULL, set_invoke_hook, 0, &post_invoke_hooks },
579 : : { "path-exclude", 0, 1, NULL, NULL, set_filter, 0 },
580 : : { "path-include", 0, 1, NULL, NULL, set_filter, 1 },
581 : : { "verify-format", 0, 1, NULL, NULL, set_verify_format },
582 : : { "status-logger", 0, 1, NULL, NULL, set_invoke_hook, 0, &status_loggers },
583 : : { "status-fd", 0, 1, NULL, NULL, set_pipe, 0 },
584 : : { "log", 0, 1, NULL, &log_file, NULL, 0 },
585 : : { "pending", 'a', 0, &f_pending, NULL, NULL, 1 },
586 : : { "recursive", 'R', 0, &f_recursive, NULL, NULL, 1 },
587 : : { "no-act", 0, 0, &f_noact, NULL, NULL, 1 },
588 : : { "dry-run", 0, 0, &f_noact, NULL, NULL, 1 },
589 : : { "simulate", 0, 0, &f_noact, NULL, NULL, 1 },
590 : : { "no-pager", 0, 0, NULL, NULL, set_no_pager, 0 },
591 : : { "no-debsig", 0, 0, &f_nodebsig, NULL, NULL, 1 },
592 : : /* Alias ('G') for --refuse. */
593 : : { NULL, 'G', 0, NULL, NULL, reset_force_option, FORCE_DOWNGRADE },
594 : : { "selected-only", 'O', 0, &f_alsoselect, NULL, NULL, 0 },
595 : : { "triggers", 0, 0, &f_triggers, NULL, NULL, 1 },
596 : : { "no-triggers", 0, 0, &f_triggers, NULL, NULL, -1 },
597 : : /* TODO: Remove ('N') sometime. */
598 : : { "no-also-select", 'N', 0, &f_alsoselect, NULL, NULL, 0 },
599 : : { "skip-same-version", 'E', 0, &f_skipsame, NULL, NULL, 1 },
600 : : { "auto-deconfigure", 'B', 0, &f_autodeconf, NULL, NULL, 1 },
601 : : { "robot", 0, 0, &f_robot, NULL, NULL, 1 },
602 : : { "root", 0, 1, NULL, NULL, set_root, 0 },
603 : : { "abort-after", 0, 1, &errabort, NULL, set_integer, 0 },
604 : : { "admindir", 0, 1, NULL, NULL, set_admindir, 0 },
605 : : { "instdir", 0, 1, NULL, NULL, set_instdir, 0 },
606 : : { "ignore-depends", 0, 1, NULL, NULL, set_ignore_depends, 0 },
607 : : { "force", 0, 2, NULL, NULL, set_force_option, 1 },
608 : : { "refuse", 0, 2, NULL, NULL, set_force_option, 0 },
609 : : { "no-force", 0, 2, NULL, NULL, set_force_option, 0 },
610 : : { "debug", 'D', 1, NULL, NULL, set_debug, 0 },
611 : : ACTIONBACKEND( "build", 'b', BACKEND),
612 : : ACTIONBACKEND( "contents", 'c', BACKEND),
613 : : ACTIONBACKEND( "control", 'e', BACKEND),
614 : : ACTIONBACKEND( "info", 'I', BACKEND),
615 : : ACTIONBACKEND( "field", 'f', BACKEND),
616 : : ACTIONBACKEND( "extract", 'x', BACKEND),
617 : : ACTIONBACKEND( "vextract", 'X', BACKEND),
618 : : ACTIONBACKEND( "ctrl-tarfile", 0, BACKEND),
619 : : ACTIONBACKEND( "fsys-tarfile", 0, BACKEND),
620 : : { NULL, 0, 0, NULL, NULL, NULL, 0 }
621 : : };
622 : :
623 : : int
624 : 0 : execbackend(const char *const *argv)
625 : : {
626 : : struct command cmd;
627 : :
628 : 0 : command_init(&cmd, cipaction->arg_ptr, NULL);
629 : 0 : command_add_arg(&cmd, cipaction->arg_ptr);
630 : 0 : command_add_arg(&cmd, str_fmt("--%s", cipaction->olong));
631 : :
632 : : /* Explicitly separate arguments from options as any user-supplied
633 : : * separator got stripped by the option parser */
634 : 0 : command_add_arg(&cmd, "--");
635 : 0 : command_add_argl(&cmd, (const char **)argv);
636 : :
637 : 0 : command_exec(&cmd);
638 : : }
639 : :
640 : : int
641 : 0 : commandfd(const char *const *argv)
642 : : {
643 : 0 : struct varbuf linevb = VARBUF_INIT;
644 : : const char * pipein;
645 : 0 : const char **newargs = NULL, **endargs;
646 : : char *ptr, *endptr;
647 : : FILE *in;
648 : : long infd;
649 : 0 : int ret = 0;
650 : : int c, lno, i;
651 : : bool skipchar;
652 : :
653 : 0 : pipein = *argv++;
654 [ # # # # ]: 0 : if (pipein == NULL || *argv)
655 : 0 : badusage(_("--%s takes exactly one argument"), cipaction->olong);
656 : :
657 : 0 : infd = dpkg_options_parse_arg_int(cipaction, pipein);
658 : 0 : in = fdopen(infd, "r");
659 [ # # ]: 0 : if (in == NULL)
660 : 0 : ohshite(_("couldn't open '%i' for stream"), (int)infd);
661 : :
662 : 0 : lno = 0;
663 : :
664 : 0 : for (;;) {
665 : 0 : bool mode = false;
666 : 0 : int argc= 1;
667 : :
668 : 0 : push_error_context();
669 : :
670 : : do {
671 : 0 : c = getc(in);
672 [ # # ]: 0 : if (c == '\n')
673 : 0 : lno++;
674 [ # # # # ]: 0 : } while (c != EOF && c_isspace(c));
675 [ # # ]: 0 : if (c == EOF) break;
676 [ # # ]: 0 : if (c == '#') {
677 [ # # # # : 0 : do { c= getc(in); if (c == '\n') lno++; } while (c != EOF && c != '\n');
# # ]
678 : 0 : continue;
679 : : }
680 : 0 : varbuf_reset(&linevb);
681 : : do {
682 : 0 : varbuf_add_char(&linevb, c);
683 : 0 : c= getc(in);
684 [ # # ]: 0 : if (c == '\n') lno++;
685 : :
686 : : /* This isn't fully accurate, but overestimating can't hurt. */
687 [ # # ]: 0 : if (c_isspace(c))
688 : 0 : argc++;
689 [ # # # # ]: 0 : } while (c != EOF && c != '\n');
690 [ # # ]: 0 : if (c == EOF)
691 : 0 : ohshit(_("unexpected end of file before end of line %d"), lno);
692 [ # # ]: 0 : if (!argc) continue;
693 : 0 : newargs = m_realloc(newargs, sizeof(const char *) * (argc + 1));
694 : 0 : argc= 1;
695 : 0 : ptr= linevb.buf;
696 : 0 : endptr = ptr + linevb.used + 1;
697 : 0 : skipchar = false;
698 [ # # ]: 0 : while(ptr < endptr) {
699 [ # # ]: 0 : if (skipchar) {
700 : 0 : skipchar = false;
701 [ # # ]: 0 : } else if (*ptr == '\\') {
702 : 0 : memmove(ptr, (ptr+1), (linevb.used-(linevb.buf - ptr)-1));
703 : 0 : endptr--;
704 : 0 : skipchar = true;
705 : 0 : continue;
706 [ # # ]: 0 : } else if (c_isspace(*ptr)) {
707 [ # # ]: 0 : if (mode == true) {
708 : 0 : *ptr = '\0';
709 : 0 : mode = false;
710 : : }
711 : : } else {
712 [ # # ]: 0 : if (mode == false) {
713 : 0 : newargs[argc]= ptr;
714 : 0 : argc++;
715 : 0 : mode = true;
716 : : }
717 : : }
718 : 0 : ptr++;
719 : : }
720 : 0 : *ptr = '\0';
721 : 0 : newargs[argc++] = NULL;
722 : :
723 : : /* We strdup() each argument, but never free it, because the
724 : : * error messages contain references back to these strings.
725 : : * Freeing them, and reusing the memory, would make those
726 : : * error messages confusing, to say the least. */
727 [ # # ]: 0 : for(i=1;i<argc;i++)
728 [ # # ]: 0 : if (newargs[i])
729 : 0 : newargs[i] = m_strdup(newargs[i]);
730 : 0 : endargs = newargs;
731 : :
732 : 0 : setaction(NULL, NULL);
733 : 0 : dpkg_options_parse((const char *const **)&endargs, cmdinfos, printforhelp);
734 [ # # ]: 0 : if (!cipaction) badusage(_("need an action option"));
735 : :
736 : 0 : ret |= cipaction->action(endargs);
737 : :
738 : 0 : fsys_hash_reset();
739 : :
740 : 0 : pop_error_context(ehflag_normaltidy);
741 : : }
742 : :
743 : 0 : fclose(in);
744 : :
745 : 0 : return ret;
746 : : }
747 : :
748 : 48 : int main(int argc, const char *const *argv) {
749 : : char *force_string;
750 : : int ret;
751 : :
752 : 48 : dpkg_locales_init(PACKAGE);
753 : 48 : dpkg_program_init("dpkg");
754 : 48 : set_force_default(FORCE_ALL);
755 : 48 : dpkg_options_load(DPKG, cmdinfos);
756 : 48 : dpkg_options_parse(&argv, cmdinfos, printforhelp);
757 : :
758 : 48 : debug(dbg_general, "root=%s admindir=%s", dpkg_fsys_get_dir(), dpkg_db_get_dir());
759 : :
760 : : /* When running as root, make sure our primary group is also root, so
761 : : * that files created by maintainer scripts have correct ownership. */
762 [ + - - + : 48 : if (!in_force(FORCE_NON_ROOT) && getuid() == 0 && getgid() != 0)
- - ]
763 [ # # ]: 0 : if (setgid(0) < 0)
764 : 0 : ohshite(_("cannot set primary group ID to root"));
765 : :
766 [ - + ]: 48 : if (!cipaction) badusage(_("need an action option"));
767 : :
768 : : /* Always set environment, to avoid possible security risks. */
769 [ - + ]: 48 : if (setenv("DPKG_ADMINDIR", dpkg_db_get_dir(), 1) < 0)
770 : 0 : ohshite(_("unable to setenv for subprocesses"));
771 [ - + ]: 48 : if (setenv("DPKG_ROOT", dpkg_fsys_get_dir(), 1) < 0)
772 : 0 : ohshite(_("unable to setenv for subprocesses"));
773 : 48 : force_string = get_force_string();
774 [ - + ]: 48 : if (setenv("DPKG_FORCE", force_string, 1) < 0)
775 : 0 : ohshite(_("unable to setenv for subprocesses"));
776 : 48 : free(force_string);
777 : :
778 [ + - ]: 48 : if (!f_triggers)
779 [ - + - - ]: 48 : f_triggers = (cipaction->arg_int == act_triggers && *argv) ? -1 : 1;
780 : :
781 [ - + ]: 48 : if (can_invoke_hooks(cipaction->arg_int)) {
782 : 0 : run_invoke_hooks(cipaction->olong, &pre_invoke_hooks);
783 : 0 : run_status_loggers(&status_loggers);
784 : : }
785 : :
786 : 48 : ret = cipaction->action(argv);
787 : :
788 [ - + ]: 48 : if (can_invoke_hooks(cipaction->arg_int))
789 : 0 : run_invoke_hooks(cipaction->olong, &post_invoke_hooks);
790 : :
791 : 48 : free_invoke_hooks(&pre_invoke_hooks);
792 : 48 : free_invoke_hooks(&post_invoke_hooks);
793 : :
794 : 48 : dpkg_program_done();
795 : 48 : dpkg_locales_done();
796 : :
797 : 48 : return reportbroken_retexitstatus(ret);
798 : : }
|