Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 18 Feb 2001 16:44:35 +0200 (EET)
From:      Maxim Sobolev <sobomax@freebsd.org>
To:        ports@freebsd.org
Cc:        jkh@freebsd.org
Subject:   Request for comment: pkg_delete(1) improvement
Message-ID:  <200102181444.f1IEif600926@vic.sabbo.net>

next in thread | raw e-mail | index | archive | help

--%--multipart-mixed-boundary-1.883.982507475--%
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi folks,


You all should know that current pkg_delete(1)'s behaviour is suboptimal
when several packages to be deleted are specified in command line. The
problem is that pkg_delete(1) tries to delete packages in exacly the same
order as they were specified in the command line, ignoring dependencies
between packages involved. Attached patch should solve this problem by
reordering packages to ensure proper removal order. After this patch
applied you should be able to delete all installed packaged in one turn
using `pkg_delete /var/db/pkg/*'.


-Maxim

--%--multipart-mixed-boundary-1.883.982507475--%
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Description: ASCII C program text
Content-Disposition: attachment; filename="pkg_delete-reordering.diff"

--- perform.c	2001/02/18 08:36:10	1.1
+++ perform.c	2001/02/18 11:44:02
@@ -30,16 +30,51 @@
 static int pkg_do(char *);
 static void sanity_check(char *);
 static void undepend(PackingList, char *);
+static int chkifdepends(char *pkgname1, char *pkgname2);
 static char LogDir[FILENAME_MAX];
 
 
 int
 pkg_perform(char **pkgs)
 {
-    int i, err_cnt = 0;
+    char *tmp;
+    int i, j;
+    int err_cnt = 0;
+    int loop_cnt;
 
-    for (i = 0; pkgs[i]; i++)
+    for (i = 0; pkgs[i]; i++) {
+	/*
+	 * Check to see if any other package in pkgs[i+1:] depends
+	 * on pkgs[i] and deffer removal of pkgs[i] if so.
+	 */
+	loop_cnt = 0;
+	for (j = i + 1; pkgs[j]; j++) {
+	    if (chkifdepends(pkgs[j], pkgs[i]) == 1) {
+		/*
+		 * Try to avoid deadlock if package A depends on B which in
+		 * turn depends on C and C due to an error depends on A.
+		 * Use ugly but simple method, becase it Should Never
+		 * Happen[tm] in the real life anyway.
+		 */
+		if (loop_cnt > 4096) {
+		    warnx("dependency loop detected for package %s", pkgs[j]);
+		    err_cnt++;
+		    break;
+		}
+		loop_cnt++;
+		tmp = pkgs[i];
+		pkgs[i] = pkgs[j];
+		pkgs[j] = tmp;
+		/*
+		 * Another iteration requred to check if new pkgs[i]
+		 * itself has any packages that depend on it
+		 */
+		j--;
+	    }
+	}
 	err_cnt += pkg_do(pkgs[i]);
+    }
+
     return err_cnt;
 }
 
@@ -292,4 +327,40 @@
 	 warnx("error renaming `%s' to `%s'", ftmp, fname);
      remove(ftmp);			/* just in case */
      return;
+}
+
+/*
+ * Check to see if pkgname1 depends on pkgname2.
+ * Returns 1 if depends, 0 if not, and -1 if error occured.
+ */ 
+static int
+chkifdepends(char *pkgname1, char *pkgname2)
+{
+    FILE *fp;
+    char fname[FILENAME_MAX];
+    char fbuf[FILENAME_MAX];
+    char *tmp;
+    int retval;
+
+    sprintf(fname, "%s/%s/%s",
+	    (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR,
+	    pkgname2, REQUIRED_BY_FNAME);
+    fp = fopen(fname, "r");
+    if (fp == NULL) {
+	/* Probably pkgname2 doesn't have any packages that depend on it */
+	return 0;
+    }
+
+    retval = 0;
+    while (fgets(fbuf, sizeof(fbuf), fp) != NULL) {
+	if (fbuf[strlen(fbuf)-1] == '\n')
+	    fbuf[strlen(fbuf)-1] = '\0';
+	if (strcmp(fbuf, pkgname1) == 0) {	/* match */
+	    retval = 1;
+	    break;
+	}
+    }
+
+    fclose(fp);
+    return retval;
 }

--%--multipart-mixed-boundary-1.883.982507475--%--


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ports" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200102181444.f1IEif600926>