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.
19 * $FreeBSD: src/usr.sbin/pkg_install/version/perform.c,v 1.10 2004/06/29 19:06:42 eik Exp $
20 * $DragonFly: src/usr.sbin/pkg_install/version/Attic/perform.c,v 1.1 2004/07/30 04:46:14 dillon Exp $
30 struct index_head Index = SLIST_HEAD_INITIALIZER(Index);
32 static int pkg_do(char *);
33 static void show_version(const char *, const char *, const char *);
36 * This is the traditional pkg_perform, except that the argument is _not_
37 * a list of packages. It is the index file from the command line.
39 * We loop over the installed packages, matching them with the -s flag
40 * if needed and calling pkg_do(). Before hand we set up a few things,
41 * and after we tear them down...
44 pkg_perform(char **indexarg)
46 char tmp[PATH_MAX], **pkgs, *pat[2], **patterns;
47 struct index_entry *ie;
52 * Try to find and open the INDEX. We only check IndexFile != NULL
53 * later, if we actually need the INDEX.
55 if (*indexarg == NULL)
56 snprintf(tmp, PATH_MAX, "%s/%s", PORTS_DIR, INDEX_FNAME);
58 strlcpy(tmp, *indexarg, PATH_MAX);
60 IndexFile = fetchGetURL(tmp, "");
62 IndexFile = fopen(tmp, "r");
64 /* Get either a list of matching or all packages */
65 if (MatchName != NULL) {
68 MatchType = RegexExtended ? MATCH_EREGEX : MATCH_REGEX;
72 MatchType = MATCH_ALL;
75 pkgs = matchinstalled(MatchType, patterns, &err_cnt);
78 errx(2, "Unable to find package database directory!");
82 warnx("no packages installed");
86 warnx("no packages match pattern");
93 for (i = 0; pkgs[i] != NULL; i++)
94 err_cnt += pkg_do(pkgs[i]);
96 /* If we opened the INDEX in pkg_do(), clean up. */
97 while (!SLIST_EMPTY(&Index)) {
98 ie = SLIST_FIRST(&Index);
99 SLIST_REMOVE_HEAD(&Index, next);
100 if (ie->name != NULL)
102 if (ie->origin != NULL)
106 if (IndexFile != NULL)
113 * Traditional pkg_do(). We take the package name we are passed and
114 * first slurp in the CONTENTS file, getting name and origin, then
115 * we look for it's corresponding Makefile. If that fails we pull in
116 * the INDEX, and check there.
121 char *ch, tmp[PATH_MAX], tmp2[PATH_MAX], *latest = NULL;
123 struct index_entry *ie;
127 /* Suck in the contents list. */
128 plist.head = plist.tail = NULL;
129 plist.name = plist.origin = NULL;
130 snprintf(tmp, PATH_MAX, "%s/%s/%s", LOG_DIR, pkg, CONTENTS_FNAME);
131 fp = fopen(tmp, "r");
133 warnx("the package info for package '%s' is corrupt", pkg);
136 read_plist(&plist, fp);
138 if (plist.name == NULL) {
139 warnx("%s does not appear to be a valid package!", pkg);
144 * First we check if the installed package has an origin, and try
145 * looking for it's Makefile. If we find the Makefile we get the
146 * latest version from there. If we fail, we start looking in the
147 * INDEX, first matching the origin and then the package name.
149 if (plist.origin != NULL) {
150 snprintf(tmp, PATH_MAX, "%s/%s", PORTS_DIR, plist.origin);
151 if (isdir(tmp) && chdir(tmp) != FAIL && isfile("Makefile")) {
152 if ((latest = vpipe("/usr/bin/make -V PKGNAME", tmp)) == NULL)
153 warnx("Failed to get PKGNAME from %s/Makefile!", tmp);
155 show_version(plist.name, latest, "port");
158 if (latest == NULL) {
159 /* We only pull in the INDEX once, if needed. */
160 if (SLIST_EMPTY(&Index)) {
162 errx(2, "Unable to open INDEX in %s.", __func__);
163 while ((ch = fgetln(IndexFile, &len)) != NULL) {
165 * Don't use strlcpy() because fgetln() doesn't
166 * return a valid C string.
168 strncpy(tmp, ch, MIN(len, PATH_MAX));
169 tmp[PATH_MAX-1] = '\0';
170 /* The INDEX has pkgname|portdir|... */
171 if ((ch = strchr(tmp, '|')) != NULL)
173 if (ch != NULL && (ch = strchr(&ch[1], '|')) != NULL)
175 /* Look backwards for the last two dirs = origin */
176 while (ch != NULL && *--ch != '/')
179 while (ch != NULL && *--ch != '/')
183 errx(2, "The INDEX does not appear to be valid!");
184 if ((ie = malloc(sizeof(struct index_entry))) == NULL)
185 errx(2, "Unable to allocate memory in %s.", __func__);
186 bzero(ie, sizeof(struct index_entry));
187 ie->name = strdup(tmp);
188 ie->origin = strdup(&ch[1]);
189 /* Who really cares if we reverse the index... */
190 SLIST_INSERT_HEAD(&Index, ie, next);
193 /* Now that we've slurped in the INDEX... */
194 SLIST_FOREACH(ie, &Index, next) {
195 if (plist.origin != NULL) {
196 if (strcmp(plist.origin, ie->origin) == 0)
197 latest = strdup(ie->name);
199 strlcpy(tmp, ie->name, PATH_MAX);
200 strlcpy(tmp2, plist.name, PATH_MAX);
201 /* Chop off the versions and compare. */
202 if ((ch = strrchr(tmp, '-')) == NULL)
203 errx(2, "The INDEX does not appear to be valid!");
205 if ((ch = strrchr(tmp2, '-')) == NULL)
206 warnx("%s is not a valid package!", plist.name);
209 if (strcmp(tmp2, tmp) == 0) {
210 if (latest != NULL) {
211 /* Multiple matches */
212 snprintf(tmp, PATH_MAX, "%s|%s", latest, ie->name);
214 latest = strdup(tmp);
216 latest = strdup(ie->name);
221 show_version(plist.name, NULL, plist.origin);
223 show_version(plist.name, latest, "index");
231 #define OUTPUT(c) ((PreventChars != NULL && !strchr(PreventChars, (c))) || \
232 (LimitChars != NULL && strchr(LimitChars, (c))) || \
233 (PreventChars == NULL && LimitChars == NULL))
236 * Do the work of comparing and outputing. Ugly, but well that's what
237 * You get when you try to match perl output in C ;-).
240 show_version(const char *installed, const char *latest, const char *source)
242 char *ch, tmp[PATH_MAX];
246 if (!installed || strlen(installed) == 0)
248 strlcpy(tmp, installed, PATH_MAX);
250 if ((ch = strrchr(tmp, '-')) != NULL)
253 if (latest == NULL) {
254 if (source == NULL && OUTPUT('!')) {
255 printf("%-34s !", tmp);
257 printf(" Comparison failed");
259 } else if (source != NULL && OUTPUT('?')) {
260 printf("%-34s ?", tmp);
262 printf(" orphaned: %s", source);
265 } else if (strchr(latest,'|') != NULL) {
267 printf("%-34s *", tmp);
269 strlcpy(tmp, latest, PATH_MAX);
270 ch = strchr(tmp, '|');
273 ver = strrchr(tmp, '-');
274 ver = ver ? &ver[1] : tmp;
275 printf(" multiple versions (index has %s", ver);
277 ver = strrchr(&ch[1], '-');
278 ver = ver ? &ver[1] : &ch[1];
279 if ((ch = strchr(&ch[1], '|')) != NULL)
282 } while (ch != NULL);
288 cmp = version_cmp(installed, latest);
289 ver = strrchr(latest, '-');
290 ver = ver ? &ver[1] : latest;
291 if (cmp < 0 && OUTPUT('<')) {
292 printf("%-34s <", tmp);
294 printf(" needs updating (%s has %s)", source, ver);
296 } else if (cmp == 0 && OUTPUT('=')) {
297 printf("%-34s =", tmp);
299 printf(" up-to-date with %s", source);
301 } else if (cmp > 0 && OUTPUT('>')) {
302 printf("%-34s >", tmp);
304 printf(" succeeds %s (%s has %s)", source, source, ver);
311 version_match(char *pattern, const char *pkgname)
316 Boolean isTMP = FALSE;
318 if (isURL(pkgname)) {
319 fp = fetchGetURL(pkgname, "");
323 errx(2, "Unable to open %s.", pkgname);
324 } else if (pkgname[0] == '/') {
325 fp = fopen(pkgname, "r");
329 errx(2, "Unable to open %s.", pkgname);
330 } else if (strcmp(pkgname, "-") == 0) {
333 } else if (isURL(pattern)) {
334 fp = fetchGetURL(pattern, "");
338 errx(2, "Unable to open %s.", pattern);
339 } else if (pattern[0] == '/') {
340 fp = fopen(pattern, "r");
344 errx(2, "Unable to open %s.", pattern);
345 } else if (strcmp(pattern, "-") == 0) {
349 ret = pattern_match(MATCH_GLOB, pattern, pkgname);
355 while ((line = fgetln(fp, &len)) != NULL) {
359 if (len > 0 && line[len-1] == '\n')
362 if (lnlen > sizeof(ln)-1)
363 lnlen = sizeof(ln)-1;
364 memcpy(ln, line, lnlen);
366 if ((ch = strchr(ln, '|')) != NULL)
369 match = pattern_match(MATCH_GLOB, pattern, ln);
371 match = pattern_match(MATCH_GLOB, ln, pkgname);
374 printf("%.*s\n", (int)len, line);