perform.c revision 84750
150472Speter#ifndef lint
237Srgrimesstatic const char rcsid[] =
378822Snik  "$FreeBSD: head/usr.sbin/pkg_install/info/perform.c 84750 2001-10-10 08:21:41Z sobomax $";
450203Srgrimes#endif
537Srgrimes
639161Sobrien/*
739490Sobrien * FreeBSD install - a package for the installation and maintainance
88571Srgrimes * of non-core utilities.
92878Srgrimes *
1039490Sobrien * Redistribution and use in source and binary forms, with or without
112878Srgrimes * modification, are permitted provided that the following conditions
128571Srgrimes * are met:
132878Srgrimes * 1. Redistributions of source code must retain the above copyright
148571Srgrimes *    notice, this list of conditions and the following disclaimer.
1550296Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
1650296Srgrimes *    notice, this list of conditions and the following disclaimer in the
1750296Srgrimes *    documentation and/or other materials provided with the distribution.
1850296Srgrimes *
1950296Srgrimes * Jordan K. Hubbard
2050296Srgrimes * 23 Aug 1993
21160945Sjb *
22160945Sjb * This is the main body of the info module.
23160822Ssimon *
24160822Ssimon */
25248979Semaste
26248979Semaste#include "lib.h"
27255384Sdes#include "info.h"
28255384Sdes#include <err.h>
292878Srgrimes#include <signal.h>
30219019Sgabor
31248979Semastestatic int pkg_do(char *);
32248979Semastestatic int find_pkg(const char *, struct which_head *);
33248979Semastestatic int cmp_path(const char *, const char *, const char *);
34248979Semastestatic char *abspath(const char *);
35255384Sdes
36255384Sdesint
37219019Sgaborpkg_perform(char **pkgs)
3814796Spaul{
39127383Sobrien    char **matched;
40127383Sobrien    const char *tmp;
4150296Srgrimes    int err_cnt = 0;
4250296Srgrimes    int i, errcode;
4350296Srgrimes
4450296Srgrimes    signal(SIGINT, cleanup);
45253637Srpaulo
46253637Srpaulo    tmp = LOG_DIR;
4714796Spaul
488571Srgrimes    /* Overriding action? */
49255036Sdelphij    if (CheckPkg) {
50255036Sdelphij	char buf[FILENAME_MAX];
51255036Sdelphij
52255036Sdelphij	snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg);
53255036Sdelphij	return abs(access(buf, R_OK));
54255036Sdelphij	/* Not reached */
55255036Sdelphij    } else if (!TAILQ_EMPTY(whead)) {
56255036Sdelphij	return find_pkg(tmp, whead);
57255036Sdelphij    }
58255036Sdelphij
59255036Sdelphij    if (MatchType != MATCH_EXACT) {
60255036Sdelphij	matched = matchinstalled(MatchType, pkgs, &errcode);
61255036Sdelphij	if (errcode != 0)
62255036Sdelphij	    return 1;
63255036Sdelphij	    /* Not reached */
64255036Sdelphij
65255036Sdelphij	if (matched != NULL)
66255036Sdelphij	    pkgs = matched;
67255036Sdelphij	else switch (MatchType) {
68255036Sdelphij	    case MATCH_GLOB:
69255036Sdelphij		break;
70255036Sdelphij	    case MATCH_ALL:
71255036Sdelphij		warnx("no packages installed");
72255036Sdelphij		return 0;
73255036Sdelphij		/* Not reached */
74255036Sdelphij	    case MATCH_REGEX:
75255036Sdelphij		warnx("no packages match pattern(s)");
76255036Sdelphij		return 1;
77255036Sdelphij		/* Not reached */
78255036Sdelphij	    default:
79255036Sdelphij		break;
80255036Sdelphij	}
81255036Sdelphij    }
82255036Sdelphij
83255036Sdelphij    for (i = 0; pkgs[i]; i++)
84255036Sdelphij	err_cnt += pkg_do(pkgs[i]);
85255036Sdelphij
86255036Sdelphij    return err_cnt;
87255036Sdelphij}
88255036Sdelphij
89255036Sdelphijstatic char *Home;
90255036Sdelphij
91255036Sdelphijstatic int
92255036Sdelphijpkg_do(char *pkg)
93255036Sdelphij{
94255036Sdelphij    Boolean installed = FALSE, isTMP = FALSE;
95255036Sdelphij    char log_dir[FILENAME_MAX];
96255036Sdelphij    char fname[FILENAME_MAX];
97255036Sdelphij    Package plist;
98255036Sdelphij    FILE *fp;
99255036Sdelphij    struct stat sb;
100255036Sdelphij    char *cp = NULL;
101255036Sdelphij    int code = 0;
102255036Sdelphij
103255036Sdelphij    if (isURL(pkg)) {
104269399Semaste	if ((cp = fileGetURL(NULL, pkg)) != NULL) {
105269399Semaste	    strcpy(fname, cp);
106269399Semaste	    isTMP = TRUE;
107269399Semaste	}
108255036Sdelphij    }
109248979Semaste    else if (fexists(pkg) && isfile(pkg)) {
110248979Semaste	int len;
111272322Sdelphij
112272322Sdelphij	if (*pkg != '/') {
1138571Srgrimes	    if (!getcwd(fname, FILENAME_MAX))
11450296Srgrimes		upchuck("getcwd");
11550296Srgrimes	    len = strlen(fname);
1162878Srgrimes	    snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg);
11755797Srgrimes	}
11855797Srgrimes	else
11950296Srgrimes	    strcpy(fname, pkg);
12050296Srgrimes	cp = fname;
1212878Srgrimes    }
12239490Sobrien    else {
1232878Srgrimes	if ((cp = fileFindByPath(NULL, pkg)) != NULL)
12472515Sru	    strncpy(fname, cp, FILENAME_MAX);
1252878Srgrimes    }
1268571Srgrimes    if (cp) {
1272878Srgrimes	/*
1288571Srgrimes	 * Apply a crude heuristic to see how much space the package will
129255036Sdelphij	 * take up once it's unpacked.  I've noticed that most packages
130255036Sdelphij	 * compress an average of 75%, but we're only unpacking the + files so
131255036Sdelphij	 * be very optimistic.
132255036Sdelphij	 */
133255036Sdelphij	if (stat(fname, &sb) == FAIL) {
134255036Sdelphij	    warnx("can't stat package file '%s'", fname);
135255036Sdelphij	    code = 1;
136255036Sdelphij	    goto bail;
137255036Sdelphij	}
138255036Sdelphij	Home = make_playpen(PlayPen, sb.st_size / 2);
139255036Sdelphij	if (unpack(fname, "+*")) {
140255036Sdelphij	    warnx("error during unpacking, no info for '%s' available", pkg);
141255036Sdelphij	    code = 1;
142255036Sdelphij	    goto bail;
143255036Sdelphij	}
144255036Sdelphij    }
1458571Srgrimes    /* It's not an ininstalled package, try and find it among the installed */
146255035Sdelphij    else {
147255035Sdelphij	sprintf(log_dir, "%s/%s", LOG_DIR, pkg);
14878045Sache	if (!fexists(log_dir)) {
14950296Srgrimes	    warnx("can't find package '%s' installed or in a file!", pkg);
15095753Sdwmalone	    return 1;
15195688Sdwmalone	}
15278045Sache	if (chdir(log_dir) == FAIL) {
15350296Srgrimes	    warnx("can't change directory to '%s'!", log_dir);
154133833Sdwmalone	    return 1;
155133833Sdwmalone	}
156255035Sdelphij	installed = TRUE;
157255035Sdelphij    }
158255035Sdelphij
159255035Sdelphij    /* Suck in the contents list */
16059949Sphantom    plist.head = plist.tail = NULL;
16150296Srgrimes    fp = fopen(CONTENTS_FNAME, "r");
162255035Sdelphij    if (!fp) {
163255035Sdelphij	warnx("unable to open %s file", CONTENTS_FNAME);
164151825Sru	code = 1;
165151825Sru	goto bail;
1662878Srgrimes    }
1678571Srgrimes    /* If we have a prefix, add it now */
1688571Srgrimes    read_plist(&plist, fp);
1698571Srgrimes    fclose(fp);
17057522Sshin
17157522Sshin    /*
172118825Sharti     * Index is special info type that has to override all others to make
173118825Sharti     * any sense.
174167165Sflz     */
175167169Sflz    if (Flags & SHOW_INDEX) {
176167169Sflz	char tmp[FILENAME_MAX];
177167169Sflz
178167169Sflz	snprintf(tmp, FILENAME_MAX, "%-19s ", pkg);
179173491Sbenjsc	show_index(tmp, COMMENT_FNAME);
180173491Sbenjsc    }
181167165Sflz    else {
182225880Sdim	/* Start showing the package contents */
183225880Sdim	if (!Quiet)
184225880Sdim	    printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
185225880Sdim	if (Flags & SHOW_COMMENT)
18655797Srgrimes	    show_file("Comment:\n", COMMENT_FNAME);
18755797Srgrimes	if (Flags & SHOW_REQUIRE)
18855797Srgrimes	    show_plist("Depends on:\n", &plist, PLIST_PKGDEP, FALSE);
189290000Sglebius	if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME))
190290000Sglebius	    show_file("Required by:\n", REQUIRED_BY_FNAME);
191290000Sglebius	if (Flags & SHOW_DESC)
192290000Sglebius	    show_file("Description:\n", DESC_FNAME);
193290000Sglebius	if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME))
194290000Sglebius	    show_file("Install notice:\n", DISPLAY_FNAME);
195290000Sglebius	if (Flags & SHOW_PLIST)
196290000Sglebius	    show_plist("Packing list:\n", &plist, (plist_t)0, TRUE);
19755797Srgrimes	if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME))
1988571Srgrimes	    show_file("Install script:\n", INSTALL_FNAME);
1998571Srgrimes	if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME))
2008571Srgrimes	    show_file("Post-Install script:\n", POST_INSTALL_FNAME);
20197098Sru	if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME))
20297098Sru	    show_file("De-Install script:\n", DEINSTALL_FNAME);
20397098Sru	if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME))
20497098Sru	    show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME);
20597098Sru	if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME))
20697098Sru	    show_file("mtree file:\n", MTREE_FNAME);
20797098Sru	if (Flags & SHOW_PREFIX)
20897098Sru	    show_plist("Prefix(s):\n", &plist, PLIST_CWD, FALSE);
20918022Sbde	if (Flags & SHOW_FILES)
21018022Sbde	    show_files("Files:\n", &plist);
21197098Sru	if ((Flags & SHOW_SIZE) && installed)
21297098Sru	    show_size("Package Size:\n", &plist);
2138571Srgrimes	if ((Flags & SHOW_CKSUM) && installed)
2148571Srgrimes	    show_cksum("Mismatched Checksums:\n", &plist);
21523379Swosch	if (Flags & SHOW_ORIGIN)
21623379Swosch	    show_origin("Origin:\n", &plist);
21797098Sru	if (Flags & SHOW_FMTREV)
21897098Sru	    show_fmtrev("Packing list format revision:\n", &plist);
21997098Sru	if (!Quiet)
22097098Sru	    puts(InfoPrefix);
22197098Sru    }
22297098Sru    free_plist(&plist);
2238571Srgrimes bail:
2248571Srgrimes    leave_playpen();
2258571Srgrimes    if (isTMP)
2268571Srgrimes	unlink(fname);
2278571Srgrimes    return code;
2288571Srgrimes}
2298571Srgrimes
2308571Srgrimesvoid
2318571Srgrimescleanup(int sig)
2328571Srgrimes{
2338571Srgrimes    static int in_cleanup = 0;
2348571Srgrimes
2358571Srgrimes    if (!in_cleanup) {
2368571Srgrimes	in_cleanup = 1;
2378571Srgrimes	leave_playpen();
2388571Srgrimes    }
2398571Srgrimes    if (sig)
2408571Srgrimes	exit(1);
2418571Srgrimes}
2428571Srgrimes
2438571Srgrimes/*
2448571Srgrimes * Return an absolute path, additionally removing all .'s, ..'s, and extraneous
2458571Srgrimes * /'s, as realpath() would, but without resolving symlinks, because that can
2468571Srgrimes * potentially screw up our comparisons later.
2478571Srgrimes */
2488571Srgrimesstatic char *
2498571Srgrimesabspath(const char *pathname)
2508571Srgrimes{
2518571Srgrimes    char *tmp, *tmp1, *resolved_path;
2528571Srgrimes    char *cwd = NULL;
2538571Srgrimes    int len;
2548571Srgrimes
2558571Srgrimes    if (pathname[0] != '/') {
2568571Srgrimes	cwd = getcwd(NULL, MAXPATHLEN);
2578571Srgrimes	asprintf(&resolved_path, "%s/%s/", cwd, pathname);
2588571Srgrimes    } else
2598571Srgrimes	asprintf(&resolved_path, "%s/", pathname);
2608571Srgrimes
2618571Srgrimes    if (resolved_path == NULL)
2628571Srgrimes	errx(2, NULL);
2638571Srgrimes
2648571Srgrimes    if (cwd != NULL)
2658571Srgrimes	free(cwd);
2668571Srgrimes
2678571Srgrimes    while ((tmp = strstr(resolved_path, "//")) != NULL)
2688571Srgrimes	strcpy(tmp, tmp + 1);
269202843Sdelphij
270202843Sdelphij    while ((tmp = strstr(resolved_path, "/./")) != NULL)
271202843Sdelphij	strcpy(tmp, tmp + 2);
272202843Sdelphij
2738571Srgrimes    while ((tmp = strstr(resolved_path, "/../")) != NULL) {
2748571Srgrimes	*tmp = '\0';
2758571Srgrimes	if ((tmp1 = strrchr(resolved_path, '/')) == NULL)
2768571Srgrimes	   tmp1 = resolved_path;
2778571Srgrimes	strcpy(tmp1, tmp + 3);
2788571Srgrimes    }
2798571Srgrimes
2808571Srgrimes    len = strlen(resolved_path);
2818571Srgrimes    if (len > 1 && resolved_path[len - 1] == '/')
2828571Srgrimes	resolved_path[len - 1] = '\0';
2838571Srgrimes
2848571Srgrimes    return resolved_path;
2858571Srgrimes}
2868571Srgrimes
2878571Srgrimes/*
2888571Srgrimes * Comparison to see if the path we're on matches the
28997098Sru * one we are looking for.
29097098Sru */
29197098Srustatic int
29297098Srucmp_path(const char *target, const char *current, const char *cwd)
2938571Srgrimes{
2948571Srgrimes    char *resolved, *temp;
295235613Sgnn    int rval;
296235613Sgnn
297235613Sgnn    asprintf(&temp, "%s/%s", cwd, current);
298248979Semaste    if (temp == NULL)
2998571Srgrimes        errx(2, NULL);
30072636Sphk
30172636Sphk    /*
3022878Srgrimes     * Make sure there's no multiple /'s or other weird things in the PLIST,
3032878Srgrimes     * since some plists seem to have them and it could screw up our strncmp.
30457522Sshin     */
30557522Sshin    resolved = abspath(temp);
306248484Sneel
307248484Sneel    if (strcmp(target, resolved) == 0)
30842006Sjkh	rval = 1;
30942006Sjkh    else
310255036Sdelphij	rval = 0;
311255036Sdelphij
312235203Seadler    free(temp);
313235203Seadler    free(resolved);
31450296Srgrimes    return rval;
31550296Srgrimes}
31622240Sjdp
31722240Sjdp/*
3188571Srgrimes * Look through package dbs in db_dir and find which
31950296Srgrimes * packages installed the files in which_list.
32050296Srgrimes */
3212878Srgrimesstatic int
32250296Srgrimesfind_pkg(const char *db_dir, struct which_head *which_list)
32350296Srgrimes{
324204080Sdelphij    char **installed;
325204080Sdelphij    int errcode, i;
326173532Ssam    struct which_entry *wp;
327173532Ssam
3283831Ssos    TAILQ_FOREACH(wp, which_list, next) {
3292878Srgrimes	const char *msg = "file cannot be found";
330206996Savg	char *tmp;
331206996Savg
33285484Sru	wp->skip = TRUE;
33385484Sru	/* If it's not a file, we'll see if it's an executable. */
33477825Sdcs	if (isfile(wp->file) == FALSE) {
33577825Sdcs	    if (strchr(wp->file, '/') == NULL) {
336171584Sscottl		tmp = vpipe("/usr/bin/which %s", wp->file);
337171584Sscottl		if (tmp != NULL) {
338214308Sjulian		    strlcpy(wp->file, tmp, PATH_MAX);
339214308Sjulian		    wp->skip = FALSE;
34041682Sdfr		    free(tmp);
34141682Sdfr		} else
34241682Sdfr		    msg = "file is not in PATH";
34341682Sdfr	    }
34441682Sdfr	} else {
34541682Sdfr	    tmp = abspath(wp->file);
34641682Sdfr	    if (isfile(tmp)) {
34763211Sabial	    	strlcpy(wp->file, tmp, PATH_MAX);
34863211Sabial	    	wp->skip = FALSE;
349200440Santoine	    }
350200440Santoine	    free(tmp);
351200440Santoine	}
352200440Santoine	if (wp->skip == TRUE)
353200440Santoine	    warnx("%s: %s", wp->file, msg);
354200440Santoine    }
355218914Slstewart
356218914Slstewart    installed = matchinstalled(MATCH_ALL, NULL, &errcode);
35742449Sjdp    if (installed == NULL)
35841682Sdfr        return errcode;
35941682Sdfr
36041682Sdfr    for (i = 0; installed[i] != NULL; i++) {
36141682Sdfr     	FILE *fp;
36241682Sdfr     	Package pkg;
36341682Sdfr     	PackingList itr;
364238618Sjoerg     	char *cwd = NULL;
365238618Sjoerg     	char tmp[PATH_MAX];
36630488Sjkh
36730488Sjkh	snprintf(tmp, PATH_MAX, "%s/%s/%s", db_dir, installed[i],
36855797Srgrimes		 CONTENTS_FNAME);
36955797Srgrimes	fp = fopen(tmp, "r");
37055797Srgrimes	if (fp == NULL) {
371121616Semax	    warn("%s", tmp);
372121616Semax	    return 1;
37355797Srgrimes	}
374209513Simp
375209513Simp	pkg.head = pkg.tail = NULL;
37650296Srgrimes	read_plist(&pkg, fp);
37750296Srgrimes	fclose(fp);
378135184Smlaier	for (itr = pkg.head; itr != pkg.tail; itr = itr->next) {
379135184Smlaier	    if (itr->type == PLIST_CWD) {
38050296Srgrimes		cwd = itr->name;
38150296Srgrimes	    } else if (itr->type == PLIST_FILE) {
38250296Srgrimes		TAILQ_FOREACH(wp, which_list, next) {
38350296Srgrimes		    if (wp->skip == TRUE)
38450296Srgrimes			continue;
38550296Srgrimes		    if (!cmp_path(wp->file, itr->name, cwd))
38655797Srgrimes			continue;
38755797Srgrimes		    if (wp->package[0] != '\0') {
38856114Sphk			warnx("both %s and %s claim to have installed %s\n",
38957611Sbillf			      wp->package, installed[i], wp->file);
39057611Sbillf		    } else {
39157611Sbillf			strlcpy(wp->package, installed[i], PATH_MAX);
39257611Sbillf		    }
39357611Sbillf		}
39457611Sbillf	    }
39557611Sbillf	}
39657611Sbillf	free_plist(&pkg);
39757611Sbillf    }
39857611Sbillf
39956114Sphk    TAILQ_FOREACH(wp, which_list, next) {
400252356Sdavide	if (wp->package[0] != '\0') {
401252356Sdavide	    if (Quiet)
402252356Sdavide		puts(wp->package);
403252356Sdavide	    else
4048571Srgrimes		printf("%s was installed by package %s\n", \
4058571Srgrimes		       wp->file, wp->package);
4068571Srgrimes	}
4078571Srgrimes    }
4088571Srgrimes    while (!TAILQ_EMPTY(which_list)) {
4098571Srgrimes	wp = TAILQ_FIRST(which_list);
4108571Srgrimes	TAILQ_REMOVE(which_list, wp, next);
4118571Srgrimes	free(wp);
41290559Smp    }
41390559Smp
4142878Srgrimes    free(which_list);
41539695Sobrien    return 0;
4168571Srgrimes}
4172878Srgrimes