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