diff options
author | sobomax <sobomax@FreeBSD.org> | 2001-02-19 13:26:13 +0000 |
---|---|---|
committer | sobomax <sobomax@FreeBSD.org> | 2001-02-19 13:26:13 +0000 |
commit | 6664ec33aac715f2be038c5e77df2aadbbd996b4 (patch) | |
tree | 45bc21e96042c8f76f4ba333eb9216dded1d9531 /usr.sbin/pkg_install/delete | |
parent | 4c1233433d4d46f6e4a755a79944ded2cc7e5420 (diff) | |
download | FreeBSD-src-6664ec33aac715f2be038c5e77df2aadbbd996b4.zip FreeBSD-src-6664ec33aac715f2be038c5e77df2aadbbd996b4.tar.gz |
Improve pkg_delete(1) behaviour when deleting several packages at once.
Instead of trying to delete packages in the same order as they were specified
in the command line, reorder deletion in such a way that if package A depends
on package B then package A will be deleted before B no matter in which order
they were specified in the command line.
Reviewed by: jkh, will
Approved by: jkh
Diffstat (limited to 'usr.sbin/pkg_install/delete')
-rw-r--r-- | usr.sbin/pkg_install/delete/perform.c | 77 |
1 files changed, 74 insertions, 3 deletions
diff --git a/usr.sbin/pkg_install/delete/perform.c b/usr.sbin/pkg_install/delete/perform.c index 7752938..7f294c0 100644 --- a/usr.sbin/pkg_install/delete/perform.c +++ b/usr.sbin/pkg_install/delete/perform.c @@ -30,16 +30,51 @@ static const char rcsid[] = 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; - - for (i = 0; pkgs[i]; i++) + char *tmp; + int i, j; + int err_cnt = 0; + int loop_cnt; + + 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; } @@ -293,3 +328,39 @@ undepend(PackingList p, char *pkgname) 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; +} |