Index: usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt =================================================================== --- usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt (revision 273339) +++ usr.sbin/bsnmpd/modules/snmp_hostres/BEGEMOT-HOSTRES-MIB.txt (working copy) @@ -113,13 +113,4 @@ DEFVAL { 300 } ::= { begemotHostresObjects 6 } -begemotHrPkgDir OBJECT-TYPE - SYNTAX OCTET STRING - MAX-ACCESS read-write - STATUS current - DESCRIPTION - "The path to the package DB directory." - DEFVAL { "/var/db/pkg" } - ::= { begemotHostresObjects 7 } - END Index: usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c =================================================================== --- usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c (revision 273339) +++ usr.sbin/bsnmpd/modules/snmp_hostres/hostres_begemot.c (working copy) @@ -69,9 +69,6 @@ case LEAF_begemotHrSWRunUpdate: value->v.uint32 = swrun_tbl_refresh; return (SNMP_ERR_NOERROR); - - case LEAF_begemotHrPkgDir: - return (string_get(value, pkg_dir, -1)); } abort(); @@ -111,8 +108,6 @@ swrun_tbl_refresh = value->v.uint32; return (SNMP_ERR_NOERROR); - case LEAF_begemotHrPkgDir: - return (string_save(value, ctx, -1, &pkg_dir)); } abort(); @@ -126,10 +121,6 @@ case LEAF_begemotHrSWInstalledUpdate: case LEAF_begemotHrSWRunUpdate: return (SNMP_ERR_NOERROR); - - case LEAF_begemotHrPkgDir: - string_commit(ctx); - return (SNMP_ERR_NOERROR); } abort(); @@ -159,10 +150,6 @@ case LEAF_begemotHrSWRunUpdate: swrun_tbl_refresh = ctx->scratch->int1; return (SNMP_ERR_NOERROR); - - case LEAF_begemotHrPkgDir: - string_rollback(ctx, &pkg_dir); - return (SNMP_ERR_NOERROR); } abort(); } Index: usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h =================================================================== --- usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h (revision 273339) +++ usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h (working copy) @@ -51,7 +51,7 @@ * Default package directory for hrSWInstalledTable. Can be overridden * via SNMP or configuration file. */ -#define PATH_PKGDIR "/var/db/pkg" +#define PATH_PKGBIN "/usr/sbin/pkg" /* * These are the default maximum caching intervals for the various tables @@ -187,9 +187,6 @@ /* maximum number of ticks between updates of network table */ extern uint32_t network_tbl_refresh; -/* package directory */ -extern u_char *pkg_dir; - /* Initialize and populate storage table */ void init_storage_tbl(void); Index: usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c =================================================================== --- usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c (revision 273339) +++ usr.sbin/bsnmpd/modules/snmp_hostres/hostres_swinstalled_tbl.c (working copy) @@ -36,15 +36,19 @@ #include #include #include +#include #include -#include #include #include +#include +#define _WITH_GETLINE +#include #include #include #include #include +#include #include "hostres_snmp.h" #include "hostres_oid.h" @@ -52,6 +56,8 @@ #define CONTENTS_FNAME "+CONTENTS" +extern char **environ; + enum SWInstalledType { SWI_UNKNOWN = 1, SWI_OPERATING_SYSTEM = 2, @@ -113,9 +119,6 @@ /* maximum number of ticks between updates of network table */ uint32_t swins_tbl_refresh = HR_SWINS_TBL_REFRESH * 100; -/* package directory */ -u_char *pkg_dir; - /* last change of package list */ static time_t os_pkg_last_change; @@ -284,6 +287,58 @@ } /** + * Execute the pkg command and return a fd on its stdout + */ +static int +exec_pkg(pid_t *pid, const char **argv) +{ + int stdout_pipe[2] = {-1, -1}; + posix_spawn_file_actions_t actions; + + if (posix_spawn_file_actions_init(&actions) != 0) + return (-1); + + if (posix_spawn_file_actions_addopen(&actions, STDERR_FILENO, + "/dev/null", O_RDONLY, 0) != 0) { + posix_spawn_file_actions_destroy(&actions); + return (-1); + } + + if (pipe(stdout_pipe) < 0) { + posix_spawn_file_actions_destroy(&actions); + return (-1); + } + + if (posix_spawn_file_actions_addclose(&actions, stdout_pipe[0]) != 0) { + close(stdout_pipe[0]); + close(stdout_pipe[1]); + posix_spawn_file_actions_destroy(&actions); + return (-1); + } + + if (posix_spawn_file_actions_adddup2(&actions, stdout_pipe[1], + STDOUT_FILENO) != 0) { + close(stdout_pipe[0]); + close(stdout_pipe[1]); + posix_spawn_file_actions_destroy(&actions); + return (-1); + } + + if (posix_spawn(pid, PATH_PKGBIN, &actions, NULL, + __DECONST(char **, argv), environ) != 0) { + close(stdout_pipe[0]); + close(stdout_pipe[1]); + posix_spawn_file_actions_destroy(&actions); + return (-1); + } + + posix_spawn_file_actions_destroy(&actions); + close(stdout_pipe[1]); + + return (stdout_pipe[0]); +} + +/** * Read the installed packages */ static int @@ -290,102 +345,151 @@ swins_get_packages(void) { struct stat sb; - DIR *p_dir; - struct dirent *ent; - struct tm k_ts; - char *pkg_file; + struct tm k_ts; + char *pkg_dbfile; struct swins_entry *entry; + const char *argv[5]; + char *line; int ret = 0; + int pstat; + size_t linecap = 0; + ssize_t linelen; + pid_t pid; + int fd; + FILE *out; + char *name, *token; + time_t timestamp; + posix_spawn_file_actions_t actions; - if (pkg_dir == NULL) - /* initialisation may have failed */ + /* check is pkg is installed */ + argv[0] = "pkg"; + argv[1] = "-N"; + argv[2] = NULL; + + if (posix_spawn_file_actions_init(&actions) != 0 || + posix_spawn_file_actions_addopen(&actions, + STDOUT_FILENO, "/dev/null", O_RDONLY, 0) != 0 || + posix_spawn_file_actions_addopen(&actions, + STDERR_FILENO, "/dev/null", O_RDONLY, 0) != 0 || + posix_spawn(&pid, PATH_PKGBIN, &actions, NULL, + __DECONST(char **, argv), environ) != 0) { + posix_spawn_file_actions_destroy(&actions); return (-1); + } + posix_spawn_file_actions_destroy(&actions); - if (stat(pkg_dir, &sb) != 0) { - syslog(LOG_ERR, "hrSWInstalledTable: stat(\"%s\") failed: %m", - pkg_dir); + while (waitpid(pid, &pstat, 0) == -1) { + if (errno != EINTR) + return (-1); + } + + /* pkg is not bootstrap so there is no packages */ + if (WEXITSTATUS(pstat) != 0) + return (0); + + /* Get the db dir from package configuration */ + argv[0] = "pkg"; + argv[1] = "config"; + argv[2] = "PKG_DBDIR"; + argv[3] = NULL; + + if ((fd = exec_pkg(&pid, argv)) == -1) return (-1); + + pkg_dbfile = NULL; + line = NULL; + out = fdopen(fd, "r"); + while ((linelen = getline(&line, &linecap, out)) > 0) { + line[linelen - 1] = '\0'; + asprintf(&pkg_dbfile, "%s/local.sqlite", line); } - if (!S_ISDIR(sb.st_mode)) { - syslog(LOG_ERR, "hrSWInstalledTable: \"%s\" is not a directory", - pkg_dir); + fclose(out); + + while (waitpid(pid, &pstat, 0) == -1) { + if (errno != EINTR) { + free(line); + free(pkg_dbfile); + return (-1); + } + } + + if (pkg_dbfile == NULL) { + free(line); return (-1); } + + if (stat(pkg_dbfile, &sb) == -1) { + free(pkg_dbfile); + free(line); + return (-1); + } + + free(pkg_dbfile); + if (sb.st_ctime <= os_pkg_last_change) { HRDBG("no need to rescan installed packages -- " - "directory time-stamp unmodified"); - + "Database time-stamp unmodified"); TAILQ_FOREACH(entry, &swins_tbl, link) entry->flags |= HR_SWINSTALLED_FOUND; + free(line); return (0); } - if ((p_dir = opendir(pkg_dir)) == NULL) { - syslog(LOG_ERR, "hrSWInstalledTable: opendir(\"%s\") failed: " - "%m", pkg_dir); - return (-1); - } - while (errno = 0, (ent = readdir(p_dir)) != NULL) { - HRDBG(" pkg file: %s", ent->d_name); + /* Get the list of packages */ + argv[0] = "pkg"; + argv[1] = "query"; + argv[2] = "-a"; + argv[3] = "%n-%v %t"; + argv[4] = NULL; - /* check that the contents file is a regular file */ - if (asprintf(&pkg_file, "%s/%s/%s", pkg_dir, ent->d_name, - CONTENTS_FNAME) == -1) - continue; + fd = exec_pkg(&pid, argv); + if (fd == -1) + return (-1); - if (stat(pkg_file, &sb) != 0 ) { - free(pkg_file); - continue; + line = NULL; + out = fdopen(fd, "r"); + while ((linelen = getline(&line, &linecap, out)) > 0) { + name = NULL; + timestamp = 0; + while ((token = strsep(&line, " \n")) != NULL) { + if (name == NULL) { + name = token; + } else { + if (strspn(token, "0123456789") == strlen(token)) + timestamp = (time_t)strtol(token, NULL, 10); + else + timestamp = 0; + } } - - if (!S_ISREG(sb.st_mode)) { - syslog(LOG_ERR, "hrSWInstalledTable: \"%s\" not a " - "regular file -- skipped", pkg_file); - free(pkg_file); + if (localtime_r(×tamp, &k_ts) == NULL) continue; - } - free(pkg_file); - - /* read directory timestamp on package */ - if (asprintf(&pkg_file, "%s/%s", pkg_dir, ent->d_name) == -1) - continue; - - if (stat(pkg_file, &sb) == -1 || - localtime_r(&sb.st_ctime, &k_ts) == NULL) { - free(pkg_file); - continue; - } - free(pkg_file); - - /* update or create entry */ - if ((entry = swins_find_by_name(ent->d_name)) == NULL && - (entry = swins_entry_create(ent->d_name)) == NULL) { + if ((entry = swins_find_by_name(name)) == NULL && + (entry = swins_entry_create(name)) == NULL) { ret = -1; goto PKG_LOOP_END; } - entry->flags |= HR_SWINSTALLED_FOUND; entry->id = &oid_zeroDotZero; entry->type = (int32_t)SWI_APPLICATION; - entry->date_len = make_date_time(entry->date, &k_ts, 0); - } + } - if (errno != 0) { - syslog(LOG_ERR, "hrSWInstalledTable: readdir_r(\"%s\") failed:" - " %m", pkg_dir); - ret = -1; - } else { - /* - * save the timestamp of directory - * to avoid any further scanning - */ - os_pkg_last_change = sb.st_ctime; + /* + * save the timestamp of directory + * to avoid any further scanning + */ + os_pkg_last_change = sb.st_ctime; + + PKG_LOOP_END: + free(line); + fclose(out); + while (waitpid(pid, &pstat, 0) == -1) { + if (errno != EINTR) + return (-1); } - PKG_LOOP_END: - (void)closedir(p_dir); + return (ret); } @@ -425,11 +529,6 @@ init_swins_tbl(void) { - if ((pkg_dir = malloc(sizeof(PATH_PKGDIR))) == NULL) - syslog(LOG_ERR, "%s: %m", __func__); - else - strcpy(pkg_dir, PATH_PKGDIR); - swins_get_OS_ident(); refresh_swins_tbl();