summaryrefslogtreecommitdiff
path: root/pkgtools/pkg_install/files/lib/plist.c
diff options
context:
space:
mode:
Diffstat (limited to 'pkgtools/pkg_install/files/lib/plist.c')
-rw-r--r--pkgtools/pkg_install/files/lib/plist.c223
1 files changed, 142 insertions, 81 deletions
diff --git a/pkgtools/pkg_install/files/lib/plist.c b/pkgtools/pkg_install/files/lib/plist.c
index 454a71fcc6b..5489a396354 100644
--- a/pkgtools/pkg_install/files/lib/plist.c
+++ b/pkgtools/pkg_install/files/lib/plist.c
@@ -1,4 +1,4 @@
-/* $NetBSD: plist.c,v 1.27 2009/04/23 19:53:52 joerg Exp $ */
+/* $NetBSD: plist.c,v 1.28 2009/04/24 14:00:26 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -7,7 +7,7 @@
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
-__RCSID("$NetBSD: plist.c,v 1.27 2009/04/23 19:53:52 joerg Exp $");
+__RCSID("$NetBSD: plist.c,v 1.28 2009/04/24 14:00:26 joerg Exp $");
/*
* FreeBSD install - a package for the installation and maintainance
@@ -30,7 +30,7 @@ __RCSID("$NetBSD: plist.c,v 1.27 2009/04/23 19:53:52 joerg Exp $");
*/
/*-
- * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -71,6 +71,8 @@ __RCSID("$NetBSD: plist.c,v 1.27 2009/04/23 19:53:52 joerg Exp $");
#include <md5.h>
#endif
+static int delete_with_parents(const char *, Boolean, Boolean);
+
/* This struct defines a plist command type */
typedef struct cmd_t {
const char *c_s; /* string to recognise */
@@ -94,6 +96,7 @@ static const cmd_t cmdv[] = {
{"display", PLIST_DISPLAY, 1, 0},
{"pkgdep", PLIST_PKGDEP, 1, 0},
{"pkgcfl", PLIST_PKGCFL, 1, 0},
+ {"pkgdir", PLIST_PKGDIR, 1, 0},
{"dirrm", PLIST_DIR_RM, 1, 0},
{"option", PLIST_OPTION, 1, 0},
{"blddep", PLIST_BLDDEP, 1, 0},
@@ -501,40 +504,81 @@ do { \
* run it too in cases of failure.
*/
int
-delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg,
- Boolean NoDeleteFiles, const char *destdir)
+delete_package(Boolean ign_err, package_t *pkg, Boolean NoDeleteFiles,
+ const char *destdir)
{
plist_t *p;
- char *Where = ".", *last_file = "";
+ char *last_file = "";
int fail = SUCCESS;
Boolean preserve;
- char tmp[MaxPathSize], *name = NULL;
+ 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;
+ }
+ }
- case PLIST_IGNORE:
- p = p->next;
+ 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_CWD:
- Where = p->name;
- if (Verbose)
- printf("Change working directory to %s\n", Where);
+ 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, Where, last_file);
+ format_cmd(tmp, sizeof(tmp), p->name, prefix, last_file);
/* XXX cleanup(0); */
printf("Executing `%s'\n", tmp);
if (!Fake && system(tmp)) {
@@ -547,7 +591,7 @@ delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg,
last_file = p->name;
(void) snprintf(tmp, sizeof(tmp), "%s%s%s/%s",
destdir ? destdir : "", destdir ? "/" : "",
- Where, p->name);
+ 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);
@@ -606,7 +650,7 @@ delete_package(Boolean ign_err, Boolean nukedirs, package_t *pkg,
if (Verbose && !NoDeleteFiles)
printf("Delete file %s\n", tmp);
if (!Fake && !NoDeleteFiles) {
- if (delete_hierarchy(tmp, ign_err, nukedirs))
+ if (delete_with_parents(tmp, ign_err, FALSE))
fail = FAIL;
if (preserve && name) {
char tmp2[MaxPathSize];
@@ -633,32 +677,6 @@ pkgdb_cleanup:
}
}
break;
-
- case PLIST_DIR_RM:
- if (NoDeleteFiles || nukedirs)
- break;
-
- (void) snprintf(tmp, sizeof(tmp), "%s%s%s/%s",
- destdir ? destdir : "", destdir ? "/" : "",
- Where, p->name);
- if (fexists(tmp)) {
- if (!isdir(tmp)) {
- warnx("cannot remove `%s' as a directory\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;
- }
- }
- } else {
- warnx("cannot remove non-existent directory `%s'\n"
- "this packing list is incorrect - ignoring delete request", tmp);
- }
- last_file = p->name;
- break;
default:
break;
}
@@ -671,51 +689,94 @@ pkgdb_cleanup:
* Selectively delete a hierarchy
* Returns 1 on error, 0 else.
*/
-int
-delete_hierarchy(const char *dir, Boolean ign_err, Boolean nukedirs)
+static int
+delete_with_parents(const char *fname, Boolean ign_err, Boolean ign_nonempty)
{
- char *cp1, *cp2, *tmp_dir;
-
- if (!fexists(dir)) {
- if (!ign_err)
- warnx("%s `%s' doesn't really exist",
- isdir(dir) ? "directory" : "file", dir);
- return !ign_err;
- } else if (nukedirs) {
- if (recursive_remove(dir, ign_err)) {
- warn("Couldn't remove %s", dir);
- return 1;
- }
- } else if (isdir(dir)) {
- if (rmdir(dir) && !ign_err)
- return 1;
- } else {
- if (remove(dir) && !ign_err)
- return 1;
- }
+ char *cp, *cp2;
- if (!nukedirs)
+ if (remove(fname)) {
+ if (!ign_err && (!ign_nonempty || errno != ENOTEMPTY))
+ warnx("Couldn't remove %s", fname);
return 0;
-
- cp1 = cp2 = tmp_dir = xstrdup(dir);;
-
- while (cp2) {
- if ((cp2 = strrchr(cp1, '/')) != NULL)
+ }
+ cp = xstrdup(fname);
+ while (*cp) {
+ if ((cp2 = strrchr(cp, '/')) != NULL)
*cp2 = '\0';
- if (!isemptydir(tmp_dir))
+ if (!isemptydir(cp))
+ break;
+ if (has_pkgdir(cp))
+ break;
+ if (rmdir(cp))
break;
- if (rmdir(tmp_dir) && !ign_err) {
- if (fexists(tmp_dir)) {
- free(tmp_dir);
- return 1;
+ }
+ free(cp);
+
+ return 0;
+}
+
+void
+add_pkgdir(const char *pkg, const char *prefix, const char *path)
+{
+ char *fullpath, *oldvalue, *newvalue;
+
+ fullpath = xasprintf("%s/%s", prefix, path);
+ oldvalue = pkgdb_retrieve(fullpath);
+ if (oldvalue) {
+ if (strncmp(oldvalue, "@pkgdir ", 8) != 0)
+ errx(EXIT_FAILURE, "Internal error while processing pkgdb, run pkg_admin rebuild");
+ newvalue = xasprintf("%s %s", oldvalue, pkg);
+ pkgdb_remove(fullpath);
+ } else {
+ newvalue = xasprintf("@pkgdir %s", pkg);
+ }
+ pkgdb_store(fullpath, newvalue);
+
+ free(fullpath);
+ free(newvalue);
+}
+
+void
+delete_pkgdir(const char *pkg, const char *prefix, const char *path)
+{
+ size_t pkg_len, len;
+ char *fullpath, *oldvalue, *newvalue, *iter;
+
+ fullpath = xasprintf("%s/%s", prefix, path);
+ oldvalue = pkgdb_retrieve(fullpath);
+ if (oldvalue && strncmp(oldvalue, "@pkgdir ", 8) == 0) {
+ newvalue = xstrdup(oldvalue);
+ iter = newvalue + 8;
+ pkg_len = strlen(pkg);
+ while (*iter) {
+ if (strncmp(iter, pkg, pkg_len) == 0 &&
+ (iter[pkg_len] == ' ' || iter[pkg_len] == '\0')) {
+ len = strlen(iter + pkg_len);
+ memmove(iter, iter + pkg_len + 1, len);
+ if (len == 0)
+ *iter = '\0';
+ } else {
+ iter += strcspn(iter, " ");
+ iter += strspn(iter, " ");
}
- warnx("directory `%s' doesn't really exist", tmp_dir);
- }
- /* back up the pathname one component */
- if (cp2) {
- cp1 = tmp_dir;
}
+ pkgdb_remove(fullpath);
+ if (iter != newvalue + 8)
+ pkgdb_store(fullpath, newvalue);
+ free(newvalue);
}
- free(tmp_dir);
- return 0;
+ free(fullpath);
+}
+
+int
+has_pkgdir(const char *path)
+{
+ const char *value;
+
+ value = pkgdb_retrieve(path);
+
+ if (value && strncmp(value, "@pkgdir ", 8) == 0)
+ return 1;
+ else
+ return 0;
}