2 * FreeBSD install - a package for the installation and maintainance
3 * of non-core utilities.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
17 * Routines used to do various operations with dependencies
18 * among installed packages.
20 * $FreeBSD: src/usr.sbin/pkg_install/lib/deps.c,v 1.11 2004/06/29 18:59:19 eik Exp $
21 * $DragonFly: src/usr.sbin/pkg_install/lib/Attic/deps.c,v 1.3 2004/07/30 04:46:13 dillon Exp $
29 * Sort given NULL-terminated list of installed packages (pkgs) in
30 * such a way that if package A depends on package B then after
31 * sorting A will be listed before B no matter how they were
32 * originally positioned in the list.
41 if (pkgs[0] == NULL || pkgs[1] == NULL)
44 for (i = 0; pkgs[i + 1]; i++) {
46 * Check to see if any other package in pkgs[i+1:] depends
47 * on pkgs[i] and swap those two packages if so.
50 for (j = i + 1; pkgs[j]; j++) {
51 if (chkifdepends(pkgs[j], pkgs[i]) == 1) {
53 * Try to avoid deadlock if package A depends on B which in
54 * turn depends on C and C due to an error depends on A.
55 * Use ugly but simple method, becase it Should Never
56 * Happen[tm] in the real life anyway.
58 if (loop_cnt > 4096) {
59 warnx("dependency loop detected for package %s", pkgs[j]);
68 * Another iteration requred to check if new pkgs[i]
69 * itself has any packages that depend on it
79 * Check to see if pkgname1 depends on pkgname2.
80 * Returns 1 if depends, 0 if not, and -1 if error occured.
83 chkifdepends(const char *pkgname1, const char *pkgname2)
87 struct reqr_by_entry *rb_entry;
88 struct reqr_by_head *rb_list;
90 cp2 = strchr(pkgname2, ':');
93 cp1 = strchr(pkgname1, ':');
98 /* Check that pkgname2 is actually installed */
99 if (isinstalledpkg(pkgname2) <= 0)
102 errcode = requiredby(pkgname2, &rb_list, FALSE, TRUE);
107 STAILQ_FOREACH(rb_entry, rb_list, link) {
108 if (strcmp(rb_entry->pkgname, pkgname1) == 0) { /* match */
123 * Load +REQUIRED_BY file and return a list with names of
124 * packages that require package reffered to by `pkgname'.
126 * Optionally check that packages listed there are actually
127 * installed and filter out those that don't (filter == TRUE).
129 * strict argument controls whether the caller want warnings
130 * to be emitted when there are some non-fatal conditions,
131 * i.e. package doesn't have +REQUIRED_BY file or some packages
132 * listed in +REQUIRED_BY don't exist.
134 * Result returned in the **list, while return value is equal
135 * to the number of entries in the resulting list. Print error
136 * message and return -1 on error.
139 requiredby(const char *pkgname, struct reqr_by_head **list, Boolean strict, Boolean filter)
142 char fbuf[FILENAME_MAX], fname[FILENAME_MAX];
144 struct reqr_by_entry *rb_entry;
145 static struct reqr_by_head rb_list = STAILQ_HEAD_INITIALIZER(rb_list);
148 /* Deallocate any previously allocated space */
149 while (!STAILQ_EMPTY(&rb_list)) {
150 rb_entry = STAILQ_FIRST(&rb_list);
151 STAILQ_REMOVE_HEAD(&rb_list, link);
155 if (isinstalledpkg(pkgname) <= 0) {
157 warnx("no such package '%s' installed", pkgname);
161 snprintf(fname, sizeof(fname), "%s/%s/%s", LOG_DIR, pkgname,
163 fp = fopen(fname, "r");
165 /* Probably pkgname doesn't have any packages that depend on it */
167 warnx("couldn't open dependency file '%s'", fname);
172 while (fgets(fbuf, sizeof(fbuf), fp) != NULL) {
173 if (fbuf[strlen(fbuf) - 1] == '\n')
174 fbuf[strlen(fbuf) - 1] = '\0';
175 if (filter == TRUE && isinstalledpkg(fbuf) <= 0) {
177 warnx("package '%s' is recorded in the '%s' but isn't "
178 "actually installed", fbuf, fname);
182 rb_entry = malloc(sizeof(*rb_entry));
183 if (rb_entry == NULL) {
184 warnx("%s(): malloc() failed", __func__);
188 strlcpy(rb_entry->pkgname, fbuf, sizeof(rb_entry->pkgname));
189 STAILQ_INSERT_TAIL(&rb_list, rb_entry, link);