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.
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 $
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...
44 pkg_perform(char **indexarg
)
46 char tmp
[PATH_MAX
], **pkgs
, *pat
[2], **patterns
;
47 struct index_entry
*ie
;
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
);
58 strlcpy(tmp
, *indexarg
, PATH_MAX
);
60 IndexFile
= fetchGetURL(tmp
, "");
62 IndexFile
= fopen(tmp
, "r");
64 /* Get either a list of matching or all packages */
65 if (MatchName
!= NULL
) {
68 MatchType
= RegexExtended
? MATCH_EREGEX
: MATCH_REGEX
;
72 MatchType
= MATCH_ALL
;
75 pkgs
= matchinstalled(MatchType
, patterns
, &err_cnt
);
78 errx(2, "Unable to find package database directory!");
82 warnx("no packages installed");
86 warnx("no packages match pattern");
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
)
102 if (ie
->origin
!= NULL
)
106 if (IndexFile
!= NULL
)
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.
121 char *ch
, tmp
[PATH_MAX
], tmp2
[PATH_MAX
], *latest
= NULL
;
123 struct index_entry
*ie
;
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");
133 warnx("the package info for package '%s' is corrupt", pkg
);
136 read_plist(&plist
, fp
);
138 if (plist
.name
== NULL
) {
139 warnx("%s does not appear to be a valid package!", pkg
);
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
);
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
)) {
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
)
173 if (ch
!= NULL
&& (ch
= strchr(&ch
[1], '|')) != NULL
)
175 /* Look backwards for the last two dirs = origin */
176 while (ch
!= NULL
&& *--ch
!= '/')
179 while (ch
!= NULL
&& *--ch
!= '/')
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
);
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!");
205 if ((ch
= strrchr(tmp2
, '-')) == NULL
)
206 warnx("%s is not a valid package!", plist
.name
);
209 if (strcmp(tmp2
, tmp
) == 0) {
210 if (latest
!= NULL
) {
211 /* Multiple matches */
212 snprintf(tmp
, PATH_MAX
, "%s|%s", latest
, ie
->name
);
214 latest
= strdup(tmp
);
216 latest
= strdup(ie
->name
);
221 show_version(plist
.name
, NULL
, plist
.origin
);
223 show_version(plist
.name
, latest
, "index");
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 ;-).
240 show_version(const char *installed
, const char *latest
, const char *source
)
242 char *ch
, tmp
[PATH_MAX
];
246 if (!installed
|| strlen(installed
) == 0)
248 strlcpy(tmp
, installed
, PATH_MAX
);
250 if ((ch
= strrchr(tmp
, '-')) != NULL
)
253 if (latest
== NULL
) {
254 if (source
== NULL
&& OUTPUT('!')) {
255 printf("%-34s !", tmp
);
257 printf(" Comparison failed");
259 } else if (source
!= NULL
&& OUTPUT('?')) {
260 printf("%-34s ?", tmp
);
262 printf(" orphaned: %s", source
);
265 } else if (strchr(latest
,'|') != NULL
) {
267 printf("%-34s *", tmp
);
269 strlcpy(tmp
, latest
, PATH_MAX
);
270 ch
= strchr(tmp
, '|');
273 ver
= strrchr(tmp
, '-');
274 ver
= ver
? &ver
[1] : tmp
;
275 printf(" multiple versions (index has %s", ver
);
277 ver
= strrchr(&ch
[1], '-');
278 ver
= ver
? &ver
[1] : &ch
[1];
279 if ((ch
= strchr(&ch
[1], '|')) != NULL
)
282 } while (ch
!= NULL
);
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' : '<');
294 printf(" needs updating (%s has %s)", source
, ver
);
296 } else if (cmp
== 0 && OUTPUT('=')) {
297 printf("%-34s %c", tmp
, Quiet
? '\0' : '=');
299 printf(" up-to-date with %s", source
);
301 } else if (cmp
> 0 && OUTPUT('>')) {
302 printf("%-34s %c", tmp
, Quiet
? '\0' : '>');
304 printf(" succeeds %s (%s has %s)", source
, source
, ver
);
311 version_match(char *pattern
, const char *pkgname
)
316 Boolean isTMP
= FALSE
;
318 if (isURL(pkgname
)) {
319 fp
= fetchGetURL(pkgname
, "");
323 errx(2, "Unable to open %s.", pkgname
);
324 } else if (pkgname
[0] == '/') {
325 fp
= fopen(pkgname
, "r");
329 errx(2, "Unable to open %s.", pkgname
);
330 } else if (strcmp(pkgname
, "-") == 0) {
333 } else if (isURL(pattern
)) {
334 fp
= fetchGetURL(pattern
, "");
338 errx(2, "Unable to open %s.", pattern
);
339 } else if (pattern
[0] == '/') {
340 fp
= fopen(pattern
, "r");
344 errx(2, "Unable to open %s.", pattern
);
345 } else if (strcmp(pattern
, "-") == 0) {
349 ret
= pattern_match(MATCH_GLOB
, pattern
, pkgname
);
355 while ((line
= fgetln(fp
, &len
)) != NULL
) {
359 if (len
> 0 && line
[len
-1] == '\n')
362 if (lnlen
> sizeof(ln
)-1)
363 lnlen
= sizeof(ln
)-1;
364 memcpy(ln
, line
, lnlen
);
366 if ((ch
= strchr(ln
, '|')) != NULL
)
369 match
= pattern_match(MATCH_GLOB
, pattern
, ln
);
371 match
= pattern_match(MATCH_GLOB
, ln
, pkgname
);
374 printf("%.*s\n", (int)len
, line
);