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 struct index_head Index = SLIST_HEAD_INITIALIZER(Index);
33 static int pkg_do(char *);
34 static void show_version(const char *, const char *, const char *);
37 * This is the traditional pkg_perform, except that the argument is _not_
38 * a list of packages. It is the index file from the command line.
40 * We loop over the installed packages, matching them with the -s flag
41 * if needed and calling pkg_do(). Before hand we set up a few things,
42 * and after we tear them down...
45 pkg_perform(char **indexarg)
47 char tmp[PATH_MAX], **pkgs, *pat[2], **patterns;
48 struct index_entry *ie;
53 * Try to find and open the INDEX. We only check IndexFile != NULL
54 * later, if we actually need the INDEX.
56 if (*indexarg == NULL)
57 snprintf(tmp, PATH_MAX, "%s/%s", PORTS_DIR, INDEX_FNAME);
59 strlcpy(tmp, *indexarg, PATH_MAX);
61 IndexFile = fetchGetURL(tmp, "");
63 IndexFile = fopen(tmp, "r");
65 /* Get either a list of matching or all packages */
66 if (MatchName != NULL) {
69 MatchType = RegexExtended ? MATCH_EREGEX : MATCH_REGEX;
73 MatchType = MATCH_ALL;
76 pkgs = matchinstalled(MatchType, patterns, &err_cnt);
79 errx(2, "Unable to find package database directory!");
83 warnx("no packages installed");
87 warnx("no packages match pattern");
94 for (i = 0; pkgs[i] != NULL; i++)
95 err_cnt += pkg_do(pkgs[i]);
97 /* If we opened the INDEX in pkg_do(), clean up. */
98 while (!SLIST_EMPTY(&Index)) {
99 ie = SLIST_FIRST(&Index);
100 SLIST_REMOVE_HEAD(&Index, next);
101 if (ie->name != NULL)
103 if (ie->origin != NULL)
107 if (IndexFile != NULL)
114 * Traditional pkg_do(). We take the package name we are passed and
115 * first slurp in the CONTENTS file, getting name and origin, then
116 * we look for it's corresponding Makefile. If that fails we pull in
117 * the INDEX, and check there.
122 char *ch, tmp[PATH_MAX], tmp2[PATH_MAX], *latest = NULL;
124 struct index_entry *ie;
128 /* Suck in the contents list. */
129 plist.head = plist.tail = NULL;
130 plist.name = plist.origin = NULL;
131 snprintf(tmp, PATH_MAX, "%s/%s/%s", LOG_DIR, pkg, CONTENTS_FNAME);
132 fp = fopen(tmp, "r");
134 warnx("the package info for package '%s' is corrupt", pkg);
137 read_plist(&plist, fp);
139 if (plist.name == NULL) {
140 warnx("%s does not appear to be a valid package!", pkg);
145 * First we check if the installed package has an origin, and try
146 * looking for it's Makefile. If we find the Makefile we get the
147 * latest version from there. If we fail, we start looking in the
148 * INDEX, first matching the origin and then the package name.
150 if (plist.origin != NULL && !UseINDEXOnly) {
151 snprintf(tmp, PATH_MAX, "%s/%s", PORTS_DIR, plist.origin);
152 if (isdir(tmp) && chdir(tmp) != FAIL && isfile("Makefile")) {
153 if ((latest = vpipe("/usr/bin/make -V PKGNAME", tmp)) == NULL)
154 warnx("Failed to get PKGNAME from %s/Makefile!", tmp);
156 show_version(plist.name, latest, "port");
159 if (latest == NULL) {
160 /* We only pull in the INDEX once, if needed. */
161 if (SLIST_EMPTY(&Index)) {
163 errx(2, "Unable to open INDEX in %s.", __func__);
164 while ((ch = fgetln(IndexFile, &len)) != NULL) {
166 * Don't use strlcpy() because fgetln() doesn't
167 * return a valid C string.
169 strncpy(tmp, ch, MIN(len, PATH_MAX));
170 tmp[PATH_MAX-1] = '\0';
171 /* The INDEX has pkgname|portdir|... */
172 if ((ch = strchr(tmp, '|')) != NULL)
174 if (ch != NULL && (ch = strchr(&ch[1], '|')) != NULL)
176 /* Look backwards for the last two dirs = origin */
177 while (ch != NULL && *--ch != '/')
180 while (ch != NULL && *--ch != '/')
184 errx(2, "The INDEX does not appear to be valid!");
185 if ((ie = malloc(sizeof(struct index_entry))) == NULL)
186 errx(2, "Unable to allocate memory in %s.", __func__);
187 bzero(ie, sizeof(struct index_entry));
188 ie->name = strdup(tmp);
189 ie->origin = strdup(&ch[1]);
190 /* Who really cares if we reverse the index... */
191 SLIST_INSERT_HEAD(&Index, ie, next);
194 /* Now that we've slurped in the INDEX... */
195 SLIST_FOREACH(ie, &Index, next) {
196 if (plist.origin != NULL) {
197 if (strcmp(plist.origin, ie->origin) == 0)
198 latest = strdup(ie->name);
200 strlcpy(tmp, ie->name, PATH_MAX);
201 strlcpy(tmp2, plist.name, PATH_MAX);
202 /* Chop off the versions and compare. */
203 if ((ch = strrchr(tmp, '-')) == NULL)
204 errx(2, "The INDEX does not appear to be valid!");
206 if ((ch = strrchr(tmp2, '-')) == NULL)
207 warnx("%s is not a valid package!", plist.name);
210 if (strcmp(tmp2, tmp) == 0) {
211 if (latest != NULL) {
212 /* Multiple matches */
213 snprintf(tmp, PATH_MAX, "%s|%s", latest, ie->name);
215 latest = strdup(tmp);
217 latest = strdup(ie->name);
222 show_version(plist.name, NULL, plist.origin);
224 show_version(plist.name, latest, "index");
232 #define OUTPUT(c) ((PreventChars != NULL && !strchr(PreventChars, (c))) || \
233 (LimitChars != NULL && strchr(LimitChars, (c))) || \
234 (PreventChars == NULL && LimitChars == NULL))
237 * Do the work of comparing and outputing. Ugly, but well that's what
238 * You get when you try to match perl output in C ;-).
241 show_version(const char *installed, const char *latest, const char *source)
243 char *ch, tmp[PATH_MAX];
247 if (!installed || strlen(installed) == 0)
249 strlcpy(tmp, installed, PATH_MAX);
251 if ((ch = strrchr(tmp, '-')) != NULL)
254 if (latest == NULL) {
255 if (source == NULL && OUTPUT('!')) {
256 printf("%-34s !", tmp);
258 printf(" Comparison failed");
260 } else if (source != NULL && OUTPUT('?')) {
261 printf("%-34s ?", tmp);
263 printf(" orphaned: %s", source);
266 } else if (strchr(latest,'|') != NULL) {
268 printf("%-34s *", tmp);
270 strlcpy(tmp, latest, PATH_MAX);
271 ch = strchr(tmp, '|');
274 ver = strrchr(tmp, '-');
275 ver = ver ? &ver[1] : tmp;
276 printf(" multiple versions (index has %s", ver);
278 ver = strrchr(&ch[1], '-');
279 ver = ver ? &ver[1] : &ch[1];
280 if ((ch = strchr(&ch[1], '|')) != NULL)
283 } while (ch != NULL);
289 cmp = version_cmp(installed, latest);
290 ver = strrchr(latest, '-');
291 ver = ver ? &ver[1] : latest;
292 if (cmp < 0 && OUTPUT('<')) {
293 printf("%-34s %c", tmp, Quiet ? '\0' : '<');
295 printf(" needs updating (%s has %s)", source, ver);
297 } else if (cmp == 0 && OUTPUT('=')) {
298 printf("%-34s %c", tmp, Quiet ? '\0' : '=');
300 printf(" up-to-date with %s", source);
302 } else if (cmp > 0 && OUTPUT('>')) {
303 printf("%-34s %c", tmp, Quiet ? '\0' : '>');
305 printf(" succeeds %s (%s has %s)", source, source, ver);
312 version_match(char *pattern, const char *pkgname)
317 Boolean isTMP = FALSE;
319 if (isURL(pkgname)) {
320 fp = fetchGetURL(pkgname, "");
324 errx(2, "Unable to open %s.", pkgname);
325 } else if (pkgname[0] == '/') {
326 fp = fopen(pkgname, "r");
330 errx(2, "Unable to open %s.", pkgname);
331 } else if (strcmp(pkgname, "-") == 0) {
334 } else if (isURL(pattern)) {
335 fp = fetchGetURL(pattern, "");
339 errx(2, "Unable to open %s.", pattern);
340 } else if (pattern[0] == '/') {
341 fp = fopen(pattern, "r");
345 errx(2, "Unable to open %s.", pattern);
346 } else if (strcmp(pattern, "-") == 0) {
350 ret = pattern_match(MATCH_GLOB, pattern, pkgname);
356 while ((line = fgetln(fp, &len)) != NULL) {
360 if (len > 0 && line[len-1] == '\n')
363 if (lnlen > sizeof(ln)-1)
364 lnlen = sizeof(ln)-1;
365 memcpy(ln, line, lnlen);
367 if ((ch = strchr(ln, '|')) != NULL)
370 match = pattern_match(MATCH_GLOB, pattern, ln);
372 match = pattern_match(MATCH_GLOB, ln, pkgname);
375 printf("%.*s\n", (int)len, line);