summaryrefslogtreecommitdiffstats
path: root/src/main/cleanup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/cleanup.c')
-rw-r--r--src/main/cleanup.c260
1 files changed, 260 insertions, 0 deletions
diff --git a/src/main/cleanup.c b/src/main/cleanup.c
new file mode 100644
index 0000000..d33e5cb
--- /dev/null
+++ b/src/main/cleanup.c
@@ -0,0 +1,260 @@
+/*
+ * dpkg - main program for package management
+ * cleanup.c - cleanup functions, used when we need to unwind
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2007-2015 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 <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <utime.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/pkg.h>
+#include <dpkg/path.h>
+#include <dpkg/options.h>
+#include <dpkg/db-fsys.h>
+
+#include "main.h"
+#include "archives.h"
+
+int cleanup_pkg_failed=0, cleanup_conflictor_failed=0;
+
+/**
+ * Something went wrong and we're undoing.
+ *
+ * We have the following possible situations for non-conffiles:
+ * «pathname».dpkg-tmp exists - in this case we want to remove
+ * «pathname» if it exists and replace it with «pathname».dpkg-tmp.
+ * This undoes the backup operation.
+ * «pathname».dpkg-tmp does not exist - «pathname» may be on the disk,
+ * as a new file which didn't fail, remove it if it is.
+ *
+ * In both cases, we also make sure we delete «pathname».dpkg-new in
+ * case that's still hanging around.
+ *
+ * For conffiles, we simply delete «pathname».dpkg-new. For these,
+ * «pathname».dpkg-tmp shouldn't exist, as we don't make a backup
+ * at this stage. Just to be on the safe side, though, we don't
+ * look for it.
+ */
+void cu_installnew(int argc, void **argv) {
+ struct fsys_namenode *namenode = argv[0];
+ struct stat stab;
+
+ cleanup_pkg_failed++; cleanup_conflictor_failed++;
+
+ debug(dbg_eachfile, "cu_installnew '%s' flags=%o",
+ namenode->name, namenode->flags);
+
+ setupfnamevbs(namenode->name);
+
+ if (!(namenode->flags & FNNF_NEW_CONFF) && !lstat(fnametmpvb.buf,&stab)) {
+ /* OK, «pathname».dpkg-tmp exists. Remove «pathname» and
+ * restore «pathname».dpkg-tmp ... */
+ if (namenode->flags & FNNF_NO_ATOMIC_OVERWRITE) {
+ /* If we can't do an atomic overwrite we have to delete first any
+ * link to the new version we may have created. */
+ debug(dbg_eachfiledetail,"cu_installnew restoring nonatomic");
+ if (secure_remove(fnamevb.buf) && errno != ENOENT && errno != ENOTDIR)
+ ohshite(_("unable to remove newly-installed version of '%.250s' to allow"
+ " reinstallation of backup copy"),namenode->name);
+ } else {
+ debug(dbg_eachfiledetail,"cu_installnew restoring atomic");
+ }
+ /* Either we can do an atomic restore, or we've made room: */
+ if (rename(fnametmpvb.buf,fnamevb.buf))
+ ohshite(_("unable to restore backup version of '%.250s'"), namenode->name);
+ /* If «pathname».dpkg-tmp was still a hard link to «pathname», then the
+ * atomic rename did nothing, so we make sure to remove the backup. */
+ else if (unlink(fnametmpvb.buf) && errno != ENOENT)
+ ohshite(_("unable to remove backup copy of '%.250s'"), namenode->name);
+ } else if (namenode->flags & FNNF_PLACED_ON_DISK) {
+ debug(dbg_eachfiledetail,"cu_installnew removing new file");
+ if (secure_remove(fnamevb.buf) && errno != ENOENT && errno != ENOTDIR)
+ ohshite(_("unable to remove newly-installed version of '%.250s'"),
+ namenode->name);
+ } else {
+ debug(dbg_eachfiledetail,"cu_installnew not restoring");
+ }
+ /* Whatever, we delete «pathname».dpkg-new now, if it still exists. */
+ if (secure_remove(fnamenewvb.buf) && errno != ENOENT && errno != ENOTDIR)
+ ohshite(_("unable to remove newly-extracted version of '%.250s'"),
+ namenode->name);
+
+ cleanup_pkg_failed--; cleanup_conflictor_failed--;
+}
+
+void cu_prermupgrade(int argc, void **argv) {
+ struct pkginfo *pkg= (struct pkginfo*)argv[0];
+
+ if (cleanup_pkg_failed++) return;
+ maintscript_postinst(pkg, "abort-upgrade",
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ NULL);
+ pkg_clear_eflags(pkg, PKG_EFLAG_REINSTREQ);
+ post_postinst_tasks(pkg, PKG_STAT_INSTALLED);
+ cleanup_pkg_failed--;
+}
+
+/*
+ * Also has conflictor in argv[1] and infavour in argv[2].
+ * conflictor may be NULL if deconfigure was due to Breaks or multi-arch
+ * instance sync.
+ */
+void ok_prermdeconfigure(int argc, void **argv) {
+ struct pkginfo *deconf= (struct pkginfo*)argv[0];
+
+ if (cipaction->arg_int == act_install)
+ enqueue_package(deconf);
+}
+
+/*
+ * conflictor may be NULL if deconfigure was due to Breaks or multi-arch
+ * instance sync.
+ */
+void cu_prermdeconfigure(int argc, void **argv) {
+ struct pkginfo *deconf= (struct pkginfo*)argv[0];
+ struct pkginfo *conflictor = (struct pkginfo *)argv[1];
+ struct pkginfo *infavour= (struct pkginfo*)argv[2];
+
+ if (conflictor) {
+ maintscript_postinst(deconf, "abort-deconfigure",
+ "in-favour",
+ pkgbin_name(infavour, &infavour->available,
+ pnaw_nonambig),
+ versiondescribe(&infavour->available.version,
+ vdew_nonambig),
+ "removing",
+ pkg_name(conflictor, pnaw_nonambig),
+ versiondescribe(&conflictor->installed.version,
+ vdew_nonambig),
+ NULL);
+ } else {
+ maintscript_postinst(deconf, "abort-deconfigure",
+ "in-favour",
+ pkgbin_name(infavour, &infavour->available,
+ pnaw_nonambig),
+ versiondescribe(&infavour->available.version,
+ vdew_nonambig),
+ NULL);
+ }
+
+ post_postinst_tasks(deconf, PKG_STAT_INSTALLED);
+}
+
+void cu_prerminfavour(int argc, void **argv) {
+ struct pkginfo *conflictor= (struct pkginfo*)argv[0];
+ struct pkginfo *infavour= (struct pkginfo*)argv[1];
+
+ if (cleanup_conflictor_failed++) return;
+ maintscript_postinst(conflictor, "abort-remove",
+ "in-favour",
+ pkgbin_name(infavour, &infavour->available,
+ pnaw_nonambig),
+ versiondescribe(&infavour->available.version,
+ vdew_nonambig),
+ NULL);
+ pkg_clear_eflags(conflictor, PKG_EFLAG_REINSTREQ);
+ post_postinst_tasks(conflictor, PKG_STAT_INSTALLED);
+ cleanup_conflictor_failed--;
+}
+
+void cu_preinstverynew(int argc, void **argv) {
+ struct pkginfo *pkg= (struct pkginfo*)argv[0];
+ char *cidir= (char*)argv[1];
+ char *cidirrest= (char*)argv[2];
+
+ if (cleanup_pkg_failed++) return;
+ maintscript_new(pkg, POSTRMFILE, "post-removal", cidir, cidirrest,
+ "abort-install", NULL);
+ pkg_set_status(pkg, PKG_STAT_NOTINSTALLED);
+ pkg_clear_eflags(pkg, PKG_EFLAG_REINSTREQ);
+ pkgbin_blank(&pkg->installed);
+ modstatdb_note(pkg);
+ cleanup_pkg_failed--;
+}
+
+void cu_preinstnew(int argc, void **argv) {
+ struct pkginfo *pkg= (struct pkginfo*)argv[0];
+ char *cidir= (char*)argv[1];
+ char *cidirrest= (char*)argv[2];
+
+ if (cleanup_pkg_failed++) return;
+ maintscript_new(pkg, POSTRMFILE, "post-removal", cidir, cidirrest,
+ "abort-install",
+ versiondescribe(&pkg->installed.version, vdew_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ NULL);
+ pkg_set_status(pkg, PKG_STAT_CONFIGFILES);
+ pkg_clear_eflags(pkg, PKG_EFLAG_REINSTREQ);
+ modstatdb_note(pkg);
+ cleanup_pkg_failed--;
+}
+
+void cu_preinstupgrade(int argc, void **argv) {
+ struct pkginfo *pkg= (struct pkginfo*)argv[0];
+ char *cidir= (char*)argv[1];
+ char *cidirrest= (char*)argv[2];
+ enum pkgstatus *oldstatusp= (enum pkgstatus*)argv[3];
+
+ if (cleanup_pkg_failed++) return;
+ maintscript_new(pkg, POSTRMFILE, "post-removal", cidir, cidirrest,
+ "abort-upgrade",
+ versiondescribe(&pkg->installed.version, vdew_nonambig),
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ NULL);
+ pkg_set_status(pkg, *oldstatusp);
+ pkg_clear_eflags(pkg, PKG_EFLAG_REINSTREQ);
+ modstatdb_note(pkg);
+ cleanup_pkg_failed--;
+}
+
+void cu_postrmupgrade(int argc, void **argv) {
+ struct pkginfo *pkg= (struct pkginfo*)argv[0];
+
+ if (cleanup_pkg_failed++) return;
+ maintscript_installed(pkg, PREINSTFILE, "pre-installation",
+ "abort-upgrade",
+ versiondescribe(&pkg->available.version, vdew_nonambig),
+ NULL);
+ cleanup_pkg_failed--;
+}
+
+void cu_prermremove(int argc, void **argv) {
+ struct pkginfo *pkg= (struct pkginfo*)argv[0];
+ enum pkgstatus *oldpkgstatus= (enum pkgstatus*)argv[1];
+
+ if (cleanup_pkg_failed++) return;
+ maintscript_postinst(pkg, "abort-remove", NULL);
+ pkg_clear_eflags(pkg, PKG_EFLAG_REINSTREQ);
+ post_postinst_tasks(pkg, *oldpkgstatus);
+ cleanup_pkg_failed--;
+}