]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/pkg_install/info/perform.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / pkg_install / info / perform.c
1 /*
2  * FreeBSD install - a package for the installation and maintenance
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  * Jordan K. Hubbard
15  * 23 Aug 1993
16  *
17  * This is the main body of the info module.
18  *
19  */
20
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
23
24 #include "lib.h"
25 #include "info.h"
26 #include <err.h>
27 #include <signal.h>
28
29 static int pkg_do(char *);
30 static int find_pkg(struct which_head *);
31 static int cmp_path(const char *, const char *, const char *);
32 static char *abspath(const char *);
33 static int find_pkgs_by_origin(const char *);
34 static int matched_packages(char **pkgs);
35
36 int
37 pkg_perform(char **pkgs)
38 {
39     char **matched;
40     int err_cnt = 0;
41     int i, errcode;
42
43     signal(SIGINT, cleanup);
44
45     /* Overriding action? */
46     if (Flags & SHOW_PKGNAME) {
47         return matched_packages(pkgs);
48     } else if (CheckPkg) {
49         return isinstalledpkg(CheckPkg) > 0 ? 0 : 1;
50         /* Not reached */
51     } else if (!TAILQ_EMPTY(whead)) {
52         return find_pkg(whead);
53     } else if (LookUpOrigin != NULL) {
54         return find_pkgs_by_origin(LookUpOrigin);
55     }
56
57     if (MatchType != MATCH_EXACT) {
58         matched = matchinstalled(MatchType, pkgs, &errcode);
59         if (errcode != 0)
60             return 1;
61             /* Not reached */
62
63         if (matched != NULL)
64             pkgs = matched;
65         else switch (MatchType) {
66             case MATCH_GLOB:
67                 break;
68             case MATCH_ALL:
69                 warnx("no packages installed");
70                 return 0;
71                 /* Not reached */
72             case MATCH_REGEX:
73             case MATCH_EREGEX:
74                 warnx("no packages match pattern(s)");
75                 return 1;
76                 /* Not reached */
77             default:
78                 break;
79         }
80     }
81
82     for (i = 0; pkgs[i]; i++)
83         err_cnt += pkg_do(pkgs[i]);
84
85     return err_cnt;
86 }
87
88 static int
89 pkg_do(char *pkg)
90 {
91     Boolean installed = FALSE, isTMP = FALSE;
92     char log_dir[FILENAME_MAX];
93     char fname[FILENAME_MAX];
94     Package plist;
95     FILE *fp;
96     struct stat sb;
97     const char *cp = NULL;
98     int code = 0;
99
100     if (isURL(pkg)) {
101         if ((cp = fileGetURL(NULL, pkg, KeepPackage)) != NULL) {
102             if (!getcwd(fname, FILENAME_MAX))
103                 upchuck("getcwd");
104             isTMP = TRUE;
105         } else {
106             goto bail;
107         }
108     }
109     else if (fexists(pkg) && isfile(pkg)) {
110         int len;
111
112         if (*pkg != '/') {
113             if (!getcwd(fname, FILENAME_MAX))
114                 upchuck("getcwd");
115             len = strlen(fname);
116             snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg);
117         }
118         else
119             strcpy(fname, pkg);
120         cp = fname;
121     }
122     else {
123         if ((cp = fileFindByPath(NULL, pkg)) != NULL)
124             strncpy(fname, cp, FILENAME_MAX);
125     }
126     if (cp) {
127         if (!isURL(pkg)) {
128             /*
129              * Apply a crude heuristic to see how much space the package will
130              * take up once it's unpacked.  I've noticed that most packages
131              * compress an average of 75%, but we're only unpacking the + files so
132              * be very optimistic.
133              */
134             if (stat(fname, &sb) == FAIL) {
135                 warnx("can't stat package file '%s'", fname);
136                 code = 1;
137                 goto bail;
138             }
139             make_playpen(PlayPen, sb.st_size / 2);
140             if (unpack(fname, "'+*'")) {
141                 warnx("error during unpacking, no info for '%s' available", pkg);
142                 code = 1;
143                 goto bail;
144             }
145         }
146     }
147     /* It's not an uninstalled package, try and find it among the installed */
148     else {
149         int isinstalled = isinstalledpkg(pkg);
150         if (isinstalled < 0) {
151             warnx("the package info for package '%s' is corrupt", pkg);
152             return 1;
153         } else if (isinstalled == 0) {
154             warnx("can't find package '%s' installed or in a file!", pkg);
155             return 1;
156         }
157         sprintf(log_dir, "%s/%s", LOG_DIR, pkg);
158         if (chdir(log_dir) == FAIL) {
159             warnx("can't change directory to '%s'!", log_dir);
160             return 1;
161         }
162         installed = TRUE;
163     }
164
165     /* Suck in the contents list */
166     plist.head = plist.tail = NULL;
167     fp = fopen(CONTENTS_FNAME, "r");
168     if (!fp) {
169         warnx("unable to open %s file", CONTENTS_FNAME);
170         code = 1;
171         goto bail;
172     }
173     /* If we have a prefix, add it now */
174     read_plist(&plist, fp);
175     fclose(fp);
176
177     /*
178      * Index is special info type that has to override all others to make
179      * any sense.
180      */
181     if (Flags & SHOW_INDEX) {
182         char tmp[FILENAME_MAX];
183
184         snprintf(tmp, FILENAME_MAX, "%-19s ", pkg);
185         show_index(tmp, COMMENT_FNAME);
186     }
187     else {
188         /* Start showing the package contents */
189         if (!Quiet)
190             printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
191         else if (QUIET)
192             printf("%s%s:", InfoPrefix, pkg);
193         if (Flags & SHOW_COMMENT)
194             show_file("Comment:\n", COMMENT_FNAME);
195         if (Flags & SHOW_DEPEND)
196             show_plist("Depends on:\n", &plist, PLIST_PKGDEP, FALSE);
197         if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME))
198             show_file("Required by:\n", REQUIRED_BY_FNAME);
199         if (Flags & SHOW_DESC)
200             show_file("Description:\n", DESC_FNAME);
201         if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME))
202             show_file("Install notice:\n", DISPLAY_FNAME);
203         if (Flags & SHOW_PLIST)
204             show_plist("Packing list:\n", &plist, (plist_t)0, TRUE);
205         if (Flags & SHOW_REQUIRE && fexists(REQUIRE_FNAME))
206             show_file("Requirements script:\n", REQUIRE_FNAME);
207         if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME))
208             show_file("Install script:\n", INSTALL_FNAME);
209         if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME))
210             show_file("Post-Install script:\n", POST_INSTALL_FNAME);
211         if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME))
212             show_file("De-Install script:\n", DEINSTALL_FNAME);
213         if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME))
214             show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME);
215         if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME))
216             show_file("mtree file:\n", MTREE_FNAME);
217         if (Flags & SHOW_PREFIX)
218             show_plist("Prefix(s):\n", &plist, PLIST_CWD, FALSE);
219         if (Flags & SHOW_FILES)
220             show_files("Files:\n", &plist);
221         if ((Flags & SHOW_SIZE) && installed)
222             show_size("Package Size:\n", &plist);
223         if ((Flags & SHOW_CKSUM) && installed)
224             code += show_cksum("Mismatched Checksums:\n", &plist);
225         if (Flags & SHOW_ORIGIN)
226             show_origin("Origin:\n", &plist);
227         if (Flags & SHOW_FMTREV)
228             show_fmtrev("Packing list format revision:\n", &plist);
229         if (!Quiet)
230             puts(InfoPrefix);
231     }
232     free_plist(&plist);
233  bail:
234     leave_playpen();
235     if (isTMP)
236         unlink(fname);
237     return (code ? 1 : 0);
238 }
239
240 void
241 cleanup(int sig)
242 {
243     static int in_cleanup = 0;
244
245     if (!in_cleanup) {
246         in_cleanup = 1;
247         leave_playpen();
248     }
249     if (sig)
250         exit(1);
251 }
252
253 /*
254  * Return an absolute path, additionally removing all .'s, ..'s, and extraneous
255  * /'s, as realpath() would, but without resolving symlinks, because that can
256  * potentially screw up our comparisons later.
257  */
258 static char *
259 abspath(const char *pathname)
260 {
261     char *tmp, *tmp1, *resolved_path;
262     char *cwd = NULL;
263     int len;
264
265     if (pathname[0] != '/') {
266         cwd = getcwd(NULL, MAXPATHLEN);
267         asprintf(&resolved_path, "%s/%s/", cwd, pathname);
268     } else
269         asprintf(&resolved_path, "%s/", pathname);
270
271     if (resolved_path == NULL)
272         errx(2, NULL);
273
274     if (cwd != NULL)
275         free(cwd);    
276
277     while ((tmp = strstr(resolved_path, "//")) != NULL)
278         strcpy(tmp, tmp + 1);
279  
280     while ((tmp = strstr(resolved_path, "/./")) != NULL)
281         strcpy(tmp, tmp + 2);
282  
283     while ((tmp = strstr(resolved_path, "/../")) != NULL) {
284         *tmp = '\0';
285         if ((tmp1 = strrchr(resolved_path, '/')) == NULL)
286            tmp1 = resolved_path;
287         strcpy(tmp1, tmp + 3);
288     }
289
290     len = strlen(resolved_path);
291     if (len > 1 && resolved_path[len - 1] == '/')
292         resolved_path[len - 1] = '\0';
293
294     return resolved_path;
295 }
296
297 /*
298  * Comparison to see if the path we're on matches the
299  * one we are looking for.
300  */
301 static int
302 cmp_path(const char *target, const char *current, const char *cwd) 
303 {
304     char *resolved, *temp;
305     int rval;
306
307     asprintf(&temp, "%s/%s", cwd, current);
308     if (temp == NULL)
309         errx(2, NULL);
310
311     /*
312      * Make sure there's no multiple /'s or other weird things in the PLIST,
313      * since some plists seem to have them and it could screw up our strncmp.
314      */
315     resolved = abspath(temp);
316
317     if (strcmp(target, resolved) == 0)
318         rval = 1;
319     else
320         rval = 0;
321
322     free(temp);
323     free(resolved);
324     return rval;
325 }
326
327 /* 
328  * Look through package dbs in LOG_DIR and find which
329  * packages installed the files in which_list.
330  */
331 static int 
332 find_pkg(struct which_head *which_list)
333 {
334     char **installed;
335     int errcode, i;
336     struct which_entry *wp;
337
338     TAILQ_FOREACH(wp, which_list, next) {
339         const char *msg = "file cannot be found";
340         char *tmp;
341
342         wp->skip = TRUE;
343         /* If it's not a file, we'll see if it's an executable. */
344         if (isfile(wp->file) == FALSE) {
345             if (strchr(wp->file, '/') == NULL) {
346                 tmp = vpipe("/usr/bin/which %s", wp->file);
347                 if (tmp != NULL) {
348                     strlcpy(wp->file, tmp, PATH_MAX);
349                     wp->skip = FALSE;
350                     free(tmp);
351                 } else
352                     msg = "file is not in PATH";
353             }
354         } else {
355             tmp = abspath(wp->file);
356             if (isfile(tmp)) {
357                 strlcpy(wp->file, tmp, PATH_MAX);
358                 wp->skip = FALSE;
359             }
360             free(tmp);
361         }
362         if (wp->skip == TRUE)
363             warnx("%s: %s", wp->file, msg);
364     }
365
366     installed = matchinstalled(MATCH_ALL, NULL, &errcode);
367     if (installed == NULL)
368         return errcode;
369  
370     for (i = 0; installed[i] != NULL; i++) {
371         FILE *fp;
372         Package pkg;
373         PackingList itr;
374         char *cwd = NULL;
375         char tmp[PATH_MAX];
376
377         snprintf(tmp, PATH_MAX, "%s/%s/%s", LOG_DIR, installed[i],
378                  CONTENTS_FNAME);
379         fp = fopen(tmp, "r");
380         if (fp == NULL) {
381             warn("%s", tmp);
382             return 1;
383         }
384
385         pkg.head = pkg.tail = NULL;
386         read_plist(&pkg, fp);
387         fclose(fp);
388         for (itr = pkg.head; itr != pkg.tail; itr = itr->next) {
389             if (itr->type == PLIST_CWD) {
390                 cwd = itr->name;
391             } else if (itr->type == PLIST_FILE) {
392                 TAILQ_FOREACH(wp, which_list, next) {
393                     if (wp->skip == TRUE)
394                         continue;
395                     if (!cmp_path(wp->file, itr->name, cwd))
396                         continue;
397                     if (wp->package[0] != '\0') {
398                         warnx("both %s and %s claim to have installed %s\n",
399                               wp->package, installed[i], wp->file);
400                     } else {
401                         strlcpy(wp->package, installed[i], PATH_MAX);
402                     }
403                 }
404             }
405         }
406         free_plist(&pkg);
407     }
408
409     TAILQ_FOREACH(wp, which_list, next) {
410         if (wp->package[0] != '\0') {
411             if (Quiet)
412                 puts(wp->package);
413             else
414                 printf("%s was installed by package %s\n", \
415                        wp->file, wp->package);
416         }
417     }
418     while (!TAILQ_EMPTY(which_list)) {
419         wp = TAILQ_FIRST(which_list);
420         TAILQ_REMOVE(which_list, wp, next);
421         free(wp);
422     }
423
424     free(which_list);
425     return 0;
426 }
427
428 /* 
429  * Look through package dbs in LOG_DIR and find which
430  * packages have the given origin. Don't use read_plist()
431  * because this increases time necessary for lookup by 40
432  * times, as we don't really have to parse all plist to
433  * get origin.
434  */
435 static int 
436 find_pkgs_by_origin(const char *origin)
437 {
438     char **matched;
439     int errcode, i;
440
441     if (!Quiet)
442         printf("The following installed package(s) has %s origin:\n", origin);
443
444     matched = matchbyorigin(origin, &errcode);
445     if (matched == NULL)
446         return errcode;
447
448     for (i = 0; matched[i] != NULL; i++)
449         puts(matched[i]);
450
451     return 0;
452 }
453
454 /*
455  * List only the matching package names.
456  * Mainly intended for scripts.
457  */
458 static int
459 matched_packages(char **pkgs)
460 {
461     char **matched;
462     int i, errcode;
463
464     matched = matchinstalled(MatchType == MATCH_GLOB ? MATCH_NGLOB : MatchType, pkgs, &errcode);
465
466     if (errcode != 0 || matched == NULL)
467         return 1;
468
469     for (i = 0; matched[i]; i++)
470         if (!Quiet)
471             printf("%s\n", matched[i]);
472         else if (QUIET)
473             printf("%s%s\n", InfoPrefix, matched[i]);
474
475     return 0;
476 }