perform.c revision 93520
1161304Snetchild/*
2161304Snetchild * FreeBSD install - a package for the installation and maintainance
3161304Snetchild * of non-core utilities.
4161304Snetchild *
5161304Snetchild * Redistribution and use in source and binary forms, with or without
6161304Snetchild * modification, are permitted provided that the following conditions
7161304Snetchild * are met:
8161304Snetchild * 1. Redistributions of source code must retain the above copyright
9161304Snetchild *    notice, this list of conditions and the following disclaimer.
10161304Snetchild * 2. Redistributions in binary form must reproduce the above copyright
11161304Snetchild *    notice, this list of conditions and the following disclaimer in the
12161304Snetchild *    documentation and/or other materials provided with the distribution.
13161304Snetchild *
14161304Snetchild * Jordan K. Hubbard
15161304Snetchild * 23 Aug 1993
16161304Snetchild *
17161304Snetchild * This is the main body of the info module.
18161304Snetchild *
19161304Snetchild */
20161304Snetchild
21161304Snetchild#include <sys/cdefs.h>
22161304Snetchild__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/info/perform.c 93520 2002-04-01 09:39:07Z obrien $");
23161304Snetchild
24161304Snetchild#include "lib.h"
25161304Snetchild#include "info.h"
26161304Snetchild#include <err.h>
27161304Snetchild#include <signal.h>
28161304Snetchild
29161304Snetchildstatic int pkg_do(char *);
30161304Snetchildstatic int find_pkg(const char *, struct which_head *);
31161304Snetchildstatic int cmp_path(const char *, const char *, const char *);
32161304Snetchildstatic char *abspath(const char *);
33161304Snetchild
34161304Snetchildint
35161304Snetchildpkg_perform(char **pkgs)
36161304Snetchild{
37161304Snetchild    char **matched;
38161304Snetchild    const char *tmp;
39235063Snetchild    int err_cnt = 0;
40161304Snetchild    int i, errcode;
41161304Snetchild
42235063Snetchild    signal(SIGINT, cleanup);
43161304Snetchild
44161304Snetchild    tmp = LOG_DIR;
45235063Snetchild
46161304Snetchild    /* Overriding action? */
47161304Snetchild    if (CheckPkg) {
48161304Snetchild	char buf[FILENAME_MAX];
49161304Snetchild
50161304Snetchild	snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg);
51161304Snetchild	return abs(access(buf, R_OK));
52161304Snetchild	/* Not reached */
53161304Snetchild    } else if (!TAILQ_EMPTY(whead)) {
54161304Snetchild	return find_pkg(tmp, whead);
55161304Snetchild    }
56161304Snetchild
57161304Snetchild    if (MatchType != MATCH_EXACT) {
58161304Snetchild	matched = matchinstalled(MatchType, pkgs, &errcode);
59161304Snetchild	if (errcode != 0)
60161304Snetchild	    return 1;
61161304Snetchild	    /* Not reached */
62235063Snetchild
63246085Sjhb	if (matched != NULL)
64235063Snetchild	    pkgs = matched;
65235063Snetchild	else switch (MatchType) {
66235063Snetchild	    case MATCH_GLOB:
67235063Snetchild		break;
68235063Snetchild	    case MATCH_ALL:
69235063Snetchild		warnx("no packages installed");
70235063Snetchild		return 0;
71235063Snetchild		/* Not reached */
72235063Snetchild	    case MATCH_REGEX:
73235063Snetchild		warnx("no packages match pattern(s)");
74235063Snetchild		return 1;
75235063Snetchild		/* Not reached */
76235063Snetchild	    default:
77235063Snetchild		break;
78235063Snetchild	}
79235063Snetchild    }
80235063Snetchild
81235063Snetchild    for (i = 0; pkgs[i]; i++)
82235063Snetchild	err_cnt += pkg_do(pkgs[i]);
83235063Snetchild
84235063Snetchild    return err_cnt;
85235063Snetchild}
86235063Snetchild
87235063Snetchildstatic char *Home;
88235063Snetchild
89235063Snetchildstatic int
90235063Snetchildpkg_do(char *pkg)
91235063Snetchild{
92235063Snetchild    Boolean installed = FALSE, isTMP = FALSE;
93235063Snetchild    char log_dir[FILENAME_MAX];
94235063Snetchild    char fname[FILENAME_MAX];
95235063Snetchild    Package plist;
96235063Snetchild    FILE *fp;
97235063Snetchild    struct stat sb;
98235063Snetchild    char *cp = NULL;
99235063Snetchild    int code = 0;
100235063Snetchild
101235063Snetchild    if (isURL(pkg)) {
102235063Snetchild	if ((cp = fileGetURL(NULL, pkg)) != NULL) {
103235063Snetchild	    strcpy(fname, cp);
104235063Snetchild	    isTMP = TRUE;
105235063Snetchild	}
106235063Snetchild    }
107235063Snetchild    else if (fexists(pkg) && isfile(pkg)) {
108235063Snetchild	int len;
109235063Snetchild
110235063Snetchild	if (*pkg != '/') {
111235063Snetchild	    if (!getcwd(fname, FILENAME_MAX))
112235063Snetchild		upchuck("getcwd");
113235063Snetchild	    len = strlen(fname);
114235063Snetchild	    snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg);
115235063Snetchild	}
116235063Snetchild	else
117235063Snetchild	    strcpy(fname, pkg);
118235063Snetchild	cp = fname;
119235063Snetchild    }
120161304Snetchild    else {
121161304Snetchild	if ((cp = fileFindByPath(NULL, pkg)) != NULL)
122165408Sjkim	    strncpy(fname, cp, FILENAME_MAX);
123161304Snetchild    }
124161304Snetchild    if (cp) {
125161304Snetchild	/*
126161304Snetchild	 * Apply a crude heuristic to see how much space the package will
127161304Snetchild	 * take up once it's unpacked.  I've noticed that most packages
128161304Snetchild	 * compress an average of 75%, but we're only unpacking the + files so
129235063Snetchild	 * be very optimistic.
130235063Snetchild	 */
131235063Snetchild	if (stat(fname, &sb) == FAIL) {
132161304Snetchild	    warnx("can't stat package file '%s'", fname);
133161304Snetchild	    code = 1;
134235063Snetchild	    goto bail;
135235063Snetchild	}
136161304Snetchild	Home = make_playpen(PlayPen, sb.st_size / 2);
137161304Snetchild	if (unpack(fname, "+*")) {
138165408Sjkim	    warnx("error during unpacking, no info for '%s' available", pkg);
139161304Snetchild	    code = 1;
140161304Snetchild	    goto bail;
141235063Snetchild	}
142235063Snetchild    }
143235063Snetchild    /* It's not an ininstalled package, try and find it among the installed */
144235063Snetchild    else {
145235063Snetchild	sprintf(log_dir, "%s/%s", LOG_DIR, pkg);
146165408Sjkim	if (!fexists(log_dir)) {
147235063Snetchild	    warnx("can't find package '%s' installed or in a file!", pkg);
148161304Snetchild	    return 1;
149161304Snetchild	}
150165408Sjkim	if (chdir(log_dir) == FAIL) {
151235063Snetchild	    warnx("can't change directory to '%s'!", log_dir);
152165408Sjkim	    return 1;
153161304Snetchild	}
154161304Snetchild	installed = TRUE;
155161304Snetchild    }
156161304Snetchild
157161304Snetchild    /* Suck in the contents list */
158235063Snetchild    plist.head = plist.tail = NULL;
159235063Snetchild    fp = fopen(CONTENTS_FNAME, "r");
160235063Snetchild    if (!fp) {
161161304Snetchild	warnx("unable to open %s file", CONTENTS_FNAME);
162161304Snetchild	code = 1;
163161304Snetchild	goto bail;
164161304Snetchild    }
165161304Snetchild    /* If we have a prefix, add it now */
166161304Snetchild    read_plist(&plist, fp);
167161304Snetchild    fclose(fp);
168161304Snetchild
169161304Snetchild    /*
170161304Snetchild     * Index is special info type that has to override all others to make
171161304Snetchild     * any sense.
172235063Snetchild     */
173235063Snetchild    if (Flags & SHOW_INDEX) {
174235063Snetchild	char tmp[FILENAME_MAX];
175235063Snetchild
176235063Snetchild	snprintf(tmp, FILENAME_MAX, "%-19s ", pkg);
177165408Sjkim	show_index(tmp, COMMENT_FNAME);
178235063Snetchild    }
179235063Snetchild    else {
180235063Snetchild	/* Start showing the package contents */
181165408Sjkim	if (!Quiet)
182165408Sjkim	    printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
183161304Snetchild	if (Flags & SHOW_COMMENT)
184161304Snetchild	    show_file("Comment:\n", COMMENT_FNAME);
185235063Snetchild	if (Flags & SHOW_REQUIRE)
186165408Sjkim	    show_plist("Depends on:\n", &plist, PLIST_PKGDEP, FALSE);
187161304Snetchild	if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME))
188161304Snetchild	    show_file("Required by:\n", REQUIRED_BY_FNAME);
189161304Snetchild	if (Flags & SHOW_DESC)
190161304Snetchild	    show_file("Description:\n", DESC_FNAME);
191161304Snetchild	if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME))
192161304Snetchild	    show_file("Install notice:\n", DISPLAY_FNAME);
193161304Snetchild	if (Flags & SHOW_PLIST)
194161304Snetchild	    show_plist("Packing list:\n", &plist, (plist_t)0, TRUE);
195161304Snetchild	if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME))
196161304Snetchild	    show_file("Install script:\n", INSTALL_FNAME);
197235063Snetchild	if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME))
198235063Snetchild	    show_file("Post-Install script:\n", POST_INSTALL_FNAME);
199161304Snetchild	if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME))
200235063Snetchild	    show_file("De-Install script:\n", DEINSTALL_FNAME);
201235063Snetchild	if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME))
202235063Snetchild	    show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME);
203235063Snetchild	if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME))
204165408Sjkim	    show_file("mtree file:\n", MTREE_FNAME);
205235063Snetchild	if (Flags & SHOW_PREFIX)
206161304Snetchild	    show_plist("Prefix(s):\n", &plist, PLIST_CWD, FALSE);
207235063Snetchild	if (Flags & SHOW_FILES)
208235063Snetchild	    show_files("Files:\n", &plist);
209235063Snetchild	if ((Flags & SHOW_SIZE) && installed)
210165408Sjkim	    show_size("Package Size:\n", &plist);
211235063Snetchild	if ((Flags & SHOW_CKSUM) && installed)
212161304Snetchild	    show_cksum("Mismatched Checksums:\n", &plist);
213161304Snetchild	if (Flags & SHOW_ORIGIN)
214235063Snetchild	    show_origin("Origin:\n", &plist);
215235063Snetchild	if (Flags & SHOW_FMTREV)
216235063Snetchild	    show_fmtrev("Packing list format revision:\n", &plist);
217235063Snetchild	if (!Quiet)
218235063Snetchild	    puts(InfoPrefix);
219235063Snetchild    }
220161304Snetchild    free_plist(&plist);
221161304Snetchild bail:
222161304Snetchild    leave_playpen();
223161304Snetchild    if (isTMP)
224161304Snetchild	unlink(fname);
225161304Snetchild    return code;
226161304Snetchild}
227161304Snetchild
228161304Snetchildvoid
229161304Snetchildcleanup(int sig)
230235063Snetchild{
231235063Snetchild    static int in_cleanup = 0;
232161304Snetchild
233235063Snetchild    if (!in_cleanup) {
234235063Snetchild	in_cleanup = 1;
235235063Snetchild	leave_playpen();
236235063Snetchild    }
237165408Sjkim    if (sig)
238235063Snetchild	exit(1);
239161304Snetchild}
240235063Snetchild
241235063Snetchild/*
242235063Snetchild * Return an absolute path, additionally removing all .'s, ..'s, and extraneous
243165408Sjkim * /'s, as realpath() would, but without resolving symlinks, because that can
244235063Snetchild * potentially screw up our comparisons later.
245165408Sjkim */
246235063Snetchildstatic char *
247235063Snetchildabspath(const char *pathname)
248235063Snetchild{
249235063Snetchild    char *tmp, *tmp1, *resolved_path;
250165408Sjkim    char *cwd = NULL;
251235063Snetchild    int len;
252161304Snetchild
253235063Snetchild    if (pathname[0] != '/') {
254235063Snetchild	cwd = getcwd(NULL, MAXPATHLEN);
255235063Snetchild	asprintf(&resolved_path, "%s/%s/", cwd, pathname);
256235063Snetchild    } else
257235063Snetchild	asprintf(&resolved_path, "%s/", pathname);
258235063Snetchild
259161304Snetchild    if (resolved_path == NULL)
260161304Snetchild	errx(2, NULL);
261161304Snetchild
262161304Snetchild    if (cwd != NULL)
263161304Snetchild	free(cwd);
264161304Snetchild
265161304Snetchild    while ((tmp = strstr(resolved_path, "//")) != NULL)
266161304Snetchild	strcpy(tmp, tmp + 1);
267161304Snetchild
268161304Snetchild    while ((tmp = strstr(resolved_path, "/./")) != NULL)
269235063Snetchild	strcpy(tmp, tmp + 2);
270235063Snetchild
271235063Snetchild    while ((tmp = strstr(resolved_path, "/../")) != NULL) {
272235063Snetchild	*tmp = '\0';
273235063Snetchild	if ((tmp1 = strrchr(resolved_path, '/')) == NULL)
274165408Sjkim	   tmp1 = resolved_path;
275235063Snetchild	strcpy(tmp1, tmp + 3);
276161304Snetchild    }
277161304Snetchild
278235063Snetchild    len = strlen(resolved_path);
279235063Snetchild    if (len > 1 && resolved_path[len - 1] == '/')
280235063Snetchild	resolved_path[len - 1] = '\0';
281235063Snetchild
282165408Sjkim    return resolved_path;
283235063Snetchild}
284161304Snetchild
285235063Snetchild/*
286235063Snetchild * Comparison to see if the path we're on matches the
287235063Snetchild * one we are looking for.
288165408Sjkim */
289235063Snetchildstatic int
290165408Sjkimcmp_path(const char *target, const char *current, const char *cwd)
291161304Snetchild{
292235063Snetchild    char *resolved, *temp;
293235063Snetchild    int rval;
294235063Snetchild
295235063Snetchild    asprintf(&temp, "%s/%s", cwd, current);
296235063Snetchild    if (temp == NULL)
297235063Snetchild        errx(2, NULL);
298161304Snetchild
299161304Snetchild    /*
300161304Snetchild     * Make sure there's no multiple /'s or other weird things in the PLIST,
301165408Sjkim     * since some plists seem to have them and it could screw up our strncmp.
302165408Sjkim     */
303165408Sjkim    resolved = abspath(temp);
304165408Sjkim
305165408Sjkim    if (strcmp(target, resolved) == 0)
306165408Sjkim	rval = 1;
307165408Sjkim    else
308235063Snetchild	rval = 0;
309235063Snetchild
310165408Sjkim    free(temp);
311235063Snetchild    free(resolved);
312235063Snetchild    return rval;
313235063Snetchild}
314165408Sjkim
315235063Snetchild/*
316165408Sjkim * Look through package dbs in db_dir and find which
317165408Sjkim * packages installed the files in which_list.
318165408Sjkim */
319165408Sjkimstatic int
320165408Sjkimfind_pkg(const char *db_dir, struct which_head *which_list)
321165408Sjkim{
322165408Sjkim    char **installed;
323235063Snetchild    int errcode, i;
324235063Snetchild    struct which_entry *wp;
325235063Snetchild
326165408Sjkim    TAILQ_FOREACH(wp, which_list, next) {
327235063Snetchild	const char *msg = "file cannot be found";
328165408Sjkim	char *tmp;
329235063Snetchild
330235063Snetchild	wp->skip = TRUE;
331235063Snetchild	/* If it's not a file, we'll see if it's an executable. */
332165408Sjkim	if (isfile(wp->file) == FALSE) {
333235063Snetchild	    if (strchr(wp->file, '/') == NULL) {
334165408Sjkim		tmp = vpipe("/usr/bin/which %s", wp->file);
335165408Sjkim		if (tmp != NULL) {
336165408Sjkim		    strlcpy(wp->file, tmp, PATH_MAX);
337165408Sjkim		    wp->skip = FALSE;
338235063Snetchild		    free(tmp);
339235063Snetchild		} else
340235063Snetchild		    msg = "file is not in PATH";
341235063Snetchild	    }
342165408Sjkim	} else {
343235063Snetchild	    tmp = abspath(wp->file);
344165408Sjkim	    if (isfile(tmp)) {
345165408Sjkim	    	strlcpy(wp->file, tmp, PATH_MAX);
346235063Snetchild	    	wp->skip = FALSE;
347165408Sjkim	    }
348165408Sjkim	    free(tmp);
349165408Sjkim	}
350165408Sjkim	if (wp->skip == TRUE)
351161304Snetchild	    warnx("%s: %s", wp->file, msg);
352161304Snetchild    }
353161304Snetchild
354161304Snetchild    installed = matchinstalled(MATCH_ALL, NULL, &errcode);
355161304Snetchild    if (installed == NULL)
356161304Snetchild        return errcode;
357161304Snetchild
358235063Snetchild    for (i = 0; installed[i] != NULL; i++) {
359235063Snetchild     	FILE *fp;
360235063Snetchild     	Package pkg;
361235063Snetchild     	PackingList itr;
362235063Snetchild     	char *cwd = NULL;
363235063Snetchild     	char tmp[PATH_MAX];
364235063Snetchild
365235063Snetchild	snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i],
366165408Sjkim		 CONTENTS_FNAME);
367235063Snetchild	fp = fopen(tmp, "r");
368161304Snetchild	if (fp == NULL) {
369235063Snetchild	    warn("%s", tmp);
370235063Snetchild	    return 1;
371235063Snetchild	}
372235063Snetchild
373165408Sjkim	pkg.head = pkg.tail = NULL;
374235063Snetchild	read_plist(&pkg, fp);
375161304Snetchild	fclose(fp);
376161304Snetchild	for (itr = pkg.head; itr != pkg.tail; itr = itr->next) {
377235063Snetchild	    if (itr->type == PLIST_CWD) {
378235063Snetchild		cwd = itr->name;
379235063Snetchild	    } else if (itr->type == PLIST_FILE) {
380235063Snetchild		TAILQ_FOREACH(wp, which_list, next) {
381165408Sjkim		    if (wp->skip == TRUE)
382235063Snetchild			continue;
383161304Snetchild		    if (!cmp_path(wp->file, itr->name, cwd))
384161304Snetchild			continue;
385161304Snetchild		    if (wp->package[0] != '\0') {
386161304Snetchild			warnx("both %s and %s claim to have installed %s\n",
387161304Snetchild			      wp->package, installed[i], wp->file);
388161304Snetchild		    } else {
389165408Sjkim			strlcpy(wp->package, installed[i], PATH_MAX);
390235063Snetchild		    }
391235063Snetchild		}
392235063Snetchild	    }
393235063Snetchild	}
394165408Sjkim	free_plist(&pkg);
395235063Snetchild    }
396161304Snetchild
397235063Snetchild    TAILQ_FOREACH(wp, which_list, next) {
398235063Snetchild	if (wp->package[0] != '\0') {
399235063Snetchild	    if (Quiet)
400235063Snetchild		puts(wp->package);
401165408Sjkim	    else
402235063Snetchild		printf("%s was installed by package %s\n", \
403165408Sjkim		       wp->file, wp->package);
404161304Snetchild	}
405161304Snetchild    }
406161304Snetchild    while (!TAILQ_EMPTY(which_list)) {
407235063Snetchild	wp = TAILQ_FIRST(which_list);
408235063Snetchild	TAILQ_REMOVE(which_list, wp, next);
409235063Snetchild	free(wp);
410235063Snetchild    }
411165408Sjkim
412235063Snetchild    free(which_list);
413161304Snetchild    return 0;
414161304Snetchild}
415235063Snetchild