perform.c revision 72174
1327Sjkh#ifndef lint
230221Scharnierstatic const char rcsid[] =
350479Speter  "$FreeBSD: head/usr.sbin/pkg_install/info/perform.c 72174 2001-02-08 17:44:00Z 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"
28327Sjkh
2972174Ssobomax#include <sys/types.h>
3072174Ssobomax#include <err.h>
3172174Ssobomax#include <glob.h>
3249300Sjdp#include <fts.h>
3372174Ssobomax#include <regex.h>
34327Sjkh#include <signal.h>
35327Sjkh
3649300Sjdpstatic int fname_cmp(const FTSENT **, const FTSENT **);
37327Sjkhstatic int pkg_do(char *);
3872174Ssobomaxstatic int rexs_match(char **, char *);
39327Sjkh
40327Sjkhint
41327Sjkhpkg_perform(char **pkgs)
42327Sjkh{
43327Sjkh    int i, err_cnt = 0;
447937Sjkh    char *tmp;
45327Sjkh
46327Sjkh    signal(SIGINT, cleanup);
47327Sjkh
487937Sjkh    tmp = getenv(PKG_DBDIR);
497937Sjkh    if (!tmp)
507937Sjkh	tmp = DEF_LOG_DIR;
51327Sjkh    /* Overriding action? */
5216404Sjkh    if (CheckPkg) {
5316404Sjkh	char buf[FILENAME_MAX];
54327Sjkh
5516404Sjkh	snprintf(buf, FILENAME_MAX, "%s/%s", tmp, CheckPkg);
5616404Sjkh	return abs(access(buf, R_OK));
5772174Ssobomax	/* Not reached */
5816404Sjkh    }
598857Srgrimes
6072174Ssobomax    switch (MatchType) {
6172174Ssobomax    case MATCH_ALL:
6272174Ssobomax    case MATCH_REGEX:
6372174Ssobomax	{
6472174Ssobomax	    FTS *ftsp;
6572174Ssobomax	    FTSENT *f;
6672174Ssobomax	    char *paths[2];
6772174Ssobomax	    int errcode;
6872174Ssobomax
6972174Ssobomax	    if (!isdir(tmp))
7072174Ssobomax		return 1;
7172174Ssobomax	    paths[0] = tmp;
7272174Ssobomax	    paths[1] = NULL;
7372174Ssobomax	    ftsp = fts_open(paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT,
7472174Ssobomax	      fname_cmp);
7572174Ssobomax	    if (ftsp != NULL) {
7672174Ssobomax		while ((f = fts_read(ftsp)) != NULL) {
7772174Ssobomax		    if (f->fts_info == FTS_D && f->fts_level == 1) {
7872174Ssobomax			fts_set(ftsp, f, FTS_SKIP);
7972174Ssobomax			if (MatchType == MATCH_REGEX) {
8072174Ssobomax			    errcode = rexs_match(pkgs, f->fts_name);
8172174Ssobomax			    if (errcode == -1) {
8272174Ssobomax				err_cnt += 1;
8372174Ssobomax				break;
8472174Ssobomax			    }
8572174Ssobomax			    else if (errcode == 0)
8672174Ssobomax				continue;
8772174Ssobomax			}
8872174Ssobomax			err_cnt += pkg_do(f->fts_name);
8972174Ssobomax		    }
9049300Sjdp		}
9172174Ssobomax		fts_close(ftsp);
9249300Sjdp	    }
9316404Sjkh	}
9472174Ssobomax	break;
9572174Ssobomax    case MATCH_GLOB:
9672174Ssobomax	{
9772174Ssobomax	    glob_t g;
9872174Ssobomax	    char *gexpr;
9972174Ssobomax	    char *cp;
10072174Ssobomax	    int gflags;
10172174Ssobomax	    int prev_matchc;
10272174Ssobomax
10372174Ssobomax	    gflags = GLOB_ERR;
10472174Ssobomax	    prev_matchc = 0;
10572174Ssobomax	    for (i = 0; pkgs[i]; i++) {
10672174Ssobomax		asprintf(&gexpr, "%s/%s", tmp, pkgs[i]);
10772174Ssobomax
10872174Ssobomax		if (glob(gexpr, gflags, NULL, &g) != 0) {
10972174Ssobomax		    warn("%s: error encountered when matching glob", pkgs[i]);
11072174Ssobomax		    return 1;
11172174Ssobomax		}
11272174Ssobomax
11372174Ssobomax		/*
11472174Ssobomax		 * If glob doesn't match try to use pkgs[i] directly - it
11572174Ssobomax		 * could be name of the tarball.
11672174Ssobomax		 */
11772174Ssobomax		if (g.gl_matchc == prev_matchc)
11872174Ssobomax		    err_cnt += pkg_do(pkgs[i]);
11972174Ssobomax
12072174Ssobomax		prev_matchc = g.gl_matchc;
12172174Ssobomax		gflags |= GLOB_APPEND;
12272174Ssobomax		free(gexpr);
12372174Ssobomax	    }
12472174Ssobomax
12572174Ssobomax	    for (i = 0; i < g.gl_matchc; i++) {
12672174Ssobomax		cp = strrchr(g.gl_pathv[i], '/');
12772174Ssobomax		if (cp == NULL)
12872174Ssobomax		    cp = g.gl_pathv[i];
12972174Ssobomax		else
13072174Ssobomax		    cp++;
13172174Ssobomax
13272174Ssobomax		err_cnt += pkg_do(cp);
13372174Ssobomax	    }
13472174Ssobomax
13572174Ssobomax	    globfree(&g);
13672174Ssobomax	}
13772174Ssobomax	break;
13872174Ssobomax    default:
13916404Sjkh	for (i = 0; pkgs[i]; i++)
14016404Sjkh	    err_cnt += pkg_do(pkgs[i]);
14172174Ssobomax	break;
14272174Ssobomax    }
14372174Ssobomax
144327Sjkh    return err_cnt;
145327Sjkh}
146327Sjkh
14711780Sjkhstatic char *Home;
14811780Sjkh
149327Sjkhstatic int
150327Sjkhpkg_do(char *pkg)
151327Sjkh{
1528086Sjkh    Boolean installed = FALSE, isTMP = FALSE;
153327Sjkh    char log_dir[FILENAME_MAX];
1548086Sjkh    char fname[FILENAME_MAX];
155327Sjkh    Package plist;
156327Sjkh    FILE *fp;
1578086Sjkh    struct stat sb;
1588142Sjkh    char *cp = NULL;
1598086Sjkh    int code = 0;
160327Sjkh
1618086Sjkh    if (isURL(pkg)) {
16211780Sjkh	if ((cp = fileGetURL(NULL, pkg)) != NULL) {
1638086Sjkh	    strcpy(fname, cp);
1648086Sjkh	    isTMP = TRUE;
1658086Sjkh	}
1668086Sjkh    }
1679782Sache    else if (fexists(pkg) && isfile(pkg)) {
1688086Sjkh	int len;
169327Sjkh
1708423Sjkh	if (*pkg != '/') {
1718423Sjkh	    if (!getcwd(fname, FILENAME_MAX))
1728423Sjkh		upchuck("getcwd");
1738423Sjkh	    len = strlen(fname);
1748423Sjkh	    snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg);
1758423Sjkh	}
1768423Sjkh	else
1778423Sjkh	    strcpy(fname, pkg);
1788086Sjkh	cp = fname;
1798086Sjkh    }
1808086Sjkh    else {
18111780Sjkh	if ((cp = fileFindByPath(NULL, pkg)) != NULL)
1828086Sjkh	    strncpy(fname, cp, FILENAME_MAX);
1838086Sjkh    }
1848086Sjkh    if (cp) {
1853364Sjkh	/*
1863364Sjkh	 * Apply a crude heuristic to see how much space the package will
1873364Sjkh	 * take up once it's unpacked.  I've noticed that most packages
1883577Sjkh	 * compress an average of 75%, but we're only unpacking the + files so
1893577Sjkh	 * be very optimistic.
1903364Sjkh	 */
1913364Sjkh	if (stat(fname, &sb) == FAIL) {
19230221Scharnier	    warnx("can't stat package file '%s'", fname);
1938086Sjkh	    code = 1;
1948086Sjkh	    goto bail;
1953364Sjkh	}
19611780Sjkh	Home = make_playpen(PlayPen, sb.st_size / 2);
197327Sjkh	if (unpack(fname, "+*")) {
19830221Scharnier	    warnx("error during unpacking, no info for '%s' available", pkg);
1998086Sjkh	    code = 1;
2008086Sjkh	    goto bail;
201327Sjkh	}
202327Sjkh    }
2038086Sjkh    /* It's not an ininstalled package, try and find it among the installed */
204327Sjkh    else {
2057937Sjkh	char *tmp;
2067937Sjkh
2077937Sjkh	sprintf(log_dir, "%s/%s", (tmp = getenv(PKG_DBDIR)) ? tmp : DEF_LOG_DIR,
2087937Sjkh		pkg);
209327Sjkh	if (!fexists(log_dir)) {
21030221Scharnier	    warnx("can't find package `%s' installed or in a file!", pkg);
211327Sjkh	    return 1;
212327Sjkh	}
213327Sjkh	if (chdir(log_dir) == FAIL) {
21430221Scharnier	    warnx("can't change directory to '%s'!", log_dir);
215327Sjkh	    return 1;
216327Sjkh	}
217327Sjkh	installed = TRUE;
218327Sjkh    }
219327Sjkh
220327Sjkh    /* Suck in the contents list */
221327Sjkh    plist.head = plist.tail = NULL;
222327Sjkh    fp = fopen(CONTENTS_FNAME, "r");
223327Sjkh    if (!fp) {
22430221Scharnier	warnx("unable to open %s file", CONTENTS_FNAME);
2258086Sjkh	code = 1;
2268086Sjkh	goto bail;
227327Sjkh    }
228327Sjkh    /* If we have a prefix, add it now */
229327Sjkh    read_plist(&plist, fp);
230327Sjkh    fclose(fp);
231327Sjkh
232327Sjkh    /*
233327Sjkh     * Index is special info type that has to override all others to make
234327Sjkh     * any sense.
235327Sjkh     */
236327Sjkh    if (Flags & SHOW_INDEX) {
2378086Sjkh	char tmp[FILENAME_MAX];
238327Sjkh
2398086Sjkh	snprintf(tmp, FILENAME_MAX, "%-19s ", pkg);
2408086Sjkh	show_index(tmp, COMMENT_FNAME);
241327Sjkh    }
242327Sjkh    else {
243327Sjkh	/* Start showing the package contents */
244411Sjkh	if (!Quiet)
245411Sjkh	    printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
246327Sjkh	if (Flags & SHOW_COMMENT)
247379Sjkh	    show_file("Comment:\n", COMMENT_FNAME);
24866339Smarko	if (Flags & SHOW_REQUIRE)
24966339Smarko	    show_plist("Depends on:\n", &plist, PLIST_PKGDEP);
2504996Sjkh	if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME))
2514996Sjkh	    show_file("Required by:\n", REQUIRED_BY_FNAME);
252327Sjkh	if (Flags & SHOW_DESC)
253379Sjkh	    show_file("Description:\n", DESC_FNAME);
2544996Sjkh	if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME))
2554996Sjkh	    show_file("Install notice:\n", DISPLAY_FNAME);
256327Sjkh	if (Flags & SHOW_PLIST)
257379Sjkh	    show_plist("Packing list:\n", &plist, (plist_t)-1);
258327Sjkh	if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME))
259379Sjkh	    show_file("Install script:\n", INSTALL_FNAME);
26041866Sjkh	if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME))
26141866Sjkh	    show_file("Post-Install script:\n", POST_INSTALL_FNAME);
262327Sjkh	if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME))
263379Sjkh	    show_file("De-Install script:\n", DEINSTALL_FNAME);
26441866Sjkh	if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME))
26541866Sjkh	    show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME);
2664996Sjkh	if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME))
2674996Sjkh	    show_file("mtree file:\n", MTREE_FNAME);
268327Sjkh	if (Flags & SHOW_PREFIX)
269379Sjkh	    show_plist("Prefix(s):\n", &plist, PLIST_CWD);
270411Sjkh	if (Flags & SHOW_FILES)
271411Sjkh	    show_files("Files:\n", &plist);
27262775Ssobomax	if ((Flags & SHOW_SIZE) && installed)
27362775Ssobomax	    show_size("Package Size:\n", &plist);
27471965Sjkh	if ((Flags & SHOW_CKSUM) && installed)
27571965Sjkh	    show_cksum("Mismatched Checksums:\n", &plist);
27667454Ssobomax	if (Flags & SHOW_ORIGIN)
27767454Ssobomax	    show_origin("Origin:\n", &plist);
278411Sjkh	if (!Quiet)
279411Sjkh	    puts(InfoPrefix);
280327Sjkh    }
281327Sjkh    free_plist(&plist);
2828086Sjkh bail:
28333427Sjkh    leave_playpen();
2848086Sjkh    if (isTMP)
2858086Sjkh	unlink(fname);
2868086Sjkh    return code;
287327Sjkh}
288327Sjkh
289327Sjkhvoid
290327Sjkhcleanup(int sig)
291327Sjkh{
29233427Sjkh    static int in_cleanup = 0;
29333427Sjkh
29433427Sjkh    if (!in_cleanup) {
29533427Sjkh	in_cleanup = 1;
29672174Ssobomax	leave_playpen();
29733427Sjkh    }
29839068Sjkh    if (sig)
29939068Sjkh	exit(1);
300327Sjkh}
30149300Sjdp
30249300Sjdpstatic int
30349300Sjdpfname_cmp(const FTSENT **a, const FTSENT **b)
30449300Sjdp{
30549300Sjdp    return strcmp((*a)->fts_name, (*b)->fts_name);
30649300Sjdp}
30772174Ssobomax
30872174Ssobomax/*
30972174Ssobomax * Returns 1 if specified pkgname matches at least one
31072174Ssobomax * of the RE from patterns. Otherwise return 0 if no
31172174Ssobomax * matches were found or -1 if RE engine reported an
31272174Ssobomax * error (usually invalid syntax).
31372174Ssobomax */
31472174Ssobomaxstatic int
31572174Ssobomaxrexs_match(char **patterns, char *pkgname)
31672174Ssobomax{
31772174Ssobomax    Boolean matched;
31872174Ssobomax    char errbuf[128];
31972174Ssobomax    int i;
32072174Ssobomax    int errcode;
32172174Ssobomax    int retval;
32272174Ssobomax    regex_t rex;
32372174Ssobomax
32472174Ssobomax    errcode = 0;
32572174Ssobomax    retval = 0;
32672174Ssobomax    matched = FALSE;
32772174Ssobomax    for (i = 0; patterns[i]; i++) {
32872174Ssobomax	errcode = regcomp(&rex, patterns[i], REG_BASIC | REG_NOSUB);
32972174Ssobomax	if (errcode != 0)
33072174Ssobomax	    break;
33172174Ssobomax
33272174Ssobomax	errcode = regexec(&rex, pkgname, 0, NULL, 0);
33372174Ssobomax	if (errcode == 0) {
33472174Ssobomax	    matched = TRUE;
33572174Ssobomax	    retval = 1;
33672174Ssobomax	    break;
33772174Ssobomax	}
33872174Ssobomax	else if (errcode != REG_NOMATCH)
33972174Ssobomax	    break;
34072174Ssobomax
34172174Ssobomax	regfree(&rex);
34272174Ssobomax	errcode = 0;
34372174Ssobomax    }
34472174Ssobomax
34572174Ssobomax    if (errcode != 0) {
34672174Ssobomax	regerror(errcode, &rex, errbuf, sizeof(errbuf));
34772174Ssobomax	warnx("%s: %s", patterns[i], errbuf);
34872174Ssobomax	retval = -1;
34972174Ssobomax    }
35072174Ssobomax
35172174Ssobomax    if ((errcode != 0) || (matched == TRUE))
35272174Ssobomax	regfree(&rex);
35372174Ssobomax
35472174Ssobomax    return retval;
35572174Ssobomax}
356