/* * pkg - Orphan package finder * https://rawnix.org * * Copyright (c) 2025 zorz@gmx.com * SPDX-License-Identifier: BSD-2-Clause */ #include "orphan.h" /* Check if package is orphan, ignoring packages in ignore list */ static bool is_orphan_internal(const char *pkg, pkgdb_t *pkgdb, depdb_t *depdb, strarray_t *ignore) { dep_entry_t *e; strarray_t *rdeps; bool orphan; size_t i; if (!pkg || !pkgdb || !depdb) return false; if (!pkgdb_installed(pkgdb, pkg)) return false; e = depdb_find(depdb, pkg); if (!e) return false; /* not in dep db = assume manual */ if (e->reason != REASON_AUTO) return false; /* manually installed = not orphan */ /* check reverse dependencies */ rdeps = depdb_rdeps(depdb, pkg); orphan = true; for (i = 0; i < rdeps->size; i++) { if (!ignore || !strarray_contains(ignore, rdeps->data[i])) { orphan = false; break; } } strarray_free(rdeps); free(rdeps); return orphan; } bool is_orphan(const char *pkg, pkgdb_t *pkgdb, depdb_t *depdb) { return is_orphan_internal(pkg, pkgdb, depdb, NULL); } /* Find all orphans using iterative algorithm */ strarray_t *find_orphans(pkgdb_t *pkgdb, depdb_t *depdb) { strarray_t *result, *installed, *found; size_t i; bool found_new; result = xmalloc(sizeof(strarray_t)); strarray_init(result); if (!pkgdb || !depdb) return result; found = xmalloc(sizeof(strarray_t)); strarray_init(found); installed = pkgdb_list(pkgdb); /* iterate until no new orphans discovered */ do { found_new = false; /* free strings from previous iteration before reuse */ strarray_free(found); strarray_init(found); for (i = 0; i < installed->size; i++) { const char *name = installed->data[i]; if (strarray_contains(result, name)) continue; if (is_orphan_internal(name, pkgdb, depdb, result)) { strarray_add(found, name); found_new = true; } } /* add new orphans to result */ for (i = 0; i < found->size; i++) strarray_add(result, found->data[i]); } while (found_new); strarray_free(found); free(found); strarray_free(installed); free(installed); return result; }