perform.c revision 74699
1327Sjkh#ifndef lint
230221Scharnierstatic const char rcsid[] =
350479Speter  "$FreeBSD: head/usr.sbin/pkg_install/info/perform.c 74699 2001-03-23 18:45:24Z sobomax $";
4327Sjkh#endif
5327Sjkh
6327Sjkh/*
7327Sjkh * FreeBSD install - a package for the installation and maintainance
8327Sjkh * of non-core utilities.
9327Sjkh *
10327Sjkh * Redistribution and use in source and binary forms, with or without
11327Sjkh * modification, are permitted provided that the following conditions
12327Sjkh * are met:
13327Sjkh * 1. Redistributions of source code must retain the above copyright
14327Sjkh *    notice, this list of conditions and the following disclaimer.
15327Sjkh * 2. Redistributions in binary form must reproduce the above copyright
16327Sjkh *    notice, this list of conditions and the following disclaimer in the
17327Sjkh *    documentation and/or other materials provided with the distribution.
18327Sjkh *
19327Sjkh * Jordan K. Hubbard
20327Sjkh * 23 Aug 1993
21327Sjkh *
22327Sjkh * This is the main body of the info module.
23327Sjkh *
24327Sjkh */
25327Sjkh
26327Sjkh#include "lib.h"
27327Sjkh#include "info.h"
2872174Ssobomax#include <err.h>
29327Sjkh#include <signal.h>
30327Sjkh
31327Sjkhstatic int pkg_do(char *);
3274699Ssobomaxstatic int find_pkg(char *, struct which_head *);
3374699Ssobomaxstatic int cmp_path(const char *, const char *, const char *);
34327Sjkh
35327Sjkhint
36327Sjkhpkg_perform(char **pkgs)
37327Sjkh{
3873134Ssobomax    char **matched;
397937Sjkh    char *tmp;
4073134Ssobomax    int err_cnt = 0;
4173134Ssobomax    int i, errcode;
42327Sjkh
43327Sjkh    signal(SIGINT, cleanup);
44327Sjkh
4574699Ssobomax    tmp = getenv(PKG_DBDIR);
4674699Ssobomax    if (!tmp)
4774699Ssobomax	tmp = DEF_LOG_DIR;
4874699Ssobomax
49327Sjkh    /* Overriding action? */
5016404Sjkh    if (CheckPkg) {
5116404Sjkh	char buf[FILENAME_MAX];
52327Sjkh
5316404Sjkh	snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg);
5416404Sjkh	return abs(access(buf, R_OK));
5572174Ssobomax	/* Not reached */
5674699Ssobomax    } else if (!TAILQ_EMPTY(whead)) {
5774699Ssobomax	return find_pkg(tmp, whead);
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 {
1487937Sjkh	char *tmp;
1497937Sjkh
1507937Sjkh	sprintf(log_dir, "%s/%s", (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR,
1517937Sjkh		pkg);
152327Sjkh	if (!fexists(log_dir)) {
15330221Scharnier	    warnx("can't find package `%s' installed or in a file!", pkg);
154327Sjkh	    return 1;
155327Sjkh	}
156327Sjkh	if (chdir(log_dir) == FAIL) {
15730221Scharnier	    warnx("can't change directory to '%s'!", log_dir);
158327Sjkh	    return 1;
159327Sjkh	}
160327Sjkh	installed = TRUE;
161327Sjkh    }
162327Sjkh
163327Sjkh    /* Suck in the contents list */
164327Sjkh    plist.head = plist.tail = NULL;
165327Sjkh    fp = fopen(CONTENTS_FNAME, "r");
166327Sjkh    if (!fp) {
16730221Scharnier	warnx("unable to open %s file", CONTENTS_FNAME);
1688086Sjkh	code = 1;
1698086Sjkh	goto bail;
170327Sjkh    }
171327Sjkh    /* If we have a prefix, add it now */
172327Sjkh    read_plist(&plist, fp);
173327Sjkh    fclose(fp);
174327Sjkh
175327Sjkh    /*
176327Sjkh     * Index is special info type that has to override all others to make
177327Sjkh     * any sense.
178327Sjkh     */
179327Sjkh    if (Flags & SHOW_INDEX) {
1808086Sjkh	char tmp[FILENAME_MAX];
181327Sjkh
1828086Sjkh	snprintf(tmp, FILENAME_MAX, "%-19s ", pkg);
1838086Sjkh	show_index(tmp, COMMENT_FNAME);
184327Sjkh    }
185327Sjkh    else {
186327Sjkh	/* Start showing the package contents */
187411Sjkh	if (!Quiet)
188411Sjkh	    printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
189327Sjkh	if (Flags & SHOW_COMMENT)
190379Sjkh	    show_file("Comment:\n", COMMENT_FNAME);
19166339Smarko	if (Flags & SHOW_REQUIRE)
19266339Smarko	    show_plist("Depends on:\n", &plist, PLIST_PKGDEP);
1934996Sjkh	if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME))
1944996Sjkh	    show_file("Required by:\n", REQUIRED_BY_FNAME);
195327Sjkh	if (Flags & SHOW_DESC)
196379Sjkh	    show_file("Description:\n", DESC_FNAME);
1974996Sjkh	if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME))
1984996Sjkh	    show_file("Install notice:\n", DISPLAY_FNAME);
199327Sjkh	if (Flags & SHOW_PLIST)
200379Sjkh	    show_plist("Packing list:\n", &plist, (plist_t)-1);
201327Sjkh	if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME))
202379Sjkh	    show_file("Install script:\n", INSTALL_FNAME);
20341866Sjkh	if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME))
20441866Sjkh	    show_file("Post-Install script:\n", POST_INSTALL_FNAME);
205327Sjkh	if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME))
206379Sjkh	    show_file("De-Install script:\n", DEINSTALL_FNAME);
20741866Sjkh	if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME))
20841866Sjkh	    show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME);
2094996Sjkh	if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME))
2104996Sjkh	    show_file("mtree file:\n", MTREE_FNAME);
211327Sjkh	if (Flags & SHOW_PREFIX)
212379Sjkh	    show_plist("Prefix(s):\n", &plist, PLIST_CWD);
213411Sjkh	if (Flags & SHOW_FILES)
214411Sjkh	    show_files("Files:\n", &plist);
21562775Ssobomax	if ((Flags & SHOW_SIZE) && installed)
21662775Ssobomax	    show_size("Package Size:\n", &plist);
21771965Sjkh	if ((Flags & SHOW_CKSUM) && installed)
21871965Sjkh	    show_cksum("Mismatched Checksums:\n", &plist);
21967454Ssobomax	if (Flags & SHOW_ORIGIN)
22067454Ssobomax	    show_origin("Origin:\n", &plist);
221411Sjkh	if (!Quiet)
222411Sjkh	    puts(InfoPrefix);
223327Sjkh    }
224327Sjkh    free_plist(&plist);
2258086Sjkh bail:
22633427Sjkh    leave_playpen();
2278086Sjkh    if (isTMP)
2288086Sjkh	unlink(fname);
2298086Sjkh    return code;
230327Sjkh}
231327Sjkh
232327Sjkhvoid
233327Sjkhcleanup(int sig)
234327Sjkh{
23533427Sjkh    static int in_cleanup = 0;
23633427Sjkh
23733427Sjkh    if (!in_cleanup) {
23833427Sjkh	in_cleanup = 1;
23972174Ssobomax	leave_playpen();
24033427Sjkh    }
24139068Sjkh    if (sig)
24239068Sjkh	exit(1);
243327Sjkh}
24449300Sjdp
24574699Ssobomax/*
24674699Ssobomax * Comparison to see if the path we're on matches the
24774699Ssobomax * one we are looking for.
24874699Ssobomax */
24974699Ssobomaxstatic int
25074699Ssobomaxcmp_path(const char *target, const char *current, const char *cwd)
25174699Ssobomax{
25274699Ssobomax    char *loc, *temp;
25374699Ssobomax    int rval;
25474699Ssobomax
25574699Ssobomax    asprintf(&temp, "%s/%s", cwd, current);
25674699Ssobomax    if (temp == NULL)
25774699Ssobomax        errx(2, NULL);
25874699Ssobomax
25974699Ssobomax    /*
26074699Ssobomax     * Make sure there's no multiple /'s, since some plists
26174699Ssobomax     * seem to have them and it could screw up our strncmp.
26274699Ssobomax     */
26374699Ssobomax    while ((loc = strstr(temp, "//")) != NULL)
26474699Ssobomax	strcpy(loc, loc + 1);
26574699Ssobomax
26674699Ssobomax    if (strcmp(target, temp) == 0)
26774699Ssobomax	rval = 1;
26874699Ssobomax    else
26974699Ssobomax	rval = 0;
27074699Ssobomax
27174699Ssobomax    free(temp);
27274699Ssobomax    return rval;
27374699Ssobomax}
27474699Ssobomax
27574699Ssobomax/*
27674699Ssobomax * Look through package dbs in db_dir and find which
27774699Ssobomax * packages installed the files in which_list.
27874699Ssobomax */
27974699Ssobomaxstatic int
28074699Ssobomaxfind_pkg(char *db_dir, struct which_head *which_list)
28174699Ssobomax{
28274699Ssobomax    char **installed;
28374699Ssobomax    int errcode, i;
28474699Ssobomax    struct which_entry *wp;
28574699Ssobomax
28674699Ssobomax    TAILQ_FOREACH(wp, which_list, next) {
28774699Ssobomax	/* If it's not a file, we'll see if it's an executable. */
28874699Ssobomax	if (isfile(wp->file) == FALSE) {
28974699Ssobomax	    if (strchr(wp->file, '/') == NULL) {
29074699Ssobomax		char *tmp;
29174699Ssobomax		tmp = vpipe("/usr/bin/which %s", wp->file);
29274699Ssobomax		if (tmp == NULL) {
29374699Ssobomax		    warnx("%s: file is not in PATH", wp->file);
29474699Ssobomax		    wp->skip = TRUE;
29574699Ssobomax		} else
29674699Ssobomax		    strlcpy(wp->file, tmp, PATH_MAX);
29774699Ssobomax		free(tmp);
29874699Ssobomax	    } else {
29974699Ssobomax		warnx("%s: file cannot be found", wp->file);
30074699Ssobomax		wp->skip = TRUE;
30174699Ssobomax	    }
30274699Ssobomax	} else if (wp->file[0] != '/') {
30374699Ssobomax	    /*
30474699Ssobomax	     * If it is a file, and it doesn't start with a /, then it's a
30574699Ssobomax	     * relative path.  in order to give us some chance of getting a
30674699Ssobomax	     * successful match, tack the current working directory on the
30774699Ssobomax	     * beginning.  this won't work for filenames that include .. or .
30874699Ssobomax	     * or extra /'s, but it's better than nothing).
30974699Ssobomax	     */
31074699Ssobomax	    char *curdir, *tmp;
31174699Ssobomax
31274699Ssobomax	    curdir = getcwd(NULL, PATH_MAX);
31374699Ssobomax	    if (curdir == NULL)
31474699Ssobomax		err(2, NULL);
31574699Ssobomax
31674699Ssobomax	    asprintf(&tmp, "%s/%s", curdir, wp->file);
31774699Ssobomax	    if (tmp == NULL)
31874699Ssobomax		err(2, NULL);
31974699Ssobomax
32074699Ssobomax	    if (!isfile(tmp)) {
32174699Ssobomax		warnx("%s: file cannot be found", tmp);
32274699Ssobomax		wp->skip = TRUE;
32374699Ssobomax	    } else
32474699Ssobomax		strlcpy(wp->file, tmp, PATH_MAX);
32574699Ssobomax
32674699Ssobomax	    free(tmp);
32774699Ssobomax	    free(curdir);
32874699Ssobomax	}
32974699Ssobomax    }
33074699Ssobomax
33174699Ssobomax    installed = matchinstalled(MATCH_ALL, NULL, &errcode);
33274699Ssobomax    if (installed == NULL)
33374699Ssobomax        return errcode;
33474699Ssobomax
33574699Ssobomax    for (i = 0; installed[i] != NULL; i++) {
33674699Ssobomax     	FILE *fp;
33774699Ssobomax     	Package pkg;
33874699Ssobomax     	PackingList itr;
33974699Ssobomax     	char *cwd = NULL;
34074699Ssobomax     	char tmp[PATH_MAX];
34174699Ssobomax
34274699Ssobomax	snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i],
34374699Ssobomax		 CONTENTS_FNAME);
34474699Ssobomax	fp = fopen(tmp, "r");
34574699Ssobomax	if (fp == NULL) {
34674699Ssobomax	    warn("%s", tmp);
34774699Ssobomax	    return 1;
34874699Ssobomax	}
34974699Ssobomax
35074699Ssobomax	pkg.head = pkg.tail = NULL;
35174699Ssobomax	read_plist(&pkg, fp);
35274699Ssobomax	fclose(fp);
35374699Ssobomax	for (itr = pkg.head; itr != pkg.tail; itr = itr->next) {
35474699Ssobomax	    if (itr->type == PLIST_CWD) {
35574699Ssobomax		cwd = itr->name;
35674699Ssobomax	    } else if (itr->type == PLIST_FILE) {
35774699Ssobomax		TAILQ_FOREACH(wp, which_list, next) {
35874699Ssobomax		    if (wp->skip == TRUE)
35974699Ssobomax			continue;
36074699Ssobomax		    if (!cmp_path(wp->file, itr->name, cwd))
36174699Ssobomax			continue;
36274699Ssobomax		    if (wp->package[0] != '\0') {
36374699Ssobomax			warnx("Both %s and %s claim to have installed %s\n",
36474699Ssobomax			      wp->package, installed[i], wp->file);
36574699Ssobomax		    } else {
36674699Ssobomax			strlcpy(wp->package, installed[i], PATH_MAX);
36774699Ssobomax		    }
36874699Ssobomax		}
36974699Ssobomax	    }
37074699Ssobomax	}
37174699Ssobomax	free_plist(&pkg);
37274699Ssobomax    }
37374699Ssobomax
37474699Ssobomax    TAILQ_FOREACH(wp, which_list, next) {
37574699Ssobomax	if (wp->package[0] != '\0') {
37674699Ssobomax	    if (Quiet)
37774699Ssobomax		puts(wp->package);
37874699Ssobomax	    else
37974699Ssobomax		printf("%s was installed by package %s\n", \
38074699Ssobomax		       wp->file, wp->package);
38174699Ssobomax	}
38274699Ssobomax    }
38374699Ssobomax    while (!TAILQ_EMPTY(which_list)) {
38474699Ssobomax	wp = TAILQ_FIRST(which_list);
38574699Ssobomax	TAILQ_REMOVE(which_list, wp, next);
38674699Ssobomax	free(wp);
38774699Ssobomax    }
38874699Ssobomax
38974699Ssobomax    free(which_list);
39074699Ssobomax    return 0;
39174699Ssobomax}
392