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.
22 #include <sys/cdefs.h>
23 __FBSDID("$FreeBSD: src/usr.sbin/pkg_install/lib/deps.c,v 1.1.2.8 2002/08/20 06:35:08 obrien Exp $");
30 * Sort given NULL-terminated list of installed packages (pkgs) in
31 * such a way that if package A depends on package B then after
32 * sorting A will be listed before B no matter how they were
33 * originally positioned in the list.
42 if (pkgs[0] == NULL || pkgs[1] == NULL)
45 for (i = 0; pkgs[i + 1]; i++) {
47 * Check to see if any other package in pkgs[i+1:] depends
48 * on pkgs[i] and swap those two packages if so.
51 for (j = i + 1; pkgs[j]; j++) {
52 if (chkifdepends(pkgs[j], pkgs[i]) == 1) {
54 * Try to avoid deadlock if package A depends on B which in
55 * turn depends on C and C due to an error depends on A.
56 * Use ugly but simple method, becase it Should Never
57 * Happen[tm] in the real life anyway.
59 if (loop_cnt > 4096) {
60 warnx("dependency loop detected for package %s", pkgs[j]);
69 * Another iteration requred to check if new pkgs[i]
70 * itself has any packages that depend on it
80 * Check to see if pkgname1 depends on pkgname2.
81 * Returns 1 if depends, 0 if not, and -1 if error occured.
84 chkifdepends(const char *pkgname1, const char *pkgname2)
88 struct reqr_by_entry *rb_entry;
89 struct reqr_by_head *rb_list;
91 cp2 = strchr(pkgname2, ':');
94 cp1 = strchr(pkgname1, ':');
99 /* Check that pkgname2 is actually installed */
100 if (!isinstalledpkg(pkgname2))
103 errcode = requiredby(pkgname2, &rb_list, FALSE, TRUE);
108 STAILQ_FOREACH(rb_entry, rb_list, link) {
109 if (strcmp(rb_entry->pkgname, pkgname1) == 0) { /* match */
124 * Load +REQUIRED_BY file and return a list with names of
125 * packages that require package reffered to by `pkgname'.
127 * Optionally check that packages listed there are actually
128 * installed and filter out those that don't (filter == TRUE).
130 * strict argument controls whether the caller want warnings
131 * to be emitted when there are some non-fatal conditions,
132 * i.e. package doesn't have +REQUIRED_BY file or some packages
133 * listed in +REQUIRED_BY don't exist.
135 * Result returned in the **list, while return value is equal
136 * to the number of entries in the resulting list. Print error
137 * message and return -1 on error.
140 requiredby(const char *pkgname, struct reqr_by_head **list, Boolean strict, Boolean filter)
143 char fbuf[FILENAME_MAX], fname[FILENAME_MAX];
145 struct reqr_by_entry *rb_entry;
146 static struct reqr_by_head rb_list = STAILQ_HEAD_INITIALIZER(rb_list);
149 /* Deallocate any previously allocated space */
150 while (!STAILQ_EMPTY(&rb_list)) {
151 rb_entry = STAILQ_FIRST(&rb_list);
152 STAILQ_REMOVE_HEAD(&rb_list, link);
156 if (!isinstalledpkg(pkgname)) {
158 warnx("no such package '%s' installed", pkgname);
162 snprintf(fname, sizeof(fname), "%s/%s/%s", LOG_DIR, pkgname,
164 fp = fopen(fname, "r");
166 /* Probably pkgname doesn't have any packages that depend on it */
168 warnx("couldn't open dependency file '%s'", fname);
173 while (fgets(fbuf, sizeof(fbuf), fp) != NULL) {
174 if (fbuf[strlen(fbuf) - 1] == '\n')
175 fbuf[strlen(fbuf) - 1] = '\0';
176 if (filter == TRUE && !isinstalledpkg(fbuf)) {
178 warnx("package '%s' is recorded in the '%s' but isn't "
179 "actually installed", fbuf, fname);
183 rb_entry = malloc(sizeof(*rb_entry));
184 if (rb_entry == NULL) {
185 warnx("%s(): malloc() failed", __func__);
189 strlcpy(rb_entry->pkgname, fbuf, sizeof(rb_entry->pkgname));
190 STAILQ_INSERT_TAIL(&rb_list, rb_entry, link);