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 * This is the version module. Based on pkg_version.pl by Bruce A. Mah.
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
31 char IndexPath[PATH_MAX] = "";
32 struct index_head Index = SLIST_HEAD_INITIALIZER(Index);
34 static int pkg_do(char *);
35 static void show_version(Package, const char *, const char *);
38 * This is the traditional pkg_perform, except that the argument is _not_ a
39 * list of packages. It is the index file from the command line.
41 * We loop over the installed packages, matching them with the -s flag if
42 * needed and calling pkg_do(). Beforehand we set up a few things, and after
43 * we tear them down...
45 * Returns 0 on success, non-zero on failure, corresponding to the number of
46 * failed attempts to access the INDEX.
49 pkg_perform(char **indexarg)
51 char **pkgs, *pat[2], **patterns;
52 struct index_entry *ie;
53 int i, err_cnt = 0, rel_major_ver;
58 if (uname(&u) == -1) {
59 warn("%s: failed to determine uname information", __func__);
61 } else if ((rel_major_ver = (int) strtol(u.release, NULL, 10)) <= 0) {
62 warnx("%s: bad release version specified: %s", __func__, u.release);
67 * Try to find and open the INDEX. We only check IndexFile != NULL
68 * later, if we actually need the INDEX.
70 if (*indexarg == NULL) {
71 snprintf(IndexPath, sizeof(IndexPath), "%s/INDEX-%d", PORTS_DIR,
74 strlcpy(IndexPath, *indexarg, sizeof(IndexPath));
76 IndexFile = fetchGetURL(IndexPath, "");
78 IndexFile = fopen(IndexPath, "r");
80 /* Get either a list of matching or all packages */
81 if (MatchName != NULL) {
84 MatchType = RegexExtended ? MATCH_EREGEX : MATCH_REGEX;
87 MatchType = MATCH_ALL;
91 if (LookUpOrigin != NULL)
92 pkgs = matchbyorigin(LookUpOrigin, &err_cnt);
94 pkgs = matchinstalled(MatchType, patterns, &err_cnt);
97 errx(2, "Unable to find package database directory!");
99 if (LookUpOrigin != NULL) {
100 warnx("no packages recorded with this origin");
105 warnx("no packages installed");
109 warnx("no packages match pattern");
117 for (i = 0; pkgs[i] != NULL; i++)
118 err_cnt += pkg_do(pkgs[i]);
120 /* If we opened the INDEX in pkg_do(), clean up. */
121 while (!SLIST_EMPTY(&Index)) {
122 ie = SLIST_FIRST(&Index);
123 SLIST_REMOVE_HEAD(&Index, next);
124 if (ie->name != NULL)
126 if (ie->origin != NULL)
130 if (IndexFile != NULL)
137 * Traditional pkg_do(). We take the package name we are passed and
138 * first slurp in the CONTENTS file, getting name and origin, then
139 * we look for it's corresponding Makefile. If that fails we pull in
140 * the INDEX, and check there.
145 char *ch, tmp[PATH_MAX], tmp2[PATH_MAX], *latest = NULL;
147 struct index_entry *ie;
151 /* Suck in the contents list. */
152 plist.head = plist.tail = NULL;
153 plist.name = plist.origin = NULL;
154 snprintf(tmp, PATH_MAX, "%s/%s/%s", LOG_DIR, pkg, CONTENTS_FNAME);
155 fp = fopen(tmp, "r");
157 warnx("the package info for package '%s' is corrupt", pkg);
160 read_plist(&plist, fp);
162 if (plist.name == NULL) {
163 warnx("%s does not appear to be a valid package!", pkg);
168 * First we check if the installed package has an origin, and try
169 * looking for it's Makefile. If we find the Makefile we get the
170 * latest version from there. If we fail, we start looking in the
171 * INDEX, first matching the origin and then the package name.
173 if (plist.origin != NULL && !UseINDEXOnly) {
174 snprintf(tmp, PATH_MAX, "%s/%s", PORTS_DIR, plist.origin);
175 if (isdir(tmp) && chdir(tmp) != FAIL && isfile("Makefile")) {
176 if ((latest = vpipe("/usr/bin/make -V PKGNAME", tmp)) == NULL)
177 warnx("Failed to get PKGNAME from %s/Makefile!", tmp);
179 show_version(plist, latest, "port");
182 if (latest == NULL) {
183 /* Report package as not found in INDEX if the INDEX is not required. */
184 if (IndexFile == NULL && !UseINDEXOnly)
185 show_version(plist, NULL, plist.origin);
187 /* We only pull in the INDEX once, if needed. */
188 if (SLIST_EMPTY(&Index)) {
190 errx(2, "Unable to open %s in %s.", IndexPath, __func__);
191 while ((ch = fgetln(IndexFile, &len)) != NULL) {
193 * Don't use strlcpy() because fgetln() doesn't
194 * return a valid C string.
196 strncpy(tmp, ch, MIN(len, PATH_MAX));
197 tmp[PATH_MAX-1] = '\0';
198 /* The INDEX has pkgname|portdir|... */
199 if ((ch = strchr(tmp, '|')) != NULL)
201 if (ch != NULL && (ch = strchr(&ch[1], '|')) != NULL)
203 /* Look backwards for the last two dirs = origin */
204 while (ch != NULL && *--ch != '/')
207 while (ch != NULL && *--ch != '/')
211 errx(2, "The INDEX does not appear to be valid!");
212 if ((ie = malloc(sizeof(struct index_entry))) == NULL)
213 errx(2, "Unable to allocate memory in %s.", __func__);
214 bzero(ie, sizeof(struct index_entry));
215 ie->name = strdup(tmp);
216 ie->origin = strdup(&ch[1]);
217 /* Who really cares if we reverse the index... */
218 SLIST_INSERT_HEAD(&Index, ie, next);
221 /* Now that we've slurped in the INDEX... */
222 SLIST_FOREACH(ie, &Index, next) {
223 if (plist.origin != NULL) {
224 if (strcmp(plist.origin, ie->origin) == 0)
225 latest = strdup(ie->name);
227 strlcpy(tmp, ie->name, PATH_MAX);
228 strlcpy(tmp2, plist.name, PATH_MAX);
229 /* Chop off the versions and compare. */
230 if ((ch = strrchr(tmp, '-')) == NULL)
231 errx(2, "The INDEX does not appear to be valid!");
233 if ((ch = strrchr(tmp2, '-')) == NULL)
234 warnx("%s is not a valid package!", plist.name);
237 if (strcmp(tmp2, tmp) == 0) {
238 if (latest != NULL) {
239 /* Multiple matches */
240 snprintf(tmp, PATH_MAX, "%s|%s", latest, ie->name);
242 latest = strdup(tmp);
244 latest = strdup(ie->name);
249 show_version(plist, NULL, NULL);
251 show_version(plist, latest, "index");
260 #define OUTPUT(c) ((PreventChars != NULL && !strchr(PreventChars, (c))) || \
261 (LimitChars != NULL && strchr(LimitChars, (c))) || \
262 (PreventChars == NULL && LimitChars == NULL))
265 * Do the work of comparing and outputing. Ugly, but well that's what
266 * You get when you try to match perl output in C ;-).
269 show_version(Package plist, const char *latest, const char *source)
271 char *ch, tmp[PATH_MAX];
275 if (!plist.name || strlen(plist.name) == 0)
277 if (ShowOrigin != FALSE && plist.origin != NULL)
278 strlcpy(tmp, plist.origin, PATH_MAX);
280 strlcpy(tmp, plist.name, PATH_MAX);
282 if ((ch = strrchr(tmp, '-')) != NULL)
286 if (latest == NULL) {
287 if (source == NULL && OUTPUT('!')) {
288 printf("%-34s !", tmp);
290 printf(" Comparison failed");
292 } else if (OUTPUT('?')) {
293 printf("%-34s ?", tmp);
295 printf(" orphaned: %s", plist.origin);
298 } else if (strchr(latest,'|') != NULL) {
300 printf("%-34s *", tmp);
302 strlcpy(tmp, latest, PATH_MAX);
303 ch = strchr(tmp, '|');
306 ver = strrchr(tmp, '-');
307 ver = ver ? &ver[1] : tmp;
308 printf(" multiple versions (index has %s", ver);
310 ver = strrchr(&ch[1], '-');
311 ver = ver ? &ver[1] : &ch[1];
312 if ((ch = strchr(&ch[1], '|')) != NULL)
315 } while (ch != NULL);
321 cmp = version_cmp(plist.name, latest);
322 ver = strrchr(latest, '-');
323 ver = ver ? &ver[1] : latest;
324 if (cmp < 0 && OUTPUT('<')) {
328 printf("%-34s <", tmp);
330 printf(" needs updating (%s has %s)", source, ver);
333 } else if (cmp == 0 && OUTPUT('=')) {
337 printf("%-34s =", tmp);
339 printf(" up-to-date with %s", source);
342 } else if (cmp > 0 && OUTPUT('>')) {
346 printf("%-34s >", tmp);
348 printf(" succeeds %s (%s has %s)", source, source, ver);
356 version_match(char *pattern, const char *pkgname)
361 Boolean isTMP = FALSE;
363 if (isURL(pkgname)) {
364 fp = fetchGetURL(pkgname, "");
368 errx(2, "Unable to open %s.", pkgname);
369 } else if (pkgname[0] == '/') {
370 fp = fopen(pkgname, "r");
374 errx(2, "Unable to open %s.", pkgname);
375 } else if (strcmp(pkgname, "-") == 0) {
378 } else if (isURL(pattern)) {
379 fp = fetchGetURL(pattern, "");
383 errx(2, "Unable to open %s.", pattern);
384 } else if (pattern[0] == '/') {
385 fp = fopen(pattern, "r");
389 errx(2, "Unable to open %s.", pattern);
390 } else if (strcmp(pattern, "-") == 0) {
394 ret = pattern_match(MATCH_GLOB, pattern, pkgname);
400 while ((line = fgetln(fp, &len)) != NULL) {
404 if (len > 0 && line[len-1] == '\n')
407 if (lnlen > sizeof(ln)-1)
408 lnlen = sizeof(ln)-1;
409 memcpy(ln, line, lnlen);
411 if ((ch = strchr(ln, '|')) != NULL)
414 match = pattern_match(MATCH_GLOB, pattern, ln);
416 match = pattern_match(MATCH_GLOB, ln, pkgname);
419 printf("%.*s\n", (int)len, line);