perform.c revision 96613
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 96613 2002-05-14 21:42:37Z sobomax $");
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];
918086Sjkh    char fname[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);
134327Sjkh	if (unpack(fname, "+*")) {
13530221Scharnier	    warnx("error during unpacking, no info for '%s' available", pkg);
1368086Sjkh	    code = 1;
1378086Sjkh	    goto bail;
138327Sjkh	}
139327Sjkh    }
1408086Sjkh    /* It's not an ininstalled package, try and find it among the installed */
141327Sjkh    else {
14296613Ssobomax	if (!isinstalledpkg(pkg)) {
14381046Ssobomax	    warnx("can't find package '%s' installed or in a file!", pkg);
144327Sjkh	    return 1;
145327Sjkh	}
14696613Ssobomax	sprintf(log_dir, "%s/%s", LOG_DIR, pkg);
147327Sjkh	if (chdir(log_dir) == FAIL) {
14830221Scharnier	    warnx("can't change directory to '%s'!", log_dir);
149327Sjkh	    return 1;
150327Sjkh	}
151327Sjkh	installed = TRUE;
152327Sjkh    }
153327Sjkh
154327Sjkh    /* Suck in the contents list */
155327Sjkh    plist.head = plist.tail = NULL;
156327Sjkh    fp = fopen(CONTENTS_FNAME, "r");
157327Sjkh    if (!fp) {
15830221Scharnier	warnx("unable to open %s file", CONTENTS_FNAME);
1598086Sjkh	code = 1;
1608086Sjkh	goto bail;
161327Sjkh    }
162327Sjkh    /* If we have a prefix, add it now */
163327Sjkh    read_plist(&plist, fp);
164327Sjkh    fclose(fp);
165327Sjkh
166327Sjkh    /*
167327Sjkh     * Index is special info type that has to override all others to make
168327Sjkh     * any sense.
169327Sjkh     */
170327Sjkh    if (Flags & SHOW_INDEX) {
1718086Sjkh	char tmp[FILENAME_MAX];
172327Sjkh
1738086Sjkh	snprintf(tmp, FILENAME_MAX, "%-19s ", pkg);
1748086Sjkh	show_index(tmp, COMMENT_FNAME);
175327Sjkh    }
176327Sjkh    else {
177327Sjkh	/* Start showing the package contents */
178411Sjkh	if (!Quiet)
179411Sjkh	    printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
180327Sjkh	if (Flags & SHOW_COMMENT)
181379Sjkh	    show_file("Comment:\n", COMMENT_FNAME);
18266339Smarko	if (Flags & SHOW_REQUIRE)
18384745Ssobomax	    show_plist("Depends on:\n", &plist, PLIST_PKGDEP, FALSE);
1844996Sjkh	if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME))
1854996Sjkh	    show_file("Required by:\n", REQUIRED_BY_FNAME);
186327Sjkh	if (Flags & SHOW_DESC)
187379Sjkh	    show_file("Description:\n", DESC_FNAME);
1884996Sjkh	if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME))
1894996Sjkh	    show_file("Install notice:\n", DISPLAY_FNAME);
190327Sjkh	if (Flags & SHOW_PLIST)
19184745Ssobomax	    show_plist("Packing list:\n", &plist, (plist_t)0, TRUE);
192327Sjkh	if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME))
193379Sjkh	    show_file("Install script:\n", INSTALL_FNAME);
19441866Sjkh	if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME))
19541866Sjkh	    show_file("Post-Install script:\n", POST_INSTALL_FNAME);
196327Sjkh	if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME))
197379Sjkh	    show_file("De-Install script:\n", DEINSTALL_FNAME);
19841866Sjkh	if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME))
19941866Sjkh	    show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME);
2004996Sjkh	if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME))
2014996Sjkh	    show_file("mtree file:\n", MTREE_FNAME);
202327Sjkh	if (Flags & SHOW_PREFIX)
20384745Ssobomax	    show_plist("Prefix(s):\n", &plist, PLIST_CWD, FALSE);
204411Sjkh	if (Flags & SHOW_FILES)
205411Sjkh	    show_files("Files:\n", &plist);
20662775Ssobomax	if ((Flags & SHOW_SIZE) && installed)
20762775Ssobomax	    show_size("Package Size:\n", &plist);
20871965Sjkh	if ((Flags & SHOW_CKSUM) && installed)
20971965Sjkh	    show_cksum("Mismatched Checksums:\n", &plist);
21067454Ssobomax	if (Flags & SHOW_ORIGIN)
21167454Ssobomax	    show_origin("Origin:\n", &plist);
21284750Ssobomax	if (Flags & SHOW_FMTREV)
21384750Ssobomax	    show_fmtrev("Packing list format revision:\n", &plist);
214411Sjkh	if (!Quiet)
215411Sjkh	    puts(InfoPrefix);
216327Sjkh    }
217327Sjkh    free_plist(&plist);
2188086Sjkh bail:
21933427Sjkh    leave_playpen();
2208086Sjkh    if (isTMP)
2218086Sjkh	unlink(fname);
2228086Sjkh    return code;
223327Sjkh}
224327Sjkh
225327Sjkhvoid
226327Sjkhcleanup(int sig)
227327Sjkh{
22833427Sjkh    static int in_cleanup = 0;
22933427Sjkh
23033427Sjkh    if (!in_cleanup) {
23133427Sjkh	in_cleanup = 1;
23272174Ssobomax	leave_playpen();
23333427Sjkh    }
23439068Sjkh    if (sig)
23539068Sjkh	exit(1);
236327Sjkh}
23749300Sjdp
23874699Ssobomax/*
23974808Ssobomax * Return an absolute path, additionally removing all .'s, ..'s, and extraneous
24074808Ssobomax * /'s, as realpath() would, but without resolving symlinks, because that can
24174808Ssobomax * potentially screw up our comparisons later.
24274808Ssobomax */
24384745Ssobomaxstatic char *
24474808Ssobomaxabspath(const char *pathname)
24574808Ssobomax{
24674808Ssobomax    char *tmp, *tmp1, *resolved_path;
24774808Ssobomax    char *cwd = NULL;
24874808Ssobomax    int len;
24974808Ssobomax
25074808Ssobomax    if (pathname[0] != '/') {
25174808Ssobomax	cwd = getcwd(NULL, MAXPATHLEN);
25274808Ssobomax	asprintf(&resolved_path, "%s/%s/", cwd, pathname);
25374808Ssobomax    } else
25474808Ssobomax	asprintf(&resolved_path, "%s/", pathname);
25574808Ssobomax
25674808Ssobomax    if (resolved_path == NULL)
25774808Ssobomax	errx(2, NULL);
25874808Ssobomax
25974808Ssobomax    if (cwd != NULL)
26074808Ssobomax	free(cwd);
26174808Ssobomax
26274808Ssobomax    while ((tmp = strstr(resolved_path, "//")) != NULL)
26374808Ssobomax	strcpy(tmp, tmp + 1);
26474808Ssobomax
26574808Ssobomax    while ((tmp = strstr(resolved_path, "/./")) != NULL)
26674808Ssobomax	strcpy(tmp, tmp + 2);
26774808Ssobomax
26874808Ssobomax    while ((tmp = strstr(resolved_path, "/../")) != NULL) {
26974808Ssobomax	*tmp = '\0';
27074808Ssobomax	if ((tmp1 = strrchr(resolved_path, '/')) == NULL)
27174808Ssobomax	   tmp1 = resolved_path;
27274808Ssobomax	strcpy(tmp1, tmp + 3);
27374808Ssobomax    }
27474808Ssobomax
27574808Ssobomax    len = strlen(resolved_path);
27674808Ssobomax    if (len > 1 && resolved_path[len - 1] == '/')
27774808Ssobomax	resolved_path[len - 1] = '\0';
27874808Ssobomax
27974808Ssobomax    return resolved_path;
28074808Ssobomax}
28174808Ssobomax
28274808Ssobomax/*
28374699Ssobomax * Comparison to see if the path we're on matches the
28474699Ssobomax * one we are looking for.
28574699Ssobomax */
28674699Ssobomaxstatic int
28774699Ssobomaxcmp_path(const char *target, const char *current, const char *cwd)
28874699Ssobomax{
28974808Ssobomax    char *resolved, *temp;
29074699Ssobomax    int rval;
29174699Ssobomax
29274699Ssobomax    asprintf(&temp, "%s/%s", cwd, current);
29374699Ssobomax    if (temp == NULL)
29474699Ssobomax        errx(2, NULL);
29574699Ssobomax
29674699Ssobomax    /*
29774808Ssobomax     * Make sure there's no multiple /'s or other weird things in the PLIST,
29874808Ssobomax     * since some plists seem to have them and it could screw up our strncmp.
29974699Ssobomax     */
30074808Ssobomax    resolved = abspath(temp);
30174699Ssobomax
30274808Ssobomax    if (strcmp(target, resolved) == 0)
30374699Ssobomax	rval = 1;
30474699Ssobomax    else
30574699Ssobomax	rval = 0;
30674699Ssobomax
30774699Ssobomax    free(temp);
30874808Ssobomax    free(resolved);
30974699Ssobomax    return rval;
31074699Ssobomax}
31174699Ssobomax
31274699Ssobomax/*
31396613Ssobomax * Look through package dbs in LOG_DIR and find which
31474699Ssobomax * packages installed the files in which_list.
31574699Ssobomax */
31674699Ssobomaxstatic int
31796613Ssobomaxfind_pkg(struct which_head *which_list)
31874699Ssobomax{
31974699Ssobomax    char **installed;
32074699Ssobomax    int errcode, i;
32174699Ssobomax    struct which_entry *wp;
32274699Ssobomax
32374699Ssobomax    TAILQ_FOREACH(wp, which_list, next) {
32484745Ssobomax	const char *msg = "file cannot be found";
32574808Ssobomax	char *tmp;
32674808Ssobomax
32774808Ssobomax	wp->skip = TRUE;
32874699Ssobomax	/* If it's not a file, we'll see if it's an executable. */
32974699Ssobomax	if (isfile(wp->file) == FALSE) {
33074699Ssobomax	    if (strchr(wp->file, '/') == NULL) {
33174699Ssobomax		tmp = vpipe("/usr/bin/which %s", wp->file);
33274808Ssobomax		if (tmp != NULL) {
33374808Ssobomax		    strlcpy(wp->file, tmp, PATH_MAX);
33474808Ssobomax		    wp->skip = FALSE;
33574808Ssobomax		    free(tmp);
33674699Ssobomax		} else
33774808Ssobomax		    msg = "file is not in PATH";
33874699Ssobomax	    }
33974808Ssobomax	} else {
34074808Ssobomax	    tmp = abspath(wp->file);
34174808Ssobomax	    if (isfile(tmp)) {
34274808Ssobomax	    	strlcpy(wp->file, tmp, PATH_MAX);
34374808Ssobomax	    	wp->skip = FALSE;
34474808Ssobomax	    }
34574699Ssobomax	    free(tmp);
34674699Ssobomax	}
34774808Ssobomax	if (wp->skip == TRUE)
34874808Ssobomax	    warnx("%s: %s", wp->file, msg);
34974699Ssobomax    }
35074699Ssobomax
35174699Ssobomax    installed = matchinstalled(MATCH_ALL, NULL, &errcode);
35274699Ssobomax    if (installed == NULL)
35374699Ssobomax        return errcode;
35474699Ssobomax
35574699Ssobomax    for (i = 0; installed[i] != NULL; i++) {
35674699Ssobomax     	FILE *fp;
35774699Ssobomax     	Package pkg;
35874699Ssobomax     	PackingList itr;
35974699Ssobomax     	char *cwd = NULL;
36074699Ssobomax     	char tmp[PATH_MAX];
36174699Ssobomax
36296613Ssobomax	snprintf(tmp, PATH_MAX, "%s/%s/%s", LOG_DIR, installed[i],
36374699Ssobomax		 CONTENTS_FNAME);
36474699Ssobomax	fp = fopen(tmp, "r");
36574699Ssobomax	if (fp == NULL) {
36674699Ssobomax	    warn("%s", tmp);
36774699Ssobomax	    return 1;
36874699Ssobomax	}
36974699Ssobomax
37074699Ssobomax	pkg.head = pkg.tail = NULL;
37174699Ssobomax	read_plist(&pkg, fp);
37274699Ssobomax	fclose(fp);
37374699Ssobomax	for (itr = pkg.head; itr != pkg.tail; itr = itr->next) {
37474699Ssobomax	    if (itr->type == PLIST_CWD) {
37574699Ssobomax		cwd = itr->name;
37674699Ssobomax	    } else if (itr->type == PLIST_FILE) {
37774699Ssobomax		TAILQ_FOREACH(wp, which_list, next) {
37874699Ssobomax		    if (wp->skip == TRUE)
37974699Ssobomax			continue;
38074699Ssobomax		    if (!cmp_path(wp->file, itr->name, cwd))
38174699Ssobomax			continue;
38274699Ssobomax		    if (wp->package[0] != '\0') {
38374809Ssobomax			warnx("both %s and %s claim to have installed %s\n",
38474699Ssobomax			      wp->package, installed[i], wp->file);
38574699Ssobomax		    } else {
38674699Ssobomax			strlcpy(wp->package, installed[i], PATH_MAX);
38774699Ssobomax		    }
38874699Ssobomax		}
38974699Ssobomax	    }
39074699Ssobomax	}
39174699Ssobomax	free_plist(&pkg);
39274699Ssobomax    }
39374699Ssobomax
39474699Ssobomax    TAILQ_FOREACH(wp, which_list, next) {
39574699Ssobomax	if (wp->package[0] != '\0') {
39674699Ssobomax	    if (Quiet)
39774699Ssobomax		puts(wp->package);
39874699Ssobomax	    else
39974699Ssobomax		printf("%s was installed by package %s\n", \
40074699Ssobomax		       wp->file, wp->package);
40174699Ssobomax	}
40274699Ssobomax    }
40374699Ssobomax    while (!TAILQ_EMPTY(which_list)) {
40474699Ssobomax	wp = TAILQ_FIRST(which_list);
40574699Ssobomax	TAILQ_REMOVE(which_list, wp, next);
40674699Ssobomax	free(wp);
40774699Ssobomax    }
40874699Ssobomax
40974699Ssobomax    free(which_list);
41074699Ssobomax    return 0;
41174699Ssobomax}
41296030Ssobomax
41396030Ssobomax/*
41496613Ssobomax * Look through package dbs in LOG_DIR and find which
41596030Ssobomax * packages have the given origin. Don't use read_plist()
41696030Ssobomax * because this increases time necessary for lookup by 40
41796030Ssobomax * times, as we don't really have to parse all plist to
41896030Ssobomax * get origin.
41996030Ssobomax */
42096030Ssobomaxstatic int
42196613Ssobomaxfind_pkgs_by_origin(const char *origin)
42296030Ssobomax{
42396613Ssobomax    char **matched;
42496030Ssobomax    int errcode, i;
42596030Ssobomax
42696030Ssobomax    if (!Quiet)
42796030Ssobomax	printf("The following installed package(s) has %s origin:\n", origin);
42896030Ssobomax
42996613Ssobomax    matched = matchbyorigin(origin, &errcode);
43096613Ssobomax    if (matched == NULL)
43196613Ssobomax	return errcode;
43296030Ssobomax
43396613Ssobomax    for (i = 0; matched[i] != NULL; i++)
43496613Ssobomax	puts(matched[i]);
43596030Ssobomax
43696030Ssobomax    return 0;
43796030Ssobomax}
438