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