Create defaults/uuids and adjust the build to copy the file to /etc/defaults
[dragonfly/vkernel-mp.git] / usr.sbin / pkg_install / version / perform.c
blob2042b4cfcd602c55c7b292d703a83a4935e04798
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.
19 * $FreeBSD: src/usr.sbin/pkg_install/version/perform.c,v 1.11 2004/10/18 05:34:54 obrien Exp $
20 * $DragonFly: src/usr.sbin/pkg_install/version/perform.c,v 1.2 2005/03/08 20:11:30 joerg Exp $
23 #include "lib.h"
24 #include "version.h"
25 #include <err.h>
26 #include <fetch.h>
27 #include <signal.h>
29 FILE *IndexFile;
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...
43 int
44 pkg_perform(char **indexarg)
46 char tmp[PATH_MAX], **pkgs, *pat[2], **patterns;
47 struct index_entry *ie;
48 int i, err_cnt = 0;
49 int MatchType;
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);
57 else
58 strlcpy(tmp, *indexarg, PATH_MAX);
59 if (isURL(tmp))
60 IndexFile = fetchGetURL(tmp, "");
61 else
62 IndexFile = fopen(tmp, "r");
64 /* Get either a list of matching or all packages */
65 if (MatchName != NULL) {
66 pat[0] = MatchName;
67 pat[1] = NULL;
68 MatchType = RegexExtended ? MATCH_EREGEX : MATCH_REGEX;
69 patterns = pat;
71 else {
72 MatchType = MATCH_ALL;
73 patterns = NULL;
75 pkgs = matchinstalled(MatchType, patterns, &err_cnt);
77 if (err_cnt != 0)
78 errx(2, "Unable to find package database directory!");
79 if (pkgs == NULL) {
80 switch (MatchType) {
81 case MATCH_ALL:
82 warnx("no packages installed");
83 return (0);
84 case MATCH_EREGEX:
85 case MATCH_REGEX:
86 warnx("no packages match pattern");
87 return (1);
88 default:
89 break;
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)
101 free(ie->name);
102 if (ie->origin != NULL)
103 free(ie->origin);
104 free(ie);
106 if (IndexFile != NULL)
107 fclose(IndexFile);
109 return err_cnt;
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.
118 static int
119 pkg_do(char *pkg)
121 char *ch, tmp[PATH_MAX], tmp2[PATH_MAX], *latest = NULL;
122 Package plist;
123 struct index_entry *ie;
124 FILE *fp;
125 size_t len;
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");
132 if (!fp) {
133 warnx("the package info for package '%s' is corrupt", pkg);
134 return 1;
136 read_plist(&plist, fp);
137 fclose(fp);
138 if (plist.name == NULL) {
139 warnx("%s does not appear to be a valid package!", pkg);
140 return 1;
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);
154 else
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)) {
161 if (!IndexFile)
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)
172 ch[0] = '\0';
173 if (ch != NULL && (ch = strchr(&ch[1], '|')) != NULL)
174 ch[0] = '\0';
175 /* Look backwards for the last two dirs = origin */
176 while (ch != NULL && *--ch != '/')
177 if (ch[0] == '\0')
178 ch = NULL;
179 while (ch != NULL && *--ch != '/')
180 if (ch[0] == '\0')
181 ch = NULL;
182 if (ch == NULL)
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);
198 } else {
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!");
204 ch[0] = '\0';
205 if ((ch = strrchr(tmp2, '-')) == NULL)
206 warnx("%s is not a valid package!", plist.name);
207 else
208 ch[0] = '\0';
209 if (strcmp(tmp2, tmp) == 0) {
210 if (latest != NULL) {
211 /* Multiple matches */
212 snprintf(tmp, PATH_MAX, "%s|%s", latest, ie->name);
213 free(latest);
214 latest = strdup(tmp);
215 } else
216 latest = strdup(ie->name);
220 if (latest == NULL)
221 show_version(plist.name, NULL, plist.origin);
222 else
223 show_version(plist.name, latest, "index");
225 if (latest != NULL)
226 free(latest);
227 free_plist(&plist);
228 return 0;
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 ;-).
239 void
240 show_version(const char *installed, const char *latest, const char *source)
242 char *ch, tmp[PATH_MAX];
243 const char *ver;
244 int cmp = 0;
246 if (!installed || strlen(installed) == 0)
247 return;
248 strlcpy(tmp, installed, PATH_MAX);
249 if (!Verbose) {
250 if ((ch = strrchr(tmp, '-')) != NULL)
251 ch[0] = '\0';
253 if (latest == NULL) {
254 if (source == NULL && OUTPUT('!')) {
255 printf("%-34s !", tmp);
256 if (Verbose)
257 printf(" Comparison failed");
258 printf("\n");
259 } else if (source != NULL && OUTPUT('?')) {
260 printf("%-34s ?", tmp);
261 if (Verbose)
262 printf(" orphaned: %s", source);
263 printf("\n");
265 } else if (strchr(latest,'|') != NULL) {
266 if (OUTPUT('*')) {
267 printf("%-34s *", tmp);
268 if (Verbose) {
269 strlcpy(tmp, latest, PATH_MAX);
270 ch = strchr(tmp, '|');
271 ch[0] = '\0';
273 ver = strrchr(tmp, '-');
274 ver = ver ? &ver[1] : tmp;
275 printf(" multiple versions (index has %s", ver);
276 do {
277 ver = strrchr(&ch[1], '-');
278 ver = ver ? &ver[1] : &ch[1];
279 if ((ch = strchr(&ch[1], '|')) != NULL)
280 ch[0] = '\0';
281 printf(", %s", ver);
282 } while (ch != NULL);
283 printf(")");
285 printf("\n");
287 } else {
288 cmp = version_cmp(installed, latest);
289 ver = strrchr(latest, '-');
290 ver = ver ? &ver[1] : latest;
291 if (cmp < 0 && OUTPUT('<')) {
292 printf("%-34s %c", tmp, Quiet ? '\0' : '<');
293 if (Verbose)
294 printf(" needs updating (%s has %s)", source, ver);
295 printf("\n");
296 } else if (cmp == 0 && OUTPUT('=')) {
297 printf("%-34s %c", tmp, Quiet ? '\0' : '=');
298 if (Verbose)
299 printf(" up-to-date with %s", source);
300 printf("\n");
301 } else if (cmp > 0 && OUTPUT('>')) {
302 printf("%-34s %c", tmp, Quiet ? '\0' : '>');
303 if (Verbose)
304 printf(" succeeds %s (%s has %s)", source, source, ver);
305 printf("\n");
311 version_match(char *pattern, const char *pkgname)
313 int ret = 0;
314 int matchstream = 0;
315 FILE *fp = NULL;
316 Boolean isTMP = FALSE;
318 if (isURL(pkgname)) {
319 fp = fetchGetURL(pkgname, "");
320 isTMP = TRUE;
321 matchstream = 1;
322 if (fp == NULL)
323 errx(2, "Unable to open %s.", pkgname);
324 } else if (pkgname[0] == '/') {
325 fp = fopen(pkgname, "r");
326 isTMP = TRUE;
327 matchstream = 1;
328 if (fp == NULL)
329 errx(2, "Unable to open %s.", pkgname);
330 } else if (strcmp(pkgname, "-") == 0) {
331 fp = stdin;
332 matchstream = 1;
333 } else if (isURL(pattern)) {
334 fp = fetchGetURL(pattern, "");
335 isTMP = TRUE;
336 matchstream = -1;
337 if (fp == NULL)
338 errx(2, "Unable to open %s.", pattern);
339 } else if (pattern[0] == '/') {
340 fp = fopen(pattern, "r");
341 isTMP = TRUE;
342 matchstream = -1;
343 if (fp == NULL)
344 errx(2, "Unable to open %s.", pattern);
345 } else if (strcmp(pattern, "-") == 0) {
346 fp = stdin;
347 matchstream = -1;
348 } else {
349 ret = pattern_match(MATCH_GLOB, pattern, pkgname);
352 if (fp != NULL) {
353 size_t len;
354 char *line;
355 while ((line = fgetln(fp, &len)) != NULL) {
356 int match;
357 char *ch, ln[2048];
358 size_t lnlen;
359 if (len > 0 && line[len-1] == '\n')
360 len --;
361 lnlen = len;
362 if (lnlen > sizeof(ln)-1)
363 lnlen = sizeof(ln)-1;
364 memcpy(ln, line, lnlen);
365 ln[lnlen] = '\0';
366 if ((ch = strchr(ln, '|')) != NULL)
367 ch[0] = '\0';
368 if (matchstream > 0)
369 match = pattern_match(MATCH_GLOB, pattern, ln);
370 else
371 match = pattern_match(MATCH_GLOB, ln, pkgname);
372 if (match == 1) {
373 ret = 1;
374 printf("%.*s\n", (int)len, line);
377 if (isTMP)
378 fclose(fp);
381 return ret;
384 void
385 cleanup(int sig)
387 if (sig)
388 exit(1);