turns printfs back on
[freebsd-src/fkvm-freebsd.git] / usr.sbin / pkg_install / version / perform.c
blobe39adaf50e66b866eb6035049ea70297fe66c4c6
1 /*
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
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.
14 * Jeremy D. Lea.
15 * 11 May 2002
17 * This is the version module. Based on pkg_version.pl by Bruce A. Mah.
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
24 #include "lib.h"
25 #include "version.h"
26 #include <err.h>
27 #include <fetch.h>
28 #include <signal.h>
30 FILE *IndexFile;
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_
39 * a 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
42 * if needed and calling pkg_do(). Before hand we set up a few things,
43 * and after we tear them down...
45 int
46 pkg_perform(char **indexarg)
48 char **pkgs, *pat[2], **patterns;
49 struct index_entry *ie;
50 int i, err_cnt = 0;
51 int MatchType;
54 * Try to find and open the INDEX. We only check IndexFile != NULL
55 * later, if we actually need the INDEX.
57 if (*indexarg == NULL)
58 snprintf(IndexPath, sizeof(IndexPath), "%s/%s", PORTS_DIR, INDEX_FNAME);
59 else
60 strlcpy(IndexPath, *indexarg, sizeof(IndexPath));
61 if (isURL(IndexPath))
62 IndexFile = fetchGetURL(IndexPath, "");
63 else
64 IndexFile = fopen(IndexPath, "r");
66 /* Get either a list of matching or all packages */
67 if (MatchName != NULL) {
68 pat[0] = MatchName;
69 pat[1] = NULL;
70 MatchType = RegexExtended ? MATCH_EREGEX : MATCH_REGEX;
71 patterns = pat;
72 } else {
73 MatchType = MATCH_ALL;
74 patterns = NULL;
77 if (LookUpOrigin != NULL)
78 pkgs = matchbyorigin(LookUpOrigin, &err_cnt);
79 else
80 pkgs = matchinstalled(MatchType, patterns, &err_cnt);
82 if (err_cnt != 0)
83 errx(2, "Unable to find package database directory!");
84 if (pkgs == NULL) {
85 if (LookUpOrigin != NULL) {
86 warnx("no packages recorded with this origin");
87 return (1);
88 } else {
89 switch (MatchType) {
90 case MATCH_ALL:
91 warnx("no packages installed");
92 return (0);
93 case MATCH_EREGEX:
94 case MATCH_REGEX:
95 warnx("no packages match pattern");
96 return (1);
97 default:
98 break;
103 for (i = 0; pkgs[i] != NULL; i++)
104 err_cnt += pkg_do(pkgs[i]);
106 /* If we opened the INDEX in pkg_do(), clean up. */
107 while (!SLIST_EMPTY(&Index)) {
108 ie = SLIST_FIRST(&Index);
109 SLIST_REMOVE_HEAD(&Index, next);
110 if (ie->name != NULL)
111 free(ie->name);
112 if (ie->origin != NULL)
113 free(ie->origin);
114 free(ie);
116 if (IndexFile != NULL)
117 fclose(IndexFile);
119 return err_cnt;
123 * Traditional pkg_do(). We take the package name we are passed and
124 * first slurp in the CONTENTS file, getting name and origin, then
125 * we look for it's corresponding Makefile. If that fails we pull in
126 * the INDEX, and check there.
128 static int
129 pkg_do(char *pkg)
131 char *ch, tmp[PATH_MAX], tmp2[PATH_MAX], *latest = NULL;
132 Package plist;
133 struct index_entry *ie;
134 FILE *fp;
135 size_t len;
137 /* Suck in the contents list. */
138 plist.head = plist.tail = NULL;
139 plist.name = plist.origin = NULL;
140 snprintf(tmp, PATH_MAX, "%s/%s/%s", LOG_DIR, pkg, CONTENTS_FNAME);
141 fp = fopen(tmp, "r");
142 if (!fp) {
143 warnx("the package info for package '%s' is corrupt", pkg);
144 return 1;
146 read_plist(&plist, fp);
147 fclose(fp);
148 if (plist.name == NULL) {
149 warnx("%s does not appear to be a valid package!", pkg);
150 return 1;
154 * First we check if the installed package has an origin, and try
155 * looking for it's Makefile. If we find the Makefile we get the
156 * latest version from there. If we fail, we start looking in the
157 * INDEX, first matching the origin and then the package name.
159 if (plist.origin != NULL && !UseINDEXOnly) {
160 snprintf(tmp, PATH_MAX, "%s/%s", PORTS_DIR, plist.origin);
161 if (isdir(tmp) && chdir(tmp) != FAIL && isfile("Makefile")) {
162 if ((latest = vpipe("/usr/bin/make -V PKGNAME", tmp)) == NULL)
163 warnx("Failed to get PKGNAME from %s/Makefile!", tmp);
164 else
165 show_version(plist, latest, "port");
168 if (latest == NULL) {
169 /* Report package as not found in INDEX if the INDEX is not required. */
170 if (IndexFile == NULL && !UseINDEXOnly)
171 show_version(plist, NULL, plist.origin);
172 else {
173 /* We only pull in the INDEX once, if needed. */
174 if (SLIST_EMPTY(&Index)) {
175 if (!IndexFile)
176 errx(2, "Unable to open %s in %s.", IndexPath, __func__);
177 while ((ch = fgetln(IndexFile, &len)) != NULL) {
179 * Don't use strlcpy() because fgetln() doesn't
180 * return a valid C string.
182 strncpy(tmp, ch, MIN(len, PATH_MAX));
183 tmp[PATH_MAX-1] = '\0';
184 /* The INDEX has pkgname|portdir|... */
185 if ((ch = strchr(tmp, '|')) != NULL)
186 ch[0] = '\0';
187 if (ch != NULL && (ch = strchr(&ch[1], '|')) != NULL)
188 ch[0] = '\0';
189 /* Look backwards for the last two dirs = origin */
190 while (ch != NULL && *--ch != '/')
191 if (ch[0] == '\0')
192 ch = NULL;
193 while (ch != NULL && *--ch != '/')
194 if (ch[0] == '\0')
195 ch = NULL;
196 if (ch == NULL)
197 errx(2, "The INDEX does not appear to be valid!");
198 if ((ie = malloc(sizeof(struct index_entry))) == NULL)
199 errx(2, "Unable to allocate memory in %s.", __func__);
200 bzero(ie, sizeof(struct index_entry));
201 ie->name = strdup(tmp);
202 ie->origin = strdup(&ch[1]);
203 /* Who really cares if we reverse the index... */
204 SLIST_INSERT_HEAD(&Index, ie, next);
207 /* Now that we've slurped in the INDEX... */
208 SLIST_FOREACH(ie, &Index, next) {
209 if (plist.origin != NULL) {
210 if (strcmp(plist.origin, ie->origin) == 0)
211 latest = strdup(ie->name);
212 } else {
213 strlcpy(tmp, ie->name, PATH_MAX);
214 strlcpy(tmp2, plist.name, PATH_MAX);
215 /* Chop off the versions and compare. */
216 if ((ch = strrchr(tmp, '-')) == NULL)
217 errx(2, "The INDEX does not appear to be valid!");
218 ch[0] = '\0';
219 if ((ch = strrchr(tmp2, '-')) == NULL)
220 warnx("%s is not a valid package!", plist.name);
221 else
222 ch[0] = '\0';
223 if (strcmp(tmp2, tmp) == 0) {
224 if (latest != NULL) {
225 /* Multiple matches */
226 snprintf(tmp, PATH_MAX, "%s|%s", latest, ie->name);
227 free(latest);
228 latest = strdup(tmp);
229 } else
230 latest = strdup(ie->name);
234 if (latest == NULL)
235 show_version(plist, NULL, NULL);
236 else
237 show_version(plist, latest, "index");
240 if (latest != NULL)
241 free(latest);
242 free_plist(&plist);
243 return 0;
246 #define OUTPUT(c) ((PreventChars != NULL && !strchr(PreventChars, (c))) || \
247 (LimitChars != NULL && strchr(LimitChars, (c))) || \
248 (PreventChars == NULL && LimitChars == NULL))
251 * Do the work of comparing and outputing. Ugly, but well that's what
252 * You get when you try to match perl output in C ;-).
254 void
255 show_version(Package plist, const char *latest, const char *source)
257 char *ch, tmp[PATH_MAX];
258 const char *ver;
259 int cmp = 0;
261 if (!plist.name || strlen(plist.name) == 0)
262 return;
263 if (ShowOrigin != FALSE && plist.origin != NULL)
264 strlcpy(tmp, plist.origin, PATH_MAX);
265 else {
266 strlcpy(tmp, plist.name, PATH_MAX);
267 if (!Verbose) {
268 if ((ch = strrchr(tmp, '-')) != NULL)
269 ch[0] = '\0';
272 if (latest == NULL) {
273 if (source == NULL && OUTPUT('!')) {
274 printf("%-34s !", tmp);
275 if (Verbose)
276 printf(" Comparison failed");
277 printf("\n");
278 } else if (OUTPUT('?')) {
279 printf("%-34s ?", tmp);
280 if (Verbose)
281 printf(" orphaned: %s", plist.origin);
282 printf("\n");
284 } else if (strchr(latest,'|') != NULL) {
285 if (OUTPUT('*')) {
286 printf("%-34s *", tmp);
287 if (Verbose) {
288 strlcpy(tmp, latest, PATH_MAX);
289 ch = strchr(tmp, '|');
290 ch[0] = '\0';
292 ver = strrchr(tmp, '-');
293 ver = ver ? &ver[1] : tmp;
294 printf(" multiple versions (index has %s", ver);
295 do {
296 ver = strrchr(&ch[1], '-');
297 ver = ver ? &ver[1] : &ch[1];
298 if ((ch = strchr(&ch[1], '|')) != NULL)
299 ch[0] = '\0';
300 printf(", %s", ver);
301 } while (ch != NULL);
302 printf(")");
304 printf("\n");
306 } else {
307 cmp = version_cmp(plist.name, latest);
308 ver = strrchr(latest, '-');
309 ver = ver ? &ver[1] : latest;
310 if (cmp < 0 && OUTPUT('<')) {
311 printf("%-34s %c", tmp, Quiet ? '\0' : '<');
312 if (Verbose)
313 printf(" needs updating (%s has %s)", source, ver);
314 printf("\n");
315 } else if (cmp == 0 && OUTPUT('=')) {
316 printf("%-34s %c", tmp, Quiet ? '\0' : '=');
317 if (Verbose)
318 printf(" up-to-date with %s", source);
319 printf("\n");
320 } else if (cmp > 0 && OUTPUT('>')) {
321 printf("%-34s %c", tmp, Quiet ? '\0' : '>');
322 if (Verbose)
323 printf(" succeeds %s (%s has %s)", source, source, ver);
324 printf("\n");
330 version_match(char *pattern, const char *pkgname)
332 int ret = 0;
333 int matchstream = 0;
334 FILE *fp = NULL;
335 Boolean isTMP = FALSE;
337 if (isURL(pkgname)) {
338 fp = fetchGetURL(pkgname, "");
339 isTMP = TRUE;
340 matchstream = 1;
341 if (fp == NULL)
342 errx(2, "Unable to open %s.", pkgname);
343 } else if (pkgname[0] == '/') {
344 fp = fopen(pkgname, "r");
345 isTMP = TRUE;
346 matchstream = 1;
347 if (fp == NULL)
348 errx(2, "Unable to open %s.", pkgname);
349 } else if (strcmp(pkgname, "-") == 0) {
350 fp = stdin;
351 matchstream = 1;
352 } else if (isURL(pattern)) {
353 fp = fetchGetURL(pattern, "");
354 isTMP = TRUE;
355 matchstream = -1;
356 if (fp == NULL)
357 errx(2, "Unable to open %s.", pattern);
358 } else if (pattern[0] == '/') {
359 fp = fopen(pattern, "r");
360 isTMP = TRUE;
361 matchstream = -1;
362 if (fp == NULL)
363 errx(2, "Unable to open %s.", pattern);
364 } else if (strcmp(pattern, "-") == 0) {
365 fp = stdin;
366 matchstream = -1;
367 } else {
368 ret = pattern_match(MATCH_GLOB, pattern, pkgname);
371 if (fp != NULL) {
372 size_t len;
373 char *line;
374 while ((line = fgetln(fp, &len)) != NULL) {
375 int match;
376 char *ch, ln[2048];
377 size_t lnlen;
378 if (len > 0 && line[len-1] == '\n')
379 len --;
380 lnlen = len;
381 if (lnlen > sizeof(ln)-1)
382 lnlen = sizeof(ln)-1;
383 memcpy(ln, line, lnlen);
384 ln[lnlen] = '\0';
385 if ((ch = strchr(ln, '|')) != NULL)
386 ch[0] = '\0';
387 if (matchstream > 0)
388 match = pattern_match(MATCH_GLOB, pattern, ln);
389 else
390 match = pattern_match(MATCH_GLOB, ln, pkgname);
391 if (match == 1) {
392 ret = 1;
393 printf("%.*s\n", (int)len, line);
396 if (isTMP)
397 fclose(fp);
400 return ret;
403 void
404 cleanup(int sig)
406 if (sig)
407 exit(1);