perform.c revision 96030
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 96030 2002-05-04 14:49:49Z sobomax $");
2393520Sobrien
24327Sjkh#include "lib.h"
25327Sjkh#include "info.h"
2672174Ssobomax#include <err.h>
27327Sjkh#include <signal.h>
28327Sjkh
29327Sjkhstatic int pkg_do(char *);
3084745Ssobomaxstatic int find_pkg(const char *, struct which_head *);
3174699Ssobomaxstatic int cmp_path(const char *, const char *, const char *);
3284745Ssobomaxstatic char *abspath(const char *);
3396030Ssobomaxstatic int find_pkgs_by_origin(const char *, const char *);
34327Sjkh
35327Sjkhint
36327Sjkhpkg_perform(char **pkgs)
37327Sjkh{
3873134Ssobomax    char **matched;
3984745Ssobomax    const char *tmp;
4073134Ssobomax    int err_cnt = 0;
4173134Ssobomax    int i, errcode;
42327Sjkh
43327Sjkh    signal(SIGINT, cleanup);
44327Sjkh
4581049Ssobomax    tmp = LOG_DIR;
4674699Ssobomax
47327Sjkh    /* Overriding action? */
4816404Sjkh    if (CheckPkg) {
4916404Sjkh	char buf[FILENAME_MAX];
50327Sjkh
5116404Sjkh	snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg);
5216404Sjkh	return abs(access(buf, R_OK));
5372174Ssobomax	/* Not reached */
5474699Ssobomax    } else if (!TAILQ_EMPTY(whead)) {
5574699Ssobomax	return find_pkg(tmp, whead);
5696030Ssobomax    } else if (LookUpOrigin != NULL) {
5796030Ssobomax	return find_pkgs_by_origin(tmp, LookUpOrigin);
5816404Sjkh    }
598857Srgrimes
6073134Ssobomax    if (MatchType != MATCH_EXACT) {
6173134Ssobomax	matched = matchinstalled(MatchType, pkgs, &errcode);
6273134Ssobomax	if (errcode != 0)
6373134Ssobomax	    return 1;
6473134Ssobomax	    /* Not reached */
6572174Ssobomax
6673134Ssobomax	if (matched != NULL)
6773134Ssobomax	    pkgs = matched;
6873134Ssobomax	else switch (MatchType) {
6973134Ssobomax	    case MATCH_GLOB:
7073134Ssobomax		break;
7173134Ssobomax	    case MATCH_ALL:
7273134Ssobomax		warnx("no packages installed");
7373134Ssobomax		return 0;
7473134Ssobomax		/* Not reached */
7573134Ssobomax	    case MATCH_REGEX:
7673134Ssobomax		warnx("no packages match pattern(s)");
7772174Ssobomax		return 1;
7873134Ssobomax		/* Not reached */
7973134Ssobomax	    default:
8073134Ssobomax		break;
8116404Sjkh	}
8273134Ssobomax    }
8372174Ssobomax
8473134Ssobomax    for (i = 0; pkgs[i]; i++)
8573134Ssobomax	err_cnt += pkg_do(pkgs[i]);
8672174Ssobomax
87327Sjkh    return err_cnt;
88327Sjkh}
89327Sjkh
9011780Sjkhstatic char *Home;
9111780Sjkh
92327Sjkhstatic int
93327Sjkhpkg_do(char *pkg)
94327Sjkh{
958086Sjkh    Boolean installed = FALSE, isTMP = FALSE;
96327Sjkh    char log_dir[FILENAME_MAX];
978086Sjkh    char fname[FILENAME_MAX];
98327Sjkh    Package plist;
99327Sjkh    FILE *fp;
1008086Sjkh    struct stat sb;
1018142Sjkh    char *cp = NULL;
1028086Sjkh    int code = 0;
103327Sjkh
1048086Sjkh    if (isURL(pkg)) {
10511780Sjkh	if ((cp = fileGetURL(NULL, pkg)) != NULL) {
1068086Sjkh	    strcpy(fname, cp);
1078086Sjkh	    isTMP = TRUE;
1088086Sjkh	}
1098086Sjkh    }
1109782Sache    else if (fexists(pkg) && isfile(pkg)) {
1118086Sjkh	int len;
112327Sjkh
1138423Sjkh	if (*pkg != '/') {
1148423Sjkh	    if (!getcwd(fname, FILENAME_MAX))
1158423Sjkh		upchuck("getcwd");
1168423Sjkh	    len = strlen(fname);
1178423Sjkh	    snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg);
1188423Sjkh	}
1198423Sjkh	else
1208423Sjkh	    strcpy(fname, pkg);
1218086Sjkh	cp = fname;
1228086Sjkh    }
1238086Sjkh    else {
12411780Sjkh	if ((cp = fileFindByPath(NULL, pkg)) != NULL)
1258086Sjkh	    strncpy(fname, cp, FILENAME_MAX);
1268086Sjkh    }
1278086Sjkh    if (cp) {
1283364Sjkh	/*
1293364Sjkh	 * Apply a crude heuristic to see how much space the package will
1303364Sjkh	 * take up once it's unpacked.  I've noticed that most packages
1313577Sjkh	 * compress an average of 75%, but we're only unpacking the + files so
1323577Sjkh	 * be very optimistic.
1333364Sjkh	 */
1343364Sjkh	if (stat(fname, &sb) == FAIL) {
13530221Scharnier	    warnx("can't stat package file '%s'", fname);
1368086Sjkh	    code = 1;
1378086Sjkh	    goto bail;
1383364Sjkh	}
13911780Sjkh	Home = make_playpen(PlayPen, sb.st_size / 2);
140327Sjkh	if (unpack(fname, "+*")) {
14130221Scharnier	    warnx("error during unpacking, no info for '%s' available", pkg);
1428086Sjkh	    code = 1;
1438086Sjkh	    goto bail;
144327Sjkh	}
145327Sjkh    }
1468086Sjkh    /* It's not an ininstalled package, try and find it among the installed */
147327Sjkh    else {
14881049Ssobomax	sprintf(log_dir, "%s/%s", LOG_DIR, pkg);
149327Sjkh	if (!fexists(log_dir)) {
15081046Ssobomax	    warnx("can't find package '%s' installed or in a file!", pkg);
151327Sjkh	    return 1;
152327Sjkh	}
153327Sjkh	if (chdir(log_dir) == FAIL) {
15430221Scharnier	    warnx("can't change directory to '%s'!", log_dir);
155327Sjkh	    return 1;
156327Sjkh	}
157327Sjkh	installed = TRUE;
158327Sjkh    }
159327Sjkh
160327Sjkh    /* Suck in the contents list */
161327Sjkh    plist.head = plist.tail = NULL;
162327Sjkh    fp = fopen(CONTENTS_FNAME, "r");
163327Sjkh    if (!fp) {
16430221Scharnier	warnx("unable to open %s file", CONTENTS_FNAME);
1658086Sjkh	code = 1;
1668086Sjkh	goto bail;
167327Sjkh    }
168327Sjkh    /* If we have a prefix, add it now */
169327Sjkh    read_plist(&plist, fp);
170327Sjkh    fclose(fp);
171327Sjkh
172327Sjkh    /*
173327Sjkh     * Index is special info type that has to override all others to make
174327Sjkh     * any sense.
175327Sjkh     */
176327Sjkh    if (Flags & SHOW_INDEX) {
1778086Sjkh	char tmp[FILENAME_MAX];
178327Sjkh
1798086Sjkh	snprintf(tmp, FILENAME_MAX, "%-19s ", pkg);
1808086Sjkh	show_index(tmp, COMMENT_FNAME);
181327Sjkh    }
182327Sjkh    else {
183327Sjkh	/* Start showing the package contents */
184411Sjkh	if (!Quiet)
185411Sjkh	    printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
186327Sjkh	if (Flags & SHOW_COMMENT)
187379Sjkh	    show_file("Comment:\n", COMMENT_FNAME);
18866339Smarko	if (Flags & SHOW_REQUIRE)
18984745Ssobomax	    show_plist("Depends on:\n", &plist, PLIST_PKGDEP, FALSE);
1904996Sjkh	if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME))
1914996Sjkh	    show_file("Required by:\n", REQUIRED_BY_FNAME);
192327Sjkh	if (Flags & SHOW_DESC)
193379Sjkh	    show_file("Description:\n", DESC_FNAME);
1944996Sjkh	if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME))
1954996Sjkh	    show_file("Install notice:\n", DISPLAY_FNAME);
196327Sjkh	if (Flags & SHOW_PLIST)
19784745Ssobomax	    show_plist("Packing list:\n", &plist, (plist_t)0, TRUE);
198327Sjkh	if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME))
199379Sjkh	    show_file("Install script:\n", INSTALL_FNAME);
20041866Sjkh	if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME))
20141866Sjkh	    show_file("Post-Install script:\n", POST_INSTALL_FNAME);
202327Sjkh	if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME))
203379Sjkh	    show_file("De-Install script:\n", DEINSTALL_FNAME);
20441866Sjkh	if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME))
20541866Sjkh	    show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME);
2064996Sjkh	if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME))
2074996Sjkh	    show_file("mtree file:\n", MTREE_FNAME);
208327Sjkh	if (Flags & SHOW_PREFIX)
20984745Ssobomax	    show_plist("Prefix(s):\n", &plist, PLIST_CWD, FALSE);
210411Sjkh	if (Flags & SHOW_FILES)
211411Sjkh	    show_files("Files:\n", &plist);
21262775Ssobomax	if ((Flags & SHOW_SIZE) && installed)
21362775Ssobomax	    show_size("Package Size:\n", &plist);
21471965Sjkh	if ((Flags & SHOW_CKSUM) && installed)
21571965Sjkh	    show_cksum("Mismatched Checksums:\n", &plist);
21667454Ssobomax	if (Flags & SHOW_ORIGIN)
21767454Ssobomax	    show_origin("Origin:\n", &plist);
21884750Ssobomax	if (Flags & SHOW_FMTREV)
21984750Ssobomax	    show_fmtrev("Packing list format revision:\n", &plist);
220411Sjkh	if (!Quiet)
221411Sjkh	    puts(InfoPrefix);
222327Sjkh    }
223327Sjkh    free_plist(&plist);
2248086Sjkh bail:
22533427Sjkh    leave_playpen();
2268086Sjkh    if (isTMP)
2278086Sjkh	unlink(fname);
2288086Sjkh    return code;
229327Sjkh}
230327Sjkh
231327Sjkhvoid
232327Sjkhcleanup(int sig)
233327Sjkh{
23433427Sjkh    static int in_cleanup = 0;
23533427Sjkh
23633427Sjkh    if (!in_cleanup) {
23733427Sjkh	in_cleanup = 1;
23872174Ssobomax	leave_playpen();
23933427Sjkh    }
24039068Sjkh    if (sig)
24139068Sjkh	exit(1);
242327Sjkh}
24349300Sjdp
24474699Ssobomax/*
24574808Ssobomax * Return an absolute path, additionally removing all .'s, ..'s, and extraneous
24674808Ssobomax * /'s, as realpath() would, but without resolving symlinks, because that can
24774808Ssobomax * potentially screw up our comparisons later.
24874808Ssobomax */
24984745Ssobomaxstatic char *
25074808Ssobomaxabspath(const char *pathname)
25174808Ssobomax{
25274808Ssobomax    char *tmp, *tmp1, *resolved_path;
25374808Ssobomax    char *cwd = NULL;
25474808Ssobomax    int len;
25574808Ssobomax
25674808Ssobomax    if (pathname[0] != '/') {
25774808Ssobomax	cwd = getcwd(NULL, MAXPATHLEN);
25874808Ssobomax	asprintf(&resolved_path, "%s/%s/", cwd, pathname);
25974808Ssobomax    } else
26074808Ssobomax	asprintf(&resolved_path, "%s/", pathname);
26174808Ssobomax
26274808Ssobomax    if (resolved_path == NULL)
26374808Ssobomax	errx(2, NULL);
26474808Ssobomax
26574808Ssobomax    if (cwd != NULL)
26674808Ssobomax	free(cwd);
26774808Ssobomax
26874808Ssobomax    while ((tmp = strstr(resolved_path, "//")) != NULL)
26974808Ssobomax	strcpy(tmp, tmp + 1);
27074808Ssobomax
27174808Ssobomax    while ((tmp = strstr(resolved_path, "/./")) != NULL)
27274808Ssobomax	strcpy(tmp, tmp + 2);
27374808Ssobomax
27474808Ssobomax    while ((tmp = strstr(resolved_path, "/../")) != NULL) {
27574808Ssobomax	*tmp = '\0';
27674808Ssobomax	if ((tmp1 = strrchr(resolved_path, '/')) == NULL)
27774808Ssobomax	   tmp1 = resolved_path;
27874808Ssobomax	strcpy(tmp1, tmp + 3);
27974808Ssobomax    }
28074808Ssobomax
28174808Ssobomax    len = strlen(resolved_path);
28274808Ssobomax    if (len > 1 && resolved_path[len - 1] == '/')
28374808Ssobomax	resolved_path[len - 1] = '\0';
28474808Ssobomax
28574808Ssobomax    return resolved_path;
28674808Ssobomax}
28774808Ssobomax
28874808Ssobomax/*
28974699Ssobomax * Comparison to see if the path we're on matches the
29074699Ssobomax * one we are looking for.
29174699Ssobomax */
29274699Ssobomaxstatic int
29374699Ssobomaxcmp_path(const char *target, const char *current, const char *cwd)
29474699Ssobomax{
29574808Ssobomax    char *resolved, *temp;
29674699Ssobomax    int rval;
29774699Ssobomax
29874699Ssobomax    asprintf(&temp, "%s/%s", cwd, current);
29974699Ssobomax    if (temp == NULL)
30074699Ssobomax        errx(2, NULL);
30174699Ssobomax
30274699Ssobomax    /*
30374808Ssobomax     * Make sure there's no multiple /'s or other weird things in the PLIST,
30474808Ssobomax     * since some plists seem to have them and it could screw up our strncmp.
30574699Ssobomax     */
30674808Ssobomax    resolved = abspath(temp);
30774699Ssobomax
30874808Ssobomax    if (strcmp(target, resolved) == 0)
30974699Ssobomax	rval = 1;
31074699Ssobomax    else
31174699Ssobomax	rval = 0;
31274699Ssobomax
31374699Ssobomax    free(temp);
31474808Ssobomax    free(resolved);
31574699Ssobomax    return rval;
31674699Ssobomax}
31774699Ssobomax
31874699Ssobomax/*
31974699Ssobomax * Look through package dbs in db_dir and find which
32074699Ssobomax * packages installed the files in which_list.
32174699Ssobomax */
32274699Ssobomaxstatic int
32384745Ssobomaxfind_pkg(const char *db_dir, struct which_head *which_list)
32474699Ssobomax{
32574699Ssobomax    char **installed;
32674699Ssobomax    int errcode, i;
32774699Ssobomax    struct which_entry *wp;
32874699Ssobomax
32974699Ssobomax    TAILQ_FOREACH(wp, which_list, next) {
33084745Ssobomax	const char *msg = "file cannot be found";
33174808Ssobomax	char *tmp;
33274808Ssobomax
33374808Ssobomax	wp->skip = TRUE;
33474699Ssobomax	/* If it's not a file, we'll see if it's an executable. */
33574699Ssobomax	if (isfile(wp->file) == FALSE) {
33674699Ssobomax	    if (strchr(wp->file, '/') == NULL) {
33774699Ssobomax		tmp = vpipe("/usr/bin/which %s", wp->file);
33874808Ssobomax		if (tmp != NULL) {
33974808Ssobomax		    strlcpy(wp->file, tmp, PATH_MAX);
34074808Ssobomax		    wp->skip = FALSE;
34174808Ssobomax		    free(tmp);
34274699Ssobomax		} else
34374808Ssobomax		    msg = "file is not in PATH";
34474699Ssobomax	    }
34574808Ssobomax	} else {
34674808Ssobomax	    tmp = abspath(wp->file);
34774808Ssobomax	    if (isfile(tmp)) {
34874808Ssobomax	    	strlcpy(wp->file, tmp, PATH_MAX);
34974808Ssobomax	    	wp->skip = FALSE;
35074808Ssobomax	    }
35174699Ssobomax	    free(tmp);
35274699Ssobomax	}
35374808Ssobomax	if (wp->skip == TRUE)
35474808Ssobomax	    warnx("%s: %s", wp->file, msg);
35574699Ssobomax    }
35674699Ssobomax
35774699Ssobomax    installed = matchinstalled(MATCH_ALL, NULL, &errcode);
35874699Ssobomax    if (installed == NULL)
35974699Ssobomax        return errcode;
36074699Ssobomax
36174699Ssobomax    for (i = 0; installed[i] != NULL; i++) {
36274699Ssobomax     	FILE *fp;
36374699Ssobomax     	Package pkg;
36474699Ssobomax     	PackingList itr;
36574699Ssobomax     	char *cwd = NULL;
36674699Ssobomax     	char tmp[PATH_MAX];
36774699Ssobomax
36874699Ssobomax	snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i],
36974699Ssobomax		 CONTENTS_FNAME);
37074699Ssobomax	fp = fopen(tmp, "r");
37174699Ssobomax	if (fp == NULL) {
37274699Ssobomax	    warn("%s", tmp);
37374699Ssobomax	    return 1;
37474699Ssobomax	}
37574699Ssobomax
37674699Ssobomax	pkg.head = pkg.tail = NULL;
37774699Ssobomax	read_plist(&pkg, fp);
37874699Ssobomax	fclose(fp);
37974699Ssobomax	for (itr = pkg.head; itr != pkg.tail; itr = itr->next) {
38074699Ssobomax	    if (itr->type == PLIST_CWD) {
38174699Ssobomax		cwd = itr->name;
38274699Ssobomax	    } else if (itr->type == PLIST_FILE) {
38374699Ssobomax		TAILQ_FOREACH(wp, which_list, next) {
38474699Ssobomax		    if (wp->skip == TRUE)
38574699Ssobomax			continue;
38674699Ssobomax		    if (!cmp_path(wp->file, itr->name, cwd))
38774699Ssobomax			continue;
38874699Ssobomax		    if (wp->package[0] != '\0') {
38974809Ssobomax			warnx("both %s and %s claim to have installed %s\n",
39074699Ssobomax			      wp->package, installed[i], wp->file);
39174699Ssobomax		    } else {
39274699Ssobomax			strlcpy(wp->package, installed[i], PATH_MAX);
39374699Ssobomax		    }
39474699Ssobomax		}
39574699Ssobomax	    }
39674699Ssobomax	}
39774699Ssobomax	free_plist(&pkg);
39874699Ssobomax    }
39974699Ssobomax
40074699Ssobomax    TAILQ_FOREACH(wp, which_list, next) {
40174699Ssobomax	if (wp->package[0] != '\0') {
40274699Ssobomax	    if (Quiet)
40374699Ssobomax		puts(wp->package);
40474699Ssobomax	    else
40574699Ssobomax		printf("%s was installed by package %s\n", \
40674699Ssobomax		       wp->file, wp->package);
40774699Ssobomax	}
40874699Ssobomax    }
40974699Ssobomax    while (!TAILQ_EMPTY(which_list)) {
41074699Ssobomax	wp = TAILQ_FIRST(which_list);
41174699Ssobomax	TAILQ_REMOVE(which_list, wp, next);
41274699Ssobomax	free(wp);
41374699Ssobomax    }
41474699Ssobomax
41574699Ssobomax    free(which_list);
41674699Ssobomax    return 0;
41774699Ssobomax}
41896030Ssobomax
41996030Ssobomax/*
42096030Ssobomax * Look through package dbs in db_dir and find which
42196030Ssobomax * packages have the given origin. Don't use read_plist()
42296030Ssobomax * because this increases time necessary for lookup by 40
42396030Ssobomax * times, as we don't really have to parse all plist to
42496030Ssobomax * get origin.
42596030Ssobomax */
42696030Ssobomaxstatic int
42796030Ssobomaxfind_pkgs_by_origin(const char *db_dir, const char *origin)
42896030Ssobomax{
42996030Ssobomax    char **installed;
43096030Ssobomax    int errcode, i;
43196030Ssobomax
43296030Ssobomax    installed = matchinstalled(MATCH_ALL, NULL, &errcode);
43396030Ssobomax    if (installed == NULL)
43496030Ssobomax        return errcode;
43596030Ssobomax
43696030Ssobomax    if (!Quiet)
43796030Ssobomax	printf("The following installed package(s) has %s origin:\n", origin);
43896030Ssobomax    for (i = 0; installed[i] != NULL; i++) {
43996030Ssobomax     	FILE *fp;
44096030Ssobomax     	char *cp, tmp[PATH_MAX];
44196030Ssobomax     	int cmd;
44296030Ssobomax
44396030Ssobomax	snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i],
44496030Ssobomax		 CONTENTS_FNAME);
44596030Ssobomax	fp = fopen(tmp, "r");
44696030Ssobomax	if (fp == NULL) {
44796030Ssobomax	    warn("%s", tmp);
44896030Ssobomax	    return 1;
44996030Ssobomax	}
45096030Ssobomax
45196030Ssobomax	cmd = -1;
45296030Ssobomax	while (fgets(tmp, sizeof(tmp), fp)) {
45396030Ssobomax	    int len = strlen(tmp);
45496030Ssobomax
45596030Ssobomax	    while (len && isspace(tmp[len - 1]))
45696030Ssobomax		tmp[--len] = '\0';
45796030Ssobomax	    if (!len)
45896030Ssobomax		continue;
45996030Ssobomax	    cp = tmp;
46096030Ssobomax	    if (tmp[0] != CMD_CHAR)
46196030Ssobomax		continue;
46296030Ssobomax	    cmd = plist_cmd(tmp + 1, &cp);
46396030Ssobomax	    if (cmd == PLIST_ORIGIN) {
46496030Ssobomax		if (strcmp(origin, cp) == 0)
46596030Ssobomax		    puts(installed[i]);
46696030Ssobomax		break;
46796030Ssobomax	    }
46896030Ssobomax	}
46996030Ssobomax	if (cmd != PLIST_ORIGIN)
47096030Ssobomax	    warnx("package %s has no origin recorded", installed[i]);
47196030Ssobomax	fclose(fp);
47296030Ssobomax    }
47396030Ssobomax
47496030Ssobomax    return 0;
47596030Ssobomax}
476