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
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.
17 * This is the version module. Based on pkg_version.pl by Bruce A. Mah.
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
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...
46 pkg_perform(char **indexarg
)
48 char **pkgs
, *pat
[2], **patterns
;
49 struct index_entry
*ie
;
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
);
60 strlcpy(IndexPath
, *indexarg
, sizeof(IndexPath
));
62 IndexFile
= fetchGetURL(IndexPath
, "");
64 IndexFile
= fopen(IndexPath
, "r");
66 /* Get either a list of matching or all packages */
67 if (MatchName
!= NULL
) {
70 MatchType
= RegexExtended
? MATCH_EREGEX
: MATCH_REGEX
;
73 MatchType
= MATCH_ALL
;
77 if (LookUpOrigin
!= NULL
)
78 pkgs
= matchbyorigin(LookUpOrigin
, &err_cnt
);
80 pkgs
= matchinstalled(MatchType
, patterns
, &err_cnt
);
83 errx(2, "Unable to find package database directory!");
85 if (LookUpOrigin
!= NULL
) {
86 warnx("no packages recorded with this origin");
91 warnx("no packages installed");
95 warnx("no packages match pattern");
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
)
112 if (ie
->origin
!= NULL
)
116 if (IndexFile
!= NULL
)
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.
131 char *ch
, tmp
[PATH_MAX
], tmp2
[PATH_MAX
], *latest
= NULL
;
133 struct index_entry
*ie
;
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");
143 warnx("the package info for package '%s' is corrupt", pkg
);
146 read_plist(&plist
, fp
);
148 if (plist
.name
== NULL
) {
149 warnx("%s does not appear to be a valid package!", pkg
);
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
);
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
);
173 /* We only pull in the INDEX once, if needed. */
174 if (SLIST_EMPTY(&Index
)) {
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
)
187 if (ch
!= NULL
&& (ch
= strchr(&ch
[1], '|')) != NULL
)
189 /* Look backwards for the last two dirs = origin */
190 while (ch
!= NULL
&& *--ch
!= '/')
193 while (ch
!= NULL
&& *--ch
!= '/')
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
);
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!");
219 if ((ch
= strrchr(tmp2
, '-')) == NULL
)
220 warnx("%s is not a valid package!", plist
.name
);
223 if (strcmp(tmp2
, tmp
) == 0) {
224 if (latest
!= NULL
) {
225 /* Multiple matches */
226 snprintf(tmp
, PATH_MAX
, "%s|%s", latest
, ie
->name
);
228 latest
= strdup(tmp
);
230 latest
= strdup(ie
->name
);
235 show_version(plist
, NULL
, NULL
);
237 show_version(plist
, latest
, "index");
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 ;-).
255 show_version(Package plist
, const char *latest
, const char *source
)
257 char *ch
, tmp
[PATH_MAX
];
261 if (!plist
.name
|| strlen(plist
.name
) == 0)
263 if (ShowOrigin
!= FALSE
&& plist
.origin
!= NULL
)
264 strlcpy(tmp
, plist
.origin
, PATH_MAX
);
266 strlcpy(tmp
, plist
.name
, PATH_MAX
);
268 if ((ch
= strrchr(tmp
, '-')) != NULL
)
272 if (latest
== NULL
) {
273 if (source
== NULL
&& OUTPUT('!')) {
274 printf("%-34s !", tmp
);
276 printf(" Comparison failed");
278 } else if (OUTPUT('?')) {
279 printf("%-34s ?", tmp
);
281 printf(" orphaned: %s", plist
.origin
);
284 } else if (strchr(latest
,'|') != NULL
) {
286 printf("%-34s *", tmp
);
288 strlcpy(tmp
, latest
, PATH_MAX
);
289 ch
= strchr(tmp
, '|');
292 ver
= strrchr(tmp
, '-');
293 ver
= ver
? &ver
[1] : tmp
;
294 printf(" multiple versions (index has %s", ver
);
296 ver
= strrchr(&ch
[1], '-');
297 ver
= ver
? &ver
[1] : &ch
[1];
298 if ((ch
= strchr(&ch
[1], '|')) != NULL
)
301 } while (ch
!= NULL
);
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' : '<');
313 printf(" needs updating (%s has %s)", source
, ver
);
315 } else if (cmp
== 0 && OUTPUT('=')) {
316 printf("%-34s %c", tmp
, Quiet
? '\0' : '=');
318 printf(" up-to-date with %s", source
);
320 } else if (cmp
> 0 && OUTPUT('>')) {
321 printf("%-34s %c", tmp
, Quiet
? '\0' : '>');
323 printf(" succeeds %s (%s has %s)", source
, source
, ver
);
330 version_match(char *pattern
, const char *pkgname
)
335 Boolean isTMP
= FALSE
;
337 if (isURL(pkgname
)) {
338 fp
= fetchGetURL(pkgname
, "");
342 errx(2, "Unable to open %s.", pkgname
);
343 } else if (pkgname
[0] == '/') {
344 fp
= fopen(pkgname
, "r");
348 errx(2, "Unable to open %s.", pkgname
);
349 } else if (strcmp(pkgname
, "-") == 0) {
352 } else if (isURL(pattern
)) {
353 fp
= fetchGetURL(pattern
, "");
357 errx(2, "Unable to open %s.", pattern
);
358 } else if (pattern
[0] == '/') {
359 fp
= fopen(pattern
, "r");
363 errx(2, "Unable to open %s.", pattern
);
364 } else if (strcmp(pattern
, "-") == 0) {
368 ret
= pattern_match(MATCH_GLOB
, pattern
, pkgname
);
374 while ((line
= fgetln(fp
, &len
)) != NULL
) {
378 if (len
> 0 && line
[len
-1] == '\n')
381 if (lnlen
> sizeof(ln
)-1)
382 lnlen
= sizeof(ln
)-1;
383 memcpy(ln
, line
, lnlen
);
385 if ((ch
= strchr(ln
, '|')) != NULL
)
388 match
= pattern_match(MATCH_GLOB
, pattern
, ln
);
390 match
= pattern_match(MATCH_GLOB
, ln
, pkgname
);
393 printf("%.*s\n", (int)len
, line
);