summaryrefslogtreecommitdiffstats
path: root/src/common/force.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/force.c')
-rw-r--r--src/common/force.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/src/common/force.c b/src/common/force.c
new file mode 100644
index 0000000..2e1fd78
--- /dev/null
+++ b/src/common/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;
+}