match.c revision 80042
173134Ssobomax#ifndef lint
273134Ssobomaxstatic const char rcsid[] =
373134Ssobomax  "$FreeBSD: head/usr.sbin/pkg_install/lib/match.c 80042 2001-07-20 13:20:32Z sobomax $";
473134Ssobomax#endif
573134Ssobomax
673134Ssobomax/*
773134Ssobomax * FreeBSD install - a package for the installation and maintainance
873134Ssobomax * of non-core utilities.
973134Ssobomax *
1073134Ssobomax * Redistribution and use in source and binary forms, with or without
1173134Ssobomax * modification, are permitted provided that the following conditions
1273134Ssobomax * are met:
1373134Ssobomax * 1. Redistributions of source code must retain the above copyright
1473134Ssobomax *    notice, this list of conditions and the following disclaimer.
1573134Ssobomax * 2. Redistributions in binary form must reproduce the above copyright
1673134Ssobomax *    notice, this list of conditions and the following disclaimer in the
1773134Ssobomax *    documentation and/or other materials provided with the distribution.
1873134Ssobomax *
1973134Ssobomax * Maxim Sobolev
2073134Ssobomax * 24 February 2001
2173134Ssobomax *
2273134Ssobomax * Routines used to query installed packages.
2373134Ssobomax *
2473134Ssobomax */
2573134Ssobomax
2673134Ssobomax#include "lib.h"
2773134Ssobomax#include <err.h>
2873134Ssobomax#include <fnmatch.h>
2973134Ssobomax#include <fts.h>
3073134Ssobomax#include <regex.h>
3173134Ssobomax
3273134Ssobomax/*
3373134Ssobomax * Simple structure representing argv-like
3473134Ssobomax * NULL-terminated list.
3573134Ssobomax */
3673134Ssobomaxstruct store {
3773134Ssobomax    int currlen;
3873134Ssobomax    int used;
3973134Ssobomax    char **store;
4073134Ssobomax};
4173134Ssobomax
4273134Ssobomaxstatic int rex_match(char *, char *);
4373144Ssobomaxstatic int storeappend(struct store *, const char *);
4473134Ssobomaxstatic int fname_cmp(const FTSENT **, const FTSENT **);
4573134Ssobomax
4673134Ssobomax/*
4773134Ssobomax * Function to query names of installed packages.
4873134Ssobomax * MatchType	- one of MATCH_ALL, MATCH_REGEX, MATCH_GLOB;
4973134Ssobomax * patterns	- NULL-terminated list of glob or regex patterns
5073134Ssobomax *		  (could be NULL for MATCH_ALL);
5173134Ssobomax * retval	- return value (could be NULL if you don't want/need
5273134Ssobomax *		  return value).
5373134Ssobomax * Returns NULL-terminated list with matching names.
5473134Ssobomax * Names in list returned are dynamically allocated and should
5573134Ssobomax * not be altered by the caller.
5673134Ssobomax */
5773134Ssobomaxchar **
5873134Ssobomaxmatchinstalled(match_t MatchType, char **patterns, int *retval)
5973134Ssobomax{
6074258Ssobomax    int i, errcode, len;
6173144Ssobomax    char *tmp, *matched;
6273134Ssobomax    char *paths[2];
6373134Ssobomax    static struct store *store = NULL;
6473134Ssobomax    FTS *ftsp;
6573134Ssobomax    FTSENT *f;
6674258Ssobomax    Boolean *lmatched;
6773134Ssobomax
6873134Ssobomax    if (store == NULL) {
6973134Ssobomax	store = malloc(sizeof *store);
7073144Ssobomax	if (store == NULL) {
7173144Ssobomax	    warnx("%s(): malloc() failed", __FUNCTION__);
7273144Ssobomax	    if (retval != NULL)
7373144Ssobomax		*retval = 1;
7473144Ssobomax	    return NULL;
7573144Ssobomax	}
7673134Ssobomax	store->currlen = 0;
7773134Ssobomax	store->store = NULL;
7873144Ssobomax    } else
7973144Ssobomax	if (store->store != NULL)
8073134Ssobomax	    /* Free previously allocated memory */
8173134Ssobomax	    for (i = 0; store->store[i] != NULL; i++)
8273134Ssobomax		free(store->store[i]);
8373134Ssobomax    store->used = 0;
8473134Ssobomax
8573134Ssobomax    if (retval != NULL)
8673134Ssobomax	*retval = 0;
8773134Ssobomax
8873134Ssobomax    tmp = getenv(PKG_DBDIR);
8973134Ssobomax    if (!tmp)
9073134Ssobomax	tmp = DEF_LOG_DIR;
9173134Ssobomax    if (!isdir(tmp)) {
9273134Ssobomax	if (retval != NULL)
9373134Ssobomax	    *retval = 1;
9473134Ssobomax	return NULL;
9573134Ssobomax	/* Not reached */
9673134Ssobomax    }
9773134Ssobomax
9874258Ssobomax    /* Count number of patterns */
9974699Ssobomax    if (patterns != NULL) {
10074699Ssobomax	for (len = 0; patterns[len]; len++) {}
10174699Ssobomax	lmatched = alloca(sizeof(*lmatched) * len);
10274699Ssobomax	if (lmatched == NULL) {
10374699Ssobomax	    warnx("%s(): alloca() failed", __FUNCTION__);
10474699Ssobomax	    if (retval != NULL)
10574699Ssobomax		*retval = 1;
10674699Ssobomax	    return NULL;
10774699Ssobomax    	}
10874699Ssobomax    } else
10974699Ssobomax	len = 0;
11074699Ssobomax
11174258Ssobomax    for (i = 0; i < len; i++)
11274258Ssobomax	lmatched[i] = FALSE;
11374258Ssobomax
11473134Ssobomax    paths[0] = tmp;
11573134Ssobomax    paths[1] = NULL;
11673134Ssobomax    ftsp = fts_open(paths, FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp);
11773134Ssobomax    if (ftsp != NULL) {
11873134Ssobomax	while ((f = fts_read(ftsp)) != NULL) {
11973134Ssobomax	    if (f->fts_info == FTS_D && f->fts_level == 1) {
12073134Ssobomax		fts_set(ftsp, f, FTS_SKIP);
12173144Ssobomax		matched = NULL;
12273144Ssobomax		errcode = 0;
12373144Ssobomax		if (MatchType == MATCH_ALL)
12473144Ssobomax		    matched = f->fts_name;
12573144Ssobomax		else
12673144Ssobomax		    for (i = 0; patterns[i]; i++) {
12773144Ssobomax			switch (MatchType) {
12873144Ssobomax			case MATCH_REGEX:
12973144Ssobomax			    errcode = rex_match(patterns[i], f->fts_name);
13073144Ssobomax			    if (errcode == 1) {
13173144Ssobomax				matched = f->fts_name;
13273144Ssobomax				errcode = 0;
13373144Ssobomax			    }
13473144Ssobomax			    break;
13573144Ssobomax			case MATCH_GLOB:
13674258Ssobomax			    if (fnmatch(patterns[i], f->fts_name, 0) == 0) {
13773144Ssobomax				matched = f->fts_name;
13874258Ssobomax				lmatched[i] = TRUE;
13974258Ssobomax			    }
14073144Ssobomax			    break;
14173144Ssobomax			default:
14273144Ssobomax			    break;
14373134Ssobomax			}
14473144Ssobomax			if (matched != NULL || errcode != 0)
14573144Ssobomax			    break;
14673134Ssobomax		    }
14773144Ssobomax		if (errcode == 0 && matched != NULL)
14873144Ssobomax		    errcode = storeappend(store, matched);
14973144Ssobomax		if (errcode != 0) {
15073144Ssobomax		    if (retval != NULL)
15173144Ssobomax			*retval = 1;
15273144Ssobomax		    return NULL;
15373144Ssobomax		    /* Not reached */
15473134Ssobomax		}
15573134Ssobomax	    }
15673134Ssobomax	}
15773134Ssobomax	fts_close(ftsp);
15873134Ssobomax    }
15973134Ssobomax
16074258Ssobomax    if (MatchType == MATCH_GLOB) {
16174258Ssobomax	for (i = 0; i < len; i++)
16274258Ssobomax	    if (lmatched[i] == FALSE)
16374258Ssobomax		storeappend(store, patterns[i]);
16474258Ssobomax    }
16574258Ssobomax
16673134Ssobomax    if (store->used == 0)
16773134Ssobomax	return NULL;
16873134Ssobomax    else
16973134Ssobomax	return store->store;
17073134Ssobomax}
17173134Ssobomax
17273134Ssobomax/*
17373134Ssobomax * Returns 1 if specified pkgname matches RE pattern.
17473134Ssobomax * Otherwise returns 0 if doesn't match or -1 if RE
17573134Ssobomax * engine reported an error (usually invalid syntax).
17673134Ssobomax */
17773134Ssobomaxstatic int
17873134Ssobomaxrex_match(char *pattern, char *pkgname)
17973134Ssobomax{
18073134Ssobomax    char errbuf[128];
18173134Ssobomax    int errcode;
18273134Ssobomax    int retval;
18373134Ssobomax    regex_t rex;
18473134Ssobomax
18573134Ssobomax    retval = 0;
18673134Ssobomax
18773134Ssobomax    errcode = regcomp(&rex, pattern, REG_BASIC | REG_NOSUB);
18873134Ssobomax    if (errcode == 0)
18973134Ssobomax	errcode = regexec(&rex, pkgname, 0, NULL, 0);
19073134Ssobomax
19173134Ssobomax    if (errcode == 0) {
19273134Ssobomax	retval = 1;
19373134Ssobomax    } else if (errcode != REG_NOMATCH) {
19473134Ssobomax	regerror(errcode, &rex, errbuf, sizeof(errbuf));
19573134Ssobomax	warnx("%s: %s", pattern, errbuf);
19673134Ssobomax	retval = -1;
19773134Ssobomax    }
19873134Ssobomax
19973134Ssobomax    regfree(&rex);
20073134Ssobomax
20173134Ssobomax    return retval;
20273134Ssobomax}
20373134Ssobomax
20473144Ssobomaxstatic int
20573134Ssobomaxstoreappend(struct store *store, const char *item)
20673134Ssobomax{
20773134Ssobomax    if (store->used + 2 > store->currlen) {
20873134Ssobomax	store->currlen += 16;
20980042Ssobomax	store->store = reallocf(store->store,
21080042Ssobomax				store->currlen * sizeof(*(store->store)));
21173144Ssobomax	if (store->store == NULL) {
21280042Ssobomax	    store->currlen = 0;
21380042Ssobomax	    warnx("%s(): reallocf() failed", __FUNCTION__);
21473144Ssobomax	    return 1;
21573144Ssobomax	}
21673134Ssobomax    }
21773134Ssobomax
21873134Ssobomax    asprintf(&(store->store[store->used]), "%s", item);
21973144Ssobomax    if (store->store[store->used] == NULL) {
22073144Ssobomax	warnx("%s(): malloc() failed", __FUNCTION__);
22173144Ssobomax	return 1;
22273144Ssobomax    }
22373134Ssobomax    store->used++;
22473134Ssobomax    store->store[store->used] = NULL;
22573144Ssobomax
22673144Ssobomax    return 0;
22773134Ssobomax}
22873134Ssobomax
22973134Ssobomaxstatic int
23073134Ssobomaxfname_cmp(const FTSENT **a, const FTSENT **b)
23173134Ssobomax{
23273134Ssobomax    return strcmp((*a)->fts_name, (*b)->fts_name);
23373134Ssobomax}
234