From f92b8b417b20a50b57daf8a0181be410e57f050a Mon Sep 17 00:00:00 2001 From: Lionel Sambuc Date: Tue, 8 Oct 2013 13:15:25 +0200 Subject: [PATCH] Step 0: pkgtools/pkg_install * Add anti-recursivity checks when computing package dependancy, (Original author Thomas Cort) --- pkgtools/pkg_install/Makefile | 9 ++- pkgtools/pkg_install/files/add/perform.c | 90 +++++++++++++++++++++++- pkgtools/pkg_install/files/lib/plist.c | 11 +-- 3 files changed, 103 insertions(+), 7 deletions(-) diff --git a/pkgtools/pkg_install/Makefile b/pkgtools/pkg_install/Makefile index 53a4834fd..4e2cff410 100644 --- a/pkgtools/pkg_install/Makefile +++ b/pkgtools/pkg_install/Makefile @@ -25,8 +25,8 @@ CONFIGURE_ARGS+= --sysconfdir=${PKG_SYSCONFDIR} CONFIGURE_ARGS+= --with-pkgdbdir=${PKG_DBDIR} USE_FEATURES= nbcompat - -NBCOMPAT_CONFIGURE_ARGS+= --enable-bsd-getopt --enable-db +# MINIX: Unsupported for now, requires mmap: --enable-db +NBCOMPAT_CONFIGURE_ARGS+= --enable-bsd-getopt SKIP_AUDIT_PACKAGES= yes NO_PKGTOOLS_REQD_CHECK= yes @@ -78,7 +78,12 @@ CPPFLAGS+= -D_FILE_OFFSET_BITS=64 CPPFLAGS+= -DDEF_UMASK=${DEF_UMASK} MAKE_ENV+= PKGSRC_MACHINE_ARCH=${MACHINE_ARCH} +.if ${OPSYS} == "NetBSD" && ${OS_VARIANT} == "Minix" +MAKE_ENV+= OPSYS=Minix +CPPFLAGS+= -DOPSYS_NAME=\"Minix\" +.else MAKE_ENV+= OPSYS=${OPSYS} +.endif # ${OPSYS} == "NetBSD" && ${OS_VARIANT} == "Minix" MAKE_ENV+= CATMAN_SECTION_SUFFIX=${CATMAN_SECTION_SUFFIX:Q} MAKE_ENV+= MANINSTALL=${MANINSTALL:Q} diff --git a/pkgtools/pkg_install/files/add/perform.c b/pkgtools/pkg_install/files/add/perform.c index feddef6bc..d921276b6 100644 --- a/pkgtools/pkg_install/files/add/perform.c +++ b/pkgtools/pkg_install/files/add/perform.c @@ -102,6 +102,13 @@ struct pkg_task { char **dependencies; }; +struct dependency_chain { + const char *pkgpath; + struct dependency_chain *next; +}; +static struct dependency_chain *dependency_chain = NULL; + + static const struct pkg_meta_desc { size_t entry_offset; const char *entry_filename; @@ -127,6 +134,9 @@ static const struct pkg_meta_desc { static int pkg_do(const char *, int, int); +static int dependency_push(const char *); +static void dependency_pop(void); + static int end_of_version(const char *opsys, const char *version_end) { @@ -748,7 +758,8 @@ extract_files(struct pkg_task *pkg) continue; case PLIST_CMD: - if (format_cmd(cmd, sizeof(cmd), p->name, pkg->prefix, last_file)) + if (format_cmd(cmd, sizeof(cmd), p->name, pkg->install_prefix, + last_file)) return -1; printf("Executing '%s'\n", cmd); if (!Fake && system(cmd)) @@ -1378,6 +1389,10 @@ pkg_do(const char *pkgpath, int mark_automatic, int top_level) #endif int status, invalid_sig; struct pkg_task *pkg; + int rc; + + if ((rc = dependency_push(pkgpath)) != 1) + return rc; pkg = xcalloc(1, sizeof(*pkg)); @@ -1577,6 +1592,7 @@ clean_memory: free(pkg->pkgname); clean_find_archive: free(pkg); + dependency_pop(); return status; } @@ -1593,5 +1609,77 @@ pkg_perform(lpkg_head_t *pkgs) free_lpkg(lpp); } + if (dependency_chain != NULL) { /* ensure stack is empty */ + warnx("leaving pkg_perform with a non-empty stack."); + ++errors; + } + return errors; } + +/* + * Add an element to the dependency chain and check for circular dependency + * while at it. + * + * returns 1 on success, 0 on circular dep detected, -1 on error. + */ +static int +dependency_push(const char *pkgpath) +{ + struct dependency_chain *dep; + struct dependency_chain **last_pdep; + + /* Check if that package is already in the chain. */ + last_pdep = &dependency_chain; + for (dep = *last_pdep; dep; last_pdep = &(dep->next), dep = dep->next) { + if (strcmp(dep->pkgpath, pkgpath) == 0) { + /* Found it - that means we have a circular dependency */ + fprintf(stderr, "warning: ignoring circular dependency:\n"); + while (dep != NULL) { + fprintf(stderr, "- %s requires\n", dep->pkgpath); + dep = dep->next; + } + fprintf(stderr, "- %s\n", pkgpath); + return 0; + } + } + + /* Not found. Add an entry to the end of the chain */ + dep = (struct dependency_chain *)malloc(sizeof(struct dependency_chain)); + if (dep == NULL) { + fprintf(stderr, "Out of memory in dependency_push for %s\n", + pkgpath); + return -1; + } + + dep->pkgpath = pkgpath; + dep->next = NULL; + *last_pdep = dep; + return 1; +} + + +/* + * Remove the last entry from the dependency chain. + */ +static void +dependency_pop(void) +{ + struct dependency_chain *dep = dependency_chain; + struct dependency_chain **pdep = &dependency_chain; + + /* This should never happen */ + if (dep == NULL) { + fprintf(stderr, "warning: empty dependency chain on pop\n"); + return; + } + + while (dep->next != NULL) { + pdep = &(dep->next); + dep = dep->next; + } + + free(dep); + *pdep = NULL; +} + diff --git a/pkgtools/pkg_install/files/lib/plist.c b/pkgtools/pkg_install/files/lib/plist.c index 1ae5dcaff..796b61135 100644 --- a/pkgtools/pkg_install/files/lib/plist.c +++ b/pkgtools/pkg_install/files/lib/plist.c @@ -514,6 +514,7 @@ delete_package(Boolean ign_err, package_t *pkg, Boolean NoDeleteFiles, int fail = SUCCESS; Boolean preserve; char tmp[MaxPathSize]; + char cmd[MaxPathSize]; const char *prefix = NULL, *name = NULL; if (!pkgdb_open(ReadWrite)) { @@ -580,10 +581,12 @@ delete_package(Boolean ign_err, package_t *pkg, Boolean NoDeleteFiles, 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); + (void) snprintf(tmp, sizeof(tmp), "%s%s%s", + destdir ? destdir : "", destdir ? "/" : "", prefix); + format_cmd(cmd, sizeof(cmd), p->name, tmp, last_file); + printf("Executing `%s'\n", cmd); + if (!Fake && system(cmd)) { + warnx("unexec command for `%s' failed", cmd); fail = FAIL; } break;