diff options
Diffstat (limited to 'src/force.c')
-rw-r--r-- | src/force.c | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/src/force.c b/src/force.c new file mode 100644 index 0000000..2e1fd78 --- /dev/null +++ b/src/force.c @@ -0,0 +1,404 @@ +/* + * dpkg - main program for package management + * force.c - force operation support + * + * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk> + * Copyright © 2006-2019 Guillem Jover <guillem@debian.org> + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <compat.h> + +#include <errno.h> +#include <string.h> +#include <stdbool.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> + +#include <dpkg/macros.h> +#include <dpkg/i18n.h> +#include <dpkg/dpkg.h> +#include <dpkg/dpkg-db.h> +#include <dpkg/options.h> + +#include "force.h" + +static int force_mask; +static int force_flags; + +enum forcetype { + FORCETYPE_DISABLED, + FORCETYPE_ENABLED, + FORCETYPE_DAMAGE, +}; + +static const char * +forcetype_str(enum forcetype type) +{ + switch (type) { + case FORCETYPE_DISABLED: + return " "; + case FORCETYPE_ENABLED: + return "[*]"; + case FORCETYPE_DAMAGE: + return "[!]"; + default: + internerr("unknown force type '%d'", type); + } +} + +static const struct forceinfo { + const char *name; + int flag; + char type; + const char *desc; +} forceinfos[] = { + { + "all", + FORCE_ALL, + FORCETYPE_DAMAGE, + N_("Set all force options"), + }, { + "security-mac", + FORCE_SECURITY_MAC, + FORCETYPE_ENABLED, + N_("Use MAC based security if available"), + }, { + "downgrade", + FORCE_DOWNGRADE, + FORCETYPE_ENABLED, + N_("Replace a package with a lower version"), + }, { + "configure-any", + FORCE_CONFIGURE_ANY, + FORCETYPE_DISABLED, + N_("Configure any package which may help this one"), + }, { + "hold", + FORCE_HOLD, + FORCETYPE_DISABLED, + N_("Install or remove incidental packages even when on hold"), + }, { + "not-root", + FORCE_NON_ROOT, + FORCETYPE_DISABLED, + N_("Try to (de)install things even when not root"), + }, { + "bad-path", + FORCE_BAD_PATH, + FORCETYPE_DISABLED, + N_("PATH is missing important programs, problems likely"), + }, { + "bad-verify", + FORCE_BAD_VERIFY, + FORCETYPE_DISABLED, + N_("Install a package even if it fails authenticity check"), + }, { + "bad-version", + FORCE_BAD_VERSION, + FORCETYPE_DISABLED, + N_("Process even packages with wrong versions"), + }, { + "statoverride-add", + FORCE_STATOVERRIDE_ADD, + FORCETYPE_DISABLED, + N_("Overwrite an existing stat override when adding it"), + }, { + "statoverride-remove", + FORCE_STATOVERRIDE_DEL, + FORCETYPE_DISABLED, + N_("Ignore a missing stat override when removing it"), + }, { + "overwrite", + FORCE_OVERWRITE, + FORCETYPE_DISABLED, + N_("Overwrite a file from one package with another"), + }, { + "overwrite-diverted", + FORCE_OVERWRITE_DIVERTED, + FORCETYPE_DISABLED, + N_("Overwrite a diverted file with an undiverted version"), + }, { + "overwrite-dir", + FORCE_OVERWRITE_DIR, + FORCETYPE_DAMAGE, + N_("Overwrite one package's directory with another's file"), + }, { + "unsafe-io", + FORCE_UNSAFE_IO, + FORCETYPE_DAMAGE, + N_("Do not perform safe I/O operations when unpacking"), + }, { + "script-chrootless", + FORCE_SCRIPT_CHROOTLESS, + FORCETYPE_DAMAGE, + N_("Do not chroot into maintainer script environment"), + }, { + "confnew", + FORCE_CONFF_NEW, + FORCETYPE_DAMAGE, + N_("Always use the new config files, don't prompt"), + }, { + "confold", + FORCE_CONFF_OLD, + FORCETYPE_DAMAGE, + N_("Always use the old config files, don't prompt"), + }, { + "confdef", + FORCE_CONFF_DEF, + FORCETYPE_DAMAGE, + N_("Use the default option for new config files if one\n" + "is available, don't prompt. If no default can be found,\n" + "you will be prompted unless one of the confold or\n" + "confnew options is also given"), + }, { + "confmiss", + FORCE_CONFF_MISS, + FORCETYPE_DAMAGE, + N_("Always install missing config files"), + }, { + "confask", + FORCE_CONFF_ASK, + FORCETYPE_DAMAGE, + N_("Offer to replace config files with no new versions"), + }, { + "architecture", + FORCE_ARCHITECTURE, + FORCETYPE_DAMAGE, + N_("Process even packages with wrong or no architecture"), + }, { + "breaks", + FORCE_BREAKS, + FORCETYPE_DAMAGE, + N_("Install even if it would break another package"), + }, { + "conflicts", + FORCE_CONFLICTS, + FORCETYPE_DAMAGE, + N_("Allow installation of conflicting packages"), + }, { + "depends", + FORCE_DEPENDS, + FORCETYPE_DAMAGE, + N_("Turn all dependency problems into warnings"), + }, { + "depends-version", + FORCE_DEPENDS_VERSION, + FORCETYPE_DAMAGE, + N_("Turn dependency version problems into warnings"), + }, { + "remove-reinstreq", + FORCE_REMOVE_REINSTREQ, + FORCETYPE_DAMAGE, + N_("Remove packages which require installation"), + }, { + "remove-protected", + FORCE_REMOVE_PROTECTED, + FORCETYPE_DAMAGE, + N_("Remove a protected package"), + }, { + "remove-essential", + FORCE_REMOVE_ESSENTIAL, + FORCETYPE_DAMAGE, + N_("Remove an essential package"), + }, { + NULL + } +}; + +bool +in_force(int flags) +{ + return (flags & force_flags) == flags; +} + +void +set_force(int flags) +{ + force_flags |= flags; +} + +void +reset_force(int flags) +{ + force_flags &= ~flags; +} + +char * +get_force_string(void) +{ + const struct forceinfo *fip; + struct varbuf vb = VARBUF_INIT; + + for (fip = forceinfos; fip->name; fip++) { + if ((enum force_flags)fip->flag == FORCE_ALL || + (fip->flag & force_mask) != fip->flag || + !in_force(fip->flag)) + continue; + + if (vb.used) + varbuf_add_char(&vb, ','); + varbuf_add_str(&vb, fip->name); + } + varbuf_end_str(&vb); + + return varbuf_detach(&vb); +} + +static inline void +print_forceinfo_line(int type, const char *name, const char *desc) +{ + printf(" %s %-18s %s\n", forcetype_str(type), name, desc); +} + +static void +print_forceinfo(const struct forceinfo *fi) +{ + char *desc, *line; + + desc = m_strdup(gettext(fi->desc)); + + line = strtok(desc, "\n"); + print_forceinfo_line(fi->type, fi->name, line); + while ((line = strtok(NULL, "\n"))) + print_forceinfo_line(FORCETYPE_DISABLED, "", line); + + free(desc); +} + +void +parse_force(const char *value, bool set) +{ + const char *comma; + size_t l; + const struct forceinfo *fip; + + if (strcmp(value, "help") == 0) { + char *force_string = get_force_string(); + + printf(_( +"%s forcing options - control behaviour when problems found:\n" +" warn but continue: --force-<thing>,<thing>,...\n" +" stop with error: --refuse-<thing>,<thing>,... | --no-force-<thing>,...\n" +" Forcing things:\n"), dpkg_get_progname()); + + for (fip = forceinfos; fip->name; fip++) + if ((enum force_flags)fip->flag == FORCE_ALL || + (fip->flag & force_mask) == fip->flag) + print_forceinfo(fip); + + printf(_( +"\n" +"WARNING - use of options marked [!] can seriously damage your installation.\n" +"Forcing options marked [*] are enabled by default.\n")); + m_output(stdout, _("<standard output>")); + + printf(_( +"\n" +"Currently enabled options:\n" +" %s\n"), force_string); + + free(force_string); + + exit(0); + } + + for (;;) { + comma = strchrnul(value, ','); + l = (size_t)(comma - value); + for (fip = forceinfos; fip->name; fip++) + if (strncmp(fip->name, value, l) == 0 && + strlen(fip->name) == l) + break; + + if (!fip->name) { + badusage(_("unknown force/refuse option '%.*s'"), + (int)min(l, 250), value); + } else if (fip->flag) { + if (set) + set_force(fip->flag); + else + reset_force(fip->flag); + } else { + warning(_("obsolete force/refuse option '%s'"), + fip->name); + } + + if (*comma == '\0') + break; + value = ++comma; + } +} + +void +set_force_default(int mask) +{ + const char *force_env; + const struct forceinfo *fip; + + force_mask = mask; + + /* If we get passed force options from the environment, do not + * initialize from the built-in defaults. */ + force_env = getenv("DPKG_FORCE"); + if (force_env != NULL) { + if (force_env[0] != '\0') + parse_force(force_env, 1); + return; + } + + for (fip = forceinfos; fip->name; fip++) + if (fip->type == FORCETYPE_ENABLED) + set_force(fip->flag); +} + +void +set_force_option(const struct cmdinfo *cip, const char *value) +{ + bool set = cip->arg_int; + + parse_force(value, set); +} + +void +reset_force_option(const struct cmdinfo *cip, const char *value) +{ + reset_force(cip->arg_int); +} + +void +forcibleerr(int forceflag, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + if (in_force(forceflag)) { + warning(_("overriding problem because --force enabled:")); + warningv(fmt, args); + } else { + ohshitv(fmt, args); + } + va_end(args); +} + +int +forcible_nonroot_error(int rc) +{ + if (in_force(FORCE_NON_ROOT) && errno == EPERM) + return 0; + return rc; +} |