summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-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
-rw-r--r--usr/src/lib/libvscan/common/libvscan.c222
-rw-r--r--usr/src/lib/libvscan/common/libvscan.h15
-rw-r--r--usr/src/pkgdefs/Makefile1
-rw-r--r--usr/src/pkgdefs/SUNWvscankr/Makefile41
-rw-r--r--usr/src/pkgdefs/SUNWvscankr/pkginfo.tmpl45
-rw-r--r--usr/src/pkgdefs/SUNWvscankr/postinstall61
-rw-r--r--usr/src/pkgdefs/SUNWvscankr/preremove68
-rw-r--r--usr/src/pkgdefs/SUNWvscankr/prototype_com41
-rw-r--r--usr/src/pkgdefs/SUNWvscankr/prototype_i38635
-rw-r--r--usr/src/pkgdefs/SUNWvscankr/prototype_sparc34
-rw-r--r--usr/src/pkgdefs/SUNWvscanr/Makefile4
-rw-r--r--usr/src/pkgdefs/SUNWvscanr/depend3
-rw-r--r--usr/src/pkgdefs/SUNWvscanr/pkginfo.tmpl4
-rw-r--r--usr/src/pkgdefs/SUNWvscanr/preremove22
-rw-r--r--usr/src/pkgdefs/SUNWvscanr/prototype_com6
-rw-r--r--usr/src/pkgdefs/SUNWvscanr/prototype_i38610
-rw-r--r--usr/src/pkgdefs/SUNWvscanr/prototype_sparc9
-rw-r--r--usr/src/pkgdefs/SUNWvscanu/depend1
-rw-r--r--usr/src/pkgdefs/SUNWvscanu/prototype_com5
-rw-r--r--usr/src/pkgdefs/SUNWvscanu/prototype_i3864
-rw-r--r--usr/src/pkgdefs/SUNWvscanu/prototype_sparc4
-rw-r--r--usr/src/uts/common/io/vscan/vscan_door.c46
-rw-r--r--usr/src/uts/common/io/vscan/vscan_drv.c348
-rw-r--r--usr/src/uts/common/io/vscan/vscan_svc.c1184
-rw-r--r--usr/src/uts/common/sys/vscan.h68
35 files changed, 2839 insertions, 1125 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,
+*/
diff --git a/usr/src/lib/libvscan/common/libvscan.c b/usr/src/lib/libvscan/common/libvscan.c
index f7d5170750..cfd012c2b2 100644
--- a/usr/src/lib/libvscan/common/libvscan.c
+++ b/usr/src/lib/libvscan/common/libvscan.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.
*/
@@ -48,8 +48,8 @@
/* SMF property group and property names */
#define VS_PGNAME_GENERAL "vs_general"
-#define VS_PGNAME_ENGINE "vs_engine_%d"
-#define VS_PGNAME_ENGINE_LEN 16
+#define VS_PGNAME_ENGINE_PREFIX "vs_engine_"
+#define VS_PGNAME_ENGINE_LEN VS_SE_NAME_LEN + 16
#define VS_PNAME_MAXSIZE "maxsize"
#define VS_PNAME_MAXSIZE_ACTION "maxsize_action"
@@ -166,6 +166,7 @@ static int vs_scf_get(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int);
static int vs_scf_values_set(const char *, vs_prop_hd_t *);
static int vs_scf_set(const vs_propdef_t *, vs_prop_hd_t *, vs_scfctx_t *, int);
static int vs_scf_pg_create(const char *, vs_prop_hd_t *);
+static int vs_scf_pg_delete(const char *);
static int vs_scf_ctx_open(vs_scfctx_t *);
static void vs_scf_ctx_close(vs_scfctx_t *);
@@ -175,8 +176,8 @@ static int vs_is_valid_types(const char *);
static int vs_is_valid_host(const char *);
static int vs_checkauth(char *);
-typedef char vs_engid_t[VS_SE_NAME_LEN];
-static int vs_props_get_engines(vs_engid_t *engids, int *count);
+static int vs_props_get_engines(char *[], int *);
+static void vs_engid_to_pgname(const char *, char [VS_PGNAME_ENGINE_LEN]);
static int vs_scf_pg_count(void);
static int vs_strtoshift(const char *);
@@ -199,8 +200,7 @@ int
vs_props_get_all(vs_props_all_t *va)
{
int i, rc, n;
- char *engid;
- vs_engid_t engids[VS_SE_MAX];
+ char *engids[VS_SE_MAX];
(void) memset(va, 0, sizeof (vs_props_all_t));
if ((rc = vs_props_get(&va->va_props, VS_PROPID_GEN_ALL))
@@ -211,17 +211,19 @@ vs_props_get_all(vs_props_all_t *va)
if ((rc = vs_props_get_engines(engids, &n)) != VS_ERR_NONE)
return (rc);
- if (n > VS_SE_MAX)
- n = VS_SE_MAX;
-
for (i = 0; i < n; i++) {
- engid = engids[i];
- rc = vs_props_se_get(engid, &va->va_se[i], VS_PROPID_SE_ALL);
- if (rc != VS_ERR_NONE)
- return (rc);
+ if ((rc = vs_props_se_get(engids[i],
+ &va->va_se[i], VS_PROPID_SE_ALL)) != VS_ERR_NONE)
+ break;
}
- return (VS_ERR_NONE);
+ /* free engids allocated in vs_props_get_engines */
+ for (i = 0; i < VS_SE_MAX; i++) {
+ if (engids[i] != NULL)
+ free(engids[i]);
+ }
+
+ return (rc);
}
@@ -311,6 +313,7 @@ int
vs_props_se_get(char *engid, vs_props_se_t *sep, uint64_t propids)
{
int rc;
+ char pgname[VS_PGNAME_ENGINE_LEN];
vs_prop_hd_t prop_hd;
/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
@@ -331,7 +334,8 @@ vs_props_se_get(char *engid, vs_props_se_t *sep, uint64_t propids)
prop_hd.vp_ids |= VS_PROPID_SE_HOST;
/* Load values from the repository */
- rc = vs_scf_values_get(engid, &prop_hd);
+ vs_engid_to_pgname(engid, pgname);
+ rc = vs_scf_values_get(pgname, &prop_hd);
if (rc != VS_ERR_NONE)
return (rc);
@@ -371,6 +375,7 @@ int
vs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids)
{
int rc;
+ char pgname[VS_PGNAME_ENGINE_LEN];
vs_prop_hd_t prop_hd;
/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
@@ -384,6 +389,8 @@ vs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids)
prop_hd.vp_type = VS_PTYPE_SE;
prop_hd.vp_all = VS_PROPID_SE_ALL;
+ vs_engid_to_pgname(engid, pgname);
+
/*
* if enabling a scan engine, ensure that a valid host
* is also being set, or already exists in the repository
@@ -392,7 +399,7 @@ vs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids)
!(propids & VS_PROPID_SE_HOST)) {
prop_hd.vp_ids = VS_PROPID_SE_HOST;
- if ((rc = vs_scf_values_get(engid, &prop_hd)) != VS_ERR_NONE)
+ if ((rc = vs_scf_values_get(pgname, &prop_hd)) != VS_ERR_NONE)
return (rc);
if (vs_validate(&prop_hd, VS_PROPID_SE_HOST) != VS_ERR_NONE)
@@ -402,7 +409,7 @@ vs_props_se_set(char *engid, const vs_props_se_t *sep, uint64_t propids)
prop_hd.vp_ids = propids;
prop_hd.vp_se = *sep;
- return (vs_scf_values_set(engid, &prop_hd));
+ return (vs_scf_values_set(pgname, &prop_hd));
}
@@ -413,6 +420,7 @@ int
vs_props_se_create(char *engid, const vs_props_se_t *sep, uint64_t propids)
{
int n;
+ char pgname[VS_PGNAME_ENGINE_LEN];
vs_prop_hd_t prop_hd;
if ((propids & VS_PROPID_SE_ALL) != propids)
@@ -428,14 +436,21 @@ vs_props_se_create(char *engid, const vs_props_se_t *sep, uint64_t propids)
if (n == VS_SE_MAX)
return (VS_ERR_MAX_SE);
+ vs_engid_to_pgname(engid, pgname);
+
(void) memset(&prop_hd, 0, sizeof (vs_prop_hd_t));
prop_hd.vp_type = VS_PTYPE_SE;
prop_hd.vp_all = VS_PROPID_SE_ALL;
prop_hd.vp_ids = propids | VS_PROPID_VALUE_AUTH;
prop_hd.vp_se = *sep;
- return (vs_scf_pg_create(engid, &prop_hd));
+ /* if hostname not specified, default it to engid */
+ if ((propids & VS_PROPID_SE_HOST) == 0) {
+ (void) strlcpy(prop_hd.vp_se.vep_host, engid, MAXHOSTNAMELEN);
+ prop_hd.vp_ids |= VS_PROPID_SE_HOST;
+ }
+ return (vs_scf_pg_create(pgname, &prop_hd));
}
@@ -445,50 +460,15 @@ vs_props_se_create(char *engid, const vs_props_se_t *sep, uint64_t propids)
int
vs_props_se_delete(const char *engid)
{
- int rc;
- vs_scfctx_t vsc;
+ char pgname[VS_PGNAME_ENGINE_LEN];
/* VS_PGNAME_GENERAL is a reserved for GENERAL property group */
if (strcmp(engid, VS_PGNAME_GENERAL) == 0)
return (VS_ERR_INVALID_SE);
- /* ensure that caller has authorization to refresh service */
- if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
- return (rc);
-
- if (vs_scf_ctx_open(&vsc) != 0) {
- vs_scf_ctx_close(&vsc);
- return (VS_ERR_SCF);
- }
-
- if (scf_instance_get_pg(vsc.vscf_inst, engid, vsc.vscf_pgroup) == -1) {
- vs_scf_ctx_close(&vsc);
- rc = scf_error();
- if ((rc == SCF_ERROR_NOT_FOUND) ||
- (rc == SCF_ERROR_INVALID_ARGUMENT))
- return (VS_ERR_INVALID_SE);
- else
- return (VS_ERR_SCF);
- }
-
- if (scf_pg_delete(vsc.vscf_pgroup) == -1) {
- vs_scf_ctx_close(&vsc);
- rc = scf_error();
- if ((rc == SCF_ERROR_NOT_FOUND) ||
- (rc == SCF_ERROR_INVALID_ARGUMENT))
- return (VS_ERR_INVALID_SE);
-
- return (VS_ERR_SCF);
- }
-
- vs_scf_ctx_close(&vsc);
-
- /* Notify the daemon that things have changed */
- if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1) {
- return (VS_ERR_SCF);
- }
+ vs_engid_to_pgname(engid, pgname);
- return (VS_ERR_NONE);
+ return (vs_scf_pg_delete(pgname));
}
@@ -769,7 +749,6 @@ vs_scf_pg_create(const char *pgname, vs_prop_hd_t *prop_hd)
{
int rc;
uint64_t propid;
- uint64_t propids = prop_hd->vp_ids;
vs_scfctx_t vsc;
/* ensure that caller has authorization to refresh service */
@@ -795,23 +774,68 @@ vs_scf_pg_create(const char *pgname, vs_prop_hd_t *prop_hd)
if ((propid & prop_hd->vp_all) && !(propid & prop_hd->vp_ids))
vs_default_value(prop_hd, propid);
}
- prop_hd->vp_ids = prop_hd->vp_all;
-
-
- if ((propids & VS_PROPID_SE_HOST) == 0)
- (void) strlcpy(prop_hd->vp_se.vep_host, pgname, MAXHOSTNAMELEN);
+ prop_hd->vp_ids = prop_hd->vp_all;
prop_hd->vp_ids |= VS_PROPID_VALUE_AUTH;
rc = vs_scf_values_set(pgname, prop_hd);
if (rc != VS_ERR_NONE)
- (void) vs_props_se_delete(pgname);
+ (void) vs_scf_pg_delete(pgname);
return (rc);
}
/*
+ * vs_scf_pg_delete
+ */
+static int
+vs_scf_pg_delete(const char *pgname)
+{
+ int rc;
+ vs_scfctx_t vsc;
+
+ /* ensure that caller has authorization to refresh service */
+ if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
+ return (rc);
+
+ if (vs_scf_ctx_open(&vsc) != 0) {
+ vs_scf_ctx_close(&vsc);
+ return (VS_ERR_SCF);
+ }
+
+ if (scf_instance_get_pg(vsc.vscf_inst, pgname, vsc.vscf_pgroup) == -1) {
+ vs_scf_ctx_close(&vsc);
+ rc = scf_error();
+ if ((rc == SCF_ERROR_NOT_FOUND) ||
+ (rc == SCF_ERROR_INVALID_ARGUMENT))
+ return (VS_ERR_INVALID_SE);
+ else
+ return (VS_ERR_SCF);
+ }
+
+ if (scf_pg_delete(vsc.vscf_pgroup) == -1) {
+ vs_scf_ctx_close(&vsc);
+ rc = scf_error();
+ if ((rc == SCF_ERROR_NOT_FOUND) ||
+ (rc == SCF_ERROR_INVALID_ARGUMENT))
+ return (VS_ERR_INVALID_SE);
+
+ return (VS_ERR_SCF);
+ }
+
+ vs_scf_ctx_close(&vsc);
+
+ /* Notify the daemon that things have changed */
+ if ((smf_refresh_instance(VS_INSTANCE_FMRI)) == -1) {
+ return (VS_ERR_SCF);
+ }
+
+ return (VS_ERR_NONE);
+}
+
+
+/*
* vs_scf_values_set
*
* Sets property values in the repository. This is the single
@@ -832,7 +856,6 @@ vs_scf_values_set(const char *pgname, vs_prop_hd_t *prop_hd)
uint64_t propid;
vs_scfctx_t vsc;
-
/* ensure that caller has authorization to refresh service */
if ((rc = vs_checkauth(VS_ACTION_AUTH)) != VS_ERR_NONE)
return (rc);
@@ -1321,41 +1344,44 @@ vs_statistics(vs_stats_t *stats)
{
int door_fd, rc = VS_ERR_NONE;
vs_stats_req_t *req;
- vs_stats_t *buf;
+ vs_stats_rsp_t *rsp;
door_arg_t arg;
if ((req = calloc(1, sizeof (vs_stats_req_t))) == NULL)
return (VS_ERR_SYS);
- if ((buf = calloc(1, sizeof (vs_stats_t))) == NULL) {
+ if ((rsp = calloc(1, sizeof (vs_stats_rsp_t))) == NULL) {
free(req);
return (VS_ERR_SYS);
}
if ((door_fd = open(VS_STATS_DOOR_NAME, O_RDONLY)) < 0) {
free(req);
- free(buf);
+ free(rsp);
return (VS_ERR_DAEMON_COMM);
}
- *req = VS_STATS_GET;
+ req->vsr_magic = VS_STATS_DOOR_MAGIC;
+ req->vsr_id = VS_STATS_GET;
arg.data_ptr = (char *)req;
arg.data_size = sizeof (vs_stats_req_t);
arg.desc_ptr = NULL;
arg.desc_num = 0;
- arg.rbuf = (char *)buf;
- arg.rsize = sizeof (vs_stats_t);
+ arg.rbuf = (char *)rsp;
+ arg.rsize = sizeof (vs_stats_rsp_t);
- if (door_call(door_fd, &arg) < 0)
+ if ((door_call(door_fd, &arg) < 0) ||
+ (rsp->vsr_magic != VS_STATS_DOOR_MAGIC)) {
rc = VS_ERR_DAEMON_COMM;
- else
- *stats = *buf;
+ } else {
+ *stats = rsp->vsr_stats;
+ }
(void) close(door_fd);
free(req);
- free(buf);
+ free(rsp);
return (rc);
}
@@ -1382,7 +1408,8 @@ vs_statistics_reset()
return (VS_ERR_DAEMON_COMM);
}
- *req = VS_STATS_RESET;
+ req->vsr_magic = VS_STATS_DOOR_MAGIC;
+ req->vsr_id = VS_STATS_RESET;
arg.data_ptr = (char *)req;
arg.data_size = sizeof (vs_stats_req_t);
@@ -1426,15 +1453,19 @@ vs_checkauth(char *auth)
/*
* vs_props_get_engines
+ *
* On input, count specifies the maximum number of engine ids to
* return. engids must be an array with count entries.
* On return, count specifies the number of engine ids being
* returned in engids.
+ *
+ * Caller is responsible for free'ing the engids allocated herein.
*/
static int
-vs_props_get_engines(vs_engid_t *engids, int *count)
+vs_props_get_engines(char *engids[], int *count)
{
- int i = 0;
+ int i, prefix_len;
+ char pgname[VS_PGNAME_ENGINE_LEN];
vs_scfctx_t vsc;
@@ -1446,19 +1477,26 @@ vs_props_get_engines(vs_engid_t *engids, int *count)
return (VS_ERR_SCF);
}
+ for (i = 0; i < *count; i++)
+ engids[i] = NULL;
+
+ i = 0;
+ prefix_len = sizeof (VS_PGNAME_ENGINE_PREFIX) - 1;
+
while ((i < VS_SE_MAX) &&
(scf_iter_next_pg(vsc.vscf_iter, vsc.vscf_pgroup) == 1)) {
- if (scf_pg_get_name(vsc.vscf_pgroup, engids[i],
- VS_SE_NAME_LEN) < 0) {
+ if (scf_pg_get_name(vsc.vscf_pgroup, pgname,
+ VS_PGNAME_ENGINE_LEN) < 0) {
vs_scf_ctx_close(&vsc);
return (VS_ERR_SCF);
}
- if (strcmp(engids[i], VS_PGNAME_GENERAL) == 0)
- *engids[i] = 0;
- else
- if (++i == *count)
- break;
+ if (strncmp(pgname, VS_PGNAME_ENGINE_PREFIX, prefix_len) == 0) {
+ if ((engids[i] = strdup(pgname + prefix_len)) != NULL) {
+ if (++i == *count)
+ break;
+ }
+ }
}
vs_scf_ctx_close(&vsc);
@@ -1494,6 +1532,20 @@ vs_scf_pg_count(void)
/*
+ * vs_engid_to_pgname
+ *
+ * To convert an engine id (engid) to a property group name (pgname),
+ * the engine id is prefixed with VS_PGNAME_ENGINE_PREFIX.
+ */
+static void
+vs_engid_to_pgname(const char *engid, char pgname[VS_PGNAME_ENGINE_LEN])
+{
+ (void) snprintf(pgname, VS_PGNAME_ENGINE_LEN, "%s%s",
+ VS_PGNAME_ENGINE_PREFIX, engid);
+}
+
+
+/*
* vs_strtonum
*
* Converts a size string in the format into an integer.
diff --git a/usr/src/lib/libvscan/common/libvscan.h b/usr/src/lib/libvscan/common/libvscan.h
index 42de60a6a5..cb8121f16b 100644
--- a/usr/src/lib/libvscan/common/libvscan.h
+++ b/usr/src/lib/libvscan/common/libvscan.h
@@ -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.
*/
@@ -99,11 +99,17 @@ extern "C" {
/* statistics door interface */
#define VS_STATS_DOOR_NAME "/var/run/vscan_stats_door"
#define VS_STATS_DOOR_VERSION 1
+#define VS_STATS_DOOR_MAGIC 0x56535354 /* VSST - VScanStats */
/* scan statistics door request type */
typedef enum {
VS_STATS_GET,
VS_STATS_RESET
+} vs_stats_req_type_t;
+
+typedef struct vs_stats_req {
+ uint32_t vsr_magic;
+ vs_stats_req_type_t vsr_id;
} vs_stats_req_t;
typedef struct vs_stats {
@@ -117,6 +123,13 @@ typedef struct vs_stats {
} vss_eng[VS_SE_MAX];
} vs_stats_t;
+typedef struct vs_stats_rsp {
+ uint32_t vsr_magic;
+ vs_stats_t vsr_stats;
+} vs_stats_rsp_t;
+
+
+
/*
* General service configuration properties
*/
diff --git a/usr/src/pkgdefs/Makefile b/usr/src/pkgdefs/Makefile
index 8de91acdcd..c5414a9557 100644
--- a/usr/src/pkgdefs/Makefile
+++ b/usr/src/pkgdefs/Makefile
@@ -418,6 +418,7 @@ COMMON_SUBDIRS= \
SUNWusb \
SUNWusbs \
SUNWusbu \
+ SUNWvscankr \
SUNWvscanr \
SUNWvscanu \
SUNWxcu4 \
diff --git a/usr/src/pkgdefs/SUNWvscankr/Makefile b/usr/src/pkgdefs/SUNWvscankr/Makefile
new file mode 100644
index 0000000000..d48aa623bc
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWvscankr/Makefile
@@ -0,0 +1,41 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SRC=../..
+
+include ../Makefile.com
+
+DATAFILES += depend
+
+.KEEP_STATE:
+
+all: $(FILES) postinstall preremove
+
+install: all pkg
+
+include ../Makefile.targ
diff --git a/usr/src/pkgdefs/SUNWvscankr/pkginfo.tmpl b/usr/src/pkgdefs/SUNWvscankr/pkginfo.tmpl
new file mode 100644
index 0000000000..c22bed8bf1
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWvscankr/pkginfo.tmpl
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+PKG="SUNWvscankr"
+NAME="Virus Scan Service Kernel (Root)"
+ARCH="ISA"
+VERSION="ONVERS,REV=0.0.0"
+SUNW_PRODNAME="SunOS"
+SUNW_PRODVERS="RELEASE/VERSION"
+SUNW_PKGTYPE="root"
+MAXINST="1000"
+CATEGORY="system"
+DESC="Virus Scan Service Kernel Root Components"
+VENDOR="Sun Microsystems, Inc."
+HOTLINE="Please contact your local service provider"
+EMAIL=""
+CLASSES="none"
+BASEDIR=/
+SUNW_PKGVERS="1.0"
+SUNW_PKG_ALLZONES="true"
+SUNW_PKG_HOLLOW="true"
+SUNW_PKG_THISZONE="false"
diff --git a/usr/src/pkgdefs/SUNWvscankr/postinstall b/usr/src/pkgdefs/SUNWvscankr/postinstall
new file mode 100644
index 0000000000..49b07dbaf0
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWvscankr/postinstall
@@ -0,0 +1,61 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PATH="/usr/bin:/usr/sbin:${PATH}"
+export PATH
+
+PKG_NAME=SUNWvscankr
+DRV=vscan
+DRVPERM='* 0640 root sys'
+
+ADD_DRV=/usr/sbin/add_drv
+
+#
+# Check if the BASEDIR option is needed
+#
+if [ "${BASEDIR}" = "/" ]; then
+ ADD_DRV_FLAGS=""
+ NAME_TO_MAJOR="/etc/name_to_major"
+else
+ ADD_DRV_FLAGS="-b ${BASEDIR}"
+ NAME_TO_MAJOR="${BASEDIR}/etc/name_to_major"
+fi
+
+#
+# Make sure add_drv has not been previously executed before attempting
+# to add the driver
+#
+grep "^${DRV} " ${NAME_TO_MAJOR} > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ ${ADD_DRV} ${ADD_DRV_FLAGS} -m "${DRVPERM}" ${DRV}
+ if [ $? -ne 0 ]; then
+ echo "${PKG_NAME}: add_drv ${DRV} failed\n" >&2
+ exit 1
+ fi
+fi
+
+exit 0
diff --git a/usr/src/pkgdefs/SUNWvscankr/preremove b/usr/src/pkgdefs/SUNWvscankr/preremove
new file mode 100644
index 0000000000..47ff0c8245
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWvscankr/preremove
@@ -0,0 +1,68 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+PATH="/usr/bin:/usr/sbin:${PATH}"
+export PATH
+
+PKG_NAME=SUNWvscankr
+DRV=vscan
+DMON=vscand
+
+#
+# Make sure that the VSCAN client daemon (vscand) is not
+# running before removing this package.
+#
+if [ "${PKG_INSTALL_ROOT:-/}" = "/" ]; then
+ /usr/bin/pgrep -x "${DMON}" >/dev/null
+ if [ $? -ne 1 ]; then
+ echo "\nUnable to remove ${PKG_NAME}: the vscan service is enabled"
+ echo "Disable vscan service and try again:"
+ echo "\tsvcadm disable system/filesystem/vscan\n"
+ exit 1
+ fi
+fi
+
+#
+# Remove driver, if this has not already been done
+#
+BASEDIR=${BASEDIR:-/}
+if [ "$BASEDIR" = "/" ]; then
+ REM_DRV="rem_drv"
+else
+ REM_DRV="rem_drv -b ${BASEDIR}"
+fi
+
+grep "^${DRV}" ${BASEDIR}/etc/name_to_major > /dev/null 2>&1
+if [ $? -eq 0 ]; then
+ ${REM_DRV} ${DRV}
+ if [ $? -ne 0 ]; then
+ echo "${PKG_NAME}: rem_drv ${DRV} failed\n" >&2
+ exit 1
+ fi
+fi
+
+exit 0
diff --git a/usr/src/pkgdefs/SUNWvscankr/prototype_com b/usr/src/pkgdefs/SUNWvscankr/prototype_com
new file mode 100644
index 0000000000..9150cc750a
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWvscankr/prototype_com
@@ -0,0 +1,41 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+# packaging files
+i copyright
+i depend
+i pkginfo
+i postinstall
+i preremove
+
+#
+# SUNWvscankr
+#
+d none kernel 0755 root sys
+d none kernel/drv 0755 root sys
+f none kernel/drv/vscan.conf 0644 root sys
diff --git a/usr/src/pkgdefs/SUNWvscankr/prototype_i386 b/usr/src/pkgdefs/SUNWvscankr/prototype_i386
new file mode 100644
index 0000000000..111191565b
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWvscankr/prototype_i386
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+!include prototype_com
+#
+# SUNWvscankr
+#
+f none kernel/drv/vscan 0755 root sys
+d none kernel/drv/amd64 0755 root sys
+f none kernel/drv/amd64/vscan 0755 root sys
diff --git a/usr/src/pkgdefs/SUNWvscankr/prototype_sparc b/usr/src/pkgdefs/SUNWvscankr/prototype_sparc
new file mode 100644
index 0000000000..bec40b506d
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWvscankr/prototype_sparc
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+!include prototype_com
+#
+# SUNWvscankr
+#
+d none kernel/drv/sparcv9 0755 root sys
+f none kernel/drv/sparcv9/vscan 0755 root sys
diff --git a/usr/src/pkgdefs/SUNWvscanr/Makefile b/usr/src/pkgdefs/SUNWvscanr/Makefile
index 251db0af11..7c6dca3c1d 100644
--- a/usr/src/pkgdefs/SUNWvscanr/Makefile
+++ b/usr/src/pkgdefs/SUNWvscanr/Makefile
@@ -20,7 +20,7 @@
#
#
-# 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"
@@ -34,7 +34,7 @@ DATAFILES += i.manifest r.manifest
.KEEP_STATE:
-all: $(FILES) depend postinstall preremove
+all: $(FILES) depend preremove
install: all pkg
diff --git a/usr/src/pkgdefs/SUNWvscanr/depend b/usr/src/pkgdefs/SUNWvscanr/depend
index 89a5efbdaf..a8ae81714c 100644
--- a/usr/src/pkgdefs/SUNWvscanr/depend
+++ b/usr/src/pkgdefs/SUNWvscanr/depend
@@ -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.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -51,3 +51,4 @@ P SUNWckr Core Solaris Kernel (Root)
P SUNWcsu Core Solaris, (Usr)
P SUNWcsd Core Solaris Devices
P SUNWcsl Core Solaris Libraries
+P SUNWvscankr Virus Scan Service Kernel (Root)
diff --git a/usr/src/pkgdefs/SUNWvscanr/pkginfo.tmpl b/usr/src/pkgdefs/SUNWvscanr/pkginfo.tmpl
index e99243e52d..267323f468 100644
--- a/usr/src/pkgdefs/SUNWvscanr/pkginfo.tmpl
+++ b/usr/src/pkgdefs/SUNWvscanr/pkginfo.tmpl
@@ -21,7 +21,7 @@
#
#ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
PKG="SUNWvscanr"
@@ -41,5 +41,5 @@ CLASSES="none manifest"
BASEDIR=/
SUNW_PKGVERS="1.0"
SUNW_PKG_ALLZONES="true"
-SUNW_PKG_HOLLOW="true"
+SUNW_PKG_HOLLOW="false"
SUNW_PKG_THISZONE="false"
diff --git a/usr/src/pkgdefs/SUNWvscanr/preremove b/usr/src/pkgdefs/SUNWvscanr/preremove
index bd870496e9..1e009d8d29 100644
--- a/usr/src/pkgdefs/SUNWvscanr/preremove
+++ b/usr/src/pkgdefs/SUNWvscanr/preremove
@@ -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.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -29,7 +29,6 @@ PATH="/usr/bin:/usr/sbin:${PATH}"
export PATH
PKG_NAME=SUNWvscanr
-DRV=vscan
DMON=vscand
#
@@ -46,23 +45,4 @@ if [ "${PKG_INSTALL_ROOT:-/}" = "/" ]; then
fi
fi
-#
-# Remove driver, if this has not already been done
-#
-BASEDIR=${BASEDIR:-/}
-if [ "$BASEDIR" = "/" ]; then
- REM_DRV="rem_drv"
-else
- REM_DRV="rem_drv -b ${BASEDIR}"
-fi
-
-grep "^${DRV}" ${BASEDIR}/etc/name_to_major > /dev/null 2>&1
-if [ $? -eq 0 ]; then
- ${REM_DRV} ${DRV}
- if [ $? -ne 0 ]; then
- echo "${PKG_NAME}: rem_drv ${DRV} failed\n" >&2
- exit 1
- fi
-fi
-
exit 0
diff --git a/usr/src/pkgdefs/SUNWvscanr/prototype_com b/usr/src/pkgdefs/SUNWvscanr/prototype_com
index b6083181ab..db0451b2e7 100644
--- a/usr/src/pkgdefs/SUNWvscanr/prototype_com
+++ b/usr/src/pkgdefs/SUNWvscanr/prototype_com
@@ -22,7 +22,7 @@
#
#ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -32,15 +32,11 @@ i depend
i pkginfo
i i.manifest
i r.manifest
-i postinstall
i preremove
#
# SUNWvscanr
#
-d none kernel 0755 root sys
-d none kernel/drv 0755 root sys
-f none kernel/drv/vscan.conf 0644 root sys
d none var 0755 root sys
d none var/svc 0755 root sys
d none var/svc/manifest 0755 root sys
diff --git a/usr/src/pkgdefs/SUNWvscanr/prototype_i386 b/usr/src/pkgdefs/SUNWvscanr/prototype_i386
index 00fb40069f..5c7ab6ea86 100644
--- a/usr/src/pkgdefs/SUNWvscanr/prototype_i386
+++ b/usr/src/pkgdefs/SUNWvscanr/prototype_i386
@@ -20,16 +20,10 @@
#
#
-#pragma ident "%Z%%M% %I% %E% SMI"
+# ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
!include prototype_com
-#
-# SUNWvscanr
-#
-f none kernel/drv/vscan 0755 root sys
-d none kernel/drv/amd64 0755 root sys
-f none kernel/drv/amd64/vscan 0755 root sys
diff --git a/usr/src/pkgdefs/SUNWvscanr/prototype_sparc b/usr/src/pkgdefs/SUNWvscanr/prototype_sparc
index 1a1978e8ab..5c7ab6ea86 100644
--- a/usr/src/pkgdefs/SUNWvscanr/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWvscanr/prototype_sparc
@@ -20,15 +20,10 @@
#
#
-#pragma ident "%Z%%M% %I% %E% SMI"
+# ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
!include prototype_com
-#
-# SUNWvscanr
-#
-d none kernel/drv/sparcv9 0755 root sys
-f none kernel/drv/sparcv9/vscan 0755 root sys
diff --git a/usr/src/pkgdefs/SUNWvscanu/depend b/usr/src/pkgdefs/SUNWvscanu/depend
index 647e83abf8..ad3fc529f2 100644
--- a/usr/src/pkgdefs/SUNWvscanu/depend
+++ b/usr/src/pkgdefs/SUNWvscanu/depend
@@ -52,4 +52,5 @@ P SUNWcsu Core Solaris, (Usr)
P SUNWcsd Core Solaris Devices
P SUNWcsl Core Solaris Libraries
P SUNWlibmsr Math & Microtasking Libraries (Root)
+P SUNWvscankr Virus Scan Service Kernel (Root)
P SUNWvscanr Virus Scan Service (Root)
diff --git a/usr/src/pkgdefs/SUNWvscanu/prototype_com b/usr/src/pkgdefs/SUNWvscanu/prototype_com
index 2051b67b47..334e853b1c 100644
--- a/usr/src/pkgdefs/SUNWvscanu/prototype_com
+++ b/usr/src/pkgdefs/SUNWvscanu/prototype_com
@@ -20,7 +20,7 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -37,6 +37,9 @@ i preremove
#
d none usr 755 root sys
d none usr/lib 755 root bin
+d none usr/lib/devfsadm 755 root sys
+d none usr/lib/devfsadm/linkmod 755 root sys
+f none usr/lib/devfsadm/linkmod/SUNW_vscan_link.so 755 root sys
d none usr/lib/vscan 755 root bin
f none usr/lib/vscan/libvscan.so.1 755 root bin
s none usr/lib/vscan/libvscan.so=libvscan.so.1
diff --git a/usr/src/pkgdefs/SUNWvscanu/prototype_i386 b/usr/src/pkgdefs/SUNWvscanu/prototype_i386
index 248ca0b5e4..5c7ab6ea86 100644
--- a/usr/src/pkgdefs/SUNWvscanu/prototype_i386
+++ b/usr/src/pkgdefs/SUNWvscanu/prototype_i386
@@ -20,9 +20,9 @@
#
#
-#pragma ident "%Z%%M% %I% %E% SMI"
+# ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
diff --git a/usr/src/pkgdefs/SUNWvscanu/prototype_sparc b/usr/src/pkgdefs/SUNWvscanu/prototype_sparc
index 248ca0b5e4..5c7ab6ea86 100644
--- a/usr/src/pkgdefs/SUNWvscanu/prototype_sparc
+++ b/usr/src/pkgdefs/SUNWvscanu/prototype_sparc
@@ -20,9 +20,9 @@
#
#
-#pragma ident "%Z%%M% %I% %E% SMI"
+# ident "%Z%%M% %I% %E% SMI"
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
diff --git a/usr/src/uts/common/io/vscan/vscan_door.c b/usr/src/uts/common/io/vscan/vscan_door.c
index 69f17809fe..737e00245a 100644
--- a/usr/src/uts/common/io/vscan/vscan_door.c
+++ b/usr/src/uts/common/io/vscan/vscan_door.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -36,7 +36,10 @@
#include <sys/vscan.h>
-static int vscan_door_id = -1;
+/* max time (secs) to wait for door calls to complete during door_close */
+#define VS_DOOR_CLOSE_TIMEOUT_DEFAULT 30
+uint32_t vs_door_close_timeout = VS_DOOR_CLOSE_TIMEOUT_DEFAULT;
+
static door_handle_t vscan_door_handle = NULL;
static kmutex_t vscan_door_mutex;
static kcondvar_t vscan_door_cv;
@@ -74,19 +77,17 @@ vscan_door_open(int door_id)
{
mutex_enter(&vscan_door_mutex);
- if (vscan_door_handle == NULL) {
- vscan_door_id = door_id;
+ if (vscan_door_handle == NULL)
vscan_door_handle = door_ki_lookup(door_id);
- }
-
- mutex_exit(&vscan_door_mutex);
if (vscan_door_handle == NULL) {
cmn_err(CE_WARN, "Internal communication error "
"- failed to access vscan service daemon.");
+ mutex_exit(&vscan_door_mutex);
return (-1);
}
+ mutex_exit(&vscan_door_mutex);
return (0);
}
@@ -97,13 +98,21 @@ vscan_door_open(int door_id)
void
vscan_door_close(void)
{
+ clock_t timeout, time_left;
+
mutex_enter(&vscan_door_mutex);
/* wait for any in-progress requests to complete */
- while (vscan_door_call_count > 0) {
- cv_wait(&vscan_door_cv, &vscan_door_mutex);
+ time_left = SEC_TO_TICK(vs_door_close_timeout);
+ while ((vscan_door_call_count > 0) && (time_left > 0)) {
+ timeout = lbolt + time_left;
+ time_left = cv_timedwait(&vscan_door_cv,
+ &vscan_door_mutex, timeout);
}
+ if (time_left == -1)
+ cmn_err(CE_WARN, "Timeout waiting for door calls to complete");
+
if (vscan_door_handle) {
door_ki_rele(vscan_door_handle);
vscan_door_handle = NULL;
@@ -115,16 +124,18 @@ vscan_door_close(void)
/*
* vscan_door_scan_file
+ *
+ * Returns: result returned in door response or VS_STATUS_ERROR
*/
int
vscan_door_scan_file(vs_scan_req_t *scan_req)
{
- int err, rc = 0;
+ int err;
door_arg_t arg;
+ uint32_t result = 0;
- if (!vscan_door_handle &&
- vscan_door_open(vscan_door_id) != 0)
- return (-1);
+ if (!vscan_door_handle)
+ return (VS_STATUS_ERROR);
mutex_enter(&vscan_door_mutex);
vscan_door_call_count++;
@@ -134,14 +145,13 @@ vscan_door_scan_file(vs_scan_req_t *scan_req)
arg.data_size = sizeof (vs_scan_req_t);
arg.desc_ptr = NULL;
arg.desc_num = 0;
- arg.rbuf = (char *)scan_req;
- arg.rsize = sizeof (vs_scan_req_t);
+ arg.rbuf = (char *)&result;
+ arg.rsize = sizeof (uint32_t);
if ((err = door_ki_upcall(vscan_door_handle, &arg)) != 0) {
cmn_err(CE_WARN, "Internal communication error (%d)"
"- failed to send scan request to vscand", err);
- vscan_door_close();
- rc = -1;
+ result = VS_STATUS_ERROR;
}
mutex_enter(&vscan_door_mutex);
@@ -149,5 +159,5 @@ vscan_door_scan_file(vs_scan_req_t *scan_req)
cv_signal(&vscan_door_cv);
mutex_exit(&vscan_door_mutex);
- return (rc);
+ return (result);
}
diff --git a/usr/src/uts/common/io/vscan/vscan_drv.c b/usr/src/uts/common/io/vscan/vscan_drv.c
index 37b150cf59..5d2cdb851d 100644
--- a/usr/src/uts/common/io/vscan/vscan_drv.c
+++ b/usr/src/uts/common/io/vscan/vscan_drv.c
@@ -42,28 +42,109 @@
#include <sys/policy.h>
#include <sys/sdt.h>
-#define VS_DRV_NODENAME_LEN 16
+/* seconds to wait for daemon to reconnect before disabling */
+#define VS_DAEMON_WAIT_SEC 60
+
+/* length of minor node name - vscan%d */
+#define VS_NODENAME_LEN 16
+
+/* global variables - tunable via /etc/system */
+uint32_t vs_reconnect_timeout = VS_DAEMON_WAIT_SEC;
+extern uint32_t vs_nodes_max; /* max in-progress scan requests */
/*
- * Instance States: VS_INIT (initial state), VS_OPEN, VS_READING
+ * vscan_drv_state
+ *
+ * Operations on instance 0 represent vscand initiated state
+ * transition events:
+ * open(0) - vscand connect
+ * close(0) - vscan disconnect
+ * enable(0) - vscand enable (ready to hand requests)
+ * disable(0) - vscand disable (shutting down)
+ *
+ * +------------------------+
+ * | VS_DRV_UNCONFIG |
+ * +------------------------+
+ * | ^
+ * | attach | detach
+ * v |
+ * +------------------------+
+ * | VS_DRV_IDLE |<------|
+ * +------------------------+ |
+ * | ^ |
+ * | open(0) | close(0) |
+ * v | |
+ * +------------------------+ |
+ * | VS_DRV_CONNECTED |<-| |
+ * +------------------------+ | |
+ * | ^ | |
+ * | enable(0) | disable(0) | |
+ * v | | |
+ * +------------------------+ | |
+ * | VS_DRV_ENABLED | | |
+ * +------------------------+ | |
+ * | | |
+ * | close(0) open(0) |
+ * v | |
+ * +------------------------+ | | timeout
+ * | VS_DRV_DELAYED_DISABLE | -- |
+ * +------------------------+ ------|
*
- * Instance 0 controls the state of the driver: vscan_drv_connected.
- * vscan_drv_state[0] should NOT be used.
- * Actions:
- * open: VS_INIT->VS_OPEN, otherwise ERROR
- * close: any->VS_INIT
- * read: VS_OPEN->VS_READING, otherwise ERROR
*/
typedef enum {
- VS_INIT,
- VS_OPEN,
- VS_READING
+ VS_DRV_UNCONFIG,
+ VS_DRV_IDLE,
+ VS_DRV_CONNECTED,
+ VS_DRV_ENABLED,
+ VS_DRV_DELAYED_DISABLE
} vscan_drv_state_t;
+static vscan_drv_state_t vscan_drv_state = VS_DRV_UNCONFIG;
-static vscan_drv_state_t vscan_drv_state[VS_DRV_MAX_FILES + 1];
-static boolean_t vscan_drv_nodes[VS_DRV_MAX_FILES + 1];
-static boolean_t vscan_drv_connected = B_FALSE; /* vscand daemon connected */
+
+/*
+ * vscan_drv_inst_state
+ *
+ * Instance 0 controls the state of the driver: vscan_drv_state.
+ * vscan_drv_inst_state[0] should NOT be used.
+ *
+ * vscan_drv_inst_state[n] represents the state of driver
+ * instance n, used by vscand to access file data for the
+ * scan request with index n in vscan_svc_reqs.
+ * Minor nodes are created as required then all are destroyed
+ * during driver detach.
+ *
+ * +------------------------+
+ * | VS_DRV_INST_UNCONFIG |
+ * +------------------------+
+ * | ^
+ * | create_node(n) | detach
+ * v |
+ * +------------------------+
+ * | VS_DRV_INST_INIT |<-|
+ * +------------------------+ |
+ * | |
+ * | open(n) |
+ * v |
+ * +------------------------+ |
+ * | VS_DRV_INST_OPEN |--|
+ * +------------------------+ |
+ * | |
+ * | read(n) |
+ * v | close(n)
+ * +------------------------+ |
+ * | VS_DRV_INST_READING |--|
+ * +------------------------+
+ */
+typedef enum {
+ VS_DRV_INST_UNCONFIG = 0, /* minor node not created */
+ VS_DRV_INST_INIT,
+ VS_DRV_INST_OPEN,
+ VS_DRV_INST_READING
+} vscan_drv_inst_state_t;
+
+static vscan_drv_inst_state_t *vscan_drv_inst_state;
+static int vscan_drv_inst_state_sz;
static dev_info_t *vscan_drv_dip;
static kmutex_t vscan_drv_mutex;
@@ -87,7 +168,6 @@ static void vscan_drv_delayed_disable(void);
/*
* module linkage info for the kernel
*/
-
static struct cb_ops cbops = {
vscan_drv_open, /* cb_open */
vscan_drv_close, /* cb_close */
@@ -145,29 +225,30 @@ _init(void)
{
int rc;
- mutex_init(&vscan_drv_mutex, NULL, MUTEX_DRIVER, NULL);
+ vscan_drv_inst_state_sz =
+ sizeof (vscan_drv_inst_state_t) * (vs_nodes_max + 1);
- if (vscan_door_init() != 0) {
- mutex_destroy(&vscan_drv_mutex);
+ if (vscan_door_init() != 0)
return (DDI_FAILURE);
- }
if (vscan_svc_init() != 0) {
vscan_door_fini();
- mutex_destroy(&vscan_drv_mutex);
return (DDI_FAILURE);
}
- (void) memset(&vscan_drv_state, 0, sizeof (vscan_drv_state));
- (void) memset(&vscan_drv_nodes, 0, sizeof (vscan_drv_nodes));
+ mutex_init(&vscan_drv_mutex, NULL, MUTEX_DRIVER, NULL);
+ vscan_drv_inst_state = kmem_zalloc(vscan_drv_inst_state_sz, KM_SLEEP);
+
+ cv_init(&vscan_drv_cv, NULL, CV_DEFAULT, NULL);
if ((rc = mod_install(&modlinkage)) != 0) {
vscan_door_fini();
vscan_svc_fini();
+ kmem_free(vscan_drv_inst_state, vscan_drv_inst_state_sz);
+ cv_destroy(&vscan_drv_cv);
mutex_destroy(&vscan_drv_mutex);
}
- cv_init(&vscan_drv_cv, NULL, CV_DEFAULT, NULL);
return (rc);
}
@@ -196,6 +277,7 @@ _fini(void)
if ((rc = mod_remove(&modlinkage)) == 0) {
vscan_door_fini();
vscan_svc_fini();
+ kmem_free(vscan_drv_inst_state, vscan_drv_inst_state_sz);
cv_destroy(&vscan_drv_cv);
mutex_destroy(&vscan_drv_mutex);
}
@@ -247,6 +329,7 @@ vscan_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
if (vscan_drv_create_node(0) == B_FALSE)
return (DDI_FAILURE);
+ vscan_drv_state = VS_DRV_IDLE;
return (DDI_SUCCESS);
}
@@ -257,6 +340,8 @@ vscan_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
static int
vscan_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
+ int i;
+
if (cmd != DDI_DETACH)
return (DDI_FAILURE);
@@ -269,8 +354,10 @@ vscan_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
/* remove all minor nodes */
vscan_drv_dip = NULL;
ddi_remove_minor_node(dip, NULL);
- (void) memset(&vscan_drv_nodes, 0, sizeof (vscan_drv_nodes));
+ for (i = 0; i <= vs_nodes_max; i++)
+ vscan_drv_inst_state[i] = VS_DRV_INST_UNCONFIG;
+ vscan_drv_state = VS_DRV_UNCONFIG;
return (DDI_SUCCESS);
}
@@ -278,35 +365,40 @@ vscan_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
/*
* vscan_drv_in_use
*
- * If vscand is connected (vscan_drv_connected == B_TRUE) the
- * vscan driver is obviously in use. Otherwise invoke
- * vscan_svc_in_use() to determine if the driver is in use,
- * even though the daemon has disconnected.
- * For example, there may be requests not yet complete, or
- * the driver may still be enabled waiting for the daemon to
- * reconnect.
- * Used to determine whether the driver can be unloaded.
+ * If the driver state is not IDLE or UNCONFIG then the
+ * driver is in use. Otherwise, check the service interface
+ * (vscan_svc) to see if it is still in use - for example
+ * there there may be requests still in progress.
*/
static boolean_t
vscan_drv_in_use()
{
- boolean_t in_use;
+ boolean_t in_use = B_FALSE;
mutex_enter(&vscan_drv_mutex);
- in_use = vscan_drv_connected;
+ if ((vscan_drv_state != VS_DRV_IDLE) &&
+ (vscan_drv_state != VS_DRV_UNCONFIG)) {
+ in_use = B_TRUE;
+ }
mutex_exit(&vscan_drv_mutex);
- if (in_use == B_FALSE)
- in_use = vscan_svc_in_use();
-
- return (in_use);
+ if (in_use)
+ return (B_TRUE);
+ else
+ return (vscan_svc_in_use());
}
/*
* vscan_drv_open
- * if inst == 0, this is vscand initializing.
- * Otherwise, open the file associated with inst.
+ *
+ * If inst == 0, this is vscand initializing.
+ * If the driver is in DELAYED_DISABLE, ie vscand previously
+ * disconnected without a clean shutdown and the driver is
+ * waiting for a period to allow vscand to reconnect, signal
+ * vscan_drv_cv to cancel the delayed disable.
+ *
+ * If inst != 0, open the file associated with inst.
*/
/* ARGSUSED */
static int
@@ -315,7 +407,7 @@ vscan_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
int rc;
int inst = getminor(*devp);
- if ((inst < 0) || (inst > VS_DRV_MAX_FILES))
+ if ((inst < 0) || (inst > vs_nodes_max))
return (EINVAL);
/* check if caller has privilege for virus scanning */
@@ -326,20 +418,27 @@ vscan_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
mutex_enter(&vscan_drv_mutex);
if (inst == 0) {
- if (vscan_drv_connected) {
+ switch (vscan_drv_state) {
+ case VS_DRV_IDLE:
+ vscan_drv_state = VS_DRV_CONNECTED;
+ break;
+ case VS_DRV_DELAYED_DISABLE:
+ cv_signal(&vscan_drv_cv);
+ vscan_drv_state = VS_DRV_CONNECTED;
+ break;
+ default:
+ DTRACE_PROBE1(vscan__drv__state__violation,
+ int, vscan_drv_state);
mutex_exit(&vscan_drv_mutex);
return (EINVAL);
}
- vscan_drv_connected = B_TRUE;
- /* wake any pending delayed disable */
- cv_signal(&vscan_drv_cv);
} else {
- if ((!vscan_drv_connected) ||
- (vscan_drv_state[inst] != VS_INIT)) {
- mutex_exit(&vscan_drv_mutex);
- return (EINVAL);
+ if ((vscan_drv_state != VS_DRV_ENABLED) ||
+ (vscan_drv_inst_state[inst] != VS_DRV_INST_INIT)) {
+ mutex_exit(&vscan_drv_mutex);
+ return (EINVAL);
}
- vscan_drv_state[inst] = VS_OPEN;
+ vscan_drv_inst_state[inst] = VS_DRV_INST_OPEN;
}
mutex_exit(&vscan_drv_mutex);
@@ -349,8 +448,14 @@ vscan_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
/*
* vscan_drv_close
- * if inst == 0, this is vscand detaching
- * Otherwise close the file associated with inst
+ *
+ * If inst == 0, this is vscand detaching.
+ * If the driver is in ENABLED state vscand has terminated without
+ * a clean shutdown (nod DISABLE received). Enter DELAYED_DISABLE
+ * state and initiate a delayed disable to allow vscand time to
+ * reconnect.
+ *
+ * If inst != 0, close the file associated with inst
*/
/* ARGSUSED */
static int
@@ -358,27 +463,46 @@ vscan_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
{
int i, inst = getminor(dev);
- if ((inst < 0) || (inst > VS_DRV_MAX_FILES))
+ if ((inst < 0) || (inst > vs_nodes_max))
return (EINVAL);
mutex_enter(&vscan_drv_mutex);
- if (inst == 0) {
- for (i = 1; i <= VS_DRV_MAX_FILES; i++)
- vscan_drv_state[i] = VS_INIT;
-
- vscan_drv_connected = B_FALSE;
- if (vscan_svc_is_enabled()) {
- if (thread_create(NULL, 0, vscan_drv_delayed_disable,
- 0, 0, &p0, TS_RUN, minclsyspri) == NULL) {
- vscan_svc_enable();
- }
+ if (inst != 0) {
+ vscan_drv_inst_state[inst] = VS_DRV_INST_INIT;
+ mutex_exit(&vscan_drv_mutex);
+ return (0);
+ }
+
+ /* instance 0 - daemon disconnect */
+ if ((vscan_drv_state != VS_DRV_CONNECTED) &&
+ (vscan_drv_state != VS_DRV_ENABLED)) {
+ DTRACE_PROBE1(vscan__drv__state__violation,
+ int, vscan_drv_state);
+ mutex_exit(&vscan_drv_mutex);
+ return (EINVAL);
+ }
+
+ for (i = 1; i <= vs_nodes_max; i++) {
+ if (vscan_drv_inst_state[i] != VS_DRV_INST_UNCONFIG)
+ vscan_drv_inst_state[i] = VS_DRV_INST_INIT;
+ }
+
+ if (vscan_drv_state == VS_DRV_CONNECTED) {
+ vscan_drv_state = VS_DRV_IDLE;
+ } else { /* VS_DRV_ENABLED */
+ cmn_err(CE_WARN, "Detected vscand exit without clean shutdown");
+ if (thread_create(NULL, 0, vscan_drv_delayed_disable,
+ 0, 0, &p0, TS_RUN, minclsyspri) == NULL) {
+ vscan_svc_disable();
+ vscan_drv_state = VS_DRV_IDLE;
+ } else {
+ vscan_drv_state = VS_DRV_DELAYED_DISABLE;
}
- vscan_door_close();
- } else {
- vscan_drv_state[inst] = VS_INIT;
}
mutex_exit(&vscan_drv_mutex);
+ vscan_svc_scan_abort();
+ vscan_door_close();
return (0);
}
@@ -388,22 +512,23 @@ vscan_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
*
* Invoked from vscan_drv_close if the daemon disconnects
* without first sending disable (e.g. daemon crashed).
- * Delays for VS_DAEMON_WAIT_SEC before disabling, to allow
+ * Delays for vs_reconnect_timeout before disabling, to allow
* the daemon to reconnect. During this time, scan requests
* will be processed locally (see vscan_svc.c)
*/
static void
vscan_drv_delayed_disable(void)
{
- clock_t timeout = lbolt + SEC_TO_TICK(VS_DAEMON_WAIT_SEC);
+ clock_t timeout = lbolt + SEC_TO_TICK(vs_reconnect_timeout);
mutex_enter(&vscan_drv_mutex);
(void) cv_timedwait(&vscan_drv_cv, &vscan_drv_mutex, timeout);
- if (vscan_drv_connected) {
- DTRACE_PROBE(vscan__reconnect);
- } else {
+ if (vscan_drv_state == VS_DRV_DELAYED_DISABLE) {
vscan_svc_disable();
+ vscan_drv_state = VS_DRV_IDLE;
+ } else {
+ DTRACE_PROBE(vscan__reconnect);
}
mutex_exit(&vscan_drv_mutex);
}
@@ -420,15 +545,16 @@ vscan_drv_read(dev_t dev, struct uio *uiop, cred_t *credp)
int inst = getminor(dev);
vnode_t *vp;
- if ((inst <= 0) || (inst > VS_DRV_MAX_FILES))
+ if ((inst <= 0) || (inst > vs_nodes_max))
return (EINVAL);
mutex_enter(&vscan_drv_mutex);
- if ((!vscan_drv_connected) || (vscan_drv_state[inst] != VS_OPEN)) {
+ if ((vscan_drv_state != VS_DRV_ENABLED) ||
+ (vscan_drv_inst_state[inst] != VS_DRV_INST_OPEN)) {
mutex_exit(&vscan_drv_mutex);
return (EINVAL);
}
- vscan_drv_state[inst] = VS_READING;
+ vscan_drv_inst_state[inst] = VS_DRV_INST_READING;
mutex_exit(&vscan_drv_mutex);
if ((vp = vscan_svc_get_vnode(inst)) == NULL)
@@ -439,8 +565,8 @@ vscan_drv_read(dev_t dev, struct uio *uiop, cred_t *credp)
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
mutex_enter(&vscan_drv_mutex);
- if (vscan_drv_state[inst] == VS_READING)
- vscan_drv_state[inst] = VS_OPEN;
+ if (vscan_drv_inst_state[inst] == VS_DRV_INST_READING)
+ vscan_drv_inst_state[inst] = VS_DRV_INST_OPEN;
mutex_exit(&vscan_drv_mutex);
return (rc);
@@ -449,6 +575,15 @@ vscan_drv_read(dev_t dev, struct uio *uiop, cred_t *credp)
/*
* vscan_drv_ioctl
+ *
+ * Process ioctls from vscand:
+ * VS_IOCTL_ENABLE - vscand is ready to handle scan requests,
+ * enable VFS interface.
+ * VS_IOCTL_DISABLE - vscand is shutting down, disable VFS interface
+ * VS_IOCTL_RESULT - scan response data
+ * VS_IOCTL_CONFIG - configuration data from vscand
+ * VS_IOCTL_MAX_REQ - provide the max request idx to vscand,
+ * to allow vscand to set appropriate resource allocation limits
*/
/* ARGSUSED */
static int
@@ -457,31 +592,64 @@ vscan_drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
{
int inst = getminor(dev);
vs_config_t conf;
+ vs_scan_rsp_t rsp;
if (inst != 0)
return (EINVAL);
switch (cmd) {
- case VS_DRV_IOCTL_ENABLE:
+ case VS_IOCTL_ENABLE:
mutex_enter(&vscan_drv_mutex);
- if ((!vscan_drv_connected) ||
- (vscan_door_open((int)arg) != 0)) {
+ if (vscan_drv_state != VS_DRV_CONNECTED) {
+ DTRACE_PROBE1(vscan__drv__state__violation,
+ int, vscan_drv_state);
mutex_exit(&vscan_drv_mutex);
return (EINVAL);
}
- vscan_svc_enable();
+ if ((vscan_door_open((int)arg) != 0) ||
+ (vscan_svc_enable() != 0)) {
+ mutex_exit(&vscan_drv_mutex);
+ return (EINVAL);
+ }
+ vscan_drv_state = VS_DRV_ENABLED;
mutex_exit(&vscan_drv_mutex);
break;
- case VS_DRV_IOCTL_DISABLE:
+
+ case VS_IOCTL_DISABLE:
+ mutex_enter(&vscan_drv_mutex);
+ if (vscan_drv_state != VS_DRV_ENABLED) {
+ DTRACE_PROBE1(vscan__drv__state__violation,
+ int, vscan_drv_state);
+ mutex_exit(&vscan_drv_mutex);
+ return (EINVAL);
+ }
vscan_svc_disable();
+ vscan_drv_state = VS_DRV_CONNECTED;
+ mutex_exit(&vscan_drv_mutex);
break;
- case VS_DRV_IOCTL_CONFIG:
+
+ case VS_IOCTL_RESULT:
+ if (ddi_copyin((void *)arg, &rsp,
+ sizeof (vs_scan_rsp_t), 0) == -1)
+ return (EFAULT);
+ else
+ vscan_svc_scan_result(&rsp);
+ break;
+
+ case VS_IOCTL_CONFIG:
if (ddi_copyin((void *)arg, &conf,
sizeof (vs_config_t), 0) == -1)
return (EFAULT);
if (vscan_svc_configure(&conf) == -1)
return (EINVAL);
break;
+
+ case VS_IOCTL_MAX_REQ:
+ if (ddi_copyout(&vs_nodes_max, (void *)arg,
+ sizeof (uint32_t), 0) == -1)
+ return (EFAULT);
+ break;
+
default:
return (ENOTTY);
}
@@ -503,22 +671,22 @@ vscan_drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
boolean_t
vscan_drv_create_node(int idx)
{
- char name[VS_DRV_NODENAME_LEN];
- boolean_t *pnode, rc;
+ char name[VS_NODENAME_LEN];
+ boolean_t rc = B_TRUE;
mutex_enter(&vscan_drv_mutex);
- pnode = &vscan_drv_nodes[idx];
- if (*pnode == B_FALSE) {
- (void) snprintf(name, VS_DRV_NODENAME_LEN, "vscan%d", idx);
+ if (vscan_drv_inst_state[idx] == VS_DRV_INST_UNCONFIG) {
+ (void) snprintf(name, VS_NODENAME_LEN, "vscan%d", idx);
if (ddi_create_minor_node(vscan_drv_dip, name,
S_IFCHR, idx, DDI_PSEUDO, 0) == DDI_SUCCESS) {
- *pnode = B_TRUE;
+ vscan_drv_inst_state[idx] = VS_DRV_INST_INIT;
+ } else {
+ rc = B_FALSE;
}
- DTRACE_PROBE2(vscan__minor__node, int, idx, int, *pnode);
+ DTRACE_PROBE2(vscan__minor__node, int, idx, int, rc);
}
- rc = *pnode;
mutex_exit(&vscan_drv_mutex);
return (rc);
diff --git a/usr/src/uts/common/io/vscan/vscan_svc.c b/usr/src/uts/common/io/vscan/vscan_svc.c
index aec070734f..bb07530321 100644
--- a/usr/src/uts/common/io/vscan/vscan_svc.c
+++ b/usr/src/uts/common/io/vscan/vscan_svc.c
@@ -41,19 +41,162 @@
#include <sys/disp.h>
#include <sys/sdt.h>
#include <sys/cred.h>
+#include <sys/list.h>
#include <sys/vscan.h>
-#define VS_TASKQ_NUM_THREADS VS_DRV_MAX_FILES
+#define VS_REQ_MAGIC 0x52515354 /* 'RQST' */
+
+#define VS_REQS_DEFAULT 20000 /* pending scan requests - reql */
+#define VS_NODES_DEFAULT 128 /* concurrent file scans */
+#define VS_WORKERS_DEFAULT 32 /* worker threads */
+#define VS_SCANWAIT_DEFAULT 15*60 /* seconds to wait for scan result */
+#define VS_REQL_HANDLER_TIMEOUT 30
#define VS_EXT_RECURSE_DEPTH 8
+
+/* access derived from scan result (VS_STATUS_XXX) and file attributes */
+#define VS_ACCESS_UNDEFINED 0
+#define VS_ACCESS_ALLOW 1 /* return 0 */
+#define VS_ACCESS_DENY 2 /* return EACCES */
+
#define tolower(C) (((C) >= 'A' && (C) <= 'Z') ? (C) - 'A' + 'a' : (C))
+#define offsetof(s, m) (size_t)(&(((s *)0)->m))
+
+/* global variables - tunable via /etc/system */
+uint32_t vs_reqs_max = VS_REQS_DEFAULT; /* max scan requests */
+uint32_t vs_nodes_max = VS_NODES_DEFAULT; /* max in-progress scan requests */
+uint32_t vs_workers = VS_WORKERS_DEFAULT; /* max workers send reqs to vscand */
+uint32_t vs_scan_wait = VS_SCANWAIT_DEFAULT; /* secs to wait for scan result */
+
+
+/*
+ * vscan_svc_state
+ *
+ * +-----------------+
+ * | VS_SVC_UNCONFIG |
+ * +-----------------+
+ * | ^
+ * | svc_init | svc_fini
+ * v |
+ * +-----------------+
+ * | VS_SVC_IDLE |<----|
+ * +-----------------+ |
+ * | |
+ * | svc_enable |
+ * |<----------------| |
+ * v | |
+ * +-----------------+ | |
+ * | VS_SVC_ENABLED |--| |
+ * +-----------------+ |
+ * | |
+ * | svc_disable | handler thread exit,
+ * v | all requests complete
+ * +-----------------+ |
+ * | VS_SVC_DISABLED |-----|
+ * +-----------------+
+ *
+ * svc_enable may occur when we are already in the ENABLED
+ * state if vscand has exited without clean shutdown and
+ * then reconnected within the delayed disable time period
+ * (vs_reconnect_timeout) - see vscan_drv
+ */
+
+typedef enum {
+ VS_SVC_UNCONFIG,
+ VS_SVC_IDLE,
+ VS_SVC_ENABLED, /* service enabled and registered */
+ VS_SVC_DISABLED /* service disabled and nunregistered */
+} vscan_svc_state_t;
+static vscan_svc_state_t vscan_svc_state = VS_SVC_UNCONFIG;
+
-/* represents request received from filesystem - currently only use vp */
-typedef struct vscan_fs_req {
+/*
+ * vscan_svc_req_state
+ *
+ * When a scan request is received from the file system it is
+ * identified in or inserted into the vscan_svc_reql (INIT).
+ * If the request is asynchronous 0 is then returned to the caller.
+ * If the request is synchronous the req's refcnt is incremented
+ * and the caller waits for the request to complete.
+ * The refcnt is also incremented when the request is inserted
+ * in vscan_svc_nodes, and decremented on scan_complete.
+ *
+ * vscan_svc_handler processes requests from the request list,
+ * inserting them into vscan_svc_nodes and the task queue (QUEUED).
+ * When the task queue call back (vscan_svc_do_scan) is invoked
+ * the request transitions to IN_PROGRESS state. If the request
+ * is sucessfully sent to vscand (door_call) and the door response
+ * is SCANNING then the scan result will be received asynchronously.
+ * Although unusual, it is possible that the async response is
+ * received before the door call returns (hence the ASYNC_COMPLETE
+ * state).
+ * When the result has been determined / received,
+ * vscan_svc_scan_complete is invoked to transition the request to
+ * COMPLETE state, decrement refcnt and signal all waiting callers.
+ * When the last waiting caller has processed the result (refcnt == 0)
+ * the request is removed from vscan_svc_reql and vscan_svc_nodes
+ * and deleted.
+ *
+ * | ^
+ * | reql_insert | refcnt == 0
+ * v | (delete)
+ * +------------------------+ +---------------------+
+ * | VS_SVC_REQ_INIT | -----DISABLE----> | VS_SVC_REQ_COMPLETE |
+ * +------------------------+ +---------------------+
+ * | ^
+ * | insert_req, tq_dispatch |
+ * v |
+ * +------------------------+ |
+ * | VS_SVC_REQ_QUEUED | scan_complete
+ * +------------------------+ |
+ * | |
+ * | tq_callback (do_scan) |
+ * | |
+ * v scan not req'd, error, |
+ * +------------------------+ or door_result != SCANNING |
+ * | VS_SVC_REQ_IN_PROGRESS |----------------->-------------|
+ * +------------------------+ |
+ * | | |
+ * | | door_result == SCANNING |
+ * | v |
+ * | +---------------------------+ async result |
+ * | | VS_SVC_REQ_SCANNING |-------->---------|
+ * | +---------------------------+ |
+ * | |
+ * | async result |
+ * v |
+ * +---------------------------+ door_result = SCANNING |
+ * | VS_SVC_REQ_ASYNC_COMPLETE |-------->------------------|
+ * +---------------------------+
+ */
+typedef enum {
+ VS_SVC_REQ_INIT,
+ VS_SVC_REQ_QUEUED,
+ VS_SVC_REQ_IN_PROGRESS,
+ VS_SVC_REQ_SCANNING,
+ VS_SVC_REQ_ASYNC_COMPLETE,
+ VS_SVC_REQ_COMPLETE
+} vscan_svc_req_state_t;
+
+
+/*
+ * vscan_svc_reql - the list of pending and in-progress scan requests
+ */
+typedef struct vscan_req {
+ uint32_t vsr_magic; /* VS_REQ_MAGIC */
+ list_node_t vsr_lnode;
vnode_t *vsr_vp;
-} vscan_fs_req_t;
+ uint32_t vsr_idx; /* vscan_svc_nodes index */
+ uint32_t vsr_seqnum; /* unigue request id */
+ uint32_t vsr_refcnt;
+ kcondvar_t vsr_cv;
+ vscan_svc_req_state_t vsr_state;
+} vscan_req_t;
+
+static list_t vscan_svc_reql;
+
/*
- * vscan_svc_files - table of files being scanned
+ * vscan_svc_nodes - table of files being scanned
*
* The index into this table is passed in the door call to
* vscand. vscand uses the idx to determine which minor node
@@ -64,34 +207,42 @@ typedef struct vscan_fs_req {
* Instance 0 is reserved for the daemon/driver control
* interface: enable/configure/disable
*/
-typedef struct vscan_file {
- vscan_fs_req_t vsf_req;
- uint32_t vsf_wait_count;
- kcondvar_t vsf_cv; /* wait for in progress scan */
- uint8_t vsf_quarantined;
- uint8_t vsf_modified;
- uint64_t vsf_size;
- timestruc_t vsf_mtime;
- vs_scanstamp_t vsf_scanstamp;
- uint32_t vsf_result;
- uint32_t vsf_access;
-} vscan_file_t;
-
-static vscan_file_t vscan_svc_files[VS_DRV_MAX_FILES + 1];
-static kcondvar_t vscan_svc_cv; /* wait for slot in vscan_svc_files */
-static int vscan_svc_wait_count = 0; /* # waiting for slot in vscan_svc_files */
-static int vscan_svc_req_count = 0; /* # scan requests */
-
+typedef struct vscan_svc_node {
+ vscan_req_t *vsn_req;
+ uint8_t vsn_quarantined;
+ uint8_t vsn_modified;
+ uint64_t vsn_size;
+ timestruc_t vsn_mtime;
+ vs_scanstamp_t vsn_scanstamp;
+ uint32_t vsn_result;
+ uint32_t vsn_access;
+} vscan_svc_node_t;
+
+static vscan_svc_node_t *vscan_svc_nodes;
+static int vscan_svc_nodes_sz;
+
+
+/* vscan_svc_taskq - queue of requests waiting to be sent to vscand */
static taskq_t *vscan_svc_taskq = NULL;
-static boolean_t vscan_svc_enabled = B_FALSE;
+
+/* counts of entries in vscan_svc_reql, vscan_svc_nodes & vscan_svc_taskq */
+typedef struct {
+ uint32_t vsc_reql;
+ uint32_t vsc_node;
+ uint32_t vsc_tq;
+} vscan_svc_counts_t;
+static vscan_svc_counts_t vscan_svc_counts;
/*
* vscan_svc_mutex protects the data pertaining to scan requests:
- * file table - vscan_svc_files
- * counts - vscan_svc_wait_count, vscan_svc_req_count
+ * request list - vscan_svc_reql
+ * node table - vscan_svc_nodes
*/
static kmutex_t vscan_svc_mutex;
+/* unique request id for vscand request/response correlation */
+static uint32_t vscan_svc_seqnum = 0;
+
/*
* vscan_svc_cfg_mutex protects the configuration data:
* vscan_svc_config, vscan_svc_types
@@ -102,24 +253,33 @@ static kmutex_t vscan_svc_cfg_mutex;
static vs_config_t vscan_svc_config;
static char *vscan_svc_types[VS_TYPES_MAX];
+/* thread to insert reql entries into vscan_svc_nodes & vscan_svc_taskq */
+static kthread_t *vscan_svc_reql_thread;
+static kcondvar_t vscan_svc_reql_cv;
+static vscan_req_t *vscan_svc_reql_next; /* next pending scan request */
+
/* local functions */
int vscan_svc_scan_file(vnode_t *, cred_t *, int);
-void vscan_svc_taskq_callback(void *);
+static void vscan_svc_taskq_callback(void *);
static int vscan_svc_exempt_file(vnode_t *, boolean_t *);
static int vscan_svc_exempt_filetype(char *);
static int vscan_svc_match_ext(char *, char *, int);
-static int vscan_svc_do_scan(vscan_fs_req_t *);
-static int vscan_svc_wait_for_scan(vnode_t *);
-static int vscan_svc_insert_file(vscan_fs_req_t *);
-static void vscan_svc_release_file(int);
-static int vscan_svc_find_slot(void);
+static void vscan_svc_do_scan(vscan_req_t *);
+static vs_scan_req_t *vscan_svc_populate_req(int);
static void vscan_svc_process_scan_result(int);
-static void vscan_svc_notify_scan_complete(int);
+static void vscan_svc_scan_complete(vscan_req_t *);
+static void vscan_svc_delete_req(vscan_req_t *);
+static int vscan_svc_insert_req(vscan_req_t *);
+static void vscan_svc_remove_req(int);
+static vscan_req_t *vscan_svc_reql_find(vnode_t *);
+static vscan_req_t *vscan_svc_reql_insert(vnode_t *);
+static void vscan_svc_reql_remove(vscan_req_t *);
+
static int vscan_svc_getattr(int);
static int vscan_svc_setattr(int, int);
-static vs_scan_req_t *vscan_svc_populate_req(int);
-static void vscan_svc_parse_rsp(int, vs_scan_req_t *);
+/* thread to insert reql entries into vscan_svc_nodes & vscan_svc_taskq */
+static void vscan_svc_reql_handler(void);
/*
@@ -128,115 +288,164 @@ static void vscan_svc_parse_rsp(int, vs_scan_req_t *);
int
vscan_svc_init()
{
- mutex_init(&vscan_svc_mutex, NULL, MUTEX_DRIVER, NULL);
- mutex_init(&vscan_svc_cfg_mutex, NULL, MUTEX_DRIVER, NULL);
- (void) memset(&vscan_svc_files, 0, sizeof (vscan_svc_files));
- cv_init(&vscan_svc_cv, NULL, CV_DEFAULT, NULL);
+ if (vscan_svc_state != VS_SVC_UNCONFIG) {
+ DTRACE_PROBE1(vscan__svc__state__violation,
+ int, vscan_svc_state);
+ return (-1);
+ }
+
+ mutex_init(&vscan_svc_mutex, NULL, MUTEX_DEFAULT, NULL);
+ mutex_init(&vscan_svc_cfg_mutex, NULL, MUTEX_DEFAULT, NULL);
+ cv_init(&vscan_svc_reql_cv, NULL, CV_DEFAULT, NULL);
+
+ vscan_svc_nodes_sz = sizeof (vscan_svc_node_t) * (vs_nodes_max + 1);
+ vscan_svc_nodes = kmem_zalloc(vscan_svc_nodes_sz, KM_SLEEP);
+
+ vscan_svc_counts.vsc_reql = 0;
+ vscan_svc_counts.vsc_node = 0;
+ vscan_svc_counts.vsc_tq = 0;
+
+ vscan_svc_state = VS_SVC_IDLE;
return (0);
}
+
/*
* vscan_svc_fini
*/
void
vscan_svc_fini()
{
- ASSERT(vscan_svc_enabled == B_FALSE);
- ASSERT(vscan_svc_in_use() == B_FALSE);
+ if (vscan_svc_state != VS_SVC_IDLE) {
+ DTRACE_PROBE1(vscan__svc__state__violation,
+ int, vscan_svc_state);
+ return;
+ }
- cv_destroy(&vscan_svc_cv);
+ kmem_free(vscan_svc_nodes, vscan_svc_nodes_sz);
+
+ cv_destroy(&vscan_svc_reql_cv);
mutex_destroy(&vscan_svc_mutex);
mutex_destroy(&vscan_svc_cfg_mutex);
+ vscan_svc_state = VS_SVC_UNCONFIG;
}
+
/*
* vscan_svc_enable
*/
-void
+int
vscan_svc_enable(void)
{
mutex_enter(&vscan_svc_mutex);
- vscan_svc_enabled = B_TRUE;
-
- if (vscan_svc_taskq == NULL) {
- if ((vscan_svc_taskq = taskq_create("vscan",
- VS_TASKQ_NUM_THREADS, MINCLSYSPRI, 1,
- INT_MAX, TASKQ_DYNAMIC)) == NULL) {
- cmn_err(CE_WARN, "All scan requests "
- "will be processed synchronously");
- }
+
+ switch (vscan_svc_state) {
+ case VS_SVC_ENABLED:
+ /*
+ * it's possible (and okay) for vscan_svc_enable to be
+ * called when already enabled if vscand reconnects
+ * during a delayed disable
+ */
+ break;
+ case VS_SVC_IDLE:
+ list_create(&vscan_svc_reql, sizeof (vscan_req_t),
+ offsetof(vscan_req_t, vsr_lnode));
+ vscan_svc_reql_next = list_head(&vscan_svc_reql);
+
+ vscan_svc_taskq = taskq_create("vscan_taskq", vs_workers,
+ MINCLSYSPRI, 1, INT_MAX, TASKQ_DYNAMIC);
+ ASSERT(vscan_svc_taskq != NULL);
+
+ vscan_svc_reql_thread = thread_create(NULL, 0,
+ vscan_svc_reql_handler, 0, 0, &p0, TS_RUN, MINCLSYSPRI);
+ ASSERT(vscan_svc_reql_thread != NULL);
+
+ /* ready to start processing requests */
+ vscan_svc_state = VS_SVC_ENABLED;
+ fs_vscan_register(vscan_svc_scan_file);
+ break;
+ default:
+ DTRACE_PROBE1(vscan__svc__state__violation,
+ int, vscan_svc_state);
+ return (-1);
}
- fs_vscan_register(vscan_svc_scan_file);
mutex_exit(&vscan_svc_mutex);
+ return (0);
}
/*
* vscan_svc_disable
+ *
+ * Resources allocated during vscan_svc_enable are free'd by
+ * the handler thread immediately prior to exiting
*/
void
vscan_svc_disable(void)
{
mutex_enter(&vscan_svc_mutex);
- vscan_svc_enabled = B_FALSE;
- fs_vscan_register(NULL);
- if (vscan_svc_taskq) {
- taskq_destroy(vscan_svc_taskq);
- vscan_svc_taskq = NULL;
+ switch (vscan_svc_state) {
+ case VS_SVC_ENABLED:
+ fs_vscan_register(NULL);
+ vscan_svc_state = VS_SVC_DISABLED;
+ cv_signal(&vscan_svc_reql_cv); /* wake handler thread */
+ break;
+ default:
+ DTRACE_PROBE1(vscan__svc__state__violation, int,
+ vscan_svc_state);
}
- mutex_exit(&vscan_svc_mutex);
-}
-
-
-/*
- * vscan_svc_is_enabled
- */
-boolean_t
-vscan_svc_is_enabled()
-{
- return (vscan_svc_enabled);
+ mutex_exit(&vscan_svc_mutex);
}
/*
* vscan_svc_in_use
- *
- * The vscan driver is considered to be in use if it is
- * enabled or if there are in-progress scan requests.
- * Used to determine whether the driver can be unloaded.
*/
boolean_t
vscan_svc_in_use()
{
- boolean_t rc;
+ boolean_t in_use;
mutex_enter(&vscan_svc_mutex);
- rc = (vscan_svc_enabled == B_TRUE) || (vscan_svc_req_count > 0);
- mutex_exit(&vscan_svc_mutex);
- return (rc);
+ switch (vscan_svc_state) {
+ case VS_SVC_IDLE:
+ case VS_SVC_UNCONFIG:
+ in_use = B_FALSE;
+ break;
+ default:
+ in_use = B_TRUE;
+ break;
+ }
+
+ mutex_exit(&vscan_svc_mutex);
+ return (in_use);
}
+
/*
* vscan_svc_get_vnode
*
* Get the file vnode indexed by idx.
- * Returns NULL if idx not valid.
*/
vnode_t *
vscan_svc_get_vnode(int idx)
{
+ vnode_t *vp = NULL;
+
ASSERT(idx > 0);
- ASSERT(idx <= VS_DRV_MAX_FILES);
+ ASSERT(idx <= vs_nodes_max);
- if ((idx <= 0) || (idx > VS_DRV_MAX_FILES))
- return (NULL);
- else
- return (vscan_svc_files[idx].vsf_req.vsr_vp);
+ mutex_enter(&vscan_svc_mutex);
+ if (vscan_svc_nodes[idx].vsn_req)
+ vp = vscan_svc_nodes[idx].vsn_req->vsr_vp;
+ mutex_exit(&vscan_svc_mutex);
+
+ return (vp);
}
@@ -245,453 +454,459 @@ vscan_svc_get_vnode(int idx)
*
* This function is the entry point for the file system to
* request that a file be virus scanned.
- *
- * Asynchronous requests:
- * If an async scan request cannot be queued it is discarded.
- * By definition the caller of an async request is not dependent
- * on the outcome of the result. Although the file will thus
- * not be scanned at this time, it will be scanned
- * (synchronously) on subsequent access.
- * This scenario should not occur during normal operation.
- *
- * Before queuing an async request do VN_HOLD(vp). VN_RELE(vp)
- * will be done when the scan completes or if the request
- * couldn't be queued.
- *
- * The vscan_fs_req_t, allocated to hold the request information
- * passed from the fs, will be free'd when the scan completes.
*/
int
vscan_svc_scan_file(vnode_t *vp, cred_t *cr, int async)
{
- int rc = 0;
- vscan_fs_req_t *req;
+ int access;
+ vscan_req_t *req;
boolean_t allow;
+ clock_t timeout, time_left;
- mutex_enter(&vscan_svc_mutex);
-
- if ((vp == NULL) || (vp->v_path == NULL) || cr == NULL) {
- mutex_exit(&vscan_svc_mutex);
+ if ((vp == NULL) || (vp->v_path == NULL) || cr == NULL)
return (0);
- }
DTRACE_PROBE2(vscan__scan__file, char *, vp->v_path, int, async);
/* check if size or type exempts file from scanning */
if (vscan_svc_exempt_file(vp, &allow)) {
- mutex_exit(&vscan_svc_mutex);
if ((allow == B_TRUE) || (async != 0))
return (0);
return (EACCES);
}
- vscan_svc_req_count++;
- mutex_exit(&vscan_svc_mutex);
+ mutex_enter(&vscan_svc_mutex);
- req = kmem_zalloc(sizeof (vscan_fs_req_t), KM_SLEEP);
- req->vsr_vp = vp;
+ if (vscan_svc_state != VS_SVC_ENABLED) {
+ DTRACE_PROBE1(vscan__svc__state__violation,
+ int, vscan_svc_state);
+ mutex_exit(&vscan_svc_mutex);
+ return (0);
+ }
- if (async) {
- VN_HOLD(vp);
- if (vscan_svc_taskq &&
- taskq_dispatch(vscan_svc_taskq, vscan_svc_taskq_callback,
- (void *)req, TQ_SLEEP)) {
- return (0);
- } else {
- VN_RELE(vp);
- kmem_free(req, sizeof (vscan_fs_req_t));
- }
- } else {
- rc = vscan_svc_do_scan(req);
- kmem_free(req, sizeof (vscan_fs_req_t));
+ /* insert (or find) request in list */
+ if ((req = vscan_svc_reql_insert(vp)) == NULL) {
+ mutex_exit(&vscan_svc_mutex);
+ cmn_err(CE_WARN, "Virus scan request list full");
+ return ((async != 0) ? 0 : EACCES);
}
- mutex_enter(&vscan_svc_mutex);
- vscan_svc_req_count--;
- mutex_exit(&vscan_svc_mutex);
+ /* asynchronous request: return 0 */
+ if (async) {
+ mutex_exit(&vscan_svc_mutex);
+ return (0);
+ }
- return (rc);
-}
+ /* synchronous scan request: wait for result */
+ ++(req->vsr_refcnt);
+ time_left = SEC_TO_TICK(vs_scan_wait);
+ while ((time_left > 0) && (req->vsr_state != VS_SVC_REQ_COMPLETE)) {
+ timeout = lbolt + time_left;
+ time_left = cv_timedwait_sig(&(req->vsr_cv),
+ &vscan_svc_mutex, timeout);
+ }
+ if (time_left == -1) {
+ cmn_err(CE_WARN, "Virus scan request timeout %s (%d) \n",
+ vp->v_path, req->vsr_seqnum);
+ DTRACE_PROBE1(vscan__scan__timeout, vscan_req_t *, req);
+ }
-/*
- * vscan_svc_taskq_callback
- *
- * Callback function for async scan requests
- */
-void
-vscan_svc_taskq_callback(void *data)
-{
- vscan_fs_req_t *req = (vscan_fs_req_t *)data;
+ ASSERT(req->vsr_magic == VS_REQ_MAGIC);
+ if (vscan_svc_state == VS_SVC_DISABLED)
+ access = VS_ACCESS_ALLOW;
+ else if (req->vsr_idx == 0)
+ access = VS_ACCESS_DENY;
+ else
+ access = vscan_svc_nodes[req->vsr_idx].vsn_access;
- (void) vscan_svc_do_scan(req);
- VN_RELE(req->vsr_vp); /* VN_HOLD done before request queued */
- kmem_free(req, sizeof (vscan_fs_req_t));
+ if ((--req->vsr_refcnt) == 0)
+ vscan_svc_delete_req(req);
- mutex_enter(&vscan_svc_mutex);
- vscan_svc_req_count--;
mutex_exit(&vscan_svc_mutex);
+ return ((access == VS_ACCESS_ALLOW) ? 0 : EACCES);
}
/*
- * vscan_svc_do_scan
+ * vscan_svc_reql_handler
*
- * Should never be called directly. Invoke via vscan_svc_scan_file()
- * If scan is in progress wait for it to complete, otherwise
- * initiate door call to scan the file.
+ * inserts scan requests (from vscan_svc_reql) into
+ * vscan_svc_nodes and vscan_svc_taskq
*/
-static int
-vscan_svc_do_scan(vscan_fs_req_t *req)
+static void
+vscan_svc_reql_handler(void)
{
- int rc = -1, idx;
- vs_scan_req_t *scan_req;
- vscan_file_t *svc_file;
+ vscan_req_t *req, *next;
- mutex_enter(&vscan_svc_mutex);
+ for (;;) {
+ mutex_enter(&vscan_svc_mutex);
+
+ if ((vscan_svc_state == VS_SVC_DISABLED) &&
+ (vscan_svc_counts.vsc_reql == 0)) {
+ /* free resources allocated durining enable */
+ taskq_destroy(vscan_svc_taskq);
+ vscan_svc_taskq = NULL;
+ list_destroy(&vscan_svc_reql);
+ vscan_svc_state = VS_SVC_IDLE;
+ mutex_exit(&vscan_svc_mutex);
+ return;
+ }
- /*
- * if a scan is in progress on the files vscan_svc_wait_for_scan will
- * wait for it to complete and return the idx of the scan request.
- * Otherwise it will return -1 and we will initiate a scan here.
- */
- if ((idx = vscan_svc_wait_for_scan(req->vsr_vp)) != -1) {
- svc_file = &vscan_svc_files[idx];
- } else {
- /* insert the scan request into vscan_svc_files */
- idx = vscan_svc_insert_file(req);
- svc_file = &vscan_svc_files[idx];
-
- if (vscan_svc_enabled) {
- if (vscan_svc_getattr(idx) == 0) {
- /* valid scan_req ptr guaranteed */
- scan_req = vscan_svc_populate_req(idx);
- mutex_exit(&vscan_svc_mutex);
- if (vscan_drv_create_node(idx) == B_TRUE)
- rc = vscan_door_scan_file(scan_req);
- mutex_enter(&vscan_svc_mutex);
- if (rc == 0)
- vscan_svc_parse_rsp(idx, scan_req);
- kmem_free(scan_req, sizeof (vs_scan_req_t));
-
- /* process scan result */
- vscan_svc_process_scan_result(idx);
- DTRACE_PROBE2(vscan__result, int,
- svc_file->vsf_result, int,
- svc_file->vsf_access);
+ /*
+ * If disabled, scan_complete any pending requests.
+ * Otherwise insert pending requests into vscan_svc_nodes
+ * and vscan_svc_taskq. If no slots are available in
+ * vscan_svc_nodes break loop and wait for one
+ */
+ req = vscan_svc_reql_next;
+
+ while (req != NULL) {
+ ASSERT(req->vsr_magic == VS_REQ_MAGIC);
+ next = list_next(&vscan_svc_reql, req);
+
+ if (vscan_svc_state == VS_SVC_DISABLED) {
+ vscan_svc_scan_complete(req);
} else {
- /* if getattr fails: log error, deny access */
- cmn_err(CE_WARN, "Can't access xattr for %s\n",
- svc_file->vsf_req.vsr_vp->v_path);
- svc_file->vsf_access = VS_ACCESS_DENY;
+ /* insert request into vscan_svc_nodes */
+ if (vscan_svc_insert_req(req) == -1)
+ break;
+
+ /* add the scan request into the taskq */
+ (void) taskq_dispatch(vscan_svc_taskq,
+ vscan_svc_taskq_callback,
+ (void *)req, TQ_SLEEP);
+ ++(vscan_svc_counts.vsc_tq);
+
+ req->vsr_state = VS_SVC_REQ_QUEUED;
}
- } else {
- /* if vscan not enabled (shutting down), allow ACCESS */
- svc_file->vsf_access = VS_ACCESS_ALLOW;
+ req = next;
}
+
+ vscan_svc_reql_next = req;
+
+ DTRACE_PROBE2(vscan__req__counts, char *, "handler wait",
+ vscan_svc_counts_t *, &vscan_svc_counts);
+
+ (void) cv_timedwait(&vscan_svc_reql_cv, &vscan_svc_mutex,
+ lbolt + SEC_TO_TICK(VS_REQL_HANDLER_TIMEOUT));
+
+ DTRACE_PROBE2(vscan__req__counts, char *, "handler wake",
+ vscan_svc_counts_t *, &vscan_svc_counts);
+
+ mutex_exit(&vscan_svc_mutex);
}
+}
- /* When a scan completes the result is saved in vscan_svc_files */
- rc = (svc_file->vsf_access == VS_ACCESS_ALLOW) ? 0 : EACCES;
- /* wake threads waiting for result, or for a slot in vscan_svc_files */
- vscan_svc_notify_scan_complete(idx);
+static void
+vscan_svc_taskq_callback(void *data)
+{
+ vscan_req_t *req;
- /* remove the entry from vscan_svc_files if nobody else is waiting */
- vscan_svc_release_file(idx);
+ mutex_enter(&vscan_svc_mutex);
- mutex_exit(&vscan_svc_mutex);
+ req = (vscan_req_t *)data;
+ ASSERT(req->vsr_magic == VS_REQ_MAGIC);
+ vscan_svc_do_scan(req);
+ if (req->vsr_state != VS_SVC_REQ_SCANNING)
+ vscan_svc_scan_complete(req);
- return (rc);
+ --(vscan_svc_counts.vsc_tq);
+ mutex_exit(&vscan_svc_mutex);
}
/*
- * vscan_svc_process_scan_result
- *
- * Sets vsf_access and updates file attributes based on vsf_result,
- * as follows:
+ * vscan_svc_do_scan
*
- * VS_STATUS_INFECTED
- * deny access, set quarantine attribute, clear scanstamp
- * VS_STATUS_CLEAN
- * allow access, set scanstamp,
- * if file not modified since scan initiated, clear modified attribute
- * VS_STATUS_NO_SCAN
- * deny access if file quarantined, otherwise allow access
- * VS_STATUS_UNDEFINED, VS_STATUS_ERROR
- * deny access if file quarantined, modified or no scanstamp
- * otherwise, allow access
+ * Note: To avoid potential deadlock it is important that
+ * vscan_svc_mutex is not held during the call to
+ * vscan_drv_create_note. vscan_drv_create_note enters
+ * the vscan_drv_mutex and it is possible that a thread
+ * holding that mutex could be waiting for vscan_svc_mutex.
*/
static void
-vscan_svc_process_scan_result(int idx)
+vscan_svc_do_scan(vscan_req_t *req)
{
- struct vattr attr;
- vnode_t *vp;
- timestruc_t *mtime;
- vscan_file_t *svc_file;
+ int idx, result;
+ vscan_svc_node_t *node;
+ vs_scan_req_t *door_req;
ASSERT(MUTEX_HELD(&vscan_svc_mutex));
- svc_file = &vscan_svc_files[idx];
-
- switch (svc_file->vsf_result) {
- case VS_STATUS_INFECTED:
- svc_file->vsf_access = VS_ACCESS_DENY;
- svc_file->vsf_quarantined = 1;
- svc_file->vsf_scanstamp[0] = '\0';
- (void) vscan_svc_setattr(idx,
- XAT_AV_QUARANTINED | XAT_AV_SCANSTAMP);
- return;
-
- case VS_STATUS_CLEAN:
- svc_file->vsf_access = VS_ACCESS_ALLOW;
+ idx = req->vsr_idx;
+ node = &vscan_svc_nodes[idx];
- /* if mtime has changed, don't clear the modified attribute */
- vp = svc_file->vsf_req.vsr_vp;
- mtime = &(svc_file->vsf_mtime);
- attr.va_mask = AT_MTIME;
- if ((VOP_GETATTR(vp, &attr, 0, kcred, NULL) != 0) ||
- (mtime->tv_sec != attr.va_mtime.tv_sec) ||
- (mtime->tv_nsec != attr.va_mtime.tv_nsec)) {
- DTRACE_PROBE1(vscan__mtime__changed, vscan_file_t *,
- svc_file);
- (void) vscan_svc_setattr(idx, XAT_AV_SCANSTAMP);
- return;
- }
+ req->vsr_state = VS_SVC_REQ_IN_PROGRESS;
- svc_file->vsf_modified = 0;
- (void) vscan_svc_setattr(idx,
- XAT_AV_SCANSTAMP | XAT_AV_MODIFIED);
+ /* if vscan not enabled (shutting down), allow ACCESS */
+ if (vscan_svc_state != VS_SVC_ENABLED) {
+ node->vsn_access = VS_ACCESS_ALLOW;
return;
+ }
- case VS_STATUS_NO_SCAN:
- if (svc_file->vsf_quarantined)
- svc_file->vsf_access = VS_ACCESS_DENY;
- else
- svc_file->vsf_access = VS_ACCESS_ALLOW;
+ if (vscan_svc_getattr(idx) != 0) {
+ cmn_err(CE_WARN, "Can't access xattr for %s\n",
+ req->vsr_vp->v_path);
+ node->vsn_access = VS_ACCESS_DENY;
return;
+ }
- case VS_STATUS_ERROR:
- case VS_STATUS_UNDEFINED:
- default:
- if ((svc_file->vsf_quarantined) ||
- (svc_file->vsf_modified) ||
- (svc_file->vsf_scanstamp[0] == '\0'))
- svc_file->vsf_access = VS_ACCESS_DENY;
- else
- svc_file->vsf_access = VS_ACCESS_ALLOW;
- return;
+ /* valid scan_req ptr guaranteed */
+ door_req = vscan_svc_populate_req(idx);
+
+ /* free up mutex around create node and door call */
+ mutex_exit(&vscan_svc_mutex);
+ if (vscan_drv_create_node(idx) != B_TRUE)
+ result = VS_STATUS_ERROR;
+ else
+ result = vscan_door_scan_file(door_req);
+ kmem_free(door_req, sizeof (vs_scan_req_t));
+ mutex_enter(&vscan_svc_mutex);
+
+ if (result != VS_STATUS_SCANNING) {
+ vscan_svc_nodes[idx].vsn_result = result;
+ vscan_svc_process_scan_result(idx);
+ } else { /* async response */
+ if (req->vsr_state == VS_SVC_REQ_IN_PROGRESS)
+ req->vsr_state = VS_SVC_REQ_SCANNING;
}
}
/*
- * vscan_svc_wait_for_scan
+ * vscan_svc_populate_req
*
- * Search for vp in vscan_svc_files. If vp already exists in
- * vscan_svc_files scan is already in progress on file so wait
- * for the inprogress scan to complete.
+ * Allocate a scan request to be sent to vscand, populating it
+ * from the data in vscan_svc_nodes[idx].
*
- * Returns: idx of file waited for
- * -1 if file not already scanning
+ * Returns: scan request object
*/
-static int
-vscan_svc_wait_for_scan(vnode_t *vp)
+static vs_scan_req_t *
+vscan_svc_populate_req(int idx)
{
- int idx;
- vscan_file_t *svc_file;
+ vs_scan_req_t *scan_req;
+ vscan_req_t *req;
+ vscan_svc_node_t *node;
- ASSERT(vp);
ASSERT(MUTEX_HELD(&vscan_svc_mutex));
- for (idx = 1; idx <= VS_DRV_MAX_FILES; idx++) {
- if (vscan_svc_files[idx].vsf_req.vsr_vp == vp)
- break;
- }
-
- /* file not found in table thus not currently being scanned */
- if (idx > VS_DRV_MAX_FILES)
- return (-1);
-
- /* file found - wait for scan to complete */
- svc_file = &vscan_svc_files[idx];
- svc_file->vsf_wait_count++;
-
- DTRACE_PROBE2(vscan__wait__scan, vscan_file_t *, svc_file, int, idx);
-
- while (svc_file->vsf_access == VS_ACCESS_UNDEFINED)
- cv_wait(&(svc_file->vsf_cv), &vscan_svc_mutex);
+ node = &vscan_svc_nodes[idx];
+ req = node->vsn_req;
+ scan_req = kmem_zalloc(sizeof (vs_scan_req_t), KM_SLEEP);
- svc_file->vsf_wait_count--;
+ scan_req->vsr_idx = idx;
+ scan_req->vsr_seqnum = req->vsr_seqnum;
+ (void) strncpy(scan_req->vsr_path, req->vsr_vp->v_path, MAXPATHLEN);
+ scan_req->vsr_size = node->vsn_size;
+ scan_req->vsr_modified = node->vsn_modified;
+ scan_req->vsr_quarantined = node->vsn_quarantined;
+ scan_req->vsr_flags = 0;
+ (void) strncpy(scan_req->vsr_scanstamp,
+ node->vsn_scanstamp, sizeof (vs_scanstamp_t));
- return (idx);
+ return (scan_req);
}
/*
- * vscan_svc_find_slot
- *
- * Find empty slot in vscan_svc_files table.
- *
- * Returns idx of slot, or -1 if not found
+ * vscan_svc_scan_complete
*/
-static int
-vscan_svc_find_slot(void)
+static void
+vscan_svc_scan_complete(vscan_req_t *req)
{
- int idx;
-
ASSERT(MUTEX_HELD(&vscan_svc_mutex));
- for (idx = 1; idx <= VS_DRV_MAX_FILES; idx++) {
- if (vscan_svc_files[idx].vsf_req.vsr_vp == NULL)
- return (idx);
- }
+ ASSERT(req != NULL);
- return (-1);
+ req->vsr_state = VS_SVC_REQ_COMPLETE;
+
+ if ((--req->vsr_refcnt) == 0)
+ vscan_svc_delete_req(req);
+ else
+ cv_broadcast(&(req->vsr_cv));
}
/*
- * vscan_svc_insert_file
- *
- * Find the next available flot in vscan_svc_files and
- * initialize it for the scan request. If no slot is
- * available, vscan_svc_find_slot will wait for one.
- *
- * Returns: idx of scan request in vscan_svc_files table
+ * vscan_svc_delete_req
*/
-static int
-vscan_svc_insert_file(vscan_fs_req_t *req)
+static void
+vscan_svc_delete_req(vscan_req_t *req)
{
int idx;
- vscan_file_t *svc_file;
ASSERT(MUTEX_HELD(&vscan_svc_mutex));
+ ASSERT(req != NULL);
+ ASSERT(req->vsr_refcnt == 0);
+ ASSERT(req->vsr_state == VS_SVC_REQ_COMPLETE);
- while ((idx = vscan_svc_find_slot()) == -1) {
- DTRACE_PROBE1(vscan__wait__slot, char *, req->vsr_vp->v_path);
- vscan_svc_wait_count++;
- cv_wait(&(vscan_svc_cv), &vscan_svc_mutex);
- vscan_svc_wait_count--;
- }
-
- svc_file = &vscan_svc_files[idx];
+ if ((idx = req->vsr_idx) != 0)
+ vscan_svc_remove_req(idx);
- (void) memset(svc_file, 0, sizeof (vscan_file_t));
- svc_file->vsf_req = *req;
- svc_file->vsf_modified = 1;
- svc_file->vsf_result = VS_STATUS_UNDEFINED;
- svc_file->vsf_access = VS_ACCESS_UNDEFINED;
- cv_init(&(svc_file->vsf_cv), NULL, CV_DEFAULT, NULL);
+ vscan_svc_reql_remove(req);
- DTRACE_PROBE2(vscan__insert, char *, req->vsr_vp->v_path, int, idx);
- return (idx);
+ cv_signal(&vscan_svc_reql_cv);
}
/*
- * vscan_svc_release_file
+ * vscan_svc_scan_result
*
- * Release the file (free the slot in vscan_svc_files)
- * if no thread is waiting on it.
+ * Invoked from vscan_drv.c on receipt of an ioctl containing
+ * an async scan result (VS_DRV_IOCTL_RESULT)
+ * If the vsr_seqnum in the response does not match that in the
+ * vscan_svc_nodes entry the result is discarded.
*/
-static void
-vscan_svc_release_file(int idx)
+void
+vscan_svc_scan_result(vs_scan_rsp_t *scan_rsp)
{
- vscan_file_t *svc_file;
+ vscan_req_t *req;
+ vscan_svc_node_t *node;
- ASSERT(MUTEX_HELD(&vscan_svc_mutex));
- svc_file = &vscan_svc_files[idx];
+ mutex_enter(&vscan_svc_mutex);
+
+ node = &vscan_svc_nodes[scan_rsp->vsr_idx];
+
+ if ((req = node->vsn_req) == NULL) {
+ mutex_exit(&vscan_svc_mutex);
+ return;
+ }
- if (svc_file->vsf_wait_count != 0)
+ ASSERT(req->vsr_magic == VS_REQ_MAGIC);
+
+ if (scan_rsp->vsr_seqnum != req->vsr_seqnum) {
+ mutex_exit(&vscan_svc_mutex);
return;
+ }
- DTRACE_PROBE2(vscan__release, char *,
- svc_file->vsf_req.vsr_vp->v_path, int, idx);
+ node->vsn_result = scan_rsp->vsr_result;
+ (void) strncpy(node->vsn_scanstamp,
+ scan_rsp->vsr_scanstamp, sizeof (vs_scanstamp_t));
- cv_destroy(&(svc_file->vsf_cv));
- (void) memset(svc_file, 0, sizeof (vscan_file_t));
+ vscan_svc_process_scan_result(scan_rsp->vsr_idx);
+
+ if (node->vsn_req->vsr_state == VS_SVC_REQ_SCANNING)
+ vscan_svc_scan_complete(node->vsn_req);
+ else
+ node->vsn_req->vsr_state = VS_SVC_REQ_ASYNC_COMPLETE;
+
+ mutex_exit(&vscan_svc_mutex);
}
/*
- * vscan_svc_populate_req
+ * vscan_svc_scan_abort
*
- * Allocate a scan request to be sent to vscand, populating it
- * from the data in vscan_svc_files[idx].
- *
- * Returns: scan request object
+ * Abort in-progress scan requests.
*/
-static vs_scan_req_t *
-vscan_svc_populate_req(int idx)
+void
+vscan_svc_scan_abort()
{
- vs_scan_req_t *scan_req;
- vscan_fs_req_t *req;
- vscan_file_t *svc_file;
+ int idx;
+ vscan_req_t *req;
- ASSERT(MUTEX_HELD(&vscan_svc_mutex));
+ mutex_enter(&vscan_svc_mutex);
- svc_file = &vscan_svc_files[idx];
- req = &(svc_file->vsf_req);
- scan_req = kmem_zalloc(sizeof (vs_scan_req_t), KM_SLEEP);
+ for (idx = 1; idx <= vs_nodes_max; idx++) {
+ if ((req = vscan_svc_nodes[idx].vsn_req) == NULL)
+ continue;
- scan_req->vsr_id = idx;
- (void) strncpy(scan_req->vsr_path, req->vsr_vp->v_path, MAXPATHLEN);
- scan_req->vsr_size = svc_file->vsf_size;
- scan_req->vsr_modified = svc_file->vsf_modified;
- scan_req->vsr_quarantined = svc_file->vsf_quarantined;
- scan_req->vsr_flags = 0;
- (void) strncpy(scan_req->vsr_scanstamp,
- svc_file->vsf_scanstamp, sizeof (vs_scanstamp_t));
+ ASSERT(req->vsr_magic == VS_REQ_MAGIC);
- return (scan_req);
+ if (req->vsr_state == VS_SVC_REQ_SCANNING) {
+ DTRACE_PROBE1(vscan__abort, vscan_req_t *, req);
+ vscan_svc_process_scan_result(idx);
+ vscan_svc_scan_complete(req);
+ }
+ }
+
+ mutex_exit(&vscan_svc_mutex);
}
/*
- * vscan_svc_parse_rsp
+ * vscan_svc_process_scan_result
+ *
+ * Sets vsn_access and updates file attributes based on vsn_result,
+ * as follows:
*
- * Parse scan response data and save in vscan_svc_files[idx]
+ * VS_STATUS_INFECTED
+ * deny access, set quarantine attribute, clear scanstamp
+ * VS_STATUS_CLEAN
+ * allow access, set scanstamp,
+ * if file not modified since scan initiated, clear modified attribute
+ * VS_STATUS_NO_SCAN
+ * deny access if file quarantined, otherwise allow access
+ * VS_STATUS_UNDEFINED, VS_STATUS_ERROR
+ * deny access if file quarantined, modified or no scanstamp
+ * otherwise, allow access
*/
static void
-vscan_svc_parse_rsp(int idx, vs_scan_req_t *scan_req)
+vscan_svc_process_scan_result(int idx)
{
- vscan_file_t *svc_file;
+ struct vattr attr;
+ vnode_t *vp;
+ timestruc_t *mtime;
+ vscan_svc_node_t *node;
ASSERT(MUTEX_HELD(&vscan_svc_mutex));
- svc_file = &vscan_svc_files[idx];
- svc_file->vsf_result = scan_req->vsr_result;
- (void) strncpy(svc_file->vsf_scanstamp,
- scan_req->vsr_scanstamp, sizeof (vs_scanstamp_t));
-}
+ node = &vscan_svc_nodes[idx];
+ switch (node->vsn_result) {
+ case VS_STATUS_INFECTED:
+ node->vsn_access = VS_ACCESS_DENY;
+ node->vsn_quarantined = 1;
+ node->vsn_scanstamp[0] = '\0';
+ (void) vscan_svc_setattr(idx,
+ XAT_AV_QUARANTINED | XAT_AV_SCANSTAMP);
+ break;
-/*
- * vscan_svc_notify_scan_complete
- *
- * signal vscan_svc_files.vsf_cv and vscan_svc_cv to wake
- * threads waiting for the scan result for the specified
- * file (vscan_svc_files[idx].vsf_cv) or for a slot in
- * vscan_svc_files table (vscan_svc_cv)
- */
-static void
-vscan_svc_notify_scan_complete(int idx)
-{
- vscan_file_t *svc_file;
+ case VS_STATUS_CLEAN:
+ node->vsn_access = VS_ACCESS_ALLOW;
- ASSERT(MUTEX_HELD(&vscan_svc_mutex));
+ /* if mtime has changed, don't clear the modified attribute */
+ vp = node->vsn_req->vsr_vp;
+ mtime = &(node->vsn_mtime);
+ attr.va_mask = AT_MTIME;
+ if ((VOP_GETATTR(vp, &attr, 0, kcred, NULL) != 0) ||
+ (mtime->tv_sec != attr.va_mtime.tv_sec) ||
+ (mtime->tv_nsec != attr.va_mtime.tv_nsec)) {
+ DTRACE_PROBE1(vscan__mtime__changed, vscan_svc_node_t *,
+ node);
+ (void) vscan_svc_setattr(idx, XAT_AV_SCANSTAMP);
+ break;
+ }
+
+ node->vsn_modified = 0;
+ (void) vscan_svc_setattr(idx,
+ XAT_AV_SCANSTAMP | XAT_AV_MODIFIED);
+ break;
- svc_file = &vscan_svc_files[idx];
+ case VS_STATUS_NO_SCAN:
+ if (node->vsn_quarantined)
+ node->vsn_access = VS_ACCESS_DENY;
+ else
+ node->vsn_access = VS_ACCESS_ALLOW;
+ break;
- /* if someone waiting for result, cv_signal */
- if (svc_file->vsf_wait_count > 0)
- cv_signal(&(svc_file->vsf_cv));
+ case VS_STATUS_ERROR:
+ case VS_STATUS_UNDEFINED:
+ default:
+ if ((node->vsn_quarantined) ||
+ (node->vsn_modified) ||
+ (node->vsn_scanstamp[0] == '\0'))
+ node->vsn_access = VS_ACCESS_DENY;
+ else
+ node->vsn_access = VS_ACCESS_ALLOW;
+ break;
+ }
- /* signal vscan_svc_cv if any threads waiting for a slot */
- if (vscan_svc_wait_count > 0)
- cv_signal(&vscan_svc_cv);
+ DTRACE_PROBE4(vscan__result,
+ int, idx, int, node->vsn_req->vsr_seqnum,
+ int, node->vsn_result, int, node->vsn_access);
}
@@ -706,12 +921,12 @@ vscan_svc_getattr(int idx)
xvattr_t xvattr;
xoptattr_t *xoap = NULL;
vnode_t *vp;
- vscan_file_t *svc_file;
+ vscan_svc_node_t *node;
ASSERT(MUTEX_HELD(&vscan_svc_mutex));
- svc_file = &vscan_svc_files[idx];
- if ((vp = svc_file->vsf_req.vsr_vp) == NULL)
+ node = &vscan_svc_nodes[idx];
+ if ((vp = node->vsn_req->vsr_vp) == NULL)
return (-1);
/* get the attributes */
@@ -732,24 +947,24 @@ vscan_svc_getattr(int idx)
return (-1);
}
- svc_file->vsf_size = xvattr.xva_vattr.va_size;
- svc_file->vsf_mtime.tv_sec = xvattr.xva_vattr.va_mtime.tv_sec;
- svc_file->vsf_mtime.tv_nsec = xvattr.xva_vattr.va_mtime.tv_nsec;
+ node->vsn_size = xvattr.xva_vattr.va_size;
+ node->vsn_mtime.tv_sec = xvattr.xva_vattr.va_mtime.tv_sec;
+ node->vsn_mtime.tv_nsec = xvattr.xva_vattr.va_mtime.tv_nsec;
if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED) == 0)
return (-1);
- svc_file->vsf_modified = xoap->xoa_av_modified;
+ node->vsn_modified = xoap->xoa_av_modified;
if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED) == 0)
return (-1);
- svc_file->vsf_quarantined = xoap->xoa_av_quarantined;
+ node->vsn_quarantined = xoap->xoa_av_quarantined;
if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP) != 0) {
- (void) memcpy(svc_file->vsf_scanstamp,
+ (void) memcpy(node->vsn_scanstamp,
xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ);
}
- DTRACE_PROBE1(vscan__getattr, vscan_file_t *, svc_file);
+ DTRACE_PROBE1(vscan__getattr, vscan_svc_node_t *, node);
return (0);
}
@@ -766,12 +981,12 @@ vscan_svc_setattr(int idx, int which)
xoptattr_t *xoap = NULL;
vnode_t *vp;
int len;
- vscan_file_t *svc_file;
+ vscan_svc_node_t *node;
ASSERT(MUTEX_HELD(&vscan_svc_mutex));
- svc_file = &vscan_svc_files[idx];
- if ((vp = svc_file->vsf_req.vsr_vp) == NULL)
+ node = &vscan_svc_nodes[idx];
+ if ((vp = node->vsn_req->vsr_vp) == NULL)
return (-1);
/* update the attributes */
@@ -781,23 +996,23 @@ vscan_svc_setattr(int idx, int which)
if (which & XAT_AV_MODIFIED) {
XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
- xoap->xoa_av_modified = svc_file->vsf_modified;
+ xoap->xoa_av_modified = node->vsn_modified;
}
if (which & XAT_AV_QUARANTINED) {
XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
- xoap->xoa_av_quarantined = svc_file->vsf_quarantined;
+ xoap->xoa_av_quarantined = node->vsn_quarantined;
}
if (which & XAT_AV_SCANSTAMP) {
XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
- len = strlen(svc_file->vsf_scanstamp);
+ len = strlen(node->vsn_scanstamp);
(void) memcpy(xoap->xoa_av_scanstamp,
- svc_file->vsf_scanstamp, len);
+ node->vsn_scanstamp, len);
}
/* if access is denied, set mtime to invalidate client cache */
- if (svc_file->vsf_access != VS_ACCESS_ALLOW) {
+ if (node->vsn_access != VS_ACCESS_ALLOW) {
xvattr.xva_vattr.va_mask |= AT_MTIME;
gethrestime(&xvattr.xva_vattr.va_mtime);
}
@@ -806,7 +1021,7 @@ vscan_svc_setattr(int idx, int which)
return (-1);
DTRACE_PROBE2(vscan__setattr,
- vscan_file_t *, svc_file, int, which);
+ vscan_svc_node_t *, node, int, which);
return (0);
}
@@ -930,7 +1145,6 @@ vscan_svc_exempt_filetype(char *filepath)
else
ext++;
-
for (i = 0; i < VS_TYPES_MAX; i ++) {
if (vscan_svc_types[i] == 0)
break;
@@ -1009,3 +1223,147 @@ vscan_svc_match_ext(char *patn, char *str, int depth)
}
/* NOT REACHED */
}
+
+
+/*
+ * vscan_svc_insert_req
+ *
+ * Insert request in next available available slot in vscan_svc_nodes
+ *
+ * Returns: idx of slot, or -1 if no slot available
+ */
+static int
+vscan_svc_insert_req(vscan_req_t *req)
+{
+ int idx;
+ vscan_svc_node_t *node;
+
+ ASSERT(MUTEX_HELD(&vscan_svc_mutex));
+
+ if (vscan_svc_counts.vsc_node == vs_nodes_max)
+ return (-1);
+
+ for (idx = 1; idx <= vs_nodes_max; idx++) {
+ if (vscan_svc_nodes[idx].vsn_req == NULL) {
+ req->vsr_idx = idx;
+
+ node = &vscan_svc_nodes[idx];
+ (void) memset(node, 0, sizeof (vscan_svc_node_t));
+ node->vsn_req = req;
+ node->vsn_modified = 1;
+ node->vsn_result = VS_STATUS_UNDEFINED;
+ node->vsn_access = VS_ACCESS_UNDEFINED;
+
+ ++(vscan_svc_counts.vsc_node);
+ return (idx);
+ }
+ }
+
+ return (-1);
+}
+
+
+/*
+ * vscan_svc_remove_req
+ */
+static void
+vscan_svc_remove_req(int idx)
+{
+ ASSERT(MUTEX_HELD(&vscan_svc_mutex));
+
+ if (idx != 0) {
+ (void) memset(&vscan_svc_nodes[idx], 0,
+ sizeof (vscan_svc_node_t));
+ --(vscan_svc_counts.vsc_node);
+ }
+}
+
+
+/*
+ * vscan_svc_reql_find
+ */
+static vscan_req_t *
+vscan_svc_reql_find(vnode_t *vp)
+{
+ vscan_req_t *req;
+ ASSERT(MUTEX_HELD(&vscan_svc_mutex));
+
+ req = list_head(&vscan_svc_reql);
+
+ while (req != NULL) {
+ ASSERT(req->vsr_magic == VS_REQ_MAGIC);
+ if ((req->vsr_vp == vp) &&
+ (req->vsr_state != VS_SVC_REQ_COMPLETE))
+ break;
+
+ req = list_next(&vscan_svc_reql, req);
+ }
+
+ return (req);
+}
+
+
+/*
+ * vscan_svc_reql_insert
+ */
+static vscan_req_t *
+vscan_svc_reql_insert(vnode_t *vp)
+{
+ vscan_req_t *req;
+
+ ASSERT(MUTEX_HELD(&vscan_svc_mutex));
+
+ /* if request already in list then return it */
+ if ((req = vscan_svc_reql_find(vp)) != NULL)
+ return (req);
+
+ /* if list is full return NULL */
+ if (vscan_svc_counts.vsc_reql == vs_reqs_max)
+ return (NULL);
+
+ /* create a new request and insert into list */
+ VN_HOLD(vp);
+
+ req = kmem_zalloc(sizeof (vscan_req_t), KM_SLEEP);
+
+ req->vsr_magic = VS_REQ_MAGIC;
+ if (vscan_svc_seqnum == UINT32_MAX)
+ vscan_svc_seqnum = 0;
+ req->vsr_seqnum = ++vscan_svc_seqnum;
+ req->vsr_vp = vp;
+ req->vsr_refcnt = 1; /* decremented in vscan_svc_scan_complete */
+ req->vsr_state = VS_SVC_REQ_INIT;
+ cv_init(&(req->vsr_cv), NULL, CV_DEFAULT, NULL);
+
+ list_insert_tail(&vscan_svc_reql, req);
+ if (vscan_svc_reql_next == NULL)
+ vscan_svc_reql_next = req;
+
+ ++(vscan_svc_counts.vsc_reql);
+
+ /* wake reql handler thread */
+ cv_signal(&vscan_svc_reql_cv);
+
+ return (req);
+}
+
+
+/*
+ * vscan_svc_reql_remove
+ */
+static void
+vscan_svc_reql_remove(vscan_req_t *req)
+{
+ ASSERT(MUTEX_HELD(&vscan_svc_mutex));
+ ASSERT(req->vsr_magic == VS_REQ_MAGIC);
+
+ if (vscan_svc_reql_next == req)
+ vscan_svc_reql_next = list_next(&vscan_svc_reql, req);
+
+ list_remove(&vscan_svc_reql, req);
+ cv_destroy(&(req->vsr_cv));
+ VN_RELE(req->vsr_vp);
+
+ kmem_free(req, sizeof (vscan_req_t));
+ --(vscan_svc_counts.vsc_reql);
+}
diff --git a/usr/src/uts/common/sys/vscan.h b/usr/src/uts/common/sys/vscan.h
index 2cf188cab6..9674d060a2 100644
--- a/usr/src/uts/common/sys/vscan.h
+++ b/usr/src/uts/common/sys/vscan.h
@@ -39,20 +39,26 @@ extern "C" {
* vscan.h provides definitions for vscan kernel module
*/
-#define VS_DRV_MAX_FILES 1024 /* max concurent file scans */
-#define VS_DRV_PATH "/devices/pseudo/vscan@0:vscan"
-#define VS_DRV_IOCTL_ENABLE 0x0001 /* door rendezvous */
-#define VS_DRV_IOCTL_DISABLE 0x0002 /* vscand shutting down */
-#define VS_DRV_IOCTL_CONFIG 0x0004 /* vscand config data update */
+#define VS_DRV_PATH "/dev/vscan/vscan" /* append minor dev num */
+
+#define VS_IOCTL_ENABLE 0x01 /* door rendezvous */
+#define VS_IOCTL_DISABLE 0x02 /* vscand shutting down */
+#define VS_IOCTL_CONFIG 0x03 /* vscand config data update */
+#define VS_IOCTL_RESULT 0x04 /* scan result */
+#define VS_IOCTL_MAX_REQ 0x05 /* max in-progress req vscand */
/* Scan Result - vsr_result */
#define VS_STATUS_UNDEFINED 0
-#define VS_STATUS_NO_SCAN 1 /* scan not required */
-#define VS_STATUS_ERROR 2 /* scan failed */
-#define VS_STATUS_CLEAN 3 /* scan successful, file clean */
-#define VS_STATUS_INFECTED 4 /* scan successful, file infected */
+#define VS_STATUS_NO_SCAN 1 /* scan not required */
+#define VS_STATUS_ERROR 2 /* scan failed */
+#define VS_STATUS_CLEAN 3 /* scan successful, file clean */
+#define VS_STATUS_INFECTED 4 /* scan successful, file infected */
+#define VS_STATUS_SCANNING 5 /* scan in progress - async */
+/* Configuration data vs_config_t - vsc_types */
#define VS_TYPES_LEN 4096 /* vs_config_t - types buffer */
+#define VS_TYPES_MAX VS_TYPES_LEN / 2
+
/*
* AV_SCANSTAMP_SZ is the size of the scanstamp stored in the
@@ -61,20 +67,29 @@ extern "C" {
*/
typedef char vs_scanstamp_t[AV_SCANSTAMP_SZ + 1];
-/* used for both request to and response from vscand */
+/* used for door request to vscand */
typedef struct vs_scan_req {
- uint32_t vsr_id;
- uint32_t vsr_flags;
+ uint32_t vsr_idx;
+ uint32_t vsr_seqnum;
uint64_t vsr_size;
+ uint32_t vsr_flags;
uint8_t vsr_modified;
uint8_t vsr_quarantined;
char vsr_path[MAXPATHLEN];
vs_scanstamp_t vsr_scanstamp;
- uint32_t vsr_result;
} vs_scan_req_t;
-/* passed in VS_DRV_IOCTL_CONFIG */
+/* passed in VS_IOCTL_RESULT - async response from vscand */
+typedef struct vs_scan_rsp {
+ uint32_t vsr_idx;
+ uint32_t vsr_seqnum;
+ uint32_t vsr_result;
+ vs_scanstamp_t vsr_scanstamp;
+} vs_scan_rsp_t;
+
+
+/* passed in VS_IOCTL_CONFIG */
typedef struct vs_config {
char vsc_types[VS_TYPES_LEN];
uint64_t vsc_types_len;
@@ -84,33 +99,14 @@ typedef struct vs_config {
#ifdef _KERNEL
-
-/*
- * max no of types in vs_config_t.vsc_types
- * used as dimention for array of pointers to types
- */
-#define VS_TYPES_MAX VS_TYPES_LEN / 2
-
-/*
- * seconds to wait for daemon to reconnect before unregistering from VFS
- * during this time, the kernel will:
- * - allow access to files that have not been modified since last scanned
- * - deny access to files which have been modified since last scanned
- */
-#define VS_DAEMON_WAIT_SEC 60
-
-/* access derived from scan result (VS_STATUS_XXX) and file attributes */
-#define VS_ACCESS_UNDEFINED 0
-#define VS_ACCESS_ALLOW 1
-#define VS_ACCESS_DENY 2
-
int vscan_svc_init(void);
void vscan_svc_fini(void);
-void vscan_svc_enable(void);
+int vscan_svc_enable(void);
void vscan_svc_disable(void);
int vscan_svc_configure(vs_config_t *);
-boolean_t vscan_svc_is_enabled(void);
boolean_t vscan_svc_in_use(void);
+void vscan_svc_scan_result(vs_scan_rsp_t *);
+void vscan_svc_scan_abort(void);
vnode_t *vscan_svc_get_vnode(int);
int vscan_door_init(void);