/* * Delete the results of a package installation. * * This is here rather than in the pkg_delete code because pkg_add needs to * run it too in cases of failure. */ int delete_package(Boolean ign_err, package_t *pkg, Boolean NoDeleteFiles, const char *destdir) { plist_t *p; const char *last_file = ""; int fail = SUCCESS; Boolean preserve; char tmp[MaxPathSize]; const char *prefix = NULL, *name = NULL; if (!pkgdb_open(ReadWrite)) { err(EXIT_FAILURE, "cannot open pkgdb"); } preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE; for (p = pkg->head; p; p = p->next) { switch (p->type) { case PLIST_NAME: name = p->name; break; case PLIST_CWD: if (prefix == NULL) prefix = p->name; break; default: break; } } if (name == NULL || prefix == NULL) errx(EXIT_FAILURE, "broken PLIST"); /* * Remove database entries first, directory removal is done * in the main loop below. */ for (p = pkg->head; p; p = p->next) { if (p->type == PLIST_PKGDIR) delete_pkgdir(name, prefix, p->name); } for (p = pkg->head; p; p = p->next) { switch (p->type) { case PLIST_NAME: /* Handled already */ break; case PLIST_PKGDIR: case PLIST_DIR_RM: (void) snprintf(tmp, sizeof(tmp), "%s/%s", prefix, p->name); if (has_pkgdir(tmp)) continue; (void) snprintf(tmp, sizeof(tmp), "%s%s%s/%s", destdir ? destdir : "", destdir ? "/" : "", prefix, p->name); if (!fexists(tmp)) { if (p->type == PLIST_PKGDIR) warnx("Directory `%s' disappeared, skipping", tmp); } else if (!isdir(tmp)) { warnx("attempting to delete a file `%s' as a directory\n" "this packing list is incorrect - ignoring delete request", tmp); } else if (delete_with_parents(tmp, ign_err, TRUE)) fail = FAIL; break; case PLIST_IGNORE: p = p->next; break; case PLIST_UNEXEC: if (NoDeleteFiles) break; format_cmd(tmp, sizeof(tmp), p->name, prefix, last_file); printf("Executing `%s'\n", tmp); if (!Fake && system(tmp)) { warnx("unexec command for `%s' failed", tmp); fail = FAIL; } break; case PLIST_FILE: last_file = p->name; (void) snprintf(tmp, sizeof(tmp), "%s%s%s/%s", destdir ? destdir : "", destdir ? "/" : "", prefix, p->name); if (isdir(tmp)) { warnx("attempting to delete directory `%s' as a file\n" "this packing list is incorrect - ignoring delete request", tmp); } else { int restored = 0; /* restored from preserve? */ if (p->next && p->next->type == PLIST_COMMENT) { if (strncmp(p->next->name, CHECKSUM_HEADER, ChecksumHeaderLen) == 0) { char *cp, buf[LegibleChecksumLen]; if ((cp = MD5File(tmp, buf)) != NULL) { /* Mismatch? */ if (strcmp(cp, p->next->name + ChecksumHeaderLen) != 0) { printf("original MD5 checksum failed, %s: %s\n", Force ? "deleting anyway" : "not deleting", tmp); if (!Force) { fail = FAIL; goto pkgdb_cleanup; } } } } else if (strncmp(p->next->name, SYMLINK_HEADER, SymlinkHeaderLen) == 0) { char buf[MaxPathSize + SymlinkHeaderLen]; int cc; (void) strlcpy(buf, SYMLINK_HEADER, sizeof(buf)); if ((cc = readlink(tmp, &buf[SymlinkHeaderLen], sizeof(buf) - SymlinkHeaderLen - 1)) < 0) { warn("can't readlink `%s'", tmp); goto pkgdb_cleanup; } buf[SymlinkHeaderLen + cc] = 0x0; if (strcmp(buf, p->next->name) != 0) { if ((cc = readlink(&buf[SymlinkHeaderLen], &buf[SymlinkHeaderLen], sizeof(buf) - SymlinkHeaderLen)) < 0) { printf("symlink %s is not same as recorded value, %s: %s\n", buf, Force ? "deleting anyway" : "not deleting", tmp); if (!Force) { fail = FAIL; goto pkgdb_cleanup; } } buf[SymlinkHeaderLen + cc] = 0x0; if (strcmp(buf, p->next->name) != 0) { printf("symlink %s is not same as recorded value, %s: %s\n", buf, Force ? "deleting anyway" : "not deleting", tmp); if (!Force) { fail = FAIL; goto pkgdb_cleanup; } } } } } if (Verbose && !NoDeleteFiles) printf("Delete file %s\n", tmp); if (!Fake && !NoDeleteFiles) { if (delete_with_parents(tmp, ign_err, FALSE)) fail = FAIL; if (preserve && name) { char tmp2[MaxPathSize]; if (make_preserve_name(tmp2, MaxPathSize, name, tmp)) { if (fexists(tmp2)) { if (rename(tmp2, tmp)) warn("preserve: unable to restore %s as %s", tmp2, tmp); else restored = 1; } } } } pkgdb_cleanup: if (!Fake) { if (!restored) { errno = 0; if (pkgdb_remove(tmp) && errno) perror("pkgdb_remove"); } } } break; default: break; } } pkgdb_close(); return fail; }
/* * Delete the results of a package installation. * * This is here rather than in the pkg_delete code because pkg_add needs to * run it too in cases of failure. */ int delete_package(Boolean ign_err, Boolean nukedirs, Package *pkg) { PackingList p; const char *Where = ".", *last_file = ""; Boolean fail = SUCCESS; Boolean preserve; char tmp[FILENAME_MAX], *name = NULL; char *prefix = NULL; preserve = find_plist_option(pkg, "preserve") ? TRUE : FALSE; for (p = pkg->head; p; p = p->next) { switch (p->type) { case PLIST_NAME: name = p->name; break; case PLIST_IGNORE: p = p->next; break; case PLIST_CWD: if (!prefix) prefix = p->name; Where = (p->name == NULL) ? prefix : p->name; if (Verbose) printf("Change working directory to %s\n", Where); break; case PLIST_UNEXEC: format_cmd(tmp, FILENAME_MAX, p->name, Where, last_file); if (Verbose) printf("Execute '%s'\n", tmp); if (!Fake && system(tmp)) { warnx("unexec command for '%s' failed", tmp); fail = FAIL; } break; case PLIST_FILE: last_file = p->name; if (*p->name == '/') strlcpy(tmp, p->name, FILENAME_MAX); else sprintf(tmp, "%s/%s", Where, p->name); if (isdir(tmp) && fexists(tmp) && !issymlink(tmp)) { warnx("cannot delete specified file '%s' - it is a directory!\n" "this packing list is incorrect - ignoring delete request", tmp); } else { if (p->next && p->next->type == PLIST_COMMENT && !strncmp(p->next->name, "MD5:", 4)) { char *cp = NULL, buf[33]; /* * For packing lists whose version is 1.1 or greater, the md5 * hash for a symlink is calculated on the string returned * by readlink(). */ if (issymlink(tmp) && verscmp(pkg, 1, 0) > 0) { int len; char linkbuf[FILENAME_MAX]; if ((len = readlink(tmp, linkbuf, FILENAME_MAX)) > 0) cp = MD5Data((unsigned char *)linkbuf, len, buf); } else if (isfile(tmp) || verscmp(pkg, 1, 1) < 0) cp = MD5File(tmp, buf); if (cp != NULL) { /* Mismatch? */ if (strcmp(cp, p->next->name + 4)) { warnx("'%s' fails original MD5 checksum - %s", tmp, Force ? "deleted anyway." : "not deleted."); if (!Force) { fail = FAIL; continue; } } } } if (Verbose) printf("Delete file %s\n", tmp); if (!Fake) { if (delete_hierarchy(tmp, ign_err, nukedirs)) fail = FAIL; if (preserve && name) { char tmp2[FILENAME_MAX]; if (make_preserve_name(tmp2, FILENAME_MAX, name, tmp)) { if (fexists(tmp2)) { if (rename(tmp2, tmp)) warn("preserve: unable to restore %s as %s", tmp2, tmp); } } } } } break; case PLIST_DIR_RM: sprintf(tmp, "%s/%s", Where, p->name); if (!isdir(tmp) && fexists(tmp)) { warnx("cannot delete specified directory '%s' - it is a file!\n" "this packing list is incorrect - ignoring delete request", tmp); } else { if (Verbose) printf("Delete directory %s\n", tmp); if (!Fake && delete_hierarchy(tmp, ign_err, FALSE)) { warnx("unable to completely remove directory '%s'", tmp); fail = FAIL; } } last_file = p->name; break; default: break; } } return fail; }