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