summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/devfsadm/Makefile.com3
-rw-r--r--usr/src/cmd/devfsadm/vscan_link.c58
-rw-r--r--usr/src/cmd/vscan/vscand/vs_door.c24
-rw-r--r--usr/src/cmd/vscan/vscand/vs_eng.c585
-rw-r--r--usr/src/cmd/vscan/vscand/vs_icap.c34
-rw-r--r--usr/src/cmd/vscan/vscand/vs_incl.h44
-rw-r--r--usr/src/cmd/vscan/vscand/vs_main.c270
-rw-r--r--usr/src/cmd/vscan/vscand/vs_stats.c59
-rw-r--r--usr/src/cmd/vscan/vscand/vs_svc.c288
-rwxr-xr-xusr/src/cmd/vscan/vscand/vscan.d318
10 files changed, 1252 insertions, 431 deletions
diff --git a/usr/src/cmd/devfsadm/Makefile.com b/usr/src/cmd/devfsadm/Makefile.com
index 01ee1836e3..ebafe17839 100644
--- a/usr/src/cmd/devfsadm/Makefile.com
+++ b/usr/src/cmd/devfsadm/Makefile.com
@@ -18,7 +18,7 @@
#
# CDDL HEADER END
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -65,6 +65,7 @@ LINK_OBJS_CMN = \
smp_link.o \
md_link.o \
dtrace_link.o \
+ vscan_link.o \
zfs_link.o
LINK_OBJS = $(LINK_OBJS_CMN) \
diff --git a/usr/src/cmd/devfsadm/vscan_link.c b/usr/src/cmd/devfsadm/vscan_link.c
new file mode 100644
index 0000000000..c84ea231f0
--- /dev/null
+++ b/usr/src/cmd/devfsadm/vscan_link.c
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <devfsadm.h>
+#include <strings.h>
+#include <stdio.h>
+#include <sys/vscan.h>
+
+static int vscan(di_minor_t minor, di_node_t node);
+
+static devfsadm_create_t vscan_create_cbt[] = {
+ { "pseudo", "ddi_pseudo", "vscan",
+ TYPE_EXACT | DRV_EXACT, ILEVEL_0, vscan },
+};
+DEVFSADM_CREATE_INIT_V0(vscan_create_cbt);
+
+static devfsadm_remove_t vscan_remove_cbt[] = {
+ { "vscan", "^vscan/vscan[0-9]+$", RM_HOT | RM_POST,
+ ILEVEL_0, devfsadm_rm_all
+ }
+};
+DEVFSADM_REMOVE_INIT_V0(vscan_remove_cbt);
+
+static int
+vscan(di_minor_t minor, di_node_t node)
+{
+ char *mname = di_minor_name(minor);
+ char path[MAXPATHLEN];
+
+ (void) snprintf(path, sizeof (path), "vscan/%s", mname);
+ (void) devfsadm_mklink(path, node, minor, 0);
+
+ return (DEVFSADM_CONTINUE);
+}
diff --git a/usr/src/cmd/vscan/vscand/vs_door.c b/usr/src/cmd/vscan/vscand/vs_door.c
index 1d2bbd522d..8061318d56 100644
--- a/usr/src/cmd/vscan/vscand/vs_door.c
+++ b/usr/src/cmd/vscan/vscand/vs_door.c
@@ -111,30 +111,14 @@ static void
vs_door_scan_req(void *cookie, char *ptr, size_t size, door_desc_t *dp,
uint_t n_desc)
{
- int flags = 0;
- vs_scan_req_t scan_rsp;
vs_scan_req_t *scan_req;
- char devname[MAXPATHLEN];
- vs_attr_t fattr;
+ uint32_t result = VS_STATUS_ERROR;
- if (ptr == NULL) {
- scan_rsp.vsr_result = VS_STATUS_ERROR;
- scan_rsp.vsr_scanstamp[0] = '\0';
- } else {
+ if (ptr != NULL) {
/* LINTED E_BAD_PTR_CAST_ALIGN - to be fixed with encoding */
scan_req = (vs_scan_req_t *)ptr;
- (void) snprintf(devname, MAXPATHLEN, "%s%d",
- VS_DRV_PATH, scan_req->vsr_id);
-
- fattr.vsa_size = scan_req->vsr_size;
- fattr.vsa_modified = scan_req->vsr_modified;
- fattr.vsa_quarantined = scan_req->vsr_quarantined;
- (void) strlcpy(fattr.vsa_scanstamp, scan_req->vsr_scanstamp,
- sizeof (vs_scanstamp_t));
-
- scan_rsp.vsr_result = vs_svc_scan_file(devname,
- scan_req->vsr_path, &fattr, flags, &scan_rsp.vsr_scanstamp);
+ result = vs_svc_queue_scan_req(scan_req);
}
- (void) door_return((char *)&scan_rsp, sizeof (vs_scan_req_t), NULL, 0);
+ (void) door_return((char *)&result, sizeof (uint32_t), NULL, 0);
}
diff --git a/usr/src/cmd/vscan/vscand/vs_eng.c b/usr/src/cmd/vscan/vscand/vs_eng.c
index 24ededc6af..0bdcb3b7bb 100644
--- a/usr/src/cmd/vscan/vscand/vs_eng.c
+++ b/usr/src/cmd/vscan/vscand/vs_eng.c
@@ -38,6 +38,7 @@
#include <sys/filio.h>
#include <sys/ioctl.h>
#include <sys/debug.h>
+#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
@@ -50,14 +51,76 @@
#include <pthread.h>
#include <time.h>
+#include <signal.h>
+#include <thread.h>
+
#include "vs_incl.h"
+/* max connections per scan engine */
+#define VS_CXN_MAX VS_VAL_SE_MAXCONN_MAX
+
+/*
+ * vs_eng_state_t - connection state
+ *
+ * Each configured scan engine supports up to vse_cfg.vep_maxconn
+ * connections. These connections are represented by a vs_connection_t
+ * which defines the connection state, associated socket descriptor
+ * and how long the connection has been available. A connection
+ * that has been available but unused for vs_inactivity_timeout
+ * seconds will be closed by the housekeeper thread.
+ *
+ * When a scan engine is reconfigured to have less connections
+ * (or is disabled) any of he superflous connections which are in
+ * AVAILABLE state are closed (DISCONNECTED). Others are set to
+ * CLOSE_PENDING to be closed (DISCONNECTED) when the engine is
+ * released (when the current request completes).
+ *
+ * +---------------------+
+ * |---------->| VS_ENG_DISCONNECTED |<-----------------|
+ * | +---------------------+ |
+ * | | |
+ * | | eng_get |
+ * | v | release/
+ * | shutdown +---------------------+ reconfig | shutdown
+ * |<----------| VS_ENG_RESERVED | -----------| |
+ * | +---------------------+ | |
+ * | | v |
+ * | | +----------------------+
+ * | | connect | VS_ENG_CLOSE_PENDING |
+ * | | +----------------------+
+ * | v ^
+ * | shutdown +---------------------+ |
+ * |<----------| VS_ENG_INUSE |------------|
+ * | +---------------------+ reconfig/error
+ * | | ^
+ * | | release | eng_get
+ * | reconfig/ | |
+ * | timeout/ v |
+ * | shutdown +---------------------+
+ * |<----------| VS_ENG_AVAILABLE |
+ * +---------------------+
+ *
+ */
+
+typedef enum {
+ VS_ENG_DISCONNECTED = 0,
+ VS_ENG_RESERVED,
+ VS_ENG_INUSE,
+ VS_ENG_AVAILABLE,
+ VS_ENG_CLOSE_PENDING
+} vs_eng_state_t;
+
+typedef struct vs_connection {
+ vs_eng_state_t vsc_state;
+ int vsc_sockfd;
+ struct timeval vsc_avail_time;
+} vs_connection_t;
typedef struct vs_engine {
- vs_props_se_t vse_cfg; /* host, port, maxcon */
- int vse_in_use; /* # connections in use */
- int vse_error;
- vs_eng_conn_t vse_conn_root;
+ vs_props_se_t vse_cfg; /* host, port, maxconn */
+ int vse_inuse; /* # connections in use */
+ boolean_t vse_error;
+ vs_connection_t vse_cxns[VS_CXN_MAX];
} vs_engine_t;
static vs_engine_t vs_engines[VS_SE_MAX];
@@ -70,22 +133,24 @@ static int vs_eng_wait_count; /* # threads waiting for connection */
static pthread_mutex_t vs_eng_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t vs_eng_cv;
-static pthread_cond_t vs_eng_shutdown_cv;
+int vs_inactivity_timeout = 60; /* seconds */
+int vs_reuse_connection = 1;
-static time_t vs_eng_wait = VS_ENG_WAIT_DFLT;
+time_t vs_eng_wait = VS_ENG_WAIT_DFLT;
/* local functions */
-static int vs_eng_check_errors(void);
-static int vs_eng_find_next(int);
-static void vs_eng_add_connection(vs_eng_conn_t *);
-static void vs_eng_remove_connection(vs_eng_conn_t *);
-static void vs_eng_close_connections(void);
+static int vs_eng_connect(char *, int);
+static boolean_t vs_eng_check_errors(void);
+static int vs_eng_find_connection(int *, int *, boolean_t);
+static int vs_eng_find_next(boolean_t);
static int vs_eng_compare(int, char *, int);
+static void vs_eng_config_close(vs_engine_t *, int);
+static void *vs_eng_housekeeper(void *);
#ifdef FIONBIO
/* non-blocking connect */
-static int nbio_connect(vs_eng_conn_t *, const struct sockaddr *, int);
+static int nbio_connect(int, const struct sockaddr *, int);
int vs_connect_timeout = 5000; /* milliseconds */
#endif /* FIONBIO */
@@ -96,18 +161,21 @@ int vs_connect_timeout = 5000; /* milliseconds */
void
vs_eng_init()
{
+ pthread_t tid;
+
(void) pthread_cond_init(&vs_eng_cv, NULL);
- (void) pthread_cond_init(&vs_eng_shutdown_cv, NULL);
(void) pthread_mutex_lock(&vs_eng_mutex);
- (void) memset(vs_engines, 0,
- sizeof (vs_engine_t) * VS_SE_MAX);
+ (void) memset(vs_engines, 0, sizeof (vs_engine_t) * VS_SE_MAX);
+
vs_eng_total_maxcon = 0;
vs_eng_total_inuse = 0;
vs_eng_count = 0;
vs_eng_next = 0;
(void) pthread_mutex_unlock(&vs_eng_mutex);
+
+ (void) pthread_create(&tid, NULL, vs_eng_housekeeper, NULL);
}
@@ -119,6 +187,10 @@ vs_eng_init()
* If a scan engine has been reconfigured (different host or port)
* the scan engine's error count is reset.
*
+ * If the host/port has changed, the engine has been disabled
+ * or less connections are configured now, connections need
+ * to be closed or placed in CLOSE_PENDING state (vs_eng_config_close)
+ *
* vs_icap_config is invoked to reset engine-specific data stored
* in vs_icap.
*
@@ -139,14 +211,20 @@ vs_eng_config(vs_props_all_t *config)
cfg = &config->va_se[i];
eng = &vs_engines[i];
- if (vs_eng_compare(i, cfg->vep_host, cfg->vep_port) != 0)
- eng->vse_error = 0;
+ if (vs_eng_compare(i, cfg->vep_host, cfg->vep_port) != 0) {
+ vs_eng_config_close(eng, 0);
+ eng->vse_error = B_FALSE;
+ }
if (cfg->vep_enable) {
+ if (cfg->vep_maxconn < eng->vse_cfg.vep_maxconn)
+ vs_eng_config_close(eng, cfg->vep_maxconn);
+
eng->vse_cfg = *cfg;
vs_eng_total_maxcon += cfg->vep_maxconn;
vs_eng_count++;
} else {
+ vs_eng_config_close(eng, 0);
(void) memset(&eng->vse_cfg, 0, sizeof (vs_props_se_t));
}
@@ -161,29 +239,93 @@ vs_eng_config(vs_props_all_t *config)
/*
- * vs_eng_fini
+ * vs_eng_config_close
*
- * Close all scan engine connections to abort in-progress scans,
- * and wait until all to sessions are complete, and there are no
- * waiting threads.
- * Set vs_eng_total_maxcon to 0 to ensure no new engine sessions
- * can be initiated while we're waiting.
+ * If the host/port has changed, the engine has been disabled
+ * or less connections are configured now, connections need
+ * to be closed or placed in CLOSE_PENDING state
+ */
+static void
+vs_eng_config_close(vs_engine_t *eng, int start_idx)
+{
+ int i;
+ vs_connection_t *cxn;
+
+ for (i = start_idx; i < eng->vse_cfg.vep_maxconn; i++) {
+ cxn = &(eng->vse_cxns[i]);
+
+ switch (cxn->vsc_state) {
+ case VS_ENG_RESERVED:
+ case VS_ENG_INUSE:
+ cxn->vsc_state = VS_ENG_CLOSE_PENDING;
+ break;
+ case VS_ENG_AVAILABLE:
+ (void) close(cxn->vsc_sockfd);
+ cxn->vsc_sockfd = -1;
+ cxn->vsc_state = VS_ENG_DISCONNECTED;
+ break;
+ case VS_ENG_CLOSE_PENDING:
+ case VS_ENG_DISCONNECTED:
+ break;
+ }
+ }
+}
+
+
+/*
+ * vs_eng_fini
*/
void
vs_eng_fini()
{
- (void) pthread_mutex_lock(&vs_eng_mutex);
+ (void) pthread_cond_destroy(&vs_eng_cv);
+}
- vs_eng_total_maxcon = 0;
- vs_eng_close_connections();
+/*
+ * vs_eng_housekeeper
+ *
+ * Wakeup every (vs_inactivity_timeout / 2) seconds and close
+ * any connections that are in AVAILABLE state but have not
+ * been used for vs_inactivity_timeout seconds.
+ */
+/* ARGSUSED */
+static void *
+vs_eng_housekeeper(void *arg)
+{
+ struct timeval now;
+ long expire;
+ int i, j;
+ vs_engine_t *eng;
+ vs_connection_t *cxn;
- while (vs_eng_total_inuse > 0 || vs_eng_wait_count > 0)
- (void) pthread_cond_wait(&vs_eng_shutdown_cv, &vs_eng_mutex);
+ for (;;) {
+ (void) sleep(vs_inactivity_timeout / 2);
- (void) pthread_mutex_unlock(&vs_eng_mutex);
- (void) pthread_cond_destroy(&vs_eng_cv);
- (void) pthread_cond_destroy(&vs_eng_shutdown_cv);
+ if (vscand_get_state() == VS_STATE_SHUTDOWN)
+ break;
+
+ (void) gettimeofday(&now, NULL);
+ expire = now.tv_sec - vs_inactivity_timeout;
+
+ (void) pthread_mutex_lock(&vs_eng_mutex);
+ for (i = 0; i < VS_SE_MAX; i++) {
+ eng = &(vs_engines[i]);
+ for (j = 0; j < eng->vse_cfg.vep_maxconn; j++) {
+ cxn = &(eng->vse_cxns[j]);
+
+ if ((cxn->vsc_state == VS_ENG_AVAILABLE) &&
+ (cxn->vsc_avail_time.tv_sec < expire)) {
+ (void) close(cxn->vsc_sockfd);
+ cxn->vsc_sockfd = -1;
+ cxn->vsc_state = VS_ENG_DISCONNECTED;
+ }
+ }
+ }
+ (void) pthread_mutex_unlock(&vs_eng_mutex);
+ }
+
+ return (NULL);
}
@@ -194,45 +336,56 @@ vs_eng_fini()
* engine in vs_engines set or clear the error state of the
* engine and update the error statistics.
*
- * If error == 0, clear the error state(0), else set the error
- * state (1)
+ * If error == 0, clear the error state(B_FALSE), else set
+ * the error state (B_TRUE) and increment engine error stats
*/
void
-vs_eng_set_error(vs_eng_conn_t *conn, int error)
+vs_eng_set_error(vs_eng_ctx_t *eng_ctx, int error)
{
- int idx = conn->vsc_idx;
+ int eidx = eng_ctx->vse_eidx;
+ int cidx = eng_ctx->vse_cidx;
+ vs_engine_t *eng;
(void) pthread_mutex_lock(&vs_eng_mutex);
- if (vs_eng_compare(idx, conn->vsc_host, conn->vsc_port) == 0)
- vs_engines[idx].vse_error = error ? 1 : 0;
+ eng = &(vs_engines[eidx]);
+
+ if (vs_eng_compare(eidx, eng_ctx->vse_host, eng_ctx->vse_port) == 0)
+ eng->vse_error = (error == 0) ? B_FALSE : B_TRUE;
+
+ if (error != 0) {
+ eng->vse_cxns[cidx].vsc_state = VS_ENG_CLOSE_PENDING;
+ vs_stats_eng_err(eng_ctx->vse_engid);
+ }
(void) pthread_mutex_unlock(&vs_eng_mutex);
}
-
/*
* vs_eng_get
* Get next available scan engine connection.
- * If retry != 0 look for a scan engine with no errors.
+ * If retry == B_TRUE look for a scan engine with no errors.
*
* Returns: 0 - success
* -1 - error
*/
int
-vs_eng_get(vs_eng_conn_t *conn, int retry)
+vs_eng_get(vs_eng_ctx_t *eng_ctx, boolean_t retry)
{
struct timespec tswait;
- int idx;
+ int eidx, cidx, sockfd;
+ vs_engine_t *eng;
+ vs_connection_t *cxn;
(void) pthread_mutex_lock(&vs_eng_mutex);
/*
- * If no engines connections configured or
+ * If no engines connections configured OR
* retry and only one engine configured, give up
*/
- if ((vs_eng_total_maxcon <= 0) || (retry && (vs_eng_count <= 1))) {
+ if ((vs_eng_total_maxcon <= 0) ||
+ ((retry == B_TRUE) && (vs_eng_count <= 1))) {
(void) pthread_mutex_unlock(&vs_eng_mutex);
return (-1);
}
@@ -241,9 +394,9 @@ vs_eng_get(vs_eng_conn_t *conn, int retry)
tswait.tv_nsec = 0;
while ((vscand_get_state() != VS_STATE_SHUTDOWN) &&
- ((idx = vs_eng_find_next(retry)) == -1)) {
+ (vs_eng_find_connection(&eidx, &cidx, retry) == -1)) {
/* If retry and all configured engines have errors, give up */
- if (retry && vs_eng_check_errors()) {
+ if (retry && vs_eng_check_errors() == B_TRUE) {
(void) pthread_mutex_unlock(&vs_eng_mutex);
return (-1);
}
@@ -255,8 +408,6 @@ vs_eng_get(vs_eng_conn_t *conn, int retry)
syslog(LOG_WARNING, "Scan Engine "
"- timeout waiting for available engine");
vs_eng_wait_count--;
- if (vscand_get_state() == VS_STATE_SHUTDOWN)
- (void) pthread_cond_signal(&vs_eng_shutdown_cv);
(void) pthread_mutex_unlock(&vs_eng_mutex);
return (-1);
}
@@ -264,31 +415,81 @@ vs_eng_get(vs_eng_conn_t *conn, int retry)
}
if (vscand_get_state() == VS_STATE_SHUTDOWN) {
- (void) pthread_cond_signal(&vs_eng_shutdown_cv);
(void) pthread_mutex_unlock(&vs_eng_mutex);
return (-1);
}
- conn->vsc_idx = idx;
- (void) strlcpy(conn->vsc_engid, vs_engines[idx].vse_cfg.vep_engid,
- sizeof (conn->vsc_engid));
- (void) strlcpy(conn->vsc_host, vs_engines[idx].vse_cfg.vep_host,
- sizeof (conn->vsc_host));
- conn->vsc_port = vs_engines[idx].vse_cfg.vep_port;
+ eng = &(vs_engines[eidx]);
+ cxn = &(eng->vse_cxns[cidx]);
/* update in use counts */
- vs_engines[idx].vse_in_use++;
+ eng->vse_inuse++;
vs_eng_total_inuse++;
- /* add to connections list for engine */
- vs_eng_add_connection(conn);
-
/* update round-robin index */
if (!retry)
- vs_eng_next = (idx == VS_SE_MAX) ? 0 : idx + 1;
+ vs_eng_next = (eidx == VS_SE_MAX) ? 0 : eidx + 1;
+
+ /* populate vs_eng_ctx_t */
+ eng_ctx->vse_eidx = eidx;
+ eng_ctx->vse_cidx = cidx;
+ (void) strlcpy(eng_ctx->vse_engid, eng->vse_cfg.vep_engid,
+ sizeof (eng_ctx->vse_engid));
+ (void) strlcpy(eng_ctx->vse_host, eng->vse_cfg.vep_host,
+ sizeof (eng_ctx->vse_host));
+ eng_ctx->vse_port = eng->vse_cfg.vep_port;
+ eng_ctx->vse_sockfd = cxn->vsc_sockfd;
+
+ if (cxn->vsc_state == VS_ENG_INUSE) {
+ (void) pthread_mutex_unlock(&vs_eng_mutex);
+ return (0);
+ }
+
+ /* state == VS_ENG_RESERVED, need to connect */
(void) pthread_mutex_unlock(&vs_eng_mutex);
+ sockfd = vs_eng_connect(eng_ctx->vse_host, eng_ctx->vse_port);
+
+ /* retry a failed connection once */
+ if (sockfd == -1) {
+ (void) sleep(1);
+ sockfd = vs_eng_connect(eng_ctx->vse_host, eng_ctx->vse_port);
+ }
+
+ if (sockfd == -1) {
+ syslog(LOG_WARNING, "Scan Engine - connection error (%s:%d) %s",
+ eng_ctx->vse_host, eng_ctx->vse_port,
+ errno ? strerror(errno) : "");
+ vs_eng_set_error(eng_ctx, 1);
+ vs_eng_release(eng_ctx);
+ return (-1);
+ }
+
+ (void) pthread_mutex_lock(&vs_eng_mutex);
+ switch (cxn->vsc_state) {
+ case VS_ENG_DISCONNECTED:
+ /* SHUTDOWN occured */
+ (void) pthread_mutex_unlock(&vs_eng_mutex);
+ vs_eng_release(eng_ctx);
+ return (-1);
+ case VS_ENG_RESERVED:
+ cxn->vsc_state = VS_ENG_INUSE;
+ break;
+ case VS_ENG_CLOSE_PENDING:
+ /* reconfigure occured. Connection will be closed after use */
+ break;
+ case VS_ENG_INUSE:
+ case VS_ENG_AVAILABLE:
+ default:
+ ASSERT(0);
+ break;
+ }
+
+ cxn->vsc_sockfd = sockfd;
+ eng_ctx->vse_sockfd = sockfd;
+
+ (void) pthread_mutex_unlock(&vs_eng_mutex);
return (0);
}
@@ -296,24 +497,73 @@ vs_eng_get(vs_eng_conn_t *conn, int retry)
/*
* vs_eng_check_errors
*
- * Check if there are any engines, with maxcon > 0,
- * which are not in error state
+ * Check if all engines with maxconn > 0 are in error state
*
- * Returns: 1 - all (valid) engines are in error state
- * 0 - otherwise
+ * Returns: B_TRUE - all (valid) engines are in error state
+ * B_FALSE - otherwise
*/
-static int
+static boolean_t
vs_eng_check_errors()
{
int i;
for (i = 0; i < VS_SE_MAX; i++) {
if (vs_engines[i].vse_cfg.vep_maxconn > 0 &&
- (vs_engines[i].vse_error == 0))
+ (vs_engines[i].vse_error == B_FALSE))
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+
+/*
+ * vs_eng_find_connection
+ *
+ * Identify the next engine to be used (vs_eng_find_next()).
+ * Select the engine's first connection in AVAILABLE state.
+ * If no connection is in AVAILABLE state, select the first
+ * that is in DISCONNECTED state.
+ *
+ * Returns: 0 success
+ * -1 no engine connections available (eng_idx & cxn_idx undefined)
+ */
+static int
+vs_eng_find_connection(int *eng_idx, int *cxn_idx, boolean_t retry)
+{
+ int i, idx;
+ vs_engine_t *eng;
+ vs_connection_t *cxn;
+
+ /* identify engine */
+ if ((idx = vs_eng_find_next(retry)) == -1)
+ return (-1);
+
+ eng = &(vs_engines[idx]);
+ *eng_idx = idx;
+
+ /* identify connection */
+ idx = -1;
+ for (i = 0; i < eng->vse_cfg.vep_maxconn; i++) {
+ cxn = &(eng->vse_cxns[i]);
+ if (cxn->vsc_state == VS_ENG_AVAILABLE) {
+ *cxn_idx = i;
+ cxn->vsc_state = VS_ENG_INUSE;
return (0);
+ }
+
+ if ((idx == -1) &&
+ (cxn->vsc_state == VS_ENG_DISCONNECTED)) {
+ idx = i;
+ }
}
- return (1);
+ if (idx == -1)
+ return (-1);
+
+ eng->vse_cxns[idx].vsc_state = VS_ENG_RESERVED;
+ *cxn_idx = idx;
+ return (0);
}
@@ -321,25 +571,25 @@ vs_eng_check_errors()
* vs_eng_find_next
*
* Returns: -1 no engine connections available
- * idx of engine to use
+ * idx of engine to use
*/
static int
-vs_eng_find_next(int retry)
+vs_eng_find_next(boolean_t retry)
{
int i;
for (i = vs_eng_next; i < VS_SE_MAX; i++) {
- if (vs_engines[i].vse_in_use <
+ if (vs_engines[i].vse_inuse <
vs_engines[i].vse_cfg.vep_maxconn) {
- if (!retry || (vs_engines[i].vse_error == 0))
+ if (!retry || (vs_engines[i].vse_error == B_FALSE))
return (i);
}
}
for (i = 0; i < vs_eng_next; i++) {
- if (vs_engines[i].vse_in_use <
+ if (vs_engines[i].vse_inuse <
vs_engines[i].vse_cfg.vep_maxconn) {
- if (!retry || (vs_engines[i].vse_error == 0))
+ if (!retry || (vs_engines[i].vse_error == B_FALSE))
return (i);
}
}
@@ -352,135 +602,144 @@ vs_eng_find_next(int retry)
* vs_eng_release
*/
void
-vs_eng_release(vs_eng_conn_t *conn)
+vs_eng_release(const vs_eng_ctx_t *eng_ctx)
{
- int idx = conn->vsc_idx;
-
- /* disconnect */
- if (conn->vsc_sockfd != -1) {
- (void) close(conn->vsc_sockfd);
- conn->vsc_sockfd = -1;
- }
+ int eidx = eng_ctx->vse_eidx;
+ int cidx = eng_ctx->vse_cidx;
+ vs_connection_t *cxn;
(void) pthread_mutex_lock(&vs_eng_mutex);
+ cxn = &(vs_engines[eidx].vse_cxns[cidx]);
+
+ switch (cxn->vsc_state) {
+ case VS_ENG_DISCONNECTED:
+ break;
+ case VS_ENG_RESERVED:
+ cxn->vsc_state = VS_ENG_DISCONNECTED;
+ break;
+ case VS_ENG_INUSE:
+ if (vs_reuse_connection) {
+ cxn->vsc_state = VS_ENG_AVAILABLE;
+ (void) gettimeofday(&cxn->vsc_avail_time, NULL);
+ break;
+ }
+ /* LINTED E_CASE_FALL_THROUGH - close connection */
+ case VS_ENG_CLOSE_PENDING:
+ (void) close(cxn->vsc_sockfd);
+ cxn->vsc_sockfd = -1;
+ cxn->vsc_state = VS_ENG_DISCONNECTED;
+ break;
+ case VS_ENG_AVAILABLE:
+ default:
+ ASSERT(0);
+ break;
+ }
/* decrement in use counts */
- vs_engines[idx].vse_in_use--;
+ vs_engines[eidx].vse_inuse--;
vs_eng_total_inuse--;
- /* remove from connections list for engine */
- vs_eng_remove_connection(conn);
-
/* wake up next thread waiting for a connection */
(void) pthread_cond_signal(&vs_eng_cv);
- /* if shutdown, send shutdown signal */
- if (vscand_get_state() == VS_STATE_SHUTDOWN)
- (void) pthread_cond_signal(&vs_eng_shutdown_cv);
-
(void) pthread_mutex_unlock(&vs_eng_mutex);
}
/*
- * vs_eng_add_connection
- * Add a connection into appropriate engine's connections list
- */
-static void
-vs_eng_add_connection(vs_eng_conn_t *conn)
-{
- vs_eng_conn_t *conn_root;
-
- conn_root = &(vs_engines[conn->vsc_idx].vse_conn_root);
- conn->vsc_prev = conn_root;
- conn->vsc_next = conn_root->vsc_next;
- if (conn->vsc_next)
- (conn->vsc_next)->vsc_prev = conn;
- conn_root->vsc_next = conn;
-}
-
-
-/*
- * vs_eng_remove_connection
- * Remove a connection from appropriate engine's connections list
- */
-static void
-vs_eng_remove_connection(vs_eng_conn_t *conn)
-{
- (conn->vsc_prev)->vsc_next = conn->vsc_next;
- if (conn->vsc_next)
- (conn->vsc_next)->vsc_prev = conn->vsc_prev;
-}
-
-
-/*
* vs_eng_close_connections
+ *
+ * Set vs_eng_total_maxcon to 0 to ensure no new engine sessions
+ * can be initiated.
* Close all open connections to abort in-progress scans.
+ * Set connection state to DISCONNECTED.
*/
-static void
+void
vs_eng_close_connections(void)
{
- int i;
- vs_eng_conn_t *conn;
+ int i, j;
+ vs_connection_t *cxn;
+
+ (void) pthread_mutex_lock(&vs_eng_mutex);
+ vs_eng_total_maxcon = 0;
for (i = 0; i < VS_SE_MAX; i++) {
- conn = vs_engines[i].vse_conn_root.vsc_next;
- while (conn) {
- (void) close(conn->vsc_sockfd);
- conn->vsc_sockfd = -1;
- conn = conn->vsc_next;
+ for (j = 0; j < VS_CXN_MAX; j++) {
+ cxn = &(vs_engines[i].vse_cxns[j]);
+
+ switch (cxn->vsc_state) {
+ case VS_ENG_INUSE:
+ case VS_ENG_AVAILABLE:
+ case VS_ENG_CLOSE_PENDING:
+ (void) close(cxn->vsc_sockfd);
+ cxn->vsc_sockfd = -1;
+ break;
+ case VS_ENG_DISCONNECTED:
+ case VS_ENG_RESERVED:
+ default:
+ break;
+
+ }
+
+ cxn->vsc_state = VS_ENG_DISCONNECTED;
}
}
+ (void) pthread_mutex_unlock(&vs_eng_mutex);
}
/*
* vs_eng_connect
* open socket connection to remote scan engine
+ *
+ * Returns: sockfd or -1 (error)
*/
-int
-vs_eng_connect(vs_eng_conn_t *conn)
+static int
+vs_eng_connect(char *host, int port)
{
- int rc, sock_opt, err_num;
+ int rc, sockfd, opt_nodelay, opt_keepalive, opt_reuseaddr, err_num;
struct sockaddr_in addr;
struct hostent *hp;
- if ((conn->vsc_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return (-1);
- hp = getipnodebyname(conn->vsc_host, AF_INET, 0, &err_num);
- if (hp == NULL)
+ hp = getipnodebyname(host, AF_INET, 0, &err_num);
+ if (hp == NULL) {
+ (void) close(sockfd);
return (-1);
+ }
(void) memset(&addr, 0, sizeof (addr));
(void) memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
- addr.sin_port = htons(conn->vsc_port);
+ addr.sin_port = htons(port);
addr.sin_family = hp->h_addrtype;
freehostent(hp);
#ifdef FIONBIO /* Use non-blocking mode for connect. */
- rc = nbio_connect(conn, (struct sockaddr *)&addr,
+ rc = nbio_connect(sockfd, (struct sockaddr *)&addr,
sizeof (struct sockaddr));
#else
- rc = connect(conn->vsc_sockfd, (struct sockaddr *)&addr,
+ rc = connect(sockfd, (struct sockaddr *)&addr,
sizeof (struct sockaddr));
#endif
- sock_opt = 1;
-
- if ((rc < 0) || (vscand_get_state() == VS_STATE_SHUTDOWN) ||
- (setsockopt(conn->vsc_sockfd, IPPROTO_TCP, TCP_NODELAY,
- &sock_opt, sizeof (sock_opt)) < 0) ||
- (setsockopt(conn->vsc_sockfd, SOL_SOCKET, SO_KEEPALIVE,
- &sock_opt, sizeof (sock_opt)) < 0)) {
- syslog(LOG_WARNING, "Scan Engine - connection error (%s:%d) %s",
- conn->vsc_host, conn->vsc_port, strerror(errno));
- (void) close(conn->vsc_sockfd);
- conn->vsc_sockfd = -1;
+ opt_nodelay = 1;
+ opt_keepalive = 1;
+ opt_reuseaddr = 1;
+
+ if ((rc < 0) ||
+ (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,
+ &opt_nodelay, sizeof (opt_nodelay)) < 0) ||
+ (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
+ &opt_keepalive, sizeof (opt_keepalive)) < 0) ||
+ (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
+ &opt_reuseaddr, sizeof (opt_reuseaddr)) < 0)) {
+ (void) close(sockfd);
return (-1);
}
- return (0);
+ return (sockfd);
}
@@ -493,20 +752,20 @@ vs_eng_connect(vs_eng_conn_t *conn)
*/
#ifdef FIONBIO
static int
-nbio_connect(vs_eng_conn_t *conn, const struct sockaddr *sa, int sa_len)
+nbio_connect(int sockfd, const struct sockaddr *sa, int sa_len)
{
struct pollfd pfd;
int nbio, rc;
- int soc = conn->vsc_sockfd;
int error, len = sizeof (error);
nbio = 1;
- if ((ioctl(soc, FIONBIO, &nbio)) < 0)
- return (connect(soc, sa, sa_len));
+ if ((ioctl(sockfd, FIONBIO, &nbio)) < 0)
+ return (connect(sockfd, sa, sa_len));
- if ((rc = connect(soc, sa, sa_len)) != 0) {
+ if ((rc = connect(sockfd, sa, sa_len)) != 0) {
if (errno == EINPROGRESS || errno == EINTR) {
- pfd.fd = soc;
+ errno = 0;
+ pfd.fd = sockfd;
pfd.events = POLLOUT;
pfd.revents = 0;
@@ -515,16 +774,24 @@ nbio_connect(vs_eng_conn_t *conn, const struct sockaddr *sa, int sa_len)
errno = ETIMEDOUT;
rc = -1;
} else {
- rc = getsockopt(soc, SOL_SOCKET, SO_ERROR,
- &error, &len);
- if (rc != 0 || error != 0)
+ if ((pfd.revents &
+ (POLLHUP | POLLERR | POLLNVAL)) ||
+ (!(pfd.revents & POLLOUT))) {
rc = -1;
+ } else {
+ rc = getsockopt(sockfd, SOL_SOCKET,
+ SO_ERROR, &error, &len);
+ if (rc != 0 || error != 0)
+ rc = -1;
+ if (error != 0)
+ errno = error;
+ }
}
}
}
nbio = 0;
- (void) ioctl(soc, FIONBIO, &nbio);
+ (void) ioctl(sockfd, FIONBIO, &nbio);
return (rc);
}
@@ -555,7 +822,7 @@ vs_eng_scanstamp_current(vs_scanstamp_t scanstamp)
(void) pthread_mutex_lock(&vs_eng_mutex);
for (i = 0; i < VS_SE_MAX; i++) {
if ((vs_engines[i].vse_cfg.vep_enable) &&
- (vs_engines[i].vse_error == 0) &&
+ (vs_engines[i].vse_error == B_FALSE) &&
(vs_icap_compare_scanstamp(i, scanstamp) == 0))
break;
}
diff --git a/usr/src/cmd/vscan/vscand/vs_icap.c b/usr/src/cmd/vscan/vscand/vs_icap.c
index cb970ffe32..ec9634841a 100644
--- a/usr/src/cmd/vscan/vscand/vs_icap.c
+++ b/usr/src/cmd/vscan/vscand/vs_icap.c
@@ -235,24 +235,33 @@ vs_icap_config(int idx, char *host, int port)
* Returns: result->vsr_rc
*/
int
-vs_icap_scan_file(vs_eng_conn_t *conn, char *devname, char *fname,
+vs_icap_scan_file(vs_eng_ctx_t *eng, char *devname, char *fname,
uint64_t fsize, int flags, vs_result_t *result)
{
vs_scan_ctx_t ctx;
int fd;
- if ((fd = open(devname, O_RDONLY)) == -1) {
- syslog(LOG_ERR, "Failed to open device %s", devname);
+ fd = open(devname, O_RDONLY);
+
+ /* retry once on ENOENT as /dev link may not be created yet */
+ if ((fd == -1) && (errno == ENOENT)) {
+ (void) sleep(1);
+ fd = open(devname, O_RDONLY);
+ }
+
+ if (fd == -1) {
+ syslog(LOG_ERR, "Failed to open device %s - %s",
+ devname, strerror(errno));
result->vsr_rc = VS_RESULT_ERROR;
return (result->vsr_rc);
}
/* initialize context */
(void) memset(&ctx, 0, sizeof (vs_scan_ctx_t));
- ctx.vsc_idx = conn->vsc_idx;
- (void) strlcpy(ctx.vsc_host, conn->vsc_host, sizeof (ctx.vsc_host));
- ctx.vsc_port = conn->vsc_port;
- ctx.vsc_sockfd = conn->vsc_sockfd;
+ ctx.vsc_idx = eng->vse_eidx;
+ (void) strlcpy(ctx.vsc_host, eng->vse_host, sizeof (ctx.vsc_host));
+ ctx.vsc_port = eng->vse_port;
+ ctx.vsc_sockfd = eng->vse_sockfd;
ctx.vsc_fd = fd;
ctx.vsc_fname = fname;
ctx.vsc_fsize = fsize;
@@ -1141,7 +1150,7 @@ vs_icap_write(int fd, char *buf, int buflen)
while (resid > 0) {
errno = 0;
- bytes_sent = write(fd, buf, resid);
+ bytes_sent = write(fd, ptr, resid);
if (bytes_sent < 0) {
if (errno == EINTR)
continue;
@@ -1171,7 +1180,7 @@ vs_icap_read(int fd, char *buf, int len)
while (resid > 0) {
errno = 0;
- bytes_read = read(fd, buf, resid);
+ bytes_read = read(fd, ptr, resid);
if (bytes_read < 0) {
if (errno == EINTR)
continue;
@@ -1275,9 +1284,10 @@ vs_icap_readline(vs_scan_ctx_t *ctx, char *buf, int buflen)
continue;
if (retval <= 0) {
- syslog(LOG_ERR, "Error receiving data from Scan Engine:"
- " %s", retval == 0 ? "Scan Engine disconnected"
- : strerror(errno));
+ if (vscand_get_state() != VS_STATE_SHUTDOWN) {
+ syslog(LOG_ERR, "Error receiving data from "
+ "Scan Engine: %s", strerror(errno));
+ }
return (-1);
}
diff --git a/usr/src/cmd/vscan/vscand/vs_incl.h b/usr/src/cmd/vscan/vscand/vs_incl.h
index 9977f2a1c2..488ef4243b 100644
--- a/usr/src/cmd/vscan/vscand/vs_incl.h
+++ b/usr/src/cmd/vscan/vscand/vs_incl.h
@@ -90,51 +90,43 @@ typedef struct vs_result {
} vs_result_t;
-/* scan engine connection */
-typedef struct vs_eng_conn {
- int vsc_idx;
- char vsc_engid[VS_SE_NAME_LEN];
- char vsc_host[MAXHOSTNAMELEN];
- int vsc_port;
- int vsc_sockfd;
- struct vs_eng_conn *vsc_next;
- struct vs_eng_conn *vsc_prev;
-} vs_eng_conn_t;
-
-
-/* file attributes used by virus scanning */
-typedef struct vs_attr {
- int vsa_modified;
- int vsa_quarantined;
- uint64_t vsa_size;
- vs_scanstamp_t vsa_scanstamp;
-}vs_attr_t;
+/* scan engine connection context */
+typedef struct vs_eng_ctx {
+ int vse_eidx; /* engine index */
+ int vse_cidx; /* connection index */
+ char vse_engid[VS_SE_NAME_LEN];
+ char vse_host[MAXHOSTNAMELEN];
+ int vse_port;
+ int vse_sockfd;
+} vs_eng_ctx_t;
/* Function Prototypes */
vs_daemon_state_t vscand_get_state(void);
char *vscand_viruslog(void);
+int vscand_kernel_result(vs_scan_rsp_t *);
int vs_door_init(void);
void vs_door_fini(void);
-void vs_svc_init(void);
+int vs_svc_init(uint32_t);
void vs_svc_fini(void);
-int vs_svc_scan_file(char *, char *, vs_attr_t *, int, vs_scanstamp_t *);
+int vs_svc_queue_scan_req(vs_scan_req_t *);
+void vs_svc_terminate(void);
void vs_eng_init(void);
void vs_eng_fini(void);
void vs_eng_config(vs_props_all_t *);
-void vs_eng_set_error(vs_eng_conn_t *, int);
-int vs_eng_get(vs_eng_conn_t *, int);
-int vs_eng_connect(vs_eng_conn_t *);
-void vs_eng_release(vs_eng_conn_t *);
+void vs_eng_set_error(vs_eng_ctx_t *, int);
+int vs_eng_get(vs_eng_ctx_t *, boolean_t);
+void vs_eng_release(const vs_eng_ctx_t *);
+void vs_eng_close_connections(void);
int vs_eng_scanstamp_current(vs_scanstamp_t);
void vs_icap_init(void);
void vs_icap_fini(void);
void vs_icap_config(int, char *, int);
-int vs_icap_scan_file(vs_eng_conn_t *, char *, char *, uint64_t,
+int vs_icap_scan_file(vs_eng_ctx_t *, char *, char *, uint64_t,
int, vs_result_t *);
void vs_icap_print_options(int);
int vs_icap_compare_scanstamp(int, vs_scanstamp_t);
diff --git a/usr/src/cmd/vscan/vscand/vs_main.c b/usr/src/cmd/vscan/vscand/vs_main.c
index dd138557cc..b66d762a91 100644
--- a/usr/src/cmd/vscan/vscand/vs_main.c
+++ b/usr/src/cmd/vscan/vscand/vs_main.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -57,13 +57,18 @@
#include <pwd.h>
#include <grp.h>
#include <priv_utils.h>
+#include <rctl.h>
#include "vs_incl.h"
+#define VS_FILE_DESCRIPTORS 512
+
static int vscand_fg = 0; /* daemon by default */
static vs_daemon_state_t vscand_state = VS_STATE_INIT;
static int vscand_sigval = 0;
static int vscand_kdrv_fd = -1;
static pthread_mutex_t vscand_cfg_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t vscand_cfg_cv;
+static pthread_t vscand_cfg_tid = 0;
/* virus log path */
static char vscand_vlog[MAXPATHLEN];
@@ -83,14 +88,20 @@ static int vscand_daemonize_init(void);
static void vscand_daemonize_fini(int, int);
static int vscand_init(void);
static void vscand_fini(void);
+static int vscand_cfg_init(void);
+static void vscand_cfg_fini(void);
+static void *vscand_cfg_handler(void *);
static int vscand_configure(void);
+static void vscand_dtrace_cfg(vs_props_all_t *);
static int vscand_kernel_bind(void);
static void vscand_kernel_unbind(void);
static int vscand_kernel_enable(int);
static void vscand_kernel_disable(void);
static int vscand_kernel_config(vs_config_t *);
+static int vscand_kernel_max_req(uint32_t *);
static void vscand_error(const char *);
static int vscand_get_viruslog(void);
+static int vscand_set_resource_limits(void);
/*
@@ -137,6 +148,8 @@ main(int argc, char **argv)
int err_stat = 0, pfd = -1;
sigset_t set;
struct sigaction act;
+ int sigval;
+
mode_t log_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
mode_t door_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
@@ -172,14 +185,12 @@ main(int argc, char **argv)
*vscand_vlog = 0;
}
- (void) unlink(VS_STATS_DOOR_NAME);
(void) vscand_init_file(VS_STATS_DOOR_NAME,
daemon_uid, sys_gid, door_mode);
/*
* Once we're done setting our global state up, set up signal handlers
- * for ensuring orderly termination on SIGTERM. If we are starting in
- * the foreground, we also use the same handler for SIGINT and SIGHUP.
+ * for ensuring orderly termination on SIGTERM.
*/
(void) sigfillset(&set);
(void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */
@@ -191,11 +202,11 @@ main(int argc, char **argv)
(void) sigaction(SIGTERM, &act, NULL);
(void) sigaction(SIGHUP, &act, NULL); /* Refresh config */
(void) sigaction(SIGINT, &act, NULL);
- (void) sigaction(SIGUSR1, &act, NULL);
+ (void) sigaction(SIGPIPE, &act, NULL);
(void) sigdelset(&set, SIGTERM);
(void) sigdelset(&set, SIGHUP);
(void) sigdelset(&set, SIGINT);
- (void) sigdelset(&set, SIGUSR1);
+ (void) sigdelset(&set, SIGPIPE);
if (vscand_fg) {
(void) sigdelset(&set, SIGTSTP);
@@ -227,23 +238,23 @@ main(int argc, char **argv)
/* Wait here until shutdown */
while (vscand_state == VS_STATE_RUNNING) {
+ if (vscand_sigval == 0)
+ (void) sigsuspend(&set);
- (void) sigsuspend(&set);
+ sigval = vscand_sigval;
+ vscand_sigval = 0;
- switch (vscand_sigval) {
+ switch (sigval) {
case 0:
- case SIGUSR1:
+ case SIGPIPE:
break;
case SIGHUP:
- if (vscand_configure() != 0)
- vscand_state = VS_STATE_SHUTDOWN;
+ (void) pthread_cond_signal(&vscand_cfg_cv);
break;
default:
vscand_state = VS_STATE_SHUTDOWN;
break;
}
-
- vscand_sigval = 0;
}
vscand_fini();
@@ -252,7 +263,7 @@ main(int argc, char **argv)
/*
- * vscand_parse_args -
+ * vscand_parse_args
* Routine to parse the arguments to the daemon program
* 'f' argument runs process in the foreground instead of as a daemon
*/
@@ -424,20 +435,20 @@ vscand_daemonize_fini(int fd, int err_status)
* create specified file and set its uid, gid and mode
*/
static int
-vscand_init_file(char *filepath, uid_t uid, gid_t gid, mode_t mode)
+vscand_init_file(char *filepath, uid_t uid, gid_t gid, mode_t access_mode)
{
int fd, rc = 0;
struct stat stat_buf;
char buf[MAXPATHLEN];
- if ((fd = open(filepath, O_RDONLY | O_CREAT, mode)) == -1)
+ if ((fd = open(filepath, O_RDONLY | O_CREAT, access_mode)) == -1) {
rc = -1;
- else {
- if (fstat(fd, &stat_buf) != 0)
+ } else {
+ if (fstat(fd, &stat_buf) != 0) {
rc = -1;
- else {
- if (stat_buf.st_mode != mode) {
- if (fchmod(fd, mode) != 0)
+ } else {
+ if ((stat_buf.st_mode & S_IAMB) != access_mode) {
+ if (fchmod(fd, access_mode) != 0)
rc = -1;
}
@@ -478,23 +489,33 @@ static int
vscand_init(void)
{
int door_fd = -1;
+ uint32_t max_req;
if (vscand_kernel_bind() < 0)
return (-1);
+ if (vscand_kernel_max_req(&max_req) == -1)
+ return (-1);
+
+ if (vs_svc_init(max_req) != 0)
+ return (-1);
+
if (vs_stats_init() != 0)
vscand_error(
gettext("failed to initialize statistics interface"));
- vs_svc_init();
vs_icap_init();
vs_eng_init();
- if (vscand_configure() != 0) {
+ /* initialize configuration and handler thread */
+ if (vscand_cfg_init() != 0) {
vscand_error(gettext("failed to initialize configuration"));
+ vscand_fini();
return (-1);
}
+ (void) vscand_set_resource_limits();
+
if (((door_fd = vs_door_init()) < 0) ||
(vscand_kernel_enable(door_fd) < 0)) {
vscand_fini();
@@ -510,8 +531,8 @@ vscand_init(void)
*
* vscand_kernel_disable - should be called first to ensure that no
* more scan requests are initiated from the kernel module
- * vs_door_fini - shouldn't be called until after the in-progress
- * scans complete (vs_eng_fini waits for in progress scans)
+ * vs_svc_terminate - terminate requests and wait for thread completion
+ * vs_xxx_fini - module cleanup routines
* vscand_kernel_unbind - should be called last to tell the kernel module
* that vscand is shutdown.
*/
@@ -520,10 +541,16 @@ vscand_fini(void)
{
vscand_kernel_disable();
+ /* terminate reconfiguration handler thread */
+ vscand_cfg_fini();
+
+ /* terminate requests and wait for completion */
+ vs_svc_terminate();
+
+ /* clean up */
vs_svc_fini();
vs_eng_fini();
vs_icap_fini();
-
vs_door_fini();
vs_stats_fini();
@@ -532,6 +559,75 @@ vscand_fini(void)
/*
+ * vscand_cfg_init
+ *
+ * initialize configuration and reconfiguration handler thread
+ */
+static int
+vscand_cfg_init(void)
+{
+ int rc;
+
+ (void) pthread_cond_init(&vscand_cfg_cv, NULL);
+
+ (void) pthread_mutex_lock(&vscand_cfg_mutex);
+ rc = vscand_configure();
+ (void) pthread_mutex_unlock(&vscand_cfg_mutex);
+
+ if (rc != 0)
+ return (-1);
+
+ if (pthread_create(&vscand_cfg_tid, NULL, vscand_cfg_handler, 0) != 0) {
+ vscand_cfg_tid = 0;
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * vscand_cfg_fini
+ *
+ * terminate reconfiguration handler thread
+ */
+static void
+vscand_cfg_fini()
+{
+ if (vscand_cfg_tid != 0) {
+ (void) pthread_cond_signal(&vscand_cfg_cv);
+ (void) pthread_join(vscand_cfg_tid, NULL);
+ vscand_cfg_tid = 0;
+ }
+ (void) pthread_cond_destroy(&vscand_cfg_cv);
+}
+
+
+/*
+ * vscand_cfg_handler
+ * wait for reconfiguration event and reload configuration
+ * exit on VS_STATE_SHUTDOWN
+ */
+/*ARGSUSED*/
+static void *
+vscand_cfg_handler(void *arg)
+{
+ (void) pthread_mutex_lock(&vscand_cfg_mutex);
+
+ while (pthread_cond_wait(&vscand_cfg_cv, &vscand_cfg_mutex) == 0) {
+ if (vscand_state == VS_STATE_SHUTDOWN)
+ break;
+
+ (void) vscand_configure();
+ }
+
+ (void) pthread_mutex_unlock(&vscand_cfg_mutex);
+
+ return (NULL);
+}
+
+
+/*
* vscand_configure
*/
static int
@@ -541,12 +637,9 @@ vscand_configure(void)
vs_config_t kconfig;
vs_props_all_t config;
- (void) pthread_mutex_lock(&vscand_cfg_mutex);
-
(void) memset(&config, 0, sizeof (vs_props_all_t));
if (vs_props_get_all(&config) != VS_ERR_NONE) {
vscand_error(gettext("configuration data error"));
- (void) pthread_mutex_unlock(&vscand_cfg_mutex);
return (-1);
}
@@ -555,7 +648,6 @@ vscand_configure(void)
if (vs_parse_types(config.va_props.vp_types,
kconfig.vsc_types, &len) != 0) {
vscand_error(gettext("configuration data error - types"));
- (void) pthread_mutex_unlock(&vscand_cfg_mutex);
return (-1);
}
kconfig.vsc_types_len = len;
@@ -564,24 +656,22 @@ vscand_configure(void)
if (vs_strtonum(config.va_props.vp_maxsize,
&kconfig.vsc_max_size) != 0) {
vscand_error(gettext("configuration data error - max-size"));
- (void) pthread_mutex_unlock(&vscand_cfg_mutex);
return (-1);
}
kconfig.vsc_allow = config.va_props.vp_maxsize_action ? 1LL : 0LL;
/* Send configuration update to kernel */
if (vscand_kernel_config(&kconfig) != 0) {
- (void) pthread_mutex_unlock(&vscand_cfg_mutex);
return (-1);
}
- /* Tell vs_eng things have changed. */
- vs_eng_config(&config);
+ /* dtrace the configuration data */
+ vscand_dtrace_cfg(&config);
- /* Tell vs_stats things have changed */
+ /* propagate configuration changes */
+ vs_eng_config(&config);
vs_stats_config(&config);
- (void) pthread_mutex_unlock(&vscand_cfg_mutex);
return (0);
}
@@ -667,7 +757,7 @@ vscand_kernel_unbind(void)
static int
vscand_kernel_enable(int door_fd)
{
- if (ioctl(vscand_kdrv_fd, VS_DRV_IOCTL_ENABLE, door_fd) < 0) {
+ if (ioctl(vscand_kdrv_fd, VS_IOCTL_ENABLE, door_fd) < 0) {
vscand_error(gettext("failed to bind to kernel"));
(void) close(vscand_kdrv_fd);
vscand_kdrv_fd = -1;
@@ -684,7 +774,7 @@ static void
vscand_kernel_disable()
{
if (vscand_kdrv_fd >= 0)
- (void) ioctl(vscand_kdrv_fd, VS_DRV_IOCTL_DISABLE);
+ (void) ioctl(vscand_kdrv_fd, VS_IOCTL_DISABLE);
}
@@ -694,11 +784,41 @@ vscand_kernel_disable()
int
vscand_kernel_config(vs_config_t *conf)
{
- if (vscand_kdrv_fd < 0)
+ if ((vscand_kdrv_fd < 0) ||
+ (ioctl(vscand_kdrv_fd, VS_IOCTL_CONFIG, conf) < 0)) {
+ vscand_error(gettext("failed to send config to kernel"));
return (-1);
+ }
- if (ioctl(vscand_kdrv_fd, VS_DRV_IOCTL_CONFIG, conf) < 0) {
- vscand_error(gettext("failed to send config to kernel"));
+ return (0);
+}
+
+
+/*
+ * vscand_kernel_result
+ */
+int
+vscand_kernel_result(vs_scan_rsp_t *scan_rsp)
+{
+ if ((vscand_kdrv_fd < 0) ||
+ (ioctl(vscand_kdrv_fd, VS_IOCTL_RESULT, scan_rsp) < 0)) {
+ vscand_error(gettext("failed to send result to kernel"));
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * vscand_kernel_max_req
+ */
+int
+vscand_kernel_max_req(uint32_t *max_req)
+{
+ if ((vscand_kdrv_fd < 0) ||
+ (ioctl(vscand_kdrv_fd, VS_IOCTL_MAX_REQ, max_req) < 0)) {
+ vscand_error(gettext("failed to get config data from kernel"));
return (-1);
}
@@ -707,6 +827,35 @@ vscand_kernel_config(vs_config_t *conf)
/*
+ * vscand_set_resource_limits
+ *
+ * If the process's max file descriptor limit is less than
+ * VS_FILE_DESCRIPTORS, increae it to VS_FILE_DESCRIPTORS.
+ */
+static int
+vscand_set_resource_limits(void)
+{
+ int rc = -1;
+ rctlblk_t *rblk;
+ char *limit = "process.max-file-descriptor";
+
+ rblk = (rctlblk_t *)malloc(rctlblk_size());
+
+ if (rblk != NULL) {
+ rc = getrctl(limit, NULL, rblk, 0);
+ if ((rc == 0) &&
+ (rctlblk_get_value(rblk) < VS_FILE_DESCRIPTORS)) {
+ rctlblk_set_value(rblk, VS_FILE_DESCRIPTORS);
+ rc = setrctl(limit, NULL, rblk, 0);
+ }
+ (void) free(rblk);
+ }
+
+ return (rc);
+}
+
+
+/*
* vscand_error
*/
static void
@@ -715,3 +864,42 @@ vscand_error(const char *errmsg)
(void) fprintf(stderr, "vscand: %s", errmsg);
syslog(LOG_ERR, "%s\n", errmsg);
}
+
+
+/*
+ * vscand_dtrace_cfg
+ * vscand_dtrace_gen
+ * vscand_dtrace_eng
+ *
+ * Support for dtracing vscand configuration when processing
+ * a reconfiguration event (SIGHUP)
+ */
+/*ARGSUSED*/
+static void
+vscand_dtrace_eng(char *id, boolean_t enable, char *host, int port, int conn)
+{
+}
+/*ARGSUSED*/
+static void
+vscand_dtrace_gen(char *size, boolean_t action, char *types, char *log)
+{
+}
+static void
+vscand_dtrace_cfg(vs_props_all_t *config)
+{
+ int i;
+
+ vscand_dtrace_gen(config->va_props.vp_maxsize,
+ config->va_props.vp_maxsize_action,
+ config->va_props.vp_types,
+ config->va_props.vp_vlog);
+
+ for (i = 0; i < VS_SE_MAX; i++) {
+ if (config->va_se[i].vep_engid[0] != 0)
+ vscand_dtrace_eng(config->va_se[i].vep_engid,
+ config->va_se[i].vep_enable,
+ config->va_se[i].vep_host,
+ config->va_se[i].vep_port,
+ config->va_se[i].vep_maxconn);
+ }
+}
diff --git a/usr/src/cmd/vscan/vscand/vs_stats.c b/usr/src/cmd/vscan/vscand/vs_stats.c
index 0d30c40d32..c053169727 100644
--- a/usr/src/cmd/vscan/vscand/vs_stats.c
+++ b/usr/src/cmd/vscan/vscand/vs_stats.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -53,6 +53,7 @@ static pthread_mutex_t vs_stats_mutex = PTHREAD_MUTEX_INITIALIZER;
/* function prototype */
static int vs_stats_check_auth(void);
+static void vs_stats_reset(void);
static void vs_stats_door_call(void *, char *, size_t, door_desc_t *, uint_t);
@@ -144,35 +145,67 @@ static void
vs_stats_door_call(void *cookie, char *ptr, size_t size, door_desc_t *dp,
uint_t n_desc)
{
- /* LINTED E_BAD_PTR_CAST_ALIGN - to be fixed with encoding */
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
vs_stats_req_t *req = (vs_stats_req_t *)ptr;
- vs_stats_t rsp;
+ vs_stats_rsp_t rsp;
- switch (*req) {
+ if ((cookie != &vs_stats_door_cookie) ||
+ (ptr == NULL) ||
+ (size != sizeof (vs_stats_req_t)) ||
+ (req->vsr_magic != VS_STATS_DOOR_MAGIC)) {
+ return;
+ }
+
+ rsp.vsr_magic = VS_STATS_DOOR_MAGIC;
+
+ switch (req->vsr_id) {
case VS_STATS_GET:
(void) pthread_mutex_lock(&vs_stats_mutex);
- (void) memcpy(&rsp, &vscan_stats, sizeof (vs_stats_t));
+ rsp.vsr_stats = vscan_stats;
(void) pthread_mutex_unlock(&vs_stats_mutex);
- (void) door_return((char *)&rsp, sizeof (vs_stats_t), NULL, 0);
+ (void) door_return((char *)&rsp, sizeof (vs_stats_rsp_t),
+ NULL, 0);
break;
case VS_STATS_RESET:
- if (vs_stats_check_auth() == 0) {
- (void) pthread_mutex_lock(&vs_stats_mutex);
- (void) memset(&vscan_stats, 0, sizeof (vs_stats_t));
- (void) pthread_mutex_unlock(&vs_stats_mutex);
- }
+ vs_stats_reset();
(void) door_return(NULL, 0, NULL, 0);
break;
default:
- (void) door_return(NULL, 0, NULL, 0);
- break;
+ return;
}
}
/*
+ * vs_stats_reset
+ *
+ * Reset totals and per-engine statistics to 0
+ */
+static void
+vs_stats_reset()
+{
+ int i;
+
+ if (vs_stats_check_auth() != 0)
+ return;
+
+ (void) pthread_mutex_lock(&vs_stats_mutex);
+
+ vscan_stats.vss_scanned = 0;
+ vscan_stats.vss_infected = 0;
+ vscan_stats.vss_cleaned = 0;
+ vscan_stats.vss_failed = 0;
+
+ for (i = 0; i < VS_SE_MAX; i++)
+ vscan_stats.vss_eng[i].vss_errors = 0;
+
+ (void) pthread_mutex_unlock(&vs_stats_mutex);
+}
+
+
+/*
* vs_stats_set
*
* Update scan request stats
diff --git a/usr/src/cmd/vscan/vscand/vs_svc.c b/usr/src/cmd/vscan/vscand/vs_svc.c
index d0fee6db30..80029fec08 100644
--- a/usr/src/cmd/vscan/vscand/vs_svc.c
+++ b/usr/src/cmd/vscan/vscand/vs_svc.c
@@ -39,26 +39,183 @@
#include <fcntl.h>
#include <bsm/adt.h>
#include <bsm/adt_event.h>
+#include <pthread.h>
#include "vs_incl.h"
+/*
+ * vs_svc_nodes - table of scan requests and their thread id and
+ * scan engine context.
+ * The table is sized by the value passed to vs_svc_init. This
+ * value is obtained from the kernel and represents the maximum
+ * request idx that the kernel will request vscand to process.
+ * The table is indexed by the vsr_idx value passed in
+ * the scan request - always non-zero. This value is also the index
+ * into the kernel scan request table and identifies the instance of
+ * the driver being used to access file data for the scan. Although
+ * this is of no consequence here, it is useful information for debug.
+ *
+ * When a scan request is received a response is sent indicating
+ * one of the following:
+ * VS_STATUS_ERROR - an error occurred
+ * VS_STATUS_NO_SCAN - no scan is required
+ * VS_STATUS_SCANNING - request has been queued for async processing
+ *
+ * If the scan is required (VS_STATUS_SCANNING) a thread is created
+ * to perform the scan. It's tid is saved in vs_svc_nodes.
+ *
+ * In the case of SHUTDOWN, vs_terminate requests that all scan
+ * engine connections be closed, thus termintaing any in-progress
+ * scans, then awaits completion of all scanning threads as identified
+ * in vs_svc_nodes.
+ */
+
+typedef struct vs_svc_node {
+ pthread_t vsn_tid;
+ vs_scan_req_t vsn_req;
+ vs_eng_ctx_t vsn_eng;
+} vs_svc_node_t;
+
+static vs_svc_node_t *vs_svc_nodes;
+static uint32_t vs_svc_max_node; /* max idx into vs_svc_nodes */
+static pthread_mutex_t vs_svc_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
/* local functions */
+static void *vs_svc_async_scan(void *);
+static int vs_svc_scan_file(vs_svc_node_t *, vs_scanstamp_t *);
static void vs_svc_vlog(char *, vs_result_t *);
static void vs_svc_audit(char *, vs_result_t *);
+
/*
* vs_svc_init, vs_svc_fini
*
* Invoked on daemon load and unload
*/
-void
-vs_svc_init()
+int
+vs_svc_init(uint32_t max_req)
{
+ vs_svc_max_node = max_req;
+ vs_svc_nodes = (vs_svc_node_t *)
+ calloc(max_req + 1, sizeof (vs_svc_node_t));
+
+ return (vs_svc_nodes == NULL ? -1 : 0);
}
void
vs_svc_fini()
{
+ if (vs_svc_nodes)
+ free(vs_svc_nodes);
+}
+
+
+/*
+ * vs_svc_terminate
+ *
+ * Close all scan engine connections to terminate in-progress scan
+ * requests, and wait for all threads in vs_svc_nodes to complete
+ */
+void
+vs_svc_terminate()
+{
+ int i;
+ pthread_t tid;
+
+ /* close connections to abort requests */
+ vs_eng_close_connections();
+
+ /* wait for threads */
+ for (i = 1; i <= vs_svc_max_node; i++) {
+
+ (void) pthread_mutex_lock(&vs_svc_mutex);
+ tid = vs_svc_nodes[i].vsn_tid;
+ (void) pthread_mutex_unlock(&vs_svc_mutex);
+
+ if (tid != 0)
+ (void) pthread_join(tid, NULL);
+ }
+}
+
+
+/*
+ * vs_svc_queue_scan_req
+ *
+ * Determine if the file needs to be scanned - either it has
+ * been modified or its scanstamp is not current.
+ * Initiate a thread to process the request, saving the tid
+ * in vs_svc_nodes[idx].vsn_tid, where idx is the vsr_idx passed in
+ * the scan request.
+ *
+ * Returns: VS_STATUS_ERROR - error
+ * VS_STATUS_NO_SCAN - no scan required
+ * VS_STATUS_SCANNING - async scan initiated
+ */
+int
+vs_svc_queue_scan_req(vs_scan_req_t *req)
+{
+ pthread_t tid;
+ vs_svc_node_t *node;
+
+ /* No scan if file quarantined */
+ if (req->vsr_quarantined)
+ return (VS_STATUS_NO_SCAN);
+
+ /* No scan if file not modified AND scanstamp is current */
+ if ((req->vsr_modified == 0) &&
+ vs_eng_scanstamp_current(req->vsr_scanstamp)) {
+ return (VS_STATUS_NO_SCAN);
+ }
+
+ /* scan required */
+ node = &(vs_svc_nodes[req->vsr_idx]);
+
+ (void) pthread_mutex_lock(&vs_svc_mutex);
+ if ((node->vsn_tid != 0) || (req->vsr_idx > vs_svc_max_node)) {
+ (void) pthread_mutex_unlock(&vs_svc_mutex);
+ return (VS_STATUS_ERROR);
+ }
+
+ node->vsn_req = *req;
+
+ if (pthread_create(&tid, NULL, vs_svc_async_scan, (void *)node) != 0) {
+ (void) pthread_mutex_unlock(&vs_svc_mutex);
+ return (VS_STATUS_ERROR);
+ }
+
+ node->vsn_tid = tid;
+ (void) pthread_mutex_unlock(&vs_svc_mutex);
+
+ return (VS_STATUS_SCANNING);
+}
+
+
+/*
+ * vs_svc_async_scan
+ *
+ * Initialize response structure, invoke vs_svc_scan_file to
+ * perform the scan, then send the result to the kernel.
+ */
+static void *
+vs_svc_async_scan(void *arg)
+{
+ vs_svc_node_t *node = (vs_svc_node_t *)arg;
+ vs_scan_req_t *scan_req = &(node->vsn_req);
+ vs_scan_rsp_t scan_rsp;
+
+ scan_rsp.vsr_idx = scan_req->vsr_idx;
+ scan_rsp.vsr_seqnum = scan_req->vsr_seqnum;
+ scan_rsp.vsr_result = vs_svc_scan_file(node, &scan_rsp.vsr_scanstamp);
+
+ /* clear node and send async response to kernel */
+ (void) pthread_mutex_lock(&vs_svc_mutex);
+ (void) memset(node, 0, sizeof (vs_svc_node_t));
+ (void) pthread_mutex_unlock(&vs_svc_mutex);
+
+ (void) vscand_kernel_result(&scan_rsp);
+
+ return (NULL);
}
@@ -66,7 +223,6 @@ vs_svc_fini()
* vs_svc_scan_file
*
* vs_svc_scan_file is responsible for:
- * - determining if a scan is required
* - obtaining & releasing a scan engine connection
* - invoking the scan engine interface code to do the scan
* - retrying a failed scan (up to VS_MAX_RETRY times)
@@ -75,78 +231,66 @@ vs_svc_fini()
*
*
* Returns:
- * VS_STATUS_NO_SCAN - scan not reqd, or daemon shutting down
+ * VS_STATUS_NO_SCAN - scan not reqd; daemon shutting down
* VS_STATUS_CLEAN - scan success. File clean.
* new scanstamp returned in scanstamp param.
* VS_STATUS_INFECTED - scan success. File infected.
* VS_STATUS_ERROR - scan failure either in vscand or scan engine.
*/
-int
-vs_svc_scan_file(char *devname, char *fname, vs_attr_t *fattr, int flags,
- vs_scanstamp_t *scanstamp)
+static int
+vs_svc_scan_file(vs_svc_node_t *node, vs_scanstamp_t *scanstamp)
{
- vs_eng_conn_t conn;
+ char devname[MAXPATHLEN];
+ int flags = 0;
int retries;
vs_result_t result;
+ vs_scan_req_t *req = &(node->vsn_req);
+ vs_eng_ctx_t *eng = &(node->vsn_eng);
- /* initialize response scanstamp to current scanstamp value */
- (void) strlcpy(*scanstamp, fattr->vsa_scanstamp,
- sizeof (vs_scanstamp_t));
-
-
- /* No scan if file quarantined */
- if (fattr->vsa_quarantined)
- return (VS_STATUS_NO_SCAN);
+ (void) snprintf(devname, MAXPATHLEN, "%s%d", VS_DRV_PATH, req->vsr_idx);
- /* No scan if file not modified AND scanstamp is current */
- if ((fattr->vsa_modified == 0) &&
- vs_eng_scanstamp_current(fattr->vsa_scanstamp)) {
- return (VS_STATUS_NO_SCAN);
- }
+ /* initialize response scanstamp to current scanstamp value */
+ (void) strlcpy(*scanstamp, req->vsr_scanstamp, sizeof (vs_scanstamp_t));
(void) memset(&result, 0, sizeof (vs_result_t));
result.vsr_rc = VS_RESULT_UNDEFINED;
for (retries = 0; retries <= VS_MAX_RETRY; retries++) {
- /* identify available engine connection */
- if (vs_eng_get(&conn, retries) != 0) {
+ /* get engine connection */
+ if (vs_eng_get(eng, (retries != 0)) != 0) {
result.vsr_rc = VS_RESULT_ERROR;
continue;
}
- /* connect to engine and scan file */
- if (vs_eng_connect(&conn) != 0) {
- result.vsr_rc = VS_RESULT_SE_ERROR;
- } else {
- if (vscand_get_state() == VS_STATE_SHUTDOWN) {
- vs_eng_release(&conn);
- return (VS_STATUS_NO_SCAN);
- }
-
- (void) vs_icap_scan_file(&conn, devname, fname,
- fattr->vsa_size, flags, &result);
+ /* shutdown could occur while waiting for engine connection */
+ if (vscand_get_state() == VS_STATE_SHUTDOWN) {
+ vs_eng_release(eng);
+ return (VS_STATUS_NO_SCAN);
}
+ /* scan file */
+ (void) vs_icap_scan_file(eng, devname, req->vsr_path,
+ req->vsr_size, flags, &result);
+
/* if no error, clear error state on engine and break */
if ((result.vsr_rc != VS_RESULT_SE_ERROR) &&
(result.vsr_rc != VS_RESULT_ERROR)) {
- vs_eng_set_error(&conn, 0);
- vs_eng_release(&conn);
+ vs_eng_set_error(eng, 0);
+ vs_eng_release(eng);
break;
}
/* treat error on shutdown as scan not required */
if (vscand_get_state() == VS_STATE_SHUTDOWN) {
- vs_eng_release(&conn);
+ vs_eng_release(eng);
return (VS_STATUS_NO_SCAN);
}
/* set engine's error state and update engine stats */
- if (result.vsr_rc == VS_RESULT_SE_ERROR) {
- vs_eng_set_error(&conn, 1);
- vs_stats_eng_err(conn.vsc_engid);
- }
- vs_eng_release(&conn);
+ if (result.vsr_rc == VS_RESULT_SE_ERROR)
+ vs_eng_set_error(eng, 1);
+
+ vs_eng_release(eng);
}
vs_stats_set(result.vsr_rc);
@@ -158,8 +302,8 @@ vs_svc_scan_file(char *devname, char *fname, vs_attr_t *fattr, int flags,
*/
if (result.vsr_rc == VS_RESULT_CLEANED ||
result.vsr_rc == VS_RESULT_FORBIDDEN) {
- vs_svc_vlog(fname, &result);
- vs_svc_audit(fname, &result);
+ vs_svc_vlog(req->vsr_path, &result);
+ vs_svc_audit(req->vsr_path, &result);
return (VS_STATUS_INFECTED);
}
@@ -177,8 +321,8 @@ vs_svc_scan_file(char *devname, char *fname, vs_attr_t *fattr, int flags,
/*
* vs_svc_vlog
*
- * log details of infections detected in file
- * If virus log is not configured or cannot be opened, use syslog.
+ * log details of infections detected in syslig
+ * If virus log is configured log details there too
*/
static void
vs_svc_vlog(char *filepath, vs_result_t *result)
@@ -190,40 +334,42 @@ vs_svc_vlog(char *filepath, vs_result_t *result)
int i;
char *log;
- if ((log = vscand_viruslog()) != NULL)
- fp = fopen(log, "a");
+ /* syslog */
+ if (result->vsr_nviolations == 0) {
+ syslog(LOG_WARNING, "quarantine %s\n", filepath);
+ } else {
+ for (i = 0; i < result->vsr_nviolations; i++) {
+ syslog(LOG_WARNING, "quarantine %s %d - %s\n",
+ filepath,
+ result->vsr_vrec[i].vr_id,
+ result->vsr_vrec[i].vr_desc);
+ }
+ }
- if (fp) {
- (void) time(&sec);
- timestamp = localtime(&sec);
- (void) strftime(timebuf, sizeof (timebuf), "%D %T", timestamp);
+ /* log file */
+ if (((log = vscand_viruslog()) == NULL) ||
+ ((fp = fopen(log, "a")) == NULL)) {
+ return;
}
+ (void) time(&sec);
+ timestamp = localtime(&sec);
+ (void) strftime(timebuf, sizeof (timebuf), "%D %T", timestamp);
+
if (result->vsr_nviolations == 0) {
- if (fp) {
- (void) fprintf(fp, "%s quarantine %s",
- timebuf, filepath);
- } else {
- syslog(LOG_WARNING, "quarantine %s\n", filepath);
- }
+ (void) fprintf(fp, "%s quarantine %d[%s]\n",
+ timebuf, strlen(filepath), filepath);
} else {
for (i = 0; i < result->vsr_nviolations; i++) {
- if (fp) {
- (void) fprintf(fp, "%s quarantine %s %d - %s\n",
- timebuf, filepath,
- result->vsr_vrec[i].vr_id,
- result->vsr_vrec[i].vr_desc);
- } else {
- syslog(LOG_WARNING, "quarantine %s %d - %s\n",
- filepath,
- result->vsr_vrec[i].vr_id,
- result->vsr_vrec[i].vr_desc);
- }
+ (void) fprintf(fp, "%s quarantine %d[%s] %d - %d[%s]\n",
+ timebuf, strlen(filepath), filepath,
+ result->vsr_vrec[i].vr_id,
+ strlen(result->vsr_vrec[i].vr_desc),
+ result->vsr_vrec[i].vr_desc);
}
}
- if (fp)
- (void) fclose(fp);
+ (void) fclose(fp);
}
diff --git a/usr/src/cmd/vscan/vscand/vscan.d b/usr/src/cmd/vscan/vscand/vscan.d
index f7a16172d6..62a88f23a8 100755
--- a/usr/src/cmd/vscan/vscand/vscan.d
+++ b/usr/src/cmd/vscan/vscand/vscan.d
@@ -26,155 +26,251 @@
#pragma ident "%Z%%M% %I% %E% SMI"
+/*
#pragma D option flowindent
+*/
/*
*** vscan kernel pseudo driver ***
*/
-/* vscan_svc.c */
-sdt:vscan::vscan-scan-file
+/*
+ * vscan_svc.c
+ */
+sdt:vscan::vscan-req-counts
{
- printf("%s (%s)", stringof(arg0), arg1 ? "async" : "sync");
+ printf("%s reql: %d, node: %d, taskq: %d",
+ stringof(arg0),
+ ((vscan_svc_counts_t *)arg1)->vsc_reql,
+ ((vscan_svc_counts_t *)arg1)->vsc_node,
+ ((vscan_svc_counts_t *)arg1)->vsc_tq);
}
-sdt:vscan::vscan-exempt-filesize
+sdt:vscan::vscan-svc-state-violation
{
- printf("%s EXEMPT (%s)", stringof(arg0), arg1 ? "DENY" : "ALLOW");
+ printf("%d %s", arg0,
+ arg0 == 0 ? "UNCONFIG" :
+ arg0 == 1 ? "IDLE" :
+ arg0 == 2 ? "ENABLED" :
+ arg0 == 3 ? "DISABLED" : "UNKNOWN");
}
-sdt:vscan::vscan-type-match
+sdt:vscan::vscan-scan-timeout
{
- printf("ext: %s matched: %s", stringof(arg0), stringof(arg1));
+ printf("idx: %d, seqnum: %d - %s",
+ ((vscan_req_t *)arg0)->vsr_idx,
+ ((vscan_req_t *)arg0)->vsr_seqnum,
+ stringof(((vscan_req_t *)arg0)->vsr_vp->v_path));
}
-sdt:vscan::vscan-exempt-filetype
-{
- printf("%s EXEMPT", stringof(arg0));
-}
-
-sdt:vscan::vscan-wait-scan
+sdt:vscan::vscan-scan-file
{
- printf("%s (%d) waiters: %d",
- stringof(((vscan_file_t *)arg0)->vsf_req.vsr_vp->v_path),
- arg1, ((vscan_file_t *)arg0)->vsf_wait_count);
+ printf("%s (%s)", stringof(arg0), arg1 ? "async" : "sync");
}
-sdt:vscan::vscan-wait-slot
+sdt:vscan::vscan-exempt-filesize
{
- printf("%s", stringof(arg0));
+ printf("%s EXEMPT (%s)", stringof(arg0), arg1 ? "DENY" : "ALLOW");
}
-sdt:vscan::vscan-insert
+sdt:vscan::vscan-type-match
{
- printf("idx: %d - %s", arg1, stringof(arg0));
+ printf("ext: %s matched: %s", stringof(arg0), stringof(arg1));
}
-sdt:vscan::vscan-release
+sdt:vscan::vscan-exempt-filetype
{
- printf("idx: %d - %s", arg1, stringof(arg0));
+ printf("%s EXEMPT", stringof(arg0));
}
sdt:vscan::vscan-getattr
{
printf("%s, m: %d, q: %d, scanstamp: %s",
- stringof(((vscan_file_t *)arg0)->vsf_req.vsr_vp->v_path),
- ((vscan_file_t *)arg0)->vsf_modified,
- ((vscan_file_t *)arg0)->vsf_quarantined,
- stringof(((vscan_file_t *)arg0)->vsf_scanstamp));
+ stringof(((vscan_svc_node_t *)arg0)->vsn_req->vsr_vp->v_path),
+ ((vscan_svc_node_t *)arg0)->vsn_modified,
+ ((vscan_svc_node_t *)arg0)->vsn_quarantined,
+ stringof(((vscan_svc_node_t *)arg0)->vsn_scanstamp));
}
sdt:vscan::vscan-setattr
{
/* XAT_AV_QUARANTINED */
printf("%s", (arg1 & 0x400) == 0 ? "" :
- ((vscan_file_t *)arg0)->vsf_quarantined ? "q: 1, " : "q: 0, ");
+ ((vscan_svc_node_t *)arg0)->vsn_quarantined ? "q: 1, " : "q: 0, ");
/* XAT_AV_MODIFIED */
printf("%s", (arg1 & 0x800) == 0 ? "" :
- ((vscan_file_t *)arg0)->vsf_modified ? "m: 1, " : "m: 0, ");
+ ((vscan_svc_node_t *)arg0)->vsn_modified ? "m: 1, " : "m: 0, ");
/* XAT_AV_SCANSTAMP */
printf("%s", (arg1 & 0x1000) == 0 ? "" : "scanstamp: ");
printf("%s", (arg1 & 0x1000) == 0 ? "" :
- stringof(((vscan_file_t *)arg0)->vsf_scanstamp));
+ stringof(((vscan_svc_node_t *)arg0)->vsn_scanstamp));
}
sdt:vscan::vscan-mtime-changed
{
printf("%s",
- stringof(((vscan_file_t *)arg0)->vsf_req.vsr_vp->v_path));
+ stringof(((vscan_svc_node_t *)arg0)->vsn_req->vsr_vp->v_path));
}
sdt:vscan::vscan-result
{
- printf("VS_STATUS_%s - VS_ACCESS_%s",
- arg0 == 0 ? "UNDEFINED" :
- arg0 == 1 ? "NO_SCAN" :
- arg0 == 2 ? "ERROR" :
- arg0 == 3 ? "CLEAN" :
- arg0 == 4 ? "INFECTED" : "XXX unknown",
- arg1 == 0 ? "UNDEFINED" :
- arg1 == 1 ? "ALLOW" : "DENY");
+ printf("idx: %d, seqnum: %d, VS_STATUS_%s - VS_ACCESS_%s",
+ arg0, arg1,
+ arg2 == 0 ? "UNDEFINED" :
+ arg2 == 1 ? "NO_SCAN" :
+ arg2 == 2 ? "ERROR" :
+ arg2 == 3 ? "CLEAN" :
+ arg2 == 4 ? "INFECTED" :
+ arg2 == 5 ? "SCANNING" : "XXX unknown",
+ arg3 == 0 ? "UNDEFINED" :
+ arg3 == 1 ? "ALLOW" : "DENY");
+}
+
+/* insert request into request list */
+fbt:vscan:vscan_svc_reql_insert:entry
+{
+ printf("%s", stringof(args[0]->v_path));
+}
+fbt:vscan:vscan_svc_reql_insert:return
+/args[1] != 0/
+{
+ printf("seqnum %d %s", args[1]->vsr_seqnum,
+ stringof(args[1]->vsr_vp->v_path));
+}
+fbt:vscan:vscan_svc_reql_insert:return
+/args[1] == 0/
+{
+ printf("request list full");
+}
+/* insert request into scan table */
+fbt:vscan:vscan_svc_insert_req:entry
+{
+ printf("seqnum: %d - %s",
+ args[0]->vsr_seqnum, stringof(args[0]->vsr_vp->v_path));
+}
+fbt:vscan:vscan_svc_insert_req:return
+{
+ printf("idx: %d", args[1]);
+}
+/* remove request from request list and scan table and delete it*/
+fbt:vscan:vscan_svc_delete_req:entry
+{
+ printf("idx: %d, seqnum: %d - %s",
+ args[0]->vsr_idx, args[0]->vsr_seqnum,
+ stringof(args[0]->vsr_vp->v_path));
}
+fbt:vscan:vscan_svc_delete_req:return,
+fbt:vscan:vscan_svc_reql_handler:entry,
+fbt:vscan:vscan_svc_reql_handler:return
+{
+}
+
+fbt:vscan:vscan_svc_taskq_callback:entry,
+fbt:vscan:vscan_svc_do_scan:entry
+{
+ printf("idx: %d, seqnum: %d - %s",
+ ((vscan_req_t *)(args[0]))->vsr_idx,
+ ((vscan_req_t *)(args[0]))->vsr_seqnum,
+ stringof(((vscan_req_t *)(args[0]))->vsr_vp->v_path));
+}
+fbt:vscan:vscan_svc_scan_complete:entry
+{
+ printf("idx: %d, seqnum: %d, state: %s - %s",
+ args[0]->vsr_idx, args[0]->vsr_seqnum,
+ args[0]->vsr_state == 0 ? "INIT" :
+ args[0]->vsr_state == 1 ? "QUEUED" :
+ args[0]->vsr_state == 2 ? "IN_PROGRESS" :
+ args[0]->vsr_state == 3 ? "SCANNING" :
+ args[0]->vsr_state == 4 ? "ASYNC_COMPLETE" :
+ args[0]->vsr_state == 5 ? "COMPLETE" : "UNKNOWN",
+ stringof(args[0]->vsr_vp->v_path));
+}
+
+fbt:vscan:vscan_svc_taskq_callback:return,
+fbt:vscan:vscan_svc_do_scan:return,
+fbt:vscan:vscan_svc_scan_complete:return
+{
+}
+
+sdt:vscan::vscan-abort
+{
+ printf("idx: %d, seqnum: %d - %s",
+ ((vscan_req_t *)(arg0))->vsr_idx,
+ ((vscan_req_t *)(arg0))->vsr_seqnum,
+ stringof(((vscan_req_t *)(arg0))->vsr_vp->v_path));
+}
fbt:vscan:vscan_svc_enable:entry,
fbt:vscan:vscan_svc_enable:return,
fbt:vscan:vscan_svc_disable:entry,
fbt:vscan:vscan_svc_disable:return,
fbt:vscan:vscan_svc_configure:entry,
-fbt:vscan:vscan_svc_configure:return,
-fbt:vscan:vscan_svc_exempt_filetype:entry,
-fbt:vscan:vscan_svc_scan_file:return,
-fbt:vscan:vscan_svc_taskq_callback:entry,
-fbt:vscan:vscan_svc_taskq_callback:return,
-fbt:vscan:vscan_svc_do_scan:return
+fbt:vscan:vscan_svc_configure:return
{
}
/*
-fbt:vscan:vscan_svc_match_ext:entry
+ * vscan_door.c
+ */
+fbt:vscan:vscan_door_open:entry,
+fbt:vscan:vscan_door_open:return,
+fbt:vscan:vscan_door_close:entry,
+fbt:vscan:vscan_door_close:return
{
- printf("ext: %s, check: %s", stringof(args[1]), stringof(args[0]));
}
-fbt:vscan:vscan_svc_match_ext:return
-{
-}
-*/
-
-/* vscan_door.c */
fbt:vscan:vscan_door_scan_file:entry
{
- printf("%s (%d)", args[0]->vsr_path, args[0]->vsr_id);
+ printf("idx: %d, seqnum: %d - %s",
+ args[0]->vsr_idx, args[0]->vsr_seqnum, args[0]->vsr_path);
}
fbt:vscan:vscan_door_scan_file:return
{
- printf("%s", args[1] == 0 ? "success" : "error");
+ printf("VS_STATUS_%s",
+ args[1] == 0 ? "UNDEFINED" :
+ args[1] == 1 ? "NO_SCAN" :
+ args[1] == 2 ? "ERROR" :
+ args[1] == 3 ? "CLEAN" :
+ args[1] == 4 ? "INFECTED" :
+ args[1] == 5 ? "SCANNING" : "XXX unknown");
}
-/* vscan_drv.c */
+
+/*
+ * vscan_drv.c
+ */
+sdt:vscan::vscan-drv-state-violation
+{
+ printf("%d %s", arg0,
+ arg0 == 0 ? "UNCONFIG" :
+ arg0 == 1 ? "IDLE" :
+ arg0 == 2 ? "CONNECTED" :
+ arg0 == 3 ? "ENABLED" :
+ arg0 == 4 ? "DELAYED_DISABLE" : "UNKNOWN");
+}
sdt:vscan::vscan-minor-node
{
printf("vscan%d %s", arg0, arg1 != 0 ? "created" : "error");
}
-/*
- * unprivileged vscan driver access attempt
- */
+/* unprivileged vscan driver access attempt */
sdt:vscan::vscan-priv
/arg0 != 0/
{
printf("vscan driver access attempt by unprivileged process");
}
-/*
- * daemon-driver synchronization
- */
+/* daemon-driver synchronization */
+sdt:vscan::vscan-reconnect
+{
+}
+
fbt:vscan:vscan_drv_open:entry
/ *(int *)args[0] == 0/
{
@@ -193,37 +289,31 @@ fbt:vscan:vscan_drv_ioctl:entry
printf("vscan daemon ioctl %d %s", args[1],
args[1] == 1 ? "ENABLE" :
args[1] == 2 ? "DISABLE" :
- args[1] == 4 ? "CONFIG" : "unknown");
+ args[1] == 3 ? "CONFIG" :
+ args[1] == 4 ? "RESULT" :
+ args[1] == 5 ? "MAX FILES" : "unknown");
}
fbt:vscan:vscan_drv_delayed_disable:entry,
-fbt:vscan:vscan_drv_delayed_disable:return
-{
-}
-
-sdt:vscan::vscan-reconnect
+fbt:vscan:vscan_drv_delayed_disable:return,
+fbt:vscan:vscan_drv_attach:entry,
+fbt:vscan:vscan_drv_detach:entry
{
}
-/*
-fbt:vscan:vscan_drv_attach:entry,
fbt:vscan:vscan_drv_attach:return,
-fbt:vscan:vscan_drv_detach:entry,
fbt:vscan:vscan_drv_detach:return
{
+ printf("%s", args[1] ? "DDI_FAILURE" : "DDI_SUCCESS");
}
-fbt:vscan:vscan_drv_in_use:return,
-fbt:vscan:vscan_svc_in_use:return
+fbt:vscan:vscan_drv_in_use:return
{
- printf("%s", args[1] ? "in use" : "not in use");
+ printf("%s", args[1] ? "TRUE" : "FALSE");
}
-*/
-/*
- * file access
- */
+/* file access */
/*
fbt:vscan:vscan_drv_open:entry
@@ -245,13 +335,30 @@ fbt:vscan:vscan_drv_read:entry
*** vscan daemon - vscand ***
*/
+pid$target::vs_svc_init:entry
+{
+ printf("Max concurrent scan requests from kernel: %d", arg1);
+}
+
+pid$target::vs_svc_init:return
+{
+}
+
+
pid$target::vs_door_scan_req:entry,
pid$target::vs_svc_scan_file:entry,
+pid$target::vs_svc_queue_scan_req:entry,
+pid$target::vs_svc_async_scan:entry,
pid$target::vs_eng_scanstamp_current:entry,
pid$target::vs_icap_scan_file:entry
{
}
+pid$target::vs_svc_queue_scan_req:return,
+pid$target::vs_svc_async_scan:return
+{
+}
+
pid$target::vs_svc_scan_file:return
{
printf("VS_STATUS_%s",
@@ -259,7 +366,8 @@ pid$target::vs_svc_scan_file:return
arg1 == 1 ? "NO_SCAN" :
arg1 == 2 ? "ERROR" :
arg1 == 3 ? "CLEAN" :
- arg1 == 4 ? "INFECTED" : "XXX unknown");
+ arg1 == 4 ? "INFECTED" :
+ arg1 == 5 ? "SCANNING" : "XXX unknown");
}
pid$target::vs_eng_scanstamp_current:return
@@ -269,11 +377,11 @@ pid$target::vs_eng_scanstamp_current:return
pid$target::vs_icap_scan_file:return
{
- printf("%ld VS_RESULT_%s", arg1,
- arg1 == 0 ? "UNDEFINED" :
- arg1 == 1 ? "CLEAN" :
- arg1 == 2 ? "CLEANED" :
- arg1 == 3 ? "FORBIDDEN" : "(SE)_ERROR");
+ printf("%d VS_RESULT_%s", (int)arg1,
+ (int)arg1 == 0 ? "UNDEFINED" :
+ (int)arg1 == 1 ? "CLEAN" :
+ (int)arg1 == 2 ? "CLEANED" :
+ (int)arg1 == 3 ? "FORBIDDEN" : "(SE)_ERROR");
}
pid$target::vs_stats_set:entry
@@ -289,7 +397,9 @@ pid$target::vs_stats_set:return
/* get engine connection */
pid$target::vs_eng_get:entry,
-pid$target::vs_eng_connect:entry
+pid$target::vs_eng_connect:entry,
+pid$target::vs_eng_release:entry,
+pid$target::vs_eng_release:return
{
}
pid$target::vs_eng_get:return,
@@ -302,9 +412,35 @@ pid$target::vs_eng_connect:return
pid$target::vs_eng_set_error:entry
/ arg1 == 1 /
{
- printf("scan engine %d error", arg0 + 1);
+ printf("scan engine error");
}
+/* configuration */
+pid$target::vscand_cfg_init:entry,
+pid$target::vscand_cfg_fini:entry,
+pid$target::vscand_cfg_init:return,
+pid$target::vscand_cfg_fini:return,
+pid$target::vscand_cfg_handler:entry,
+pid$target::vscand_cfg_handler:return
+{
+}
+
+pid$target::vscand_dtrace_gen:entry
+{
+ printf("maxsize: %s action: %s\n",
+ copyinstr(arg0), (arg1 == 1) ? "allow" : "deny");
+ printf("types: %s\n", copyinstr(arg2));
+ printf("log: %s\n", copyinstr(arg3));
+}
+pid$target::vscand_dtrace_eng:entry
+{
+ printf("\n%s %s \nhost: %s \nport: %d \nmax connections: %d\n",
+ copyinstr(arg0), (arg1 == 1) ? "enabled" : "disabled",
+ copyinstr(arg2), arg3, arg4);
+}
+
+
+
/* shutdown */
pid$target::vscand_sig_handler:entry
{
@@ -317,6 +453,10 @@ pid$target::vscand_kernel_disable:entry,
pid$target::vscand_kernel_disable:return,
pid$target::vscand_kernel_unbind:entry,
pid$target::vscand_kernel_unbind:return,
+pid$target::vscand_kernel_result:entry,
+pid$target::vscand_kernel_result:return,
+pid$target::vs_svc_terminate:entry,
+pid$target::vs_svc_terminate:return,
pid$target::vs_eng_fini:entry,
pid$target::vs_eng_fini:return,
pid$target::vs_eng_close_connections:entry,
@@ -346,7 +486,7 @@ pid$target::vs_icap_send_preview:return,
pid$target::vs_icap_send_respmod_hdr:return,
pid$target::vs_icap_read_respmod_resp:return
{
- printf("%s", arg1 < 0 ? "error" : "success");
+ printf("%s", (int)arg1 < 0 ? "error" : "success");
}
pid$target::vs_icap_may_preview:return
@@ -368,7 +508,7 @@ pid$target::vs_icap_read:return,
pid$target::vs_icap_readline:return,
pid$target::vs_icap_send_chunk:return,
pid$target::gethostname:return
-/arg1 < 0/
+/(int)arg1 == -1/
{
printf("error");
}
@@ -389,10 +529,12 @@ pid$target::vs_icap_resp_encap:return
pid$target::write:return,
pid$target::read:return,
-pid$target::recv:return,
pid$target::open:return,
pid$target::calloc:return
/arg1 <= 0/
{
printf("error");
}
+/*
+pid$target::recv:return,
+*/