Commit | Line | Data |
---|---|---|
1479465f GJ |
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/path.h> | |
50 | #include <dpkg/subproc.h> | |
51 | #include <dpkg/command.h> | |
52 | #include <dpkg/options.h> | |
53 | ||
54 | #include "main.h" | |
55 | #include "filesdb.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 | int fc_downgrade=1, fc_configureany=0, fc_hold=0, fc_removereinstreq=0, fc_overwrite=0; | |
196 | int fc_removeessential=0, fc_conflicts=0, fc_depends=0, fc_dependsversion=0; | |
197 | int fc_breaks=0, fc_badpath=0, fc_overwritediverted=0, fc_architecture=0; | |
198 | int fc_nonroot=0, fc_overwritedir=0, fc_conff_new=0, fc_conff_miss=0; | |
199 | int fc_conff_old=0, fc_conff_def=0; | |
200 | int fc_conff_ask = 0; | |
201 | int fc_unsafe_io = 0; | |
202 | int fc_badverify = 0; | |
203 | int fc_badversion = 0; | |
204 | int fc_script_chrootless = 0; | |
205 | ||
206 | int errabort = 50; | |
207 | static const char *admindir = ADMINDIR; | |
208 | const char *instdir= ""; | |
209 | struct pkg_list *ignoredependss = NULL; | |
210 | ||
211 | static const char * | |
212 | forcetype_str(char type) | |
213 | { | |
214 | switch (type) { | |
215 | case '\0': | |
216 | case ' ': | |
217 | return " "; | |
218 | case '*': | |
219 | return "[*]"; | |
220 | case '!': | |
221 | return "[!]"; | |
222 | default: | |
223 | internerr("unknown force type '%c'", type); | |
224 | } | |
225 | } | |
226 | ||
227 | static const struct forceinfo { | |
228 | const char *name; | |
229 | int *opt; | |
230 | char type; | |
231 | const char *desc; | |
232 | } forceinfos[]= { | |
233 | { "all", NULL, | |
234 | '!', N_("Set all force options")}, | |
235 | { "downgrade", &fc_downgrade, | |
236 | '*', N_("Replace a package with a lower version") }, | |
237 | { "configure-any", &fc_configureany, | |
238 | ' ', N_("Configure any package which may help this one") }, | |
239 | { "hold", &fc_hold, | |
240 | ' ', N_("Process incidental packages even when on hold") }, | |
241 | { "not-root", &fc_nonroot, | |
242 | ' ', N_("Try to (de)install things even when not root") }, | |
243 | { "bad-path", &fc_badpath, | |
244 | ' ', N_("PATH is missing important programs, problems likely") }, | |
245 | { "bad-verify", &fc_badverify, | |
246 | ' ', N_("Install a package even if it fails authenticity check") }, | |
247 | { "bad-version", &fc_badversion, | |
248 | ' ', N_("Process even packages with wrong versions") }, | |
249 | { "overwrite", &fc_overwrite, | |
250 | ' ', N_("Overwrite a file from one package with another") }, | |
251 | { "overwrite-diverted", &fc_overwritediverted, | |
252 | ' ', N_("Overwrite a diverted file with an undiverted version") }, | |
253 | { "overwrite-dir", &fc_overwritedir, | |
254 | '!', N_("Overwrite one package's directory with another's file") }, | |
255 | { "unsafe-io", &fc_unsafe_io, | |
256 | '!', N_("Do not perform safe I/O operations when unpacking") }, | |
257 | { "script-chrootless", &fc_script_chrootless, | |
258 | '!', N_("Do not chroot into maintainer script environment") }, | |
259 | { "confnew", &fc_conff_new, | |
260 | '!', N_("Always use the new config files, don't prompt") }, | |
261 | { "confold", &fc_conff_old, | |
262 | '!', N_("Always use the old config files, don't prompt") }, | |
263 | { "confdef", &fc_conff_def, | |
264 | '!', N_("Use the default option for new config files if one\n" | |
265 | "is available, don't prompt. If no default can be found,\n" | |
266 | "you will be prompted unless one of the confold or\n" | |
267 | "confnew options is also given") }, | |
268 | { "confmiss", &fc_conff_miss, | |
269 | '!', N_("Always install missing config files") }, | |
270 | { "confask", &fc_conff_ask, | |
271 | '!', N_("Offer to replace config files with no new versions") }, | |
272 | { "architecture", &fc_architecture, | |
273 | '!', N_("Process even packages with wrong or no architecture") }, | |
274 | { "breaks", &fc_breaks, | |
275 | '!', N_("Install even if it would break another package") }, | |
276 | { "conflicts", &fc_conflicts, | |
277 | '!', N_("Allow installation of conflicting packages") }, | |
278 | { "depends", &fc_depends, | |
279 | '!', N_("Turn all dependency problems into warnings") }, | |
280 | { "depends-version", &fc_dependsversion, | |
281 | '!', N_("Turn dependency version problems into warnings") }, | |
282 | { "remove-reinstreq", &fc_removereinstreq, | |
283 | '!', N_("Remove packages which require installation") }, | |
284 | { "remove-essential", &fc_removeessential, | |
285 | '!', N_("Remove an essential package") }, | |
286 | { NULL } | |
287 | }; | |
288 | ||
289 | #define DBG_DEF(n, d) \ | |
290 | { .flag = dbg_##n, .name = #n, .desc = d } | |
291 | ||
292 | static const struct debuginfo { | |
293 | int flag; | |
294 | const char *name; | |
295 | const char *desc; | |
296 | } debuginfos[] = { | |
297 | DBG_DEF(general, N_("Generally helpful progress information")), | |
298 | DBG_DEF(scripts, N_("Invocation and status of maintainer scripts")), | |
299 | DBG_DEF(eachfile, N_("Output for each file processed")), | |
300 | DBG_DEF(eachfiledetail, N_("Lots of output for each file processed")), | |
301 | DBG_DEF(conff, N_("Output for each configuration file")), | |
302 | DBG_DEF(conffdetail, N_("Lots of output for each configuration file")), | |
303 | DBG_DEF(depcon, N_("Dependencies and conflicts")), | |
304 | DBG_DEF(depcondetail, N_("Lots of dependencies/conflicts output")), | |
305 | DBG_DEF(triggers, N_("Trigger activation and processing")), | |
306 | DBG_DEF(triggersdetail, N_("Lots of output regarding triggers")), | |
307 | DBG_DEF(triggersstupid, N_("Silly amounts of output regarding triggers")), | |
308 | DBG_DEF(veryverbose, N_("Lots of drivel about eg the dpkg/info directory")), | |
309 | DBG_DEF(stupidlyverbose, N_("Insane amounts of drivel")), | |
310 | { 0, NULL, NULL } | |
311 | }; | |
312 | ||
313 | static void | |
314 | set_debug(const struct cmdinfo *cpi, const char *value) | |
315 | { | |
316 | char *endp; | |
317 | long mask; | |
318 | const struct debuginfo *dip; | |
319 | ||
320 | if (*value == 'h') { | |
321 | printf(_( | |
322 | "%s debugging option, --debug=<octal> or -D<octal>:\n" | |
323 | "\n" | |
324 | " Number Ref. in source Description\n"), DPKG); | |
325 | ||
326 | for (dip = debuginfos; dip->name; dip++) | |
327 | printf(" %6o %-16s %s\n", dip->flag, dip->name, gettext(dip->desc)); | |
328 | ||
329 | printf(_("\n" | |
330 | "Debugging options can be mixed using bitwise-or.\n" | |
331 | "Note that the meanings and values are subject to change.\n")); | |
332 | m_output(stdout, _("<standard output>")); | |
333 | exit(0); | |
334 | } | |
335 | ||
336 | errno = 0; | |
337 | mask = strtol(value, &endp, 8); | |
338 | if (value == endp || *endp || mask < 0 || errno == ERANGE) | |
339 | badusage(_("--%s requires a positive octal argument"), cpi->olong); | |
340 | ||
341 | debug_set_mask(mask); | |
342 | } | |
343 | ||
344 | static void | |
345 | set_filter(const struct cmdinfo *cip, const char *value) | |
346 | { | |
347 | filter_add(value, cip->arg_int); | |
348 | } | |
349 | ||
350 | static void | |
351 | set_verify_format(const struct cmdinfo *cip, const char *value) | |
352 | { | |
353 | if (!verify_set_output(value)) | |
354 | badusage(_("unknown verify output format '%s'"), value); | |
355 | } | |
356 | ||
357 | static void | |
358 | set_instdir(const struct cmdinfo *cip, const char *value) | |
359 | { | |
360 | char *new_instdir; | |
361 | ||
362 | new_instdir = m_strdup(value); | |
363 | path_trim_slash_slashdot(new_instdir); | |
364 | ||
365 | instdir = new_instdir; | |
366 | } | |
367 | ||
368 | static void | |
369 | set_root(const struct cmdinfo *cip, const char *value) | |
370 | { | |
371 | set_instdir(cip, value); | |
372 | admindir = str_fmt("%s%s", instdir, ADMINDIR); | |
373 | } | |
374 | ||
375 | static void | |
376 | set_ignore_depends(const struct cmdinfo *cip, const char *value) | |
377 | { | |
378 | char *copy, *p; | |
379 | ||
380 | copy= m_malloc(strlen(value)+2); | |
381 | strcpy(copy,value); | |
382 | copy[strlen(value) + 1] = '\0'; | |
383 | for (p=copy; *p; p++) { | |
384 | if (*p != ',') continue; | |
385 | *p++ = '\0'; | |
386 | if (!*p || *p==',' || p==copy+1) | |
387 | badusage(_("null package name in --%s comma-separated list '%.250s'"), | |
388 | cip->olong, value); | |
389 | } | |
390 | p= copy; | |
391 | while (*p) { | |
392 | struct pkginfo *pkg; | |
393 | ||
394 | pkg = dpkg_options_parse_pkgname(cip, p); | |
395 | pkg_list_prepend(&ignoredependss, pkg); | |
396 | ||
397 | p+= strlen(p)+1; | |
398 | } | |
399 | ||
400 | free(copy); | |
401 | } | |
402 | ||
403 | static void | |
404 | set_integer(const struct cmdinfo *cip, const char *value) | |
405 | { | |
406 | *cip->iassignto = dpkg_options_parse_arg_int(cip, value); | |
407 | } | |
408 | ||
409 | static void | |
410 | set_pipe(const struct cmdinfo *cip, const char *value) | |
411 | { | |
412 | long v; | |
413 | ||
414 | v = dpkg_options_parse_arg_int(cip, value); | |
415 | ||
416 | statusfd_add(v); | |
417 | } | |
418 | ||
419 | static bool | |
420 | is_invoke_action(enum action action) | |
421 | { | |
422 | switch (action) { | |
423 | case act_unpack: | |
424 | case act_configure: | |
425 | case act_install: | |
426 | case act_triggers: | |
427 | case act_remove: | |
428 | case act_purge: | |
429 | case act_arch_add: | |
430 | case act_arch_remove: | |
431 | return true; | |
432 | default: | |
433 | return false; | |
434 | } | |
435 | } | |
436 | ||
437 | struct invoke_list pre_invoke_hooks = { .head = NULL, .tail = &pre_invoke_hooks.head }; | |
438 | struct invoke_list post_invoke_hooks = { .head = NULL, .tail = &post_invoke_hooks.head }; | |
439 | struct invoke_list status_loggers = { .head = NULL, .tail = &status_loggers.head }; | |
440 | ||
441 | static void | |
442 | set_invoke_hook(const struct cmdinfo *cip, const char *value) | |
443 | { | |
444 | struct invoke_list *hook_list = cip->arg_ptr; | |
445 | struct invoke_hook *hook_new; | |
446 | ||
447 | hook_new = m_malloc(sizeof(struct invoke_hook)); | |
448 | hook_new->command = m_strdup(value); | |
449 | hook_new->next = NULL; | |
450 | ||
451 | /* Add the new hook at the tail of the list to preserve the order. */ | |
452 | *hook_list->tail = hook_new; | |
453 | hook_list->tail = &hook_new->next; | |
454 | } | |
455 | ||
456 | static void | |
457 | run_invoke_hooks(const char *action, struct invoke_list *hook_list) | |
458 | { | |
459 | struct invoke_hook *hook; | |
460 | ||
461 | setenv("DPKG_HOOK_ACTION", action, 1); | |
462 | ||
463 | for (hook = hook_list->head; hook; hook = hook->next) { | |
464 | int status; | |
465 | ||
466 | /* XXX: As an optimization, use exec instead if no shell metachar are | |
467 | * used “!$=&|\\`'"^~;<>{}[]()?*#”. */ | |
468 | status = system(hook->command); | |
469 | if (status != 0) | |
470 | ohshit(_("error executing hook '%s', exit code %d"), hook->command, | |
471 | status); | |
472 | } | |
473 | ||
474 | unsetenv("DPKG_HOOK_ACTION"); | |
475 | } | |
476 | ||
477 | static void | |
478 | free_invoke_hooks(struct invoke_list *hook_list) | |
479 | { | |
480 | struct invoke_hook *hook, *hook_next; | |
481 | ||
482 | for (hook = hook_list->head; hook; hook = hook_next) { | |
483 | hook_next = hook->next; | |
484 | free(hook->command); | |
485 | free(hook); | |
486 | } | |
487 | } | |
488 | ||
489 | static int | |
490 | run_logger(struct invoke_hook *hook, const char *name) | |
491 | { | |
492 | pid_t pid; | |
493 | int p[2]; | |
494 | ||
495 | m_pipe(p); | |
496 | ||
497 | pid = subproc_fork(); | |
498 | if (pid == 0) { | |
499 | /* Setup stdin and stdout. */ | |
500 | m_dup2(p[0], 0); | |
501 | close(1); | |
502 | ||
503 | close(p[0]); | |
504 | close(p[1]); | |
505 | ||
506 | command_shell(hook->command, name); | |
507 | } | |
508 | close(p[0]); | |
509 | ||
510 | return p[1]; | |
511 | } | |
512 | ||
513 | static void | |
514 | run_status_loggers(struct invoke_list *hook_list) | |
515 | { | |
516 | struct invoke_hook *hook; | |
517 | ||
518 | for (hook = hook_list->head; hook; hook = hook->next) { | |
519 | int fd; | |
520 | ||
521 | fd = run_logger(hook, _("status logger")); | |
522 | statusfd_add(fd); | |
523 | } | |
524 | } | |
525 | ||
526 | static int | |
527 | arch_add(const char *const *argv) | |
528 | { | |
529 | struct dpkg_arch *arch; | |
530 | const char *archname = *argv++; | |
531 | ||
532 | if (archname == NULL || *argv) | |
533 | badusage(_("--%s takes exactly one argument"), cipaction->olong); | |
534 | ||
535 | dpkg_arch_load_list(); | |
536 | ||
537 | arch = dpkg_arch_add(archname); | |
538 | switch (arch->type) { | |
539 | case DPKG_ARCH_NATIVE: | |
540 | case DPKG_ARCH_FOREIGN: | |
541 | break; | |
542 | case DPKG_ARCH_ILLEGAL: | |
543 | ohshit(_("architecture '%s' is illegal: %s"), archname, | |
544 | dpkg_arch_name_is_illegal(archname)); | |
545 | default: | |
546 | ohshit(_("architecture '%s' is reserved and cannot be added"), archname); | |
547 | } | |
548 | ||
549 | dpkg_arch_save_list(); | |
550 | ||
551 | return 0; | |
552 | } | |
553 | ||
554 | static int | |
555 | arch_remove(const char *const *argv) | |
556 | { | |
557 | const char *archname = *argv++; | |
558 | struct dpkg_arch *arch; | |
559 | struct pkgiterator *iter; | |
560 | struct pkginfo *pkg; | |
561 | ||
562 | if (archname == NULL || *argv) | |
563 | badusage(_("--%s takes exactly one argument"), cipaction->olong); | |
564 | ||
565 | modstatdb_open(msdbrw_readonly); | |
566 | ||
567 | arch = dpkg_arch_find(archname); | |
568 | if (arch->type != DPKG_ARCH_FOREIGN) { | |
569 | warning(_("cannot remove non-foreign architecture '%s'"), arch->name); | |
570 | return 0; | |
571 | } | |
572 | ||
573 | /* Check if it's safe to remove the architecture from the db. */ | |
574 | iter = pkg_db_iter_new(); | |
575 | while ((pkg = pkg_db_iter_next_pkg(iter))) { | |
576 | if (pkg->status < PKG_STAT_HALFINSTALLED) | |
577 | continue; | |
578 | if (pkg->installed.arch == arch) { | |
579 | if (fc_architecture) | |
580 | warning(_("removing architecture '%s' currently in use by database"), | |
581 | arch->name); | |
582 | else | |
583 | ohshit(_("cannot remove architecture '%s' currently in use by the database"), | |
584 | arch->name); | |
585 | break; | |
586 | } | |
587 | } | |
588 | pkg_db_iter_free(iter); | |
589 | ||
590 | dpkg_arch_unmark(arch); | |
591 | dpkg_arch_save_list(); | |
592 | ||
593 | modstatdb_shutdown(); | |
594 | ||
595 | return 0; | |
596 | } | |
597 | ||
598 | static inline void | |
599 | print_forceinfo_line(int type, const char *name, const char *desc) | |
600 | { | |
601 | printf(" %s %-18s %s\n", forcetype_str(type), name, desc); | |
602 | } | |
603 | ||
604 | static void | |
605 | print_forceinfo(const struct forceinfo *fi) | |
606 | { | |
607 | char *desc, *line; | |
608 | ||
609 | desc = m_strdup(gettext(fi->desc)); | |
610 | ||
611 | line = strtok(desc, "\n"); | |
612 | print_forceinfo_line(fi->type, fi->name, line); | |
613 | while ((line = strtok(NULL, "\n"))) | |
614 | print_forceinfo_line(' ', "", line); | |
615 | ||
616 | free(desc); | |
617 | } | |
618 | ||
619 | static void | |
620 | set_force(const struct cmdinfo *cip, const char *value) | |
621 | { | |
622 | const char *comma; | |
623 | size_t l; | |
624 | const struct forceinfo *fip; | |
625 | ||
626 | if (strcmp(value, "help") == 0) { | |
627 | printf(_( | |
628 | "%s forcing options - control behaviour when problems found:\n" | |
629 | " warn but continue: --force-<thing>,<thing>,...\n" | |
630 | " stop with error: --refuse-<thing>,<thing>,... | --no-force-<thing>,...\n" | |
631 | " Forcing things:\n"), DPKG); | |
632 | ||
633 | for (fip = forceinfos; fip->name; fip++) | |
634 | print_forceinfo(fip); | |
635 | ||
636 | printf(_( | |
637 | "\n" | |
638 | "WARNING - use of options marked [!] can seriously damage your installation.\n" | |
639 | "Forcing options marked [*] are enabled by default.\n")); | |
640 | m_output(stdout, _("<standard output>")); | |
641 | exit(0); | |
642 | } | |
643 | ||
644 | for (;;) { | |
645 | comma= strchr(value,','); | |
646 | l = comma ? (size_t)(comma - value) : strlen(value); | |
647 | for (fip=forceinfos; fip->name; fip++) | |
648 | if (strncmp(fip->name, value, l) == 0 && strlen(fip->name) == l) | |
649 | break; | |
650 | ||
651 | if (!fip->name) { | |
652 | badusage(_("unknown force/refuse option '%.*s'"), | |
653 | (int)min(l, 250), value); | |
654 | } else if (strcmp(fip->name, "all") == 0) { | |
655 | for (fip = forceinfos; fip->name; fip++) | |
656 | if (fip->opt) | |
657 | *fip->opt = cip->arg_int; | |
658 | } else if (fip->opt) { | |
659 | *fip->opt = cip->arg_int; | |
660 | } else { | |
661 | warning(_("obsolete force/refuse option '%s'"), fip->name); | |
662 | } | |
663 | ||
664 | if (!comma) break; | |
665 | value= ++comma; | |
666 | } | |
667 | } | |
668 | ||
669 | int execbackend(const char *const *argv) DPKG_ATTR_NORET; | |
670 | int commandfd(const char *const *argv); | |
671 | ||
672 | /* This table has both the action entries in it and the normal options. | |
673 | * The action entries are made with the ACTION macro, as they all | |
674 | * have a very similar structure. */ | |
675 | static const struct cmdinfo cmdinfos[]= { | |
676 | #define ACTIONBACKEND(longopt, shortopt, backend) \ | |
677 | { longopt, shortopt, 0, NULL, NULL, setaction, 0, (void *)backend, execbackend } | |
678 | ||
679 | ACTION( "install", 'i', act_install, archivefiles ), | |
680 | ACTION( "unpack", 0, act_unpack, archivefiles ), | |
681 | ACTION( "record-avail", 'A', act_avail, archivefiles ), | |
682 | ACTION( "configure", 0, act_configure, packages ), | |
683 | ACTION( "remove", 'r', act_remove, packages ), | |
684 | ACTION( "purge", 'P', act_purge, packages ), | |
685 | ACTION( "triggers-only", 0, act_triggers, packages ), | |
686 | ACTION( "verify", 'V', act_verify, verify ), | |
687 | ACTIONBACKEND( "listfiles", 'L', DPKGQUERY), | |
688 | ACTIONBACKEND( "status", 's', DPKGQUERY), | |
689 | ACTION( "get-selections", 0, act_getselections, getselections ), | |
690 | ACTION( "set-selections", 0, act_setselections, setselections ), | |
691 | ACTION( "clear-selections", 0, act_clearselections, clearselections ), | |
692 | ACTIONBACKEND( "print-avail", 'p', DPKGQUERY), | |
693 | ACTION( "update-avail", 0, act_avreplace, updateavailable ), | |
694 | ACTION( "merge-avail", 0, act_avmerge, updateavailable ), | |
695 | ACTION( "clear-avail", 0, act_avclear, updateavailable ), | |
696 | ACTION( "forget-old-unavail", 0, act_forgetold, forgetold ), | |
697 | ACTION( "audit", 'C', act_audit, audit ), | |
698 | ACTION( "yet-to-unpack", 0, act_unpackchk, unpackchk ), | |
699 | ACTIONBACKEND( "list", 'l', DPKGQUERY), | |
700 | ACTIONBACKEND( "search", 'S', DPKGQUERY), | |
701 | ACTION( "assert-support-predepends", 0, act_assertpredep, assertpredep ), | |
702 | ACTION( "assert-working-epoch", 0, act_assertepoch, assertepoch ), | |
703 | ACTION( "assert-long-filenames", 0, act_assertlongfilenames, assertlongfilenames ), | |
704 | ACTION( "assert-multi-conrep", 0, act_assertmulticonrep, assertmulticonrep ), | |
705 | ACTION( "assert-multi-arch", 0, act_assertmultiarch, assertmultiarch ), | |
706 | ACTION( "assert-versioned-provides", 0, act_assertverprovides, assertverprovides ), | |
707 | ACTION( "add-architecture", 0, act_arch_add, arch_add ), | |
708 | ACTION( "remove-architecture", 0, act_arch_remove, arch_remove ), | |
709 | ACTION( "print-architecture", 0, act_printarch, printarch ), | |
710 | ACTION( "print-foreign-architectures", 0, act_printforeignarches, print_foreign_arches ), | |
711 | ACTION( "predep-package", 0, act_predeppackage, predeppackage ), | |
712 | ACTION( "validate-pkgname", 0, act_validate_pkgname, validate_pkgname ), | |
713 | ACTION( "validate-trigname", 0, act_validate_trigname, validate_trigname ), | |
714 | ACTION( "validate-archname", 0, act_validate_archname, validate_archname ), | |
715 | ACTION( "validate-version", 0, act_validate_version, validate_version ), | |
716 | ACTION( "compare-versions", 0, act_cmpversions, cmpversions ), | |
717 | /* | |
718 | ACTION( "command-fd", 'c', act_commandfd, commandfd ), | |
719 | */ | |
720 | ||
721 | { "pre-invoke", 0, 1, NULL, NULL, set_invoke_hook, 0, &pre_invoke_hooks }, | |
722 | { "post-invoke", 0, 1, NULL, NULL, set_invoke_hook, 0, &post_invoke_hooks }, | |
723 | { "path-exclude", 0, 1, NULL, NULL, set_filter, 0 }, | |
724 | { "path-include", 0, 1, NULL, NULL, set_filter, 1 }, | |
725 | { "verify-format", 0, 1, NULL, NULL, set_verify_format }, | |
726 | { "status-logger", 0, 1, NULL, NULL, set_invoke_hook, 0, &status_loggers }, | |
727 | { "status-fd", 0, 1, NULL, NULL, set_pipe, 0 }, | |
728 | { "log", 0, 1, NULL, &log_file, NULL, 0 }, | |
729 | { "pending", 'a', 0, &f_pending, NULL, NULL, 1 }, | |
730 | { "recursive", 'R', 0, &f_recursive, NULL, NULL, 1 }, | |
731 | { "no-act", 0, 0, &f_noact, NULL, NULL, 1 }, | |
732 | { "dry-run", 0, 0, &f_noact, NULL, NULL, 1 }, | |
733 | { "simulate", 0, 0, &f_noact, NULL, NULL, 1 }, | |
734 | { "no-debsig", 0, 0, &f_nodebsig, NULL, NULL, 1 }, | |
735 | /* Alias ('G') for --refuse. */ | |
736 | { NULL, 'G', 0, &fc_downgrade, NULL, NULL, 0 }, | |
737 | { "selected-only", 'O', 0, &f_alsoselect, NULL, NULL, 0 }, | |
738 | { "triggers", 0, 0, &f_triggers, NULL, NULL, 1 }, | |
739 | { "no-triggers", 0, 0, &f_triggers, NULL, NULL, -1 }, | |
740 | /* FIXME: Remove ('N') sometime. */ | |
741 | { "no-also-select", 'N', 0, &f_alsoselect, NULL, NULL, 0 }, | |
742 | { "skip-same-version", 'E', 0, &f_skipsame, NULL, NULL, 1 }, | |
743 | { "auto-deconfigure", 'B', 0, &f_autodeconf, NULL, NULL, 1 }, | |
744 | { "root", 0, 1, NULL, NULL, set_root, 0 }, | |
745 | { "abort-after", 0, 1, &errabort, NULL, set_integer, 0 }, | |
746 | { "admindir", 0, 1, NULL, &admindir, NULL, 0 }, | |
747 | { "instdir", 0, 1, NULL, NULL, set_instdir, 0 }, | |
748 | { "ignore-depends", 0, 1, NULL, NULL, set_ignore_depends, 0 }, | |
749 | { "force", 0, 2, NULL, NULL, set_force, 1 }, | |
750 | { "refuse", 0, 2, NULL, NULL, set_force, 0 }, | |
751 | { "no-force", 0, 2, NULL, NULL, set_force, 0 }, | |
752 | { "debug", 'D', 1, NULL, NULL, set_debug, 0 }, | |
753 | { "help", '?', 0, NULL, NULL, usage, 0 }, | |
754 | { "version", 0, 0, NULL, NULL, printversion, 0 }, | |
755 | ACTIONBACKEND( "build", 'b', BACKEND), | |
756 | ACTIONBACKEND( "contents", 'c', BACKEND), | |
757 | ACTIONBACKEND( "control", 'e', BACKEND), | |
758 | ACTIONBACKEND( "info", 'I', BACKEND), | |
759 | ACTIONBACKEND( "field", 'f', BACKEND), | |
760 | ACTIONBACKEND( "extract", 'x', BACKEND), | |
761 | ACTIONBACKEND( "vextract", 'X', BACKEND), | |
762 | ACTIONBACKEND( "ctrl-tarfile", 0, BACKEND), | |
763 | ACTIONBACKEND( "fsys-tarfile", 0, BACKEND), | |
764 | { NULL, 0, 0, NULL, NULL, NULL, 0 } | |
765 | }; | |
766 | ||
767 | int | |
768 | execbackend(const char *const *argv) | |
769 | { | |
770 | struct command cmd; | |
771 | ||
772 | command_init(&cmd, cipaction->arg_ptr, NULL); | |
773 | command_add_arg(&cmd, cipaction->arg_ptr); | |
774 | command_add_arg(&cmd, str_fmt("--%s", cipaction->olong)); | |
775 | ||
776 | /* Explicitly separate arguments from options as any user-supplied | |
777 | * separator got stripped by the option parser */ | |
778 | command_add_arg(&cmd, "--"); | |
779 | command_add_argl(&cmd, (const char **)argv); | |
780 | ||
781 | command_exec(&cmd); | |
782 | } | |
783 | ||
784 | int | |
785 | commandfd(const char *const *argv) | |
786 | { | |
787 | struct varbuf linevb = VARBUF_INIT; | |
788 | const char * pipein; | |
789 | const char **newargs = NULL, **endargs; | |
790 | char *ptr, *endptr; | |
791 | FILE *in; | |
792 | long infd; | |
793 | int ret = 0; | |
794 | int c, lno, i; | |
795 | bool skipchar; | |
796 | ||
797 | pipein = *argv++; | |
798 | if (pipein == NULL || *argv) | |
799 | badusage(_("--%s takes exactly one argument"), cipaction->olong); | |
800 | ||
801 | infd = dpkg_options_parse_arg_int(cipaction, pipein); | |
802 | in = fdopen(infd, "r"); | |
803 | if (in == NULL) | |
804 | ohshite(_("couldn't open '%i' for stream"), (int)infd); | |
805 | ||
806 | for (;;) { | |
807 | bool mode = false; | |
808 | int argc= 1; | |
809 | lno= 0; | |
810 | ||
811 | push_error_context(); | |
812 | ||
813 | do { | |
814 | c = getc(in); | |
815 | if (c == '\n') | |
816 | lno++; | |
817 | } while (c != EOF && c_isspace(c)); | |
818 | if (c == EOF) break; | |
819 | if (c == '#') { | |
820 | do { c= getc(in); if (c == '\n') lno++; } while (c != EOF && c != '\n'); | |
821 | continue; | |
822 | } | |
823 | varbuf_reset(&linevb); | |
824 | do { | |
825 | varbuf_add_char(&linevb, c); | |
826 | c= getc(in); | |
827 | if (c == '\n') lno++; | |
828 | ||
829 | /* This isn't fully accurate, but overestimating can't hurt. */ | |
830 | if (c_isspace(c)) | |
831 | argc++; | |
832 | } while (c != EOF && c != '\n'); | |
833 | if (c == EOF) | |
834 | ohshit(_("unexpected end of file before end of line %d"), lno); | |
835 | if (!argc) continue; | |
836 | varbuf_end_str(&linevb); | |
837 | newargs = m_realloc(newargs, sizeof(const char *) * (argc + 1)); | |
838 | argc= 1; | |
839 | ptr= linevb.buf; | |
840 | endptr = ptr + linevb.used + 1; | |
841 | skipchar = false; | |
842 | while(ptr < endptr) { | |
843 | if (skipchar) { | |
844 | skipchar = false; | |
845 | } else if (*ptr == '\\') { | |
846 | memmove(ptr, (ptr+1), (linevb.used-(linevb.buf - ptr)-1)); | |
847 | endptr--; | |
848 | skipchar = true; | |
849 | continue; | |
850 | } else if (c_isspace(*ptr)) { | |
851 | if (mode == true) { | |
852 | *ptr = '\0'; | |
853 | mode = false; | |
854 | } | |
855 | } else { | |
856 | if (mode == false) { | |
857 | newargs[argc]= ptr; | |
858 | argc++; | |
859 | mode = true; | |
860 | } | |
861 | } | |
862 | ptr++; | |
863 | } | |
864 | *ptr = '\0'; | |
865 | newargs[argc++] = NULL; | |
866 | ||
867 | /* We strdup() each argument, but never free it, because the | |
868 | * error messages contain references back to these strings. | |
869 | * Freeing them, and reusing the memory, would make those | |
870 | * error messages confusing, to say the least. */ | |
871 | for(i=1;i<argc;i++) | |
872 | if (newargs[i]) | |
873 | newargs[i] = m_strdup(newargs[i]); | |
874 | endargs = newargs; | |
875 | ||
876 | setaction(NULL, NULL); | |
877 | dpkg_options_parse((const char *const **)&endargs, cmdinfos, printforhelp); | |
878 | if (!cipaction) badusage(_("need an action option")); | |
879 | ||
880 | filesdbinit(); | |
881 | ||
882 | ret |= cipaction->action(endargs); | |
883 | ||
884 | files_db_reset(); | |
885 | ||
886 | pop_error_context(ehflag_normaltidy); | |
887 | } | |
888 | ||
889 | return ret; | |
890 | } | |
891 | ||
892 | int main(int argc, const char *const *argv) { | |
893 | int ret; | |
894 | ||
895 | dpkg_locales_init(PACKAGE); | |
896 | dpkg_program_init("dpkg"); | |
897 | dpkg_options_load(DPKG, cmdinfos); | |
898 | dpkg_options_parse(&argv, cmdinfos, printforhelp); | |
899 | ||
900 | /* When running as root, make sure our primary group is also root, so | |
901 | * that files created by maintainer scripts have correct ownership. */ | |
902 | if (!fc_nonroot && getuid() == 0) | |
903 | if (setgid(0) < 0) | |
904 | ohshite(_("cannot set primary group ID to root")); | |
905 | ||
906 | if (!cipaction) badusage(_("need an action option")); | |
907 | ||
908 | admindir = dpkg_db_set_dir(admindir); | |
909 | ||
910 | /* Always set environment, to avoid possible security risks. */ | |
911 | if (setenv("DPKG_ADMINDIR", admindir, 1) < 0) | |
912 | ohshite(_("unable to setenv for subprocesses")); | |
913 | if (setenv("DPKG_ROOT", instdir, 1) < 0) | |
914 | ohshite(_("unable to setenv for subprocesses")); | |
915 | ||
916 | if (!f_triggers) | |
917 | f_triggers = (cipaction->arg_int == act_triggers && *argv) ? -1 : 1; | |
918 | ||
919 | if (is_invoke_action(cipaction->arg_int)) { | |
920 | run_invoke_hooks(cipaction->olong, &pre_invoke_hooks); | |
921 | run_status_loggers(&status_loggers); | |
922 | } | |
923 | ||
924 | filesdbinit(); | |
925 | ||
926 | ret = cipaction->action(argv); | |
927 | ||
928 | if (is_invoke_action(cipaction->arg_int)) | |
929 | run_invoke_hooks(cipaction->olong, &post_invoke_hooks); | |
930 | ||
931 | free_invoke_hooks(&pre_invoke_hooks); | |
932 | free_invoke_hooks(&post_invoke_hooks); | |
933 | ||
934 | dpkg_program_done(); | |
935 | ||
936 | return reportbroken_retexitstatus(ret); | |
937 | } |