diff --git a/usr.sbin/pkg_install/Makefile b/usr.sbin/pkg_install/Makefile index bf1a213..0d7536d 100644 --- a/usr.sbin/pkg_install/Makefile +++ b/usr.sbin/pkg_install/Makefile @@ -2,7 +2,7 @@ .include -SUBDIR= lib add create delete info updating version +SUBDIR= lib add create delete info updating version audit .include diff --git a/usr.sbin/pkg_install/audit/Makefile b/usr.sbin/pkg_install/audit/Makefile new file mode 100644 index 0000000..2ece5f8 --- /dev/null +++ b/usr.sbin/pkg_install/audit/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +PROG= pkg_audit +SRCS= main.c parse.c + +CFLAGS+= -I${.CURDIR}/../lib + +WARNS?= 6 +WFORMAT?= 1 + +DPADD= ${LIBINSTALL} ${LIBFETCH} ${LIBMD} +LDADD= ${LIBINSTALL} -lfetch -lmd + +.include diff --git a/usr.sbin/pkg_install/audit/audit.h b/usr.sbin/pkg_install/audit/audit.h new file mode 100644 index 0000000..1f0a369 --- /dev/null +++ b/usr.sbin/pkg_install/audit/audit.h @@ -0,0 +1,43 @@ +/* + * + * FreeBSD install - a package for the installation and maintainance + * of non-core utilities. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Eygene Ryabinkin + * 26 August 2008 + * + * Parsing module for pkg_audit, header file. + * + */ + +#ifndef __AUDIT_H__ +#define __AUDIT_H__ + +#include + +SLIST_HEAD(audit_contents, audit_entry); + +struct audit_entry { + char *pkgglob; /* Package name glob */ + char *url; /* URL of advisory */ + char *descr; /* Description of vulnerability */ + size_t pfx_size; /* Metacharacter-less glob part size */ + SLIST_ENTRY(audit_entry) entries; +}; + + +/* Function prototypes */ +int +parse_auditfile(FILE *_fp, struct audit_contents *_head); + + +#endif /* defined(__AUDIT_H__) */ diff --git a/usr.sbin/pkg_install/audit/main.c b/usr.sbin/pkg_install/audit/main.c new file mode 100644 index 0000000..1d27e09 --- /dev/null +++ b/usr.sbin/pkg_install/audit/main.c @@ -0,0 +1,211 @@ +/* + * + * FreeBSD install - a package for the installation and maintainance + * of non-core utilities. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Eygene Ryabinkin + * 26 August 2008 + * + * This is the audit module -- fast helper for the portaudit script. + * + * It is filter-like utility: it reads the audit file from the + * standard input, intersects the vulnerable port list with the + * packages installed in the system and outputs the entries for + * the vulnerable ports that are present in the system to the + * standard output. + * + * The installed package can be listed multiple times, since it + * can be vulnerable to more than one bug at a time. But the + * whole output entries will be unique -- package name and + * vulnerability details should produce unique entry. + * + * One more field is prepended to the list of the input fields -- + * the name of the matched port. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#ifdef PROFILING +#include +#endif + +#include +#include +#include +#include +#include + +#include "lib.h" +#include "audit.h" + +static inline void +audit_package(const char *_pkgname, struct audit_contents *_head, + struct match_session *_msess, FILE *_fp); +static void usage(void); + +/* Getopt stuff */ +static char opts[] = "o"; +static struct option longopts[] = { + { "origin", no_argument, NULL, 'o' }, + { NULL, 0, NULL, 0 } +}; + +/* Options */ +static int opt_printorigin = 0; + +int +main(int argc, char *argv[]) +{ + char freebsd[sizeof("FreeBSD-XXYYZZXXYYZZ")]; + unsigned long reldate; + size_t reldate_size = sizeof(reldate); + int mib[2], ch; + + FILE *in = stdin, *out = stdout; + struct match_session *msess; + struct audit_entry *item; +#ifdef PROFILING + struct timeval t1, t2; + double dt; +#endif + + struct audit_contents head = + SLIST_HEAD_INITIALIZER(head); + + /* Parse options */ + while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1) { + switch (ch) { + case 'o': + opt_printorigin++; + break; + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELDATE; + if (sysctl(mib, 2, (void *)&reldate, &reldate_size, NULL, 0) != 0) + errx(1, "Unable to get kern.osreldate"); + snprintf(freebsd, sizeof(freebsd), "%s-%lu", "FreeBSD", reldate); + + SLIST_INIT(&head); +#ifdef PROFILING + gettimeofday(&t1, NULL); +#endif + if (parse_auditfile(in, &head) != 0) { + errx(1, "Failed to parse audit entries"); + } +#ifdef PROFILING + gettimeofday(&t2, NULL); + dt = t2.tv_sec - t1.tv_sec + 1e-6 * (t2.tv_usec - t1.tv_usec); + fprintf(stderr, "parse_auditfile(): %.6lf sec\n", dt); +#endif + + msess = match_begin(MATCH_GLOB); + if (msess == NULL) + return 1; + +#ifdef PROFILING + gettimeofday(&t1, NULL); +#endif + + /* Special check: FreeBSD itself */ + SLIST_FOREACH (item, &head, entries) { + if (strncmp(item->pkgglob, + "FreeBSD", sizeof("FreeBSD") - 1) == 0 && + pattern_match(MATCH_GLOB, item->pkgglob, freebsd)) { + fprintf(out, "%s|%s|%s|%s\n", + freebsd, + item->pkgglob, item->url, item->descr); + if (opt_printorigin) + fputs("|/usr/src\n", out); + else + fputc('\n', out); + } + } + + /* Installed packages */ + while (match_next_package(msess)) + audit_package(match_get_pkgname(msess), &head, msess, out); + +#ifdef PROFILING + gettimeofday(&t2, NULL); + dt = t2.tv_sec - t1.tv_sec + 1e-6 * (t2.tv_usec - t1.tv_usec); + fprintf(stderr, "match loop: %.6lf sec\n", dt); +#endif + + match_end(msess); + + SLIST_FOREACH (item, &head, entries) { + free((void *)item->pkgglob); + free((void *)item); + } + + return 0; +} + +void +cleanup(int sig) +{ + sig = 0; + return; +} + +/* + * Loops over audit file contents and checks each entry in turn. + * + * The great speedup is to test the package prefix at the first + * place and only if it matches perform full match -- match_matches + * uses slow matching routines without precompilation and other + * tricks. For hundreds of installed ports and a couple of thousands + * audit entries this slows things down very well. + */ +static inline void +audit_package(const char *pkgname, struct audit_contents *head, + struct match_session *msess, FILE *fp) +{ + struct audit_entry *item; + const char *origin; + + SLIST_FOREACH (item, head, entries) { + if (strncmp(pkgname, item->pkgglob, + item->pfx_size) == 0 && + match_matches(msess, item->pkgglob)) { + fprintf(fp, "%s|%s|%s|%s", + pkgname, + item->pkgglob, item->url, item->descr); + if (opt_printorigin) { + origin = match_get_pkgorigin(msess); + fprintf(fp, "|%s\n", + (origin == NULL ? "" : origin)); + if (origin) + free((void *)origin); + } else { + fputc('\n', fp); + } + } + } +} + +static void +usage() +{ + fprintf(stderr, "%s\n", + "usage: pkg_audit [-o|--origin]"); + exit(1); +} diff --git a/usr.sbin/pkg_install/audit/parse.c b/usr.sbin/pkg_install/audit/parse.c new file mode 100644 index 0000000..ab5f645 --- /dev/null +++ b/usr.sbin/pkg_install/audit/parse.c @@ -0,0 +1,259 @@ +/* + * + * FreeBSD install - a package for the installation and maintainance + * of non-core utilities. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Eygene Ryabinkin + * 26 August 2008 + * + * Parsing module for pkg_audit. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include "lib.h" +#include "audit.h" + +/* Simple exponentially-growing buffer. */ + +struct dyn_buffer { + char *buf; + size_t size; +}; + +/* Prototypes */ +static int +parse_audit_entry(struct dyn_buffer *_b, struct audit_entry *_e); + +static int +read_line(FILE *_fp, struct dyn_buffer *_b); + +static struct dyn_buffer * +buf_init(size_t _size); +static void +buf_destroy(struct dyn_buffer *_b); +static int +buf_grow(struct dyn_buffer *_b); + +/* + * Parses audit file to the linked list of single entries. + * + * Return values: + * 0 -- file was successfully parsed; + * 1 -- parsing or read error occured; + * -1 -- bad arguments, memory allocation problems, etc. + */ +int +parse_auditfile(FILE *fp, struct audit_contents *head) +{ + struct audit_entry *e; + struct dyn_buffer *b; + int errcode; + + b = buf_init(256); + if (b == NULL) + return 1; + + while ((errcode = read_line(fp, b)) == 0) { + if (b->buf[0] == '#') + continue; + e = (struct audit_entry *)malloc(sizeof(*e)); + if (e == NULL) { + buf_destroy(b); + return -1; + } + bzero((void *)e, sizeof(*e)); + if ((errcode = parse_audit_entry(b, e)) != 0) { + buf_destroy(b); + return errcode; + } + SLIST_INSERT_HEAD(head, e, entries); + } + + buf_destroy(b); + + if (errcode != 1) + return 1; + else + return 0; +} + +/* + * Helpers for audit file parsing routine. + */ + +static struct dyn_buffer * +buf_init(size_t size) +{ + struct dyn_buffer *b; + + if (size <= 0) + return NULL; + + b = (struct dyn_buffer *)malloc(sizeof(*b)); + if (b == NULL) + return NULL; + + bzero((void *)b, sizeof(*b)); + b->size = size; + b->buf = (char *)malloc(b->size * sizeof(b->buf[0])); + if (b->buf == NULL) { + free((void *)b); + return NULL; + } + + bzero((void *)b->buf, b->size); + return b; +} + +static void +buf_destroy(struct dyn_buffer *b) +{ + if (b == NULL) + return; + + if (b->buf != NULL) + free((void *)b->buf); + free((void *)b); + return; +} + +static int +buf_grow(struct dyn_buffer *b) +{ + char *newbuf; + + if (b == NULL || b->buf == NULL || b->size <= 0) + return -1; + + newbuf = (char *)malloc(2 * b->size * sizeof(newbuf)); + if (newbuf == NULL) + return 1; + + bzero(newbuf, 2 * b->size); + bcopy((void *)b->buf, (void *)newbuf, b->size); + b->buf = newbuf; + b->size *= 2; + + return 0; +} + +/* + * fgets()-like function that reads the whole input line + * Returns 0 on the successful read, 1 for the end-of-file + * condition, -1 for any error. + * + * Terminating '\n' is removed from the line. + */ +static int +read_line(FILE *fp, struct dyn_buffer *b) +{ + size_t offset = 0, len = 0; + + if (fp == NULL || b == NULL) + return -1; + + if (feof(fp)) + return 1; + + /* We need at least two-character buffer */ + if (b->size == 1 && buf_grow(b) != 0) + return -1; + + b->buf[b->size - 1] = '\0'; + offset = 0; + while (fgets(b->buf + offset, b->size - offset, fp) != NULL) { + len = strlen(b->buf); + /* + * Read zero characters or buffer even shrinked? + * Strange, let's indicate error. + */ + if (len <= offset) + return -1; + if (b->buf[len - 1] == '\n') { + b->buf[len - 1] = '\0'; + return 0; + } + + offset = len; + if (buf_grow(b) != 0) + return -1; + + /* Should not happen, but who knows */ + if (offset >= b->size) + return -1; + } + + if (feof(fp)) { + /* + * If we read no characters, if means that we were + * at the EOF, but it was detected only by fgets(), + * not the first feof(). + */ + if (len == 0) + return 1; + else + return 0; + } else { + return -1; + } +} + +/* + * Parses single audit line and places it to the structure. + * Calculates length of the package name suffix that is free + * from metacharacters -- it is used for the quick matches + * against port name. + */ +static int +parse_audit_entry(struct dyn_buffer *b, struct audit_entry *e) +{ + size_t len; + char *string = NULL, *d1 = NULL, *d2 = NULL; + static const char globset[] = "{*?><=!"; + + /* + * At least 5 characters: + * two delimiters and three non-empty fields. + */ + len = strlen(b->buf); + if (len < 5) + return 1; + + /* Locate delimiters. */ + d1 = strchr(b->buf, '|'); + if (d1 == NULL) + return 1; + d2 = strchr(d1 + 1, '|'); + if (d2 == NULL) + return 1; + + string = (char *)malloc((len + 1) * sizeof(string[0])); + if (string == NULL) + return -1; + + bcopy((void *)b->buf, (void *)string, (len + 1) * sizeof(string[0])); + string[d1 - b->buf] = '\0'; + string[d2 - b->buf] = '\0'; + e->pkgglob = string; + e->url = string + (d1 - b->buf) + 1; + e->descr = string + (d2 - b->buf) + 1; + e->pfx_size = strcspn(e->pkgglob, globset); + + return 0; +} diff --git a/usr.sbin/pkg_install/audit/pkg_audit.1 b/usr.sbin/pkg_install/audit/pkg_audit.1 new file mode 100644 index 0000000..71a0cc8 --- /dev/null +++ b/usr.sbin/pkg_install/audit/pkg_audit.1 @@ -0,0 +1,74 @@ +.\" +.\" FreeBSD install - a package for the installation and maintenance +.\" of non-core utilities. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" Eygene Ryabinkin +.\" +.\" +.\" @(#)pkg_audit.1 +.\" $FreeBSD$ +.\" +.Dd Aug 26, 2008 +.Dt PKG_AUDIT 1 +.Os +.Sh NAME +.Nm pkg_audit +.Nd lists vulnerable ports installed in the system +.Sh SYNOPSIS +.Nm +.Op Fl o +.Sh DESCRIPTION +The +.Nm +command is used to extract vulnerability information from the audit +file and list vulnerable packages that are present in the system. +It is main purpose to help +.Xr portaudit 1 +utility to avoid time-consuming scripting. +.Pp +.Nm +reads vulnerability information from the standard input and writes +the list of vulnerable ports to the standard output. +Format of the output lines is the same as for the audit file, but +the names of matched packages are prepended to the field set and +package origins are appended to the field set, if it was requested +via the +.Fl o +flag. +.Pp +Thus, the input lines should look like +.D1 pkg_glob|references|description +and output lines will look like +.D1 pkg_version|pkg_glob|references|description[|origin] +.Sh TECHNICAL DETAILS +First the audit file is parsed to the internal representation +(currently it is linked list). +Then we are traversing installed packages database and trying to +match the package name against each audit entry. +The crucial step for the speeding up the process is to first +match the package prefix that has no CSH-like metacharacters +and perform full comparison only if match is found. +One more name is tested prior to the installed packages: it is +.Qo FreeBSD-`sysctl -n kern.osreldate` Qc , +the version of +.Fx +the current system is running. +.Sh SEE ALSO +.Xr portaudit 1 , +.Xr pkg_add 1 , +.Xr pkg_create 1 , +.Xr pkg_delete 1 , +.Xr pkg_version 1 . +.Sh AUTHORS +.An Eygene Ryabinkin Aq rea-fbsd@codelabs.ru +.Sh BUGS +Sure to be some. diff --git a/usr.sbin/pkg_install/lib/lib.h b/usr.sbin/pkg_install/lib/lib.h index 422912e..559d10b 100644 --- a/usr.sbin/pkg_install/lib/lib.h +++ b/usr.sbin/pkg_install/lib/lib.h @@ -228,6 +228,12 @@ char **matchbyorigin(const char *, int *); char ***matchallbyorigin(const char **, int *); int isinstalledpkg(const char *name); int pattern_match(match_t MatchType, char *pattern, const char *pkgname); +struct match_session *match_begin(match_t); +void match_end(struct match_session *); +Boolean match_next_package(struct match_session *); +int match_matches(struct match_session *, char *); +const char *match_get_pkgname(struct match_session *); +const char *match_get_pkgorigin(struct match_session *); /* Dependencies */ int sortdeps(char **); diff --git a/usr.sbin/pkg_install/lib/match.c b/usr.sbin/pkg_install/lib/match.c index 1f8b02a..b4d1c82 100644 --- a/usr.sbin/pkg_install/lib/match.c +++ b/usr.sbin/pkg_install/lib/match.c @@ -37,11 +37,30 @@ struct store { char **store; }; +/* + * Structure that holds information about package traversal + * and matching session. + */ +struct match_session { + FTS *ftsp; + FTSENT *f; + match_t match_type;; +}; + +/* Return values for getorigin() */ +enum st_getorigin { + e_origin_ok = 0, /* All OK */ + e_origin_emptydir, /* Package directory is empty */ + e_origin_infocorrupt, /* Package information is corrupt */ + e_origin_missing /* Package origin is not recorded */ +}; + static int rex_match(const char *, const char *, int); static int csh_match(const char *, const char *, int); struct store *storecreate(struct store *); static int storeappend(struct store *, const char *); static int fname_cmp(const FTSENT * const *, const FTSENT * const *); +static enum st_getorigin getorigin(const char *_name, char **_origin); /* * Function to query names of installed packages. @@ -91,10 +110,10 @@ matchinstalled(match_t MatchType, char **patterns, int *retval) if (retval != NULL) *retval = 1; return NULL; - } + } } else len = 0; - + for (i = 0; i < len; i++) lmatched[i] = FALSE; @@ -107,7 +126,7 @@ matchinstalled(match_t MatchType, char **patterns, int *retval) errcode = 0; if (MatchType == MATCH_ALL) matched = f->fts_name; - else + else for (i = 0; patterns[i]; i++) { errcode = pattern_match(MatchType, patterns[i], f->fts_name); if (errcode == 1) { @@ -234,45 +253,32 @@ pattern_match(match_t MatchType, char *pattern, const char *pkgname) } /* - * Synopsis is similar to matchinstalled(), but use origin - * as a key for matching packages. + * Obtains package origin from the package name. + * Arguments: + * - name, the name of the package; + * - origin, pointer to a pointer where origin will be saved. + * On error, *origin will be NULLified. */ -char *** -matchallbyorigin(const char **origins, int *retval) +static enum st_getorigin getorigin(const char *name, char **origin) { - char **installed, **allorigins = NULL; - char ***matches = NULL; - int i, j; - - if (retval != NULL) - *retval = 0; - - installed = matchinstalled(MATCH_ALL, NULL, retval); - if (installed == NULL) - return NULL; - - /* Gather origins for all installed packages */ - for (i = 0; installed[i] != NULL; i++) { FILE *fp; - char *buf, *cp, tmp[PATH_MAX]; + char *cp, tmp[PATH_MAX]; int cmd; - allorigins = realloc(allorigins, (i + 1) * sizeof(*allorigins)); - allorigins[i] = NULL; - - snprintf(tmp, PATH_MAX, "%s/%s", LOG_DIR, installed[i]); + *origin = NULL; + snprintf(tmp, PATH_MAX, "%s/%s", LOG_DIR, name); /* * SPECIAL CASE: ignore empty dirs, since we can can see them * during port installation. */ if (isemptydir(tmp)) - continue; - snprintf(tmp, PATH_MAX, "%s/%s", tmp, CONTENTS_FNAME); + return e_origin_emptydir; + if (PATH_MAX - strlen(tmp) > 0) + snprintf(tmp + strlen(tmp), PATH_MAX - strlen(tmp), + "/%s", CONTENTS_FNAME); fp = fopen(tmp, "r"); - if (fp == NULL) { - warnx("the package info for package '%s' is corrupt", installed[i]); - continue; - } + if (fp == NULL) + return e_origin_infocorrupt; cmd = -1; while (fgets(tmp, sizeof(tmp), fp)) { @@ -287,14 +293,53 @@ matchallbyorigin(const char **origins, int *retval) continue; cmd = plist_cmd(tmp + 1, &cp); if (cmd == PLIST_ORIGIN) { - asprintf(&buf, "%s", cp); - allorigins[i] = buf; + asprintf(origin, "%s", cp); break; } } - if (cmd != PLIST_ORIGIN && ( Verbose || 0 != strncmp("bsdpan-", installed[i], 7 ) ) ) - warnx("package %s has no origin recorded", installed[i]); fclose(fp); + if (cmd != PLIST_ORIGIN) + return e_origin_missing; + else + return e_origin_ok; +} + +/* + * Synopsis is similar to matchinstalled(), but use origin + * as a key for matching packages. + */ +char *** +matchallbyorigin(const char **origins, int *retval) +{ + char **installed, **allorigins = NULL; + char ***matches = NULL; + int i, j; + + if (retval != NULL) + *retval = 0; + + installed = matchinstalled(MATCH_ALL, NULL, retval); + if (installed == NULL) + return NULL; + + /* Gather origins for all installed packages */ + for (i = 0; installed[i] != NULL; i++) { + allorigins = realloc(allorigins, (i + 1) * sizeof(*allorigins)); + allorigins[i] = NULL; + + switch (getorigin(installed[i], &allorigins[i])) { + case e_origin_ok: + break; + case e_origin_emptydir: + continue; + case e_origin_infocorrupt: + warnx("the package info for package '%s' is corrupt", installed[i]); + continue; + case e_origin_missing: + if (Verbose || 0 != strncmp("bsdpan-", installed[i], 7)) + warnx("package %s has no origin recorded", installed[i]); + break; + } } /* Resolve origins into package names, retaining the sequence */ @@ -359,7 +404,7 @@ struct iip_memo { LIST_HEAD(, iip_memo) iip_memo = LIST_HEAD_INITIALIZER(iip_memo); /* - * + * * Return 1 if the specified package is installed, * 0 if not, and -1 if an error occured. */ @@ -374,7 +419,7 @@ isinstalledpkg(const char *name) if (strcmp(memo->iip_name, name) == 0) return memo->iip_result; } - + buf2 = NULL; asprintf(&buf, "%s/%s", LOG_DIR, name); if (buf == NULL) @@ -416,6 +461,112 @@ errout: } /* + * Prepares package database for the traversal. + */ +struct match_session * +match_begin(match_t MatchType) +{ + struct match_session *sess; + const char *paths[2] = {LOG_DIR, NULL}; + + if (!isdir(paths[0])) + return NULL; + + sess = (struct match_session *)malloc(sizeof(*sess)); + if (sess == NULL) + return NULL; + bzero((void *)sess, sizeof(*sess)); + + sess->match_type = MatchType; + sess->ftsp = fts_open((char * const *)(uintptr_t)paths, + FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT, fname_cmp); + if (sess->ftsp == NULL) { + free((void *)sess); + return NULL; + } + + return sess; +} + +/* + * Ends package traversal session. + */ +void +match_end(struct match_session *sess) +{ + if (sess == NULL) + return; + if (sess->ftsp != NULL) + fts_close(sess->ftsp); + free((void *)sess); + return; +} + +/* + * Proceeds to the next package in the session. + * Returns TRUE if package was selected, FALSE otherwise. + */ +Boolean +match_next_package(struct match_session *sess) +{ + if (sess == NULL || sess->ftsp == NULL) + return FALSE; + + while ((sess->f = fts_read(sess->ftsp)) != NULL) { + if (sess->f->fts_info == FTS_D && + sess->f->fts_level == 1) { + fts_set(sess->ftsp, sess->f, FTS_SKIP); + return TRUE; + } + } + return FALSE; +} + +/* + * Matches the current package name against the given pattern. + * Returns 1 if pattern matches, 0 if not matches and -1 for + * the error condition. + */ +int +match_matches(struct match_session *sess, char *pattern) +{ + if (sess == NULL || sess->ftsp == NULL || sess->f == NULL || + pattern == NULL) + return FALSE; + + return pattern_match(sess->match_type, pattern, + sess->f->fts_name); +} + +/* + * Returns name of the current package. + */ +const char * +match_get_pkgname(struct match_session *sess) +{ + if (sess == NULL || sess->ftsp == NULL || sess->f == NULL) + return NULL; + + return (const char *)(sess->f->fts_name); +} + +/* + * Returns origin of the current package. Caller should free the + * returned value when it will not be needed anymore. + */ +const char * +match_get_pkgorigin(struct match_session *sess) +{ + char *origin; + + if (sess == NULL || sess->ftsp == NULL || sess->f == NULL) + return NULL; + + getorigin(sess->f->fts_name, &origin); + return (const char *)origin; +} + +/* * Returns 1 if specified pkgname matches RE pattern. * Otherwise returns 0 if doesn't match or -1 if RE * engine reported an error (usually invalid syntax).