perform.c revision 112572
1327Sjkh/*
2327Sjkh * FreeBSD install - a package for the installation and maintainance
3327Sjkh * of non-core utilities.
4327Sjkh *
5327Sjkh * Redistribution and use in source and binary forms, with or without
6327Sjkh * modification, are permitted provided that the following conditions
7327Sjkh * are met:
8327Sjkh * 1. Redistributions of source code must retain the above copyright
9327Sjkh *    notice, this list of conditions and the following disclaimer.
10327Sjkh * 2. Redistributions in binary form must reproduce the above copyright
11327Sjkh *    notice, this list of conditions and the following disclaimer in the
12327Sjkh *    documentation and/or other materials provided with the distribution.
13327Sjkh *
14327Sjkh * Jordan K. Hubbard
15327Sjkh * 23 Aug 1993
16327Sjkh *
17327Sjkh * This is the main body of the info module.
18327Sjkh *
19327Sjkh */
20327Sjkh
2193520Sobrien#include <sys/cdefs.h>
2293520Sobrien__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/info/perform.c 112572 2003-03-25 00:51:41Z mdodd $");
2393520Sobrien
24327Sjkh#include "lib.h"
25327Sjkh#include "info.h"
2672174Ssobomax#include <err.h>
27327Sjkh#include <signal.h>
28327Sjkh
29327Sjkhstatic int pkg_do(char *);
3096613Ssobomaxstatic int find_pkg(struct which_head *);
3174699Ssobomaxstatic int cmp_path(const char *, const char *, const char *);
3284745Ssobomaxstatic char *abspath(const char *);
3396613Ssobomaxstatic int find_pkgs_by_origin(const char *);
34327Sjkh
35327Sjkhint
36327Sjkhpkg_perform(char **pkgs)
37327Sjkh{
3873134Ssobomax    char **matched;
3973134Ssobomax    int err_cnt = 0;
4073134Ssobomax    int i, errcode;
41327Sjkh
42327Sjkh    signal(SIGINT, cleanup);
43327Sjkh
44327Sjkh    /* Overriding action? */
4516404Sjkh    if (CheckPkg) {
4696613Ssobomax	return isinstalledpkg(CheckPkg) == TRUE ? 0 : 1;
4772174Ssobomax	/* Not reached */
4874699Ssobomax    } else if (!TAILQ_EMPTY(whead)) {
4996613Ssobomax	return find_pkg(whead);
5096030Ssobomax    } else if (LookUpOrigin != NULL) {
5196613Ssobomax	return find_pkgs_by_origin(LookUpOrigin);
5216404Sjkh    }
538857Srgrimes
5473134Ssobomax    if (MatchType != MATCH_EXACT) {
5573134Ssobomax	matched = matchinstalled(MatchType, pkgs, &errcode);
5673134Ssobomax	if (errcode != 0)
5773134Ssobomax	    return 1;
5873134Ssobomax	    /* Not reached */
5972174Ssobomax
6073134Ssobomax	if (matched != NULL)
6173134Ssobomax	    pkgs = matched;
6273134Ssobomax	else switch (MatchType) {
6373134Ssobomax	    case MATCH_GLOB:
6473134Ssobomax		break;
6573134Ssobomax	    case MATCH_ALL:
6673134Ssobomax		warnx("no packages installed");
6773134Ssobomax		return 0;
6873134Ssobomax		/* Not reached */
6973134Ssobomax	    case MATCH_REGEX:
7073134Ssobomax		warnx("no packages match pattern(s)");
7172174Ssobomax		return 1;
7273134Ssobomax		/* Not reached */
7373134Ssobomax	    default:
7473134Ssobomax		break;
7516404Sjkh	}
7673134Ssobomax    }
7772174Ssobomax
7873134Ssobomax    for (i = 0; pkgs[i]; i++)
7973134Ssobomax	err_cnt += pkg_do(pkgs[i]);
8072174Ssobomax
81327Sjkh    return err_cnt;
82327Sjkh}
83327Sjkh
8411780Sjkhstatic char *Home;
8511780Sjkh
86327Sjkhstatic int
87327Sjkhpkg_do(char *pkg)
88327Sjkh{
898086Sjkh    Boolean installed = FALSE, isTMP = FALSE;
90327Sjkh    char log_dir[FILENAME_MAX];
91103116Ssobomax    char fname[FILENAME_MAX], extrlist[FILENAME_MAX];
92327Sjkh    Package plist;
93327Sjkh    FILE *fp;
948086Sjkh    struct stat sb;
958142Sjkh    char *cp = NULL;
968086Sjkh    int code = 0;
97327Sjkh
988086Sjkh    if (isURL(pkg)) {
9911780Sjkh	if ((cp = fileGetURL(NULL, pkg)) != NULL) {
1008086Sjkh	    strcpy(fname, cp);
1018086Sjkh	    isTMP = TRUE;
1028086Sjkh	}
1038086Sjkh    }
1049782Sache    else if (fexists(pkg) && isfile(pkg)) {
1058086Sjkh	int len;
106327Sjkh
1078423Sjkh	if (*pkg != '/') {
1088423Sjkh	    if (!getcwd(fname, FILENAME_MAX))
1098423Sjkh		upchuck("getcwd");
1108423Sjkh	    len = strlen(fname);
1118423Sjkh	    snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg);
1128423Sjkh	}
1138423Sjkh	else
1148423Sjkh	    strcpy(fname, pkg);
1158086Sjkh	cp = fname;
1168086Sjkh    }
1178086Sjkh    else {
11811780Sjkh	if ((cp = fileFindByPath(NULL, pkg)) != NULL)
1198086Sjkh	    strncpy(fname, cp, FILENAME_MAX);
1208086Sjkh    }
1218086Sjkh    if (cp) {
1223364Sjkh	/*
1233364Sjkh	 * Apply a crude heuristic to see how much space the package will
1243364Sjkh	 * take up once it's unpacked.  I've noticed that most packages
1253577Sjkh	 * compress an average of 75%, but we're only unpacking the + files so
1263577Sjkh	 * be very optimistic.
1273364Sjkh	 */
1283364Sjkh	if (stat(fname, &sb) == FAIL) {
12930221Scharnier	    warnx("can't stat package file '%s'", fname);
1308086Sjkh	    code = 1;
1318086Sjkh	    goto bail;
1323364Sjkh	}
13311780Sjkh	Home = make_playpen(PlayPen, sb.st_size / 2);
134103116Ssobomax	snprintf(extrlist, sizeof(extrlist), "--fast-read %s %s %s",
135103116Ssobomax		 CONTENTS_FNAME, COMMENT_FNAME, DESC_FNAME);
136103116Ssobomax	if (Flags & SHOW_DISPLAY)
137103116Ssobomax	    snprintf(extrlist, sizeof(extrlist), "%s %s", extrlist,
138103116Ssobomax		     DISPLAY_FNAME);
139103116Ssobomax	if (Flags & SHOW_INSTALL)
140103116Ssobomax	    snprintf(extrlist, sizeof(extrlist), "%s %s %s", extrlist,
141103116Ssobomax		     INSTALL_FNAME, POST_INSTALL_FNAME);
142103116Ssobomax	if (Flags & SHOW_DEINSTALL)
143103116Ssobomax	    snprintf(extrlist, sizeof(extrlist), "%s %s %s", extrlist,
144103116Ssobomax		     DEINSTALL_FNAME, POST_DEINSTALL_FNAME);
145103116Ssobomax	if (Flags & SHOW_MTREE)
146103116Ssobomax	    snprintf(extrlist, sizeof(extrlist), "%s %s", extrlist,
147103116Ssobomax		     MTREE_FNAME);
148103116Ssobomax	if (unpack(fname, extrlist)) {
14930221Scharnier	    warnx("error during unpacking, no info for '%s' available", pkg);
1508086Sjkh	    code = 1;
1518086Sjkh	    goto bail;
152327Sjkh	}
153327Sjkh    }
1548086Sjkh    /* It's not an ininstalled package, try and find it among the installed */
155327Sjkh    else {
15696613Ssobomax	if (!isinstalledpkg(pkg)) {
15781046Ssobomax	    warnx("can't find package '%s' installed or in a file!", pkg);
158327Sjkh	    return 1;
159327Sjkh	}
16096613Ssobomax	sprintf(log_dir, "%s/%s", LOG_DIR, pkg);
161327Sjkh	if (chdir(log_dir) == FAIL) {
16230221Scharnier	    warnx("can't change directory to '%s'!", log_dir);
163327Sjkh	    return 1;
164327Sjkh	}
165327Sjkh	installed = TRUE;
166327Sjkh    }
167327Sjkh
168327Sjkh    /* Suck in the contents list */
169327Sjkh    plist.head = plist.tail = NULL;
170327Sjkh    fp = fopen(CONTENTS_FNAME, "r");
171327Sjkh    if (!fp) {
17230221Scharnier	warnx("unable to open %s file", CONTENTS_FNAME);
1738086Sjkh	code = 1;
1748086Sjkh	goto bail;
175327Sjkh    }
176327Sjkh    /* If we have a prefix, add it now */
177327Sjkh    read_plist(&plist, fp);
178327Sjkh    fclose(fp);
179327Sjkh
180327Sjkh    /*
181327Sjkh     * Index is special info type that has to override all others to make
182327Sjkh     * any sense.
183327Sjkh     */
184327Sjkh    if (Flags & SHOW_INDEX) {
1858086Sjkh	char tmp[FILENAME_MAX];
186327Sjkh
1878086Sjkh	snprintf(tmp, FILENAME_MAX, "%-19s ", pkg);
1888086Sjkh	show_index(tmp, COMMENT_FNAME);
189327Sjkh    }
190327Sjkh    else {
191327Sjkh	/* Start showing the package contents */
192411Sjkh	if (!Quiet)
193411Sjkh	    printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
194112572Smdodd	else if (QUIET)
195112572Smdodd	    printf("%s%s:", InfoPrefix, pkg);
196327Sjkh	if (Flags & SHOW_COMMENT)
197379Sjkh	    show_file("Comment:\n", COMMENT_FNAME);
19866339Smarko	if (Flags & SHOW_REQUIRE)
19984745Ssobomax	    show_plist("Depends on:\n", &plist, PLIST_PKGDEP, FALSE);
2004996Sjkh	if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME))
2014996Sjkh	    show_file("Required by:\n", REQUIRED_BY_FNAME);
202327Sjkh	if (Flags & SHOW_DESC)
203379Sjkh	    show_file("Description:\n", DESC_FNAME);
2044996Sjkh	if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME))
2054996Sjkh	    show_file("Install notice:\n", DISPLAY_FNAME);
206327Sjkh	if (Flags & SHOW_PLIST)
20784745Ssobomax	    show_plist("Packing list:\n", &plist, (plist_t)0, TRUE);
208327Sjkh	if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME))
209379Sjkh	    show_file("Install script:\n", INSTALL_FNAME);
21041866Sjkh	if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME))
21141866Sjkh	    show_file("Post-Install script:\n", POST_INSTALL_FNAME);
212327Sjkh	if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME))
213379Sjkh	    show_file("De-Install script:\n", DEINSTALL_FNAME);
21441866Sjkh	if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME))
21541866Sjkh	    show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME);
2164996Sjkh	if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME))
2174996Sjkh	    show_file("mtree file:\n", MTREE_FNAME);
218327Sjkh	if (Flags & SHOW_PREFIX)
21984745Ssobomax	    show_plist("Prefix(s):\n", &plist, PLIST_CWD, FALSE);
220411Sjkh	if (Flags & SHOW_FILES)
221411Sjkh	    show_files("Files:\n", &plist);
22262775Ssobomax	if ((Flags & SHOW_SIZE) && installed)
22362775Ssobomax	    show_size("Package Size:\n", &plist);
22471965Sjkh	if ((Flags & SHOW_CKSUM) && installed)
22571965Sjkh	    show_cksum("Mismatched Checksums:\n", &plist);
22667454Ssobomax	if (Flags & SHOW_ORIGIN)
22767454Ssobomax	    show_origin("Origin:\n", &plist);
22884750Ssobomax	if (Flags & SHOW_FMTREV)
22984750Ssobomax	    show_fmtrev("Packing list format revision:\n", &plist);
230411Sjkh	if (!Quiet)
231411Sjkh	    puts(InfoPrefix);
232327Sjkh    }
233327Sjkh    free_plist(&plist);
2348086Sjkh bail:
23533427Sjkh    leave_playpen();
2368086Sjkh    if (isTMP)
2378086Sjkh	unlink(fname);
2388086Sjkh    return code;
239327Sjkh}
240327Sjkh
241327Sjkhvoid
242327Sjkhcleanup(int sig)
243327Sjkh{
24433427Sjkh    static int in_cleanup = 0;
24533427Sjkh
24633427Sjkh    if (!in_cleanup) {
24733427Sjkh	in_cleanup = 1;
24872174Ssobomax	leave_playpen();
24933427Sjkh    }
25039068Sjkh    if (sig)
25139068Sjkh	exit(1);
252327Sjkh}
25349300Sjdp
25474699Ssobomax/*
25574808Ssobomax * Return an absolute path, additionally removing all .'s, ..'s, and extraneous
25674808Ssobomax * /'s, as realpath() would, but without resolving symlinks, because that can
25774808Ssobomax * potentially screw up our comparisons later.
25874808Ssobomax */
25984745Ssobomaxstatic char *
26074808Ssobomaxabspath(const char *pathname)
26174808Ssobomax{
26274808Ssobomax    char *tmp, *tmp1, *resolved_path;
26374808Ssobomax    char *cwd = NULL;
26474808Ssobomax    int len;
26574808Ssobomax
26674808Ssobomax    if (pathname[0] != '/') {
26774808Ssobomax	cwd = getcwd(NULL, MAXPATHLEN);
26874808Ssobomax	asprintf(&resolved_path, "%s/%s/", cwd, pathname);
26974808Ssobomax    } else
27074808Ssobomax	asprintf(&resolved_path, "%s/", pathname);
27174808Ssobomax
27274808Ssobomax    if (resolved_path == NULL)
27374808Ssobomax	errx(2, NULL);
27474808Ssobomax
27574808Ssobomax    if (cwd != NULL)
27674808Ssobomax	free(cwd);
27774808Ssobomax
27874808Ssobomax    while ((tmp = strstr(resolved_path, "//")) != NULL)
27974808Ssobomax	strcpy(tmp, tmp + 1);
28074808Ssobomax
28174808Ssobomax    while ((tmp = strstr(resolved_path, "/./")) != NULL)
28274808Ssobomax	strcpy(tmp, tmp + 2);
28374808Ssobomax
28474808Ssobomax    while ((tmp = strstr(resolved_path, "/../")) != NULL) {
28574808Ssobomax	*tmp = '\0';
28674808Ssobomax	if ((tmp1 = strrchr(resolved_path, '/')) == NULL)
28774808Ssobomax	   tmp1 = resolved_path;
28874808Ssobomax	strcpy(tmp1, tmp + 3);
28974808Ssobomax    }
29074808Ssobomax
29174808Ssobomax    len = strlen(resolved_path);
29274808Ssobomax    if (len > 1 && resolved_path[len - 1] == '/')
29374808Ssobomax	resolved_path[len - 1] = '\0';
29474808Ssobomax
29574808Ssobomax    return resolved_path;
29674808Ssobomax}
29774808Ssobomax
29874808Ssobomax/*
29974699Ssobomax * Comparison to see if the path we're on matches the
30074699Ssobomax * one we are looking for.
30174699Ssobomax */
30274699Ssobomaxstatic int
30374699Ssobomaxcmp_path(const char *target, const char *current, const char *cwd)
30474699Ssobomax{
30574808Ssobomax    char *resolved, *temp;
30674699Ssobomax    int rval;
30774699Ssobomax
30874699Ssobomax    asprintf(&temp, "%s/%s", cwd, current);
30974699Ssobomax    if (temp == NULL)
31074699Ssobomax        errx(2, NULL);
31174699Ssobomax
31274699Ssobomax    /*
31374808Ssobomax     * Make sure there's no multiple /'s or other weird things in the PLIST,
31474808Ssobomax     * since some plists seem to have them and it could screw up our strncmp.
31574699Ssobomax     */
31674808Ssobomax    resolved = abspath(temp);
31774699Ssobomax
31874808Ssobomax    if (strcmp(target, resolved) == 0)
31974699Ssobomax	rval = 1;
32074699Ssobomax    else
32174699Ssobomax	rval = 0;
32274699Ssobomax
32374699Ssobomax    free(temp);
32474808Ssobomax    free(resolved);
32574699Ssobomax    return rval;
32674699Ssobomax}
32774699Ssobomax
32874699Ssobomax/*
32996613Ssobomax * Look through package dbs in LOG_DIR and find which
33074699Ssobomax * packages installed the files in which_list.
33174699Ssobomax */
33274699Ssobomaxstatic int
33396613Ssobomaxfind_pkg(struct which_head *which_list)
33474699Ssobomax{
33574699Ssobomax    char **installed;
33674699Ssobomax    int errcode, i;
33774699Ssobomax    struct which_entry *wp;
33874699Ssobomax
33974699Ssobomax    TAILQ_FOREACH(wp, which_list, next) {
34084745Ssobomax	const char *msg = "file cannot be found";
34174808Ssobomax	char *tmp;
34274808Ssobomax
34374808Ssobomax	wp->skip = TRUE;
34474699Ssobomax	/* If it's not a file, we'll see if it's an executable. */
34574699Ssobomax	if (isfile(wp->file) == FALSE) {
34674699Ssobomax	    if (strchr(wp->file, '/') == NULL) {
34774699Ssobomax		tmp = vpipe("/usr/bin/which %s", wp->file);
34874808Ssobomax		if (tmp != NULL) {
34974808Ssobomax		    strlcpy(wp->file, tmp, PATH_MAX);
35074808Ssobomax		    wp->skip = FALSE;
35174808Ssobomax		    free(tmp);
35274699Ssobomax		} else
35374808Ssobomax		    msg = "file is not in PATH";
35474699Ssobomax	    }
35574808Ssobomax	} else {
35674808Ssobomax	    tmp = abspath(wp->file);
35774808Ssobomax	    if (isfile(tmp)) {
35874808Ssobomax	    	strlcpy(wp->file, tmp, PATH_MAX);
35974808Ssobomax	    	wp->skip = FALSE;
36074808Ssobomax	    }
36174699Ssobomax	    free(tmp);
36274699Ssobomax	}
36374808Ssobomax	if (wp->skip == TRUE)
36474808Ssobomax	    warnx("%s: %s", wp->file, msg);
36574699Ssobomax    }
36674699Ssobomax
36774699Ssobomax    installed = matchinstalled(MATCH_ALL, NULL, &errcode);
36874699Ssobomax    if (installed == NULL)
36974699Ssobomax        return errcode;
37074699Ssobomax
37174699Ssobomax    for (i = 0; installed[i] != NULL; i++) {
37274699Ssobomax     	FILE *fp;
37374699Ssobomax     	Package pkg;
37474699Ssobomax     	PackingList itr;
37574699Ssobomax     	char *cwd = NULL;
37674699Ssobomax     	char tmp[PATH_MAX];
37774699Ssobomax
37896613Ssobomax	snprintf(tmp, PATH_MAX, "%s/%s/%s", LOG_DIR, installed[i],
37974699Ssobomax		 CONTENTS_FNAME);
38074699Ssobomax	fp = fopen(tmp, "r");
38174699Ssobomax	if (fp == NULL) {
38274699Ssobomax	    warn("%s", tmp);
38374699Ssobomax	    return 1;
38474699Ssobomax	}
38574699Ssobomax
38674699Ssobomax	pkg.head = pkg.tail = NULL;
38774699Ssobomax	read_plist(&pkg, fp);
38874699Ssobomax	fclose(fp);
38974699Ssobomax	for (itr = pkg.head; itr != pkg.tail; itr = itr->next) {
39074699Ssobomax	    if (itr->type == PLIST_CWD) {
39174699Ssobomax		cwd = itr->name;
39274699Ssobomax	    } else if (itr->type == PLIST_FILE) {
39374699Ssobomax		TAILQ_FOREACH(wp, which_list, next) {
39474699Ssobomax		    if (wp->skip == TRUE)
39574699Ssobomax			continue;
39674699Ssobomax		    if (!cmp_path(wp->file, itr->name, cwd))
39774699Ssobomax			continue;
39874699Ssobomax		    if (wp->package[0] != '\0') {
39974809Ssobomax			warnx("both %s and %s claim to have installed %s\n",
40074699Ssobomax			      wp->package, installed[i], wp->file);
40174699Ssobomax		    } else {
40274699Ssobomax			strlcpy(wp->package, installed[i], PATH_MAX);
40374699Ssobomax		    }
40474699Ssobomax		}
40574699Ssobomax	    }
40674699Ssobomax	}
40774699Ssobomax	free_plist(&pkg);
40874699Ssobomax    }
40974699Ssobomax
41074699Ssobomax    TAILQ_FOREACH(wp, which_list, next) {
41174699Ssobomax	if (wp->package[0] != '\0') {
41274699Ssobomax	    if (Quiet)
41374699Ssobomax		puts(wp->package);
41474699Ssobomax	    else
41574699Ssobomax		printf("%s was installed by package %s\n", \
41674699Ssobomax		       wp->file, wp->package);
41774699Ssobomax	}
41874699Ssobomax    }
41974699Ssobomax    while (!TAILQ_EMPTY(which_list)) {
42074699Ssobomax	wp = TAILQ_FIRST(which_list);
42174699Ssobomax	TAILQ_REMOVE(which_list, wp, next);
42274699Ssobomax	free(wp);
42374699Ssobomax    }
42474699Ssobomax
42574699Ssobomax    free(which_list);
42674699Ssobomax    return 0;
42774699Ssobomax}
42896030Ssobomax
42996030Ssobomax/*
43096613Ssobomax * Look through package dbs in LOG_DIR and find which
43196030Ssobomax * packages have the given origin. Don't use read_plist()
43296030Ssobomax * because this increases time necessary for lookup by 40
43396030Ssobomax * times, as we don't really have to parse all plist to
43496030Ssobomax * get origin.
43596030Ssobomax */
43696030Ssobomaxstatic int
43796613Ssobomaxfind_pkgs_by_origin(const char *origin)
43896030Ssobomax{
43996613Ssobomax    char **matched;
44096030Ssobomax    int errcode, i;
44196030Ssobomax
44296030Ssobomax    if (!Quiet)
44396030Ssobomax	printf("The following installed package(s) has %s origin:\n", origin);
44496030Ssobomax
44596613Ssobomax    matched = matchbyorigin(origin, &errcode);
44696613Ssobomax    if (matched == NULL)
44796613Ssobomax	return errcode;
44896030Ssobomax
44996613Ssobomax    for (i = 0; matched[i] != NULL; i++)
45096613Ssobomax	puts(matched[i]);
45196030Ssobomax
45296030Ssobomax    return 0;
45396030Ssobomax}
454