Deleted Added
full compact
deps.c (93520) deps.c (96076)
1/*
2 * FreeBSD install - a package for the installation and maintainance
3 * of non-core utilities.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
14 * Maxim Sobolev
15 * 14 March 2001
16 *
17 * Routines used to do various operations with dependencies
18 * among installed packages.
19 *
20 */
21
22#include <sys/cdefs.h>
1/*
2 * FreeBSD install - a package for the installation and maintainance
3 * of non-core utilities.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
14 * Maxim Sobolev
15 * 14 March 2001
16 *
17 * Routines used to do various operations with dependencies
18 * among installed packages.
19 *
20 */
21
22#include <sys/cdefs.h>
23__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/lib/deps.c 93520 2002-04-01 09:39:07Z obrien $");
23__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/lib/deps.c 96076 2002-05-05 21:03:25Z sobomax $");
24
25#include "lib.h"
26#include <err.h>
27#include <stdio.h>
28
29/*
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.
34 */
35int
36sortdeps(char **pkgs)
37{
38 char *tmp;
39 int i, j, loop_cnt;
40 int err_cnt = 0;
41
42 if (pkgs[0] == NULL || pkgs[1] == NULL)
43 return (0);
44
45 for (i = 0; pkgs[i + 1]; i++) {
46 /*
47 * Check to see if any other package in pkgs[i+1:] depends
48 * on pkgs[i] and swap those two packages if so.
49 */
50 loop_cnt = 0;
51 for (j = i + 1; pkgs[j]; j++) {
52 if (chkifdepends(pkgs[j], pkgs[i]) == 1) {
53 /*
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.
58 */
59 if (loop_cnt > 4096) {
60 warnx("dependency loop detected for package %s", pkgs[j]);
61 err_cnt++;
62 break;
63 }
64 loop_cnt++;
65 tmp = pkgs[i];
66 pkgs[i] = pkgs[j];
67 pkgs[j] = tmp;
68 /*
69 * Another iteration requred to check if new pkgs[i]
70 * itself has any packages that depend on it
71 */
72 j = i + 1;
73 }
74 }
75 }
76 return err_cnt;
77}
78
79/*
80 * Check to see if pkgname1 depends on pkgname2.
81 * Returns 1 if depends, 0 if not, and -1 if error occured.
82 */
83int
84chkifdepends(const char *pkgname1, const char *pkgname2)
85{
24
25#include "lib.h"
26#include <err.h>
27#include <stdio.h>
28
29/*
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.
34 */
35int
36sortdeps(char **pkgs)
37{
38 char *tmp;
39 int i, j, loop_cnt;
40 int err_cnt = 0;
41
42 if (pkgs[0] == NULL || pkgs[1] == NULL)
43 return (0);
44
45 for (i = 0; pkgs[i + 1]; i++) {
46 /*
47 * Check to see if any other package in pkgs[i+1:] depends
48 * on pkgs[i] and swap those two packages if so.
49 */
50 loop_cnt = 0;
51 for (j = i + 1; pkgs[j]; j++) {
52 if (chkifdepends(pkgs[j], pkgs[i]) == 1) {
53 /*
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.
58 */
59 if (loop_cnt > 4096) {
60 warnx("dependency loop detected for package %s", pkgs[j]);
61 err_cnt++;
62 break;
63 }
64 loop_cnt++;
65 tmp = pkgs[i];
66 pkgs[i] = pkgs[j];
67 pkgs[j] = tmp;
68 /*
69 * Another iteration requred to check if new pkgs[i]
70 * itself has any packages that depend on it
71 */
72 j = i + 1;
73 }
74 }
75 }
76 return err_cnt;
77}
78
79/*
80 * Check to see if pkgname1 depends on pkgname2.
81 * Returns 1 if depends, 0 if not, and -1 if error occured.
82 */
83int
84chkifdepends(const char *pkgname1, const char *pkgname2)
85{
86 char *cp1, *cp2;
86 char pkgdir[FILENAME_MAX];
87 int errcode;
88 struct reqr_by_entry *rb_entry;
89 struct reqr_by_head *rb_list;
90
87 char pkgdir[FILENAME_MAX];
88 int errcode;
89 struct reqr_by_entry *rb_entry;
90 struct reqr_by_head *rb_list;
91
92 cp2 = strchr(pkgname2, ':');
93 if (cp2 != NULL)
94 *cp2 = '\0';
95 cp1 = strchr(pkgname1, ':');
96 if (cp1 != NULL)
97 *cp1 = '\0';
98
99 errcode = 0;
91 /* Check that pkgname2 is actually installed */
92 snprintf(pkgdir, sizeof(pkgdir), "%s/%s", LOG_DIR, pkgname2);
93 if (!isdir(pkgdir))
100 /* Check that pkgname2 is actually installed */
101 snprintf(pkgdir, sizeof(pkgdir), "%s/%s", LOG_DIR, pkgname2);
102 if (!isdir(pkgdir))
94 return 0;
103 goto exit;
95
96 errcode = requiredby(pkgname2, &rb_list, FALSE, TRUE);
97 if (errcode < 0)
104
105 errcode = requiredby(pkgname2, &rb_list, FALSE, TRUE);
106 if (errcode < 0)
98 return errcode;
107 goto exit;
99
108
100 STAILQ_FOREACH(rb_entry, rb_list, link)
101 if (strcmp(rb_entry->pkgname, pkgname1) == 0) /* match */
102 return 1;
109 errcode = 0;
110 STAILQ_FOREACH(rb_entry, rb_list, link) {
111 if (strcmp(rb_entry->pkgname, pkgname1) == 0) { /* match */
112 errcode = 1;
113 break;
114 }
115 }
103
116
104 return 0;
117exit:
118 if (cp1 != NULL)
119 *cp1 = ':';
120 if (cp2 != NULL)
121 *cp2 = ':';
122 return errcode;
105}
106
107/*
108 * Load +REQUIRED_BY file and return a list with names of
109 * packages that require package reffered to by `pkgname'.
110 *
111 * Optionally check that packages listed there are actually
112 * installed and filter out those that don't (filter == TRUE).
113 *
114 * strict argument controls whether the caller want warnings
115 * to be emitted when there are some non-fatal conditions,
116 * i.e. package doesn't have +REQUIRED_BY file or some packages
117 * listed in +REQUIRED_BY don't exist.
118 *
119 * Result returned in the **list, while return value is equal
120 * to the number of entries in the resulting list. Print error
121 * message and return -1 on error.
122 */
123int
124requiredby(const char *pkgname, struct reqr_by_head **list, Boolean strict, Boolean filter)
125{
126 FILE *fp;
127 char fbuf[FILENAME_MAX], fname[FILENAME_MAX], pkgdir[FILENAME_MAX];
128 int retval;
129 struct reqr_by_entry *rb_entry;
130 static struct reqr_by_head rb_list = STAILQ_HEAD_INITIALIZER(rb_list);
131
132 *list = &rb_list;
133 /* Deallocate any previously allocated space */
134 while (!STAILQ_EMPTY(&rb_list)) {
135 rb_entry = STAILQ_FIRST(&rb_list);
136 STAILQ_REMOVE_HEAD(&rb_list, link);
137 free(rb_entry);
138 }
139
140 snprintf(fname, sizeof(fname), "%s/%s", LOG_DIR, pkgname);
141 if (!isdir(fname)) {
142 if (strict == TRUE)
143 warnx("no such package '%s' installed", pkgname);
144 return -1;
145 }
146
147 snprintf(fname, sizeof(fname), "%s/%s", fname, REQUIRED_BY_FNAME);
148 fp = fopen(fname, "r");
149 if (fp == NULL) {
150 /* Probably pkgname doesn't have any packages that depend on it */
151 if (strict == TRUE)
152 warnx("couldn't open dependency file '%s'", fname);
153 return 0;
154 }
155
156 retval = 0;
157 while (fgets(fbuf, sizeof(fbuf), fp) != NULL) {
158 if (fbuf[strlen(fbuf) - 1] == '\n')
159 fbuf[strlen(fbuf) - 1] = '\0';
160 snprintf(pkgdir, sizeof(pkgdir), "%s/%s", LOG_DIR, fbuf);
161 if (filter == TRUE && !isdir(pkgdir)) {
162 if (strict == TRUE)
163 warnx("package '%s' is recorded in the '%s' but isn't "
164 "actually installed", fbuf, fname);
165 continue;
166 }
167 retval++;
168 rb_entry = malloc(sizeof(*rb_entry));
169 if (rb_entry == NULL) {
170 warnx("%s(): malloc() failed", __FUNCTION__);
171 retval = -1;
172 break;
173 }
174 strlcpy(rb_entry->pkgname, fbuf, sizeof(rb_entry->pkgname));
175 STAILQ_INSERT_TAIL(&rb_list, rb_entry, link);
176 }
177 fclose(fp);
178
179 return retval;
180}
123}
124
125/*
126 * Load +REQUIRED_BY file and return a list with names of
127 * packages that require package reffered to by `pkgname'.
128 *
129 * Optionally check that packages listed there are actually
130 * installed and filter out those that don't (filter == TRUE).
131 *
132 * strict argument controls whether the caller want warnings
133 * to be emitted when there are some non-fatal conditions,
134 * i.e. package doesn't have +REQUIRED_BY file or some packages
135 * listed in +REQUIRED_BY don't exist.
136 *
137 * Result returned in the **list, while return value is equal
138 * to the number of entries in the resulting list. Print error
139 * message and return -1 on error.
140 */
141int
142requiredby(const char *pkgname, struct reqr_by_head **list, Boolean strict, Boolean filter)
143{
144 FILE *fp;
145 char fbuf[FILENAME_MAX], fname[FILENAME_MAX], pkgdir[FILENAME_MAX];
146 int retval;
147 struct reqr_by_entry *rb_entry;
148 static struct reqr_by_head rb_list = STAILQ_HEAD_INITIALIZER(rb_list);
149
150 *list = &rb_list;
151 /* Deallocate any previously allocated space */
152 while (!STAILQ_EMPTY(&rb_list)) {
153 rb_entry = STAILQ_FIRST(&rb_list);
154 STAILQ_REMOVE_HEAD(&rb_list, link);
155 free(rb_entry);
156 }
157
158 snprintf(fname, sizeof(fname), "%s/%s", LOG_DIR, pkgname);
159 if (!isdir(fname)) {
160 if (strict == TRUE)
161 warnx("no such package '%s' installed", pkgname);
162 return -1;
163 }
164
165 snprintf(fname, sizeof(fname), "%s/%s", fname, REQUIRED_BY_FNAME);
166 fp = fopen(fname, "r");
167 if (fp == NULL) {
168 /* Probably pkgname doesn't have any packages that depend on it */
169 if (strict == TRUE)
170 warnx("couldn't open dependency file '%s'", fname);
171 return 0;
172 }
173
174 retval = 0;
175 while (fgets(fbuf, sizeof(fbuf), fp) != NULL) {
176 if (fbuf[strlen(fbuf) - 1] == '\n')
177 fbuf[strlen(fbuf) - 1] = '\0';
178 snprintf(pkgdir, sizeof(pkgdir), "%s/%s", LOG_DIR, fbuf);
179 if (filter == TRUE && !isdir(pkgdir)) {
180 if (strict == TRUE)
181 warnx("package '%s' is recorded in the '%s' but isn't "
182 "actually installed", fbuf, fname);
183 continue;
184 }
185 retval++;
186 rb_entry = malloc(sizeof(*rb_entry));
187 if (rb_entry == NULL) {
188 warnx("%s(): malloc() failed", __FUNCTION__);
189 retval = -1;
190 break;
191 }
192 strlcpy(rb_entry->pkgname, fbuf, sizeof(rb_entry->pkgname));
193 STAILQ_INSERT_TAIL(&rb_list, rb_entry, link);
194 }
195 fclose(fp);
196
197 return retval;
198}