29
32
#include <unistd.h>
31
34
#include <sys/types.h>
32
36
#include <dirent.h>
34
37
#include <sys/socket.h>
35
#ifdef HAVE_SYS_SELECT_H
36
#include <sys/select.h>
38
#ifdef HAVE_FD_PASSING
44
38
#include <sys/time.h>
46
40
#include <pthread.h>
49
44
#include <stddef.h>
52
46
#include "libclamav/clamav.h"
53
47
#include "libclamav/str.h"
54
#include "libclamav/others.h"
56
#include "shared/optparser.h"
49
#include "shared/cfgparser.h"
50
#include "shared/memory.h"
57
51
#include "shared/output.h"
58
52
#include "shared/misc.h"
60
54
#include "others.h"
61
55
#include "scanner.h"
62
56
#include "server.h"
63
58
#include "session.h"
64
59
#include "thrmgr.h"
66
#ifndef HAVE_FDPASSING
67
#define FEATURE_FDPASSING 0
69
#define FEATURE_FDPASSING 1
75
enum commands cmdtype;
80
{CMD1, sizeof(CMD1)-1, COMMAND_SCAN, 1, 1, 0},
81
{CMD3, sizeof(CMD3)-1, COMMAND_SHUTDOWN, 0, 1, 0},
82
{CMD4, sizeof(CMD4)-1, COMMAND_RELOAD, 0, 1, 0},
83
{CMD5, sizeof(CMD5)-1, COMMAND_PING, 0, 1, 0},
84
{CMD6, sizeof(CMD6)-1, COMMAND_CONTSCAN, 1, 1, 0},
85
/* must be before VERSION, because they share common prefix! */
86
{CMD18, sizeof(CMD18)-1, COMMAND_COMMANDS, 0, 0, 1},
87
{CMD7, sizeof(CMD7)-1, COMMAND_VERSION, 0, 1, 1},
88
{CMD8, sizeof(CMD8)-1, COMMAND_STREAM, 0, 1, 1},
89
{CMD10, sizeof(CMD10)-1, COMMAND_END, 0, 0, 1},
90
{CMD11, sizeof(CMD11)-1, COMMAND_SHUTDOWN, 0, 1, 1},
91
{CMD13, sizeof(CMD13)-1, COMMAND_MULTISCAN, 1, 1, 1},
92
{CMD14, sizeof(CMD14)-1, COMMAND_FILDES, 0, 1, FEATURE_FDPASSING},
93
{CMD15, sizeof(CMD15)-1, COMMAND_STATS, 0, 0, 1},
94
{CMD16, sizeof(CMD16)-1, COMMAND_IDSESSION, 0, 0, 1},
95
{CMD17, sizeof(CMD17)-1, COMMAND_INSTREAM, 0, 0, 1},
96
{CMD19, sizeof(CMD19)-1, COMMAND_DETSTATSCLEAR, 0, 1, 1},
97
{CMD20, sizeof(CMD20)-1, COMMAND_DETSTATS, 0, 1, 1}
62
static pthread_mutex_t ctime_mutex = PTHREAD_MUTEX_INITIALIZER;
68
const struct cfgstruct *copt;
70
const struct cl_engine *engine;
71
const struct cl_limits *limits;
100
enum commands parse_command(const char *cmd, const char **argument, int oldstyle)
104
for (i=0; i < sizeof(commands)/sizeof(commands[0]); i++) {
105
const size_t len = commands[i].len;
106
if (!strncmp(cmd, commands[i].cmd, len)) {
107
const char *arg = cmd + len;
108
if (commands[i].need_arg) {
109
if (!*arg) {/* missing argument */
110
logg("$Command %s missing argument!\n", commands[i].cmd);
111
return COMMAND_UNKNOWN;
115
if (*arg) {/* extra stuff after command */
116
logg("$Command %s has trailing garbage!\n", commands[i].cmd);
117
return COMMAND_UNKNOWN;
121
if (oldstyle && !commands[i].support_old) {
122
logg("$Command sent as old-style when not supported: %s\n", commands[i].cmd);
123
return COMMAND_UNKNOWN;
125
return commands[i].cmdtype;
128
return COMMAND_UNKNOWN;
131
int conn_reply_single(const client_conn_t *conn, const char *path, const char *status)
135
return mdprintf(conn->sd, "%u: %s: %s%c", conn->id, path, status, conn->term);
136
return mdprintf(conn->sd, "%u: %s%c", conn->id, status, conn->term);
139
return mdprintf(conn->sd, "%s: %s%c", path, status, conn->term);
140
return mdprintf(conn->sd, "%s%c", status, conn->term);
143
int conn_reply(const client_conn_t *conn, const char *path,
144
const char *msg, const char *status)
148
return mdprintf(conn->sd, "%u: %s: %s %s%c", conn->id, path, msg,
150
return mdprintf(conn->sd, "%u: %s %s%c", conn->id, msg, status,
154
return mdprintf(conn->sd, "%s: %s %s%c", path, msg, status, conn->term);
155
return mdprintf(conn->sd, "%s %s%c", msg, status, conn->term);
158
int conn_reply_virus(const client_conn_t *conn, const char *file,
162
return mdprintf(conn->sd, "%u: %s: %s FOUND%c", conn->id, file, virname,
165
return mdprintf(conn->sd, "%s: %s FOUND%c", file, virname, conn->term);
168
int conn_reply_error(const client_conn_t *conn, const char *msg)
170
return conn_reply(conn, NULL, msg, "ERROR");
173
#define BUFFSIZE 1024
174
int conn_reply_errno(const client_conn_t *conn, const char *path,
177
char err[BUFFSIZE + sizeof(". ERROR")];
178
cli_strerror(errno, err, BUFFSIZE-1);
179
strcat(err, ". ERROR");
180
return conn_reply(conn, path, msg, err);
184
* -1 on fatal error (shutdown)
186
* >0 errors encountered
188
int command(client_conn_t *conn, int *virus)
191
struct cl_engine *engine = conn->engine;
192
unsigned int options = conn->options;
193
const struct optstruct *opts = conn->opts;
194
int type = -1; /* TODO: make this enum */
197
int flags = CLI_FTW_STD;
199
struct scan_cb_data scandata;
200
struct cli_ftw_cbdata data;
201
unsigned ok, error, total;
203
jobgroup_t *group = NULL;
205
if (thrmgr_group_need_terminate(conn->group)) {
206
logg("$Client disconnected while command was active\n");
207
if (conn->scanfd != -1)
211
thrmgr_setactiveengine(engine);
213
data.data = &scandata;
214
memset(&scandata, 0, sizeof(scandata));
215
scandata.id = conn->id;
216
scandata.group = conn->group;
217
scandata.odesc = desc;
218
scandata.conn = conn;
219
scandata.options = options;
220
scandata.engine = engine;
221
scandata.opts = opts;
222
scandata.thr_pool = conn->thrpool;
223
scandata.toplevel_path = conn->filename;
225
switch (conn->cmdtype) {
227
thrmgr_setactivetask(NULL, "SCAN");
230
case COMMAND_CONTSCAN:
231
thrmgr_setactivetask(NULL, "CONTSCAN");
232
type = TYPE_CONTSCAN;
234
case COMMAND_MULTISCAN: {
235
int multiscan, max, alive;
74
static void multiscanfile(void *arg)
76
struct multi_tag *tag = (struct multi_tag *) arg;
85
/* ignore all signals */
87
pthread_sigmask(SIG_SETMASK, &sigset, NULL);
90
ret = cl_scanfile(tag->fname, &virname, NULL, tag->engine, tag->limits, tag->options);
93
mdprintf(tag->sd, "%s: %s FOUND\n", tag->fname, virname);
94
logg("%s: %s FOUND\n", tag->fname, virname);
95
virusaction(tag->fname, virname, tag->copt);
96
} else if(ret != CL_CLEAN) {
97
mdprintf(tag->sd, "%s: %s ERROR\n", tag->fname, cl_strerror(ret));
98
logg("%s: %s ERROR\n", tag->fname, cl_strerror(ret));
100
logg("%s: OK\n", tag->fname);
108
static int multiscan(const char *dirname, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options, const struct cfgstruct *copt, int odesc, unsigned int *reclev, threadpool_t *multi_pool)
112
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
115
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
121
unsigned int maxdirrec = 0;
122
struct multi_tag *scandata;
125
maxdirrec = cfgopt(copt, "MaxDirectoryRecursion")->numarg;
127
if(*reclev > maxdirrec) {
128
logg("*multiscan: Directory recursion limit exceeded at %s\n", dirname);
134
if((dd = opendir(dirname)) != NULL) {
135
#ifdef HAVE_READDIR_R_3
136
while(!readdir_r(dd, &result.d, &dent) && dent) {
137
#elif defined(HAVE_READDIR_R_2)
138
while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
140
while((dent = readdir(dd))) {
142
if (!is_fd_connected(odesc)) {
143
logg("multiscan: Client disconnected\n");
153
#if (!defined(C_INTERIX)) && (!defined(C_WINDOWS)) && (!defined(C_CYGWIN))
157
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
158
/* build the full name */
159
fname = (char *) mcalloc(strlen(dirname) + strlen(dent->d_name) + 2, sizeof(char));
161
logg("!multiscan: Can't allocate memory for fname\n");
165
sprintf(fname, "%s/%s", dirname, dent->d_name);
168
if(lstat(fname, &statbuf) != -1) {
169
if((S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) || (S_ISLNK(statbuf.st_mode) && (checksymlink(fname) == 1) && cfgopt(copt, "FollowDirectorySymlinks")->enabled)) {
170
if(multiscan(fname, engine, limits, options, copt, odesc, reclev, multi_pool) == -1) {
177
if(S_ISREG(statbuf.st_mode) || (S_ISLNK(statbuf.st_mode) && (checksymlink(fname) == 2) && cfgopt(copt, "FollowFileSymlinks")->enabled)) {
180
if(procdev && (statbuf.st_dev == procdev))
185
scandata = (struct multi_tag *) mmalloc(sizeof(struct multi_tag));
187
logg("!multiscan: Can't allocate memory for scandata\n");
192
scandata->sd = odesc;
193
scandata->options = options;
194
scandata->copt = copt;
195
scandata->fname = fname;
196
scandata->engine = engine;
197
scandata->limits = limits;
198
if(!thrmgr_dispatch(multi_pool, scandata)) {
199
logg("!multiscan: thread dispatch failed for multi_pool (file %s)\n", fname);
200
mdprintf(odesc, "ERROR: Can't scan file %s\n", fname);
207
while(!multi_pool->thr_idle) /* non-critical */
231
int command(int desc, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options, const struct cfgstruct *copt, int timeout)
237
bread = readsock(desc, buff, sizeof(buff)-1, '\n', timeout, 0, 1);
238
if(bread == -2) /* timeout */
240
if(bread == 0) /* Connection closed */
243
mdprintf(desc, "ERROR\n");
244
logg("!Command: readsock() failed.\n");
251
if(!strncmp(buff, CMD1, strlen(CMD1))) { /* SCAN */
252
if(scan(buff + strlen(CMD1) + 1, NULL, engine, limits, options, copt, desc, 0) == -2)
253
if(cfgopt(copt, "ExitOnOOM")->enabled)
254
return COMMAND_SHUTDOWN;
256
} else if(!strncmp(buff, CMD2, strlen(CMD2))) { /* RAWSCAN */
257
opt = options & ~CL_SCAN_ARCHIVE;
258
if(scan(buff + strlen(CMD2) + 1, NULL, engine, NULL, opt, copt, desc, 0) == -2)
259
if(cfgopt(copt, "ExitOnOOM")->enabled)
260
return COMMAND_SHUTDOWN;
262
} else if(!strncmp(buff, CMD3, strlen(CMD3))) { /* QUIT */
263
return COMMAND_SHUTDOWN;
265
} else if(!strncmp(buff, CMD4, strlen(CMD4))) { /* RELOAD */
266
mdprintf(desc, "RELOADING\n");
267
return COMMAND_RELOAD;
269
} else if(!strncmp(buff, CMD5, strlen(CMD5))) { /* PING */
270
mdprintf(desc, "PONG\n");
272
} else if(!strncmp(buff, CMD6, strlen(CMD6))) { /* CONTSCAN */
273
if(scan(buff + strlen(CMD6) + 1, NULL, engine, limits, options, copt, desc, 1) == -2)
274
if(cfgopt(copt, "ExitOnOOM")->enabled)
275
return COMMAND_SHUTDOWN;
277
} else if(!strncmp(buff, CMD7, strlen(CMD7))) { /* VERSION */
278
const char *dbdir = cfgopt(copt, "DatabaseDirectory")->strarg;
280
struct cl_cvd *daily;
284
if(!(path = mmalloc(strlen(dbdir) + 30))) {
285
mdprintf(desc, "Memory allocation error - SHUTDOWN forced\n");
286
return COMMAND_SHUTDOWN;
289
sprintf(path, "%s/daily.cvd", dbdir);
290
if(stat(path, &foo) == -1)
291
sprintf(path, "%s/daily.inc/daily.info", dbdir);
293
if((daily = cl_cvdhead(path))) {
294
time_t t = (time_t) daily->stime;
296
pthread_mutex_lock(&ctime_mutex);
297
mdprintf(desc, "ClamAV "VERSION"/%d/%s", daily->version, ctime(&t));
298
pthread_mutex_unlock(&ctime_mutex);
301
mdprintf(desc, "ClamAV "VERSION"\n");
306
} else if(!strncmp(buff, CMD8, strlen(CMD8))) { /* STREAM */
307
if(scanstream(desc, NULL, engine, limits, options, copt) == CL_EMEM)
308
if(cfgopt(copt, "ExitOnOOM")->enabled)
309
return COMMAND_SHUTDOWN;
311
} else if(!strncmp(buff, CMD9, strlen(CMD9))) { /* SESSION */
312
return COMMAND_SESSION;
314
} else if(!strncmp(buff, CMD10, strlen(CMD10))) { /* END */
317
} else if(!strncmp(buff, CMD11, strlen(CMD11))) { /* SHUTDOWN */
318
return COMMAND_SHUTDOWN;
320
} else if(!strncmp(buff, CMD12, strlen(CMD12))) { /* FD */
321
int fd = atoi(buff + strlen(CMD12) + 1);
323
scanfd(fd, NULL, engine, limits, options, copt, desc);
324
close(fd); /* FIXME: should we close it here? */
326
} else if(!strncmp(buff, CMD13, strlen(CMD13))) { /* MULTISCAN */
327
threadpool_t *multi_pool;
328
int idletimeout = cfgopt(copt, "IdleTimeout")->numarg;
329
int max_threads = cfgopt(copt, "MaxThreads")->numarg;
331
unsigned int reclev = 0;
332
const char *path = buff + strlen(CMD13) + 1;
238
/* use MULTISCAN only for directories (bb #1869) */
239
if (stat(conn->filename, &sb) == 0 &&
240
!S_ISDIR(sb.st_mode)) {
241
thrmgr_setactivetask(NULL, "CONTSCAN");
242
type = TYPE_CONTSCAN;
246
pthread_mutex_lock(&conn->thrpool->pool_mutex);
247
multiscan = conn->thrpool->thr_multiscan;
248
max = conn->thrpool->thr_max;
249
if (multiscan+1 < max)
250
conn->thrpool->thr_multiscan = multiscan+1;
252
alive = conn->thrpool->thr_alive;
255
pthread_mutex_unlock(&conn->thrpool->pool_mutex);
257
/* multiscan has 1 control thread, so there needs to be at least
258
1 threads that is a non-multiscan controlthread to scan and
260
logg("^Not enough threads for multiscan. Max: %d, Alive: %d, Multiscan: %d+1\n",
261
max, alive, multiscan);
262
conn_reply(conn, conn->filename, "Not enough threads for multiscan. Increase MaxThreads.", "ERROR");
265
flags &= ~CLI_FTW_NEED_STAT;
266
thrmgr_setactivetask(NULL, "MULTISCAN");
267
type = TYPE_MULTISCAN;
268
scandata.group = group = thrmgr_group_new();
273
case COMMAND_MULTISCANFILE:
274
thrmgr_setactivetask(NULL, "MULTISCANFILE");
275
scandata.group = NULL;
276
scandata.type = TYPE_SCAN;
277
scandata.thr_pool = NULL;
278
/* TODO: check ret value */
279
ret = scan_callback(NULL, conn->filename, conn->filename, visit_file, &data); /* callback freed it */
280
conn->filename = NULL;
281
*virus = scandata.infected;
282
if (ret == CL_BREAK) {
283
thrmgr_group_terminate(conn->group);
286
return scandata.errors > 0 ? scandata.errors : 0;
288
thrmgr_setactivetask(NULL, "FILDES");
289
#ifdef HAVE_FD_PASSING
290
if (conn->scanfd == -1)
291
conn_reply_error(conn, "FILDES: didn't receive file descriptor.");
293
ret = scanfd(conn->scanfd, conn, NULL, engine, options, opts, desc, 0);
294
if (ret == CL_VIRUS) {
296
} else if (ret == CL_EMEM) {
297
if(optget(opts, "ExitOnOOM")->enabled)
299
} else if (ret == CL_ETIMEOUT) {
300
thrmgr_group_terminate(conn->group);
305
logg("$Closed fd %d\n", conn->scanfd);
309
conn_reply_error(conn, "FILDES support not compiled in.");
314
thrmgr_setactivetask(NULL, "STATS");
316
mdprintf(desc, "%u: ", conn->id);
317
thrmgr_printstats(desc, conn->term);
320
thrmgr_setactivetask(NULL, "STREAM");
321
ret = scanstream(desc, NULL, engine, options, opts, conn->term);
324
if (ret == CL_EMEM) {
325
if(optget(opts, "ExitOnOOM")->enabled)
329
case COMMAND_INSTREAMSCAN:
330
thrmgr_setactivetask(NULL, "INSTREAM");
331
ret = scanfd(conn->scanfd, conn, NULL, engine, options, opts, desc, 1);
332
if (ret == CL_VIRUS) {
334
} else if (ret == CL_EMEM) {
335
if(optget(opts, "ExitOnOOM")->enabled)
337
} else if (ret == CL_ETIMEOUT) {
338
thrmgr_group_terminate(conn->group);
342
if (ftruncate(conn->scanfd, 0) == -1) {
343
/* not serious, we're going to close it and unlink it anyway */
344
logg("*ftruncate failed: %d\n", errno);
348
cli_unlink(conn->filename);
351
logg("!Invalid command distpached: %d\n", conn->cmdtype);
355
scandata.type = type;
356
maxdirrec = optget(opts, "MaxDirectoryRecursion")->numarg;
357
if (optget(opts, "FollowDirectorySymlinks")->enabled)
358
flags |= CLI_FTW_FOLLOW_DIR_SYMLINK;
359
if (optget(opts, "FollowFileSymlinks")->enabled)
360
flags |= CLI_FTW_FOLLOW_FILE_SYMLINK;
362
if(!optget(opts, "CrossFilesystems")->enabled)
363
if(stat(conn->filename, &sb) == 0)
364
scandata.dev = sb.st_dev;
366
ret = cli_ftw(conn->filename, flags, maxdirrec ? maxdirrec : INT_MAX, scan_callback, &data, scan_pathchk);
368
if(optget(opts, "ExitOnOOM")->enabled)
336
if(stat(path, &sb) == -1) {
337
mdprintf(desc, "Can't stat file %s\n", path);
370
if (scandata.group && conn->cmdtype == COMMAND_MULTISCAN) {
371
thrmgr_group_waitforall(group, &ok, &error, &total);
372
pthread_mutex_lock(&conn->thrpool->pool_mutex);
373
conn->thrpool->thr_multiscan--;
374
pthread_mutex_unlock(&conn->thrpool->pool_mutex);
341
if(S_ISDIR(sb.st_mode)) {
342
if((multi_pool = thrmgr_new(max_threads, idletimeout, multiscanfile)) == NULL) {
343
logg("!thrmgr_new failed for multi_pool\n");
344
mdprintf(desc, "ERROR: thrmgr_new failed for multi_pool\n");
348
ret = multiscan(path, engine, limits, options, copt, desc, &reclev, multi_pool);
349
thrmgr_destroy(multi_pool);
355
ret = cl_scanfile(path, &virname, NULL, engine, limits, options);
357
if(ret == CL_VIRUS) {
358
mdprintf(desc, "%s: %s FOUND\n", path, virname);
359
logg("%s: %s FOUND\n", path, virname);
360
virusaction(path, virname, copt);
361
} else if(ret != CL_CLEAN) {
362
mdprintf(desc, "%s: %s ERROR\n", path, cl_strerror(ret));
363
logg("%s: %s ERROR\n", path, cl_strerror(ret));
365
mdprintf(desc, "%s: OK\n", path);
367
logg("%s: OK\n", path);
376
error = scandata.errors;
377
total = scandata.total;
378
ok = total - error - scandata.infected;
381
if (ok + error == total && (error != total)) {
382
if (conn_reply_single(conn, conn->filename, "OK") == -1)
385
*virus = total - (ok + error);
387
if (ret == CL_ETIMEOUT)
388
thrmgr_group_terminate(conn->group);
392
static int dispatch_command(client_conn_t *conn, enum commands cmd, const char *argument)
396
client_conn_t *dup_conn = (client_conn_t *) malloc(sizeof(struct client_conn_tag));
399
logg("!Can't allocate memory for client_conn\n");
402
memcpy(dup_conn, conn, sizeof(*conn));
403
dup_conn->cmdtype = cmd;
404
if(cl_engine_addref(dup_conn->engine)) {
405
logg("!cl_engine_addref() failed\n");
409
dup_conn->scanfd = -1;
413
if (conn->scanfd == -1) {
414
conn_reply_error(dup_conn, "No file descriptor received.");
417
dup_conn->scanfd = conn->scanfd;
422
case COMMAND_CONTSCAN:
423
case COMMAND_MULTISCAN:
424
dup_conn->filename = strdup(argument);
425
if (!dup_conn->filename) {
426
logg("!Failed to allocate memory for filename\n");
430
case COMMAND_INSTREAMSCAN:
431
dup_conn->scanfd = conn->scanfd;
436
/* not a scan command, don't queue to bulk */
438
/* just dispatch the command */
441
logg("!Invalid command dispatch: %d\n", cmd);
445
if (!dup_conn->group)
447
if(!ret && !thrmgr_group_dispatch(dup_conn->thrpool, dup_conn->group, dup_conn, bulk)) {
448
logg("!thread dispatch failed\n");
452
cl_engine_free(dup_conn->engine);
458
static int print_ver(int desc, char term, const struct cl_engine *engine)
462
ver = cl_engine_get_num(engine, CL_ENGINE_DB_VERSION, NULL);
467
t = cl_engine_get_num(engine, CL_ENGINE_DB_TIME, NULL);
468
tstr = cli_ctime(&t, timestr, sizeof(timestr));
469
/* cut trailing \n */
470
timestr[strlen(tstr)-1] = '\0';
471
return mdprintf(desc, "ClamAV %s/%u/%s%c", get_version(), (unsigned int) ver, tstr, term);
473
return mdprintf(desc, "ClamAV %s%c", get_version(), term);
476
static void print_commands(int desc, char term, const struct cl_engine *engine)
479
const char *engine_ver = cl_retver();
480
const char *clamd_ver = get_version();
481
if (strcmp(engine_ver, clamd_ver)) {
482
mdprintf(desc, "ENGINE VERSION MISMATCH: %s != %s. ERROR%c",
483
engine_ver, clamd_ver, term);
486
print_ver(desc, '|', engine);
487
mdprintf(desc, " COMMANDS:");
488
n = sizeof(commands)/sizeof(commands[0]);
490
mdprintf(desc, " %s", commands[i].cmd);
492
mdprintf(desc, "%c", term);
499
* 0 for async dispatched
500
* 1 for command completed (connection can be closed)
502
int execute_or_dispatch_command(client_conn_t *conn, enum commands cmd, const char *argument)
505
char term = conn->term;
506
const struct cl_engine *engine = conn->engine;
507
/* execute commands that can be executed quickly on the recvloop thread,
509
* - not involve any operation that can block for a long time, such as disk
511
* - send of atomic message is allowed.
512
* Dispatch other commands */
518
case COMMAND_INSTREAM:
519
case COMMAND_INSTREAMSCAN:
520
case COMMAND_VERSION:
523
case COMMAND_COMMANDS:
524
/* These commands are accepted inside IDSESSION */
527
/* these commands are not recognized inside an IDSESSION */
528
conn_reply_error(conn, "Command invalid inside IDSESSION.");
529
logg("$SESSION: command is not valid inside IDSESSION: %d\n", cmd);
536
case COMMAND_SHUTDOWN:
537
pthread_mutex_lock(&exit_mutex);
539
pthread_mutex_unlock(&exit_mutex);
542
pthread_mutex_lock(&reload_mutex);
544
pthread_mutex_unlock(&reload_mutex);
545
mdprintf(desc, "RELOADING%c", term);
546
/* we set reload flag, and we'll reload before closing the
551
mdprintf(desc, "%u: PONG%c", conn->id, term);
553
mdprintf(desc, "PONG%c", term);
554
return conn->group ? 0 : 1;
555
case COMMAND_VERSION:
558
mdprintf(desc, "%u: ", conn->id);
559
print_ver(desc, conn->term, engine);
560
return conn->group ? 0 : 1;
562
case COMMAND_COMMANDS:
565
mdprintf(desc, "%u: ", conn->id);
566
print_commands(desc, conn->term, engine);
567
return conn->group ? 0 : 1;
569
case COMMAND_DETSTATSCLEAR:
574
case COMMAND_DETSTATS:
576
detstats_print(desc, conn->term);
579
case COMMAND_INSTREAM:
581
int rc = cli_gentempfd(optget(conn->opts, "TemporaryDirectory")->strarg, &conn->filename, &conn->scanfd);
582
if (rc != CL_SUCCESS)
584
conn->quota = optget(conn->opts, "StreamMaxLength")->numarg;
585
conn->mode = MODE_STREAM;
589
case COMMAND_MULTISCAN:
590
case COMMAND_CONTSCAN:
594
case COMMAND_INSTREAMSCAN:
595
return dispatch_command(conn, cmd, argument);
596
case COMMAND_IDSESSION:
597
conn->group = thrmgr_group_new();
603
/* end without idsession? */
604
conn_reply_single(conn, NULL, "UNKNOWN COMMAND");
607
/* need to close connection if we were last in group */
609
/*case COMMAND_UNKNOWN:*/
611
conn_reply_single(conn, NULL, "UNKNOWN COMMAND");
372
mdprintf(desc, "UNKNOWN COMMAND\n");
375
return 0; /* no error and no 'special' command executed */