another temp commit

git-svn-id: file:///var/lib/svn/clamav-devel/branches/clamd-proto@4667 77e5149b-7576-45b1-b177-96237e5ba77b
0.95
Török Edvin 17 years ago
parent b1442ed1df
commit ed2b37c685
  1. 5
      ChangeLog
  2. 4
      clamd/others.c
  3. 3
      clamd/scanner.c
  4. 152
      clamd/server-th.c
  5. 38
      clamd/server.h
  6. 304
      clamd/session.c
  7. 43
      clamd/session.h

@ -1,3 +1,8 @@
Mon Feb 2 12:56:21 EET 2009 (edwin)
------------------------------------
* clamd/others.c, clamd/server-th.c, clamd/server.h,
clamd/session.c, clamd/session.h: temp commit
Thu Jan 29 11:47:16 EET 2009 (edwin)
------------------------------------
* libclamav/others.h, libclamav/others_common.c: s/msg/path/

@ -389,7 +389,9 @@ int fds_add(struct fd_data *data, int fd, int listen_only)
data->buf[n-1].recvfd = -1;
if (!listen_only) {
data->buf[n-1].bufsize = PATH_MAX+8;
if (!(data->buf[n-1].buffer = malloc(data->buf[n-1].bufsize))) {
/* plus extra space for a \0 so we can make sure every command is \0
* terminated */
if (!(data->buf[n-1].buffer = malloc(data->buf[n-1].bufsize + 1))) {
logg("!add_fd: Memory allocation failed for command buffer\n");
return -1;
}

@ -383,9 +383,8 @@ int scan_callback(struct stat *sb, char *filename, const char *msg, enum cli_ftw
client_conn->scanfd = -1;
client_conn->sd = scandata->odesc;
client_conn->fds = NULL;
client_conn->cmdlen = 0;
client_conn->cmd = "MULTISCANFILE";
client_conn->filename = filename;
client_conn->cmdtype = COMMAND_MULTISCANFILE;
client_conn->term = scandata->term;
client_conn->options = scandata->options;
client_conn->opts = scandata->opts;

@ -104,83 +104,12 @@ static void scanner_thread(void *arg)
if(!timeout)
timeout = -1;
if (conn->filename) {
/* TODO: this is the bad place for this */
ret = 0;
if (access(conn->filename, R_OK)) {
mdprintf(conn->sd, "%s: Access denied. ERROR%c",
conn->filename, conn->term);
errors++;
} else {
const char *virname;
thrmgr_setactivetask(conn->filename,
"MULTISCANFILE");
ret = cl_scanfile(conn->filename, &virname, NULL, conn->engine, conn->options);
thrmgr_setactivetask(NULL, NULL);
if (ret == CL_EMEM) {
if(optget(conn->opts, "ExitOnOOM")->enabled)
ret = COMMAND_SHUTDOWN;
errors++;
} else {
if(ret == CL_VIRUS) {
mdprintf(conn->sd, "%s: %s FOUND%c", conn->filename, virname, conn->term);
logg("~%s: %s FOUND\n", conn->filename, virname);
virusaction(conn->filename, virname, conn->opts);
virus++;
} else if(ret != CL_CLEAN) {
errors++;
mdprintf(conn->sd, "%s: %s ERROR%c", conn->filename, cl_strerror(ret), conn->term);
logg("~%s: %s ERROR\n", conn->filename, cl_strerror(ret));
} else if(logok) {
logg("~%s: OK\n", conn->filename);
}
ret = 0;
}
}
}
do {
if (!conn->filename) /* TODO: */
ret = command(conn, timeout);
if (ret < 0) {
break;
}
switch(ret) {
case COMMAND_SHUTDOWN:
command(conn);
if (ret == COMMAND_SHUTDOWN) {
pthread_mutex_lock(&exit_mutex);
progexit = 1;
pthread_mutex_unlock(&exit_mutex);
break;
case COMMAND_RELOAD:
pthread_mutex_lock(&reload_mutex);
reload = 1;
pthread_mutex_unlock(&reload_mutex);
break;
case COMMAND_SESSION:
session = TRUE;
break;
case COMMAND_END:
session = FALSE;
break;
}
if (session) {
pthread_mutex_lock(&exit_mutex);
if(progexit) {
session = FALSE;
}
pthread_mutex_unlock(&exit_mutex);
pthread_mutex_lock(&reload_mutex);
if (conn->engine_timestamp != reloaded_time) {
session = FALSE;
}
pthread_mutex_unlock(&reload_mutex);
}
} while (session);
if (conn->scanfd != -1)
close(conn->scanfd);
@ -195,8 +124,6 @@ static void scanner_thread(void *arg)
if (conn->group)
thrmgr_group_finished(conn->group, virus ? EXIT_OTHER : errors ? EXIT_ERROR : EXIT_OK);
cl_engine_free(conn->engine);
if (conn->cmdlen)
free(conn->cmd);
free(conn);
return;
}
@ -336,12 +263,18 @@ static const char *get_cmd(struct fd_buf *buf, size_t off, size_t *len, char *te
return NULL;
}
*pos = '\0';
*len = pos - buf->buffer;
return buf->buffer + 1;
if (*term) {
*len = cli_chomp(buf->buffer + off);
} else {
*len = pos - buf->buffer - off;
}
return buf->buffer + off + 1;
default:
/* one packet = one command */
*len = buf->off;
return buf->buffer;
*len = buf->off - off;
buf->buffer[buf->off] = '\0';
cli_chomp(buf->buffer + off);
return buf->buffer + off;
}
}
@ -842,6 +775,7 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
}
if (buf->fd != -1 && buf->buffer) {
client_conn_t conn;
const unsigned char *cmd;
size_t cmdlen = 0;
size_t pos = 0;
@ -849,12 +783,21 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
char term;
/* New data available to read on socket. */
memset(&conn, 0, sizeof(conn));
conn.scanfd = buf->recvfd;
buf->recvfd = -1;
conn.sd = buf->fd;
conn.options = options;
conn.opts = opts;
conn.thrpool = thr_pool;
conn.engine = engine;
/* Parse & dispatch commands */
while ((cmd = get_cmd(buf, pos, &cmdlen, &term)) != NULL) {
int rc;
const char *argument;
enum commands command = parse_command(cmd, &argument);
/* TODO: when we'll parse commands here, move this out into another
* function */
if (!strncmp(cmd, CMD14, strlen(CMD14))) {/* FILDES */
if (command = COMMAND_FILDES) {
if ((buf->buffer + buf->off) - (cmd + cmdlen) < 1) {
/* we need the extra byte from recvmsg */
cmdlen = 0;
@ -863,51 +806,18 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
/* eat extra \0 for controlmsg */
cmdlen++;
}
client_conn_t *client_conn = (client_conn_t *) malloc(sizeof(struct client_conn_tag));
if(client_conn) {
client_conn->scanfd = buf->recvfd;
buf->recvfd = -1;
client_conn->filename = NULL;
client_conn->group = NULL;
client_conn->sd = buf->fd;
client_conn->fds = fds;
client_conn->cmdlen = cmdlen;
client_conn->cmd = malloc(cmdlen+1);
client_conn->term = term;
if (!client_conn->cmd) {
logg("!acceptloop_th: failed to allocate memory for command\n");
error = 1;
break;
}
memcpy(client_conn->cmd, cmd, cmdlen);
client_conn->cmd[cmdlen] = '\0';
client_conn->options = options;
client_conn->opts = opts;
client_conn->thrpool = thr_pool;
if(cl_engine_addref(engine)) {
logg("!cl_engine_addref() failed\n");
error = 1;
pthread_mutex_lock(&exit_mutex);
progexit = 1;
pthread_mutex_unlock(&exit_mutex);
} else {
client_conn->engine = engine;
client_conn->engine_timestamp = reloaded_time;
if(!thrmgr_dispatch(thr_pool, client_conn)) {
logg("!thread dispatch failed\n");
error = 1;
}
}
} else {
logg("!Can't allocate memory for client_conn\n");
if(optget(opts, "ExitOnOOM")->enabled) {
conn.term = term;
if ((rc = execute_or_dispatch_command(&conn, command, argument)) < 0) {
if(rc == -1 && optget(opts, "ExitOnOOM")->enabled) {
pthread_mutex_lock(&exit_mutex);
progexit = 1;
pthread_mutex_unlock(&exit_mutex);
}
error = 1;
break;
}
conn.scanfd = -1;
pos += cmdlen+1;
}

@ -26,23 +26,7 @@
#include "libclamav/clamav.h"
#include "shared/optparser.h"
#include "thrmgr.h"
/* TODO: these don't belong here */
enum commands {
COMMAND_SHUTDOWN = 1,
COMMAND_RELOAD,
COMMAND_END,
COMMAND_SESSION,
COMMAND_SCAN,
COMMAND_PING,
COMMAND_CONTSCAN,
COMMAND_VERSION,
COMMAND_STREAM,
COMMAND_MULTISCAN,
COMMAND_FILDES,
COMMAND_STATS,
COMMAND_MULTISCANFILE /* internal */
};
#include "session.h"
struct thrarg {
int sid;
int options;
@ -60,26 +44,12 @@ struct thrwarg {
unsigned int options;
};
typedef struct client_conn_tag {
char *cmd;
size_t cmdlen;
enum commands cmdtype;
char *filename;
int scanfd;
int sd;
struct fd_data *fds;
unsigned int options;
const struct optstruct *opts;
struct cl_engine *engine;
time_t engine_timestamp;
char term;
threadpool_t *thrpool;
jobgroup_t *group;
} client_conn_t;
int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigned int dboptions, const struct optstruct *opts);
void sighandler(int sig);
void sighandler_th(int sig);
void sigsegv(int sig);
extern pthread_mutex_t exit_mutex, reload_mutex;
extern int progexit, reload;
#endif

@ -114,132 +114,250 @@ static int recvfd_and_scan(int desc, const struct cl_engine *engine, unsigned in
}
#endif
int command(client_conn_t *conn, int timeout)
enum commands parse_command(const char *cmd, const char **argument)
{
*argument = NULL;
if (!strncmp(cmd, CMD1, strlen(CMD1))) { /* SCAN */
*argument = cmd + strlen(CMD1) + 1;
return COMMAND_SCAN;
} else if (!strncmp(cmd, CMD3, strlen(CMD3))) { /* QUIT */
return COMMAND_SHUTDOWN;
} else if (!strncmp(cmd, CMD4, strlen(CMD4))) { /* RELOAD */
return COMMAND_RELOAD;
} else if (!strncmp(cmd, CMD5, strlen(CMD5))) { /* PING */
return COMMAND_PING;
} else if (!strncmp(cmd, CMD6, strlen(CMD6))) { /* CONTSCAN */
*argument = cmd + strlen(CMD6) + 1;
return COMMAND_CONTSCAN;
} else if (!strncmp(cmd, CMD7, strlen(CMD7))) { /* VERSION */
return COMMAND_VERSION;
} else if (!strncmp(cmd, CMD8, strlen(CMD8))) { /* STREAM */
return COMMAND_STREAM;
#if 0
} else if (!strncmp(cmd, CMD9, strlen(CMD9))) { /* SESSION */
return COMMAND_SESSION;
#endif
} else if (!strncmp(cmd, CMD10, strlen(CMD10))) { /* END */
return COMMAND_END;
} else if (!strncmp(cmd, CMD11, strlen(CMD11))) { /* SHUTDOWN */
return COMMAND_SHUTDOWN;
} else if (!strncmp(cmd, CMD13, strlen(CMD13))) { /* MULTISCAN */
*argument = cmd + strlen(CMD13) + 1;
return COMMAND_MULTISCAN;
} else if (!strncmp(cmd, CMD14, strlen(CMD14))) { /* FILDES */
return COMMAND_FILDES;
} else if (!strncmp(cmd, CMD15, strlen(CMD15))) { /* STATS */
return COMMAND_STATS;
} else if (!strncmp(cmd, CMD16, strlen(CMD16))) { /* IDSESSION */
return COMMAND_IDSESSION;
}
return COMMAND_UNKNOWN;
}
int command(client_conn_t *conn)
{
int desc = conn->sd;
char *buff = conn->cmd;
size_t cmdlen = conn->cmdlen;
struct cl_engine *engine = conn->engine;
unsigned int options = conn->options;
const struct optstruct *opts = conn->opts;
const char term = conn->term;
int type; /* TODO: make this enum */
if (conn->term)
cli_chomp(buff);
thrmgr_setactiveengine(engine);
if(!strncmp(buff, CMD1, strlen(CMD1))) { /* SCAN */
thrmgr_setactivetask(NULL, CMD1);
if(scan(buff + strlen(CMD1) + 1, term, NULL, engine, options, opts, desc, TYPE_SCAN) == -2)
if(optget(opts, "ExitOnOOM")->enabled)
return COMMAND_SHUTDOWN;
} else if(!strncmp(buff, CMD3, strlen(CMD3))) { /* QUIT */
thrmgr_setactivetask(NULL, CMD3);
return COMMAND_SHUTDOWN;
} else if(!strncmp(buff, CMD4, strlen(CMD4))) { /* RELOAD */
thrmgr_setactivetask(NULL, CMD4);
/* we'll reload, hide the engine, if we are the last
* holding a ref to the engine it'll be freed,
* we don't want STATS command to access it */
thrmgr_setactiveengine(NULL);
mdprintf(desc, "RELOADING%c", conn->term);
return COMMAND_RELOAD;
} else if(!strncmp(buff, CMD5, strlen(CMD5))) { /* PING */
thrmgr_setactivetask(NULL, CMD5);
mdprintf(desc, "PONG%c", conn->term);
} else if(!strncmp(buff, CMD6, strlen(CMD6))) { /* CONTSCAN */
thrmgr_setactivetask(NULL, CMD6);
if(scan(buff + strlen(CMD6) + 1, term, NULL, engine, options, opts, desc, TYPE_CONTSCAN) == -2)
if(optget(opts, "ExitOnOOM")->enabled)
return COMMAND_SHUTDOWN;
} else if(!strncmp(buff, CMD7, strlen(CMD7))) { /* VERSION */
uint32_t ver;
thrmgr_setactivetask(NULL, CMD7);
cl_engine_get(engine, CL_ENGINE_DB_VERSION, &ver);
if(ver) {
char timestr[32];
const char *tstr;
time_t t;
cl_engine_get(engine, CL_ENGINE_DB_TIME, &t);
tstr = cli_ctime(&t, timestr, sizeof(timestr));
/* cut trailing \n */
timestr[strlen(tstr)-1] = '\0';
mdprintf(desc, "ClamAV %s/%u/%s%c", get_version(), (unsigned int) ver, tstr, conn->term);
} else {
mdprintf(desc, "ClamAV %s%c", get_version(), conn->term);
}
} else if(!strncmp(buff, CMD8, strlen(CMD8))) { /* STREAM */
thrmgr_setactivetask(NULL, CMD8);
if(scanstream(desc, NULL, engine, options, opts, conn->term) == CL_EMEM)
if(optget(opts, "ExitOnOOM")->enabled)
return COMMAND_SHUTDOWN;
} else if(!strncmp(buff, CMD9, strlen(CMD9))) { /* SESSION */
thrmgr_setactivetask(NULL, CMD9);
return COMMAND_SESSION;
} else if(!strncmp(buff, CMD10, strlen(CMD10))) { /* END */
thrmgr_setactivetask(NULL, CMD10);
return COMMAND_END;
} else if(!strncmp(buff, CMD11, strlen(CMD11))) { /* SHUTDOWN */
thrmgr_setactivetask(NULL, CMD11);
return COMMAND_SHUTDOWN;
} else if(!strncmp(buff, CMD13, strlen(CMD13))) { /* MULTISCAN */
struct scan_cb_data scandata;
struct cli_ftw_cbdata data;
unsigned ok, error, total;
const char *path = buff + strlen(CMD13) + 1;
jobgroup_t group = JOBGROUP_INITIALIZER;
data.data = &scandata;
thrmgr_setactiveengine(engine);
data.data = &scandata;
memset(&scandata, 0, sizeof(scandata));
scandata.type = TYPE_MULTISCAN;
scandata.group = conn->group;
scandata.type = type;
scandata.odesc = desc;
scandata.term = term;
scandata.options = options;
scandata.engine = engine;
scandata.opts = opts;
scandata.thr_pool = conn->thrpool;
scandata.group = &group;
thrmgr_setactivetask(buff+strlen(CMD13)+1, CMD13);
int maxdirrec = optget(opts, "MaxDirectoryRecursion")->numarg;
if (cli_ftw(path, CLI_FTW_STD, maxdirrec ? maxdirrec : INT_MAX, scan_callback, &data) == CL_EMEM)
if(optget(opts, "ExitOnOOM")->enabled)
return COMMAND_SHUTDOWN;
thrmgr_group_waitforall(&group, &ok, &error, &total);
if (ok + error == total) {
mdprintf(desc, "%s: OK%c", path, conn->term);
}
} else if(!strncmp(buff, CMD14, strlen(CMD14))) { /* FILDES */
thrmgr_setactivetask(NULL, CMD14);
switch (conn->cmdtype) {
case COMMAND_SCAN:
thrmgr_setactivetask(NULL, "SCAN");
type = TYPE_SCAN;
break;
case COMMAND_CONTSCAN:
thrmgr_setactivetask(NULL, "CONTSCAN");
type = TYPE_CONTSCAN;
break;
case COMMAND_MULTISCAN:
thrmgr_setactivetask(NULL, "MULTISCAN");
type = TYPE_MULTISCAN;
scandata.group = &group;
break;
case COMMAND_MULTISCANFILE:
thrmgr_setactivetask(NULL, "MULTISCANFILE");
scandata.group = NULL;
/* TODO: check ret value */
scan_callback(NULL, conn->filename, conn->filename, visit_file, &data);
break;
case COMMAND_FILDES:
thrmgr_setactivetask(NULL, "FILDES");
#ifdef HAVE_FD_PASSING
if (conn->scanfd == -1)
mdprintf(desc, "FILDES: didn't receive file descriptor %c", conn->term);
else if (scanfd(conn->scanfd, conn->term, NULL, engine, options, opts, desc) == -2)
if(optget(opts, "ExitOnOOM")->enabled)
return COMMAND_SHUTDOWN;
return 0;
#else
mdprintf(desc, "FILDES support not compiled inERROR%c",conn->term);
return -1;
#endif
} else if(!strncmp(buff, CMD15, strlen(CMD15))) { /* STATS */
thrmgr_setactivetask(NULL, CMD15);
case COMMAND_STATS:
thrmgr_setactivetask(NULL, "STATS");
thrmgr_printstats(desc);
} else {
mdprintf(desc, "UNKNOWN COMMAND%c", conn->term);
return 0;
case COMMAND_STREAM:
thrmgr_setactivetask(NULL, "STREAM");
if(scanstream(desc, NULL, engine, options, opts, conn->term) == CL_EMEM)
if(optget(opts, "ExitOnOOM")->enabled)
return COMMAND_SHUTDOWN;
return 0;
}
int maxdirrec = optget(opts, "MaxDirectoryRecursion")->numarg;
// TODO: flags symlink from opt
if (cli_ftw(conn->filename, CLI_FTW_STD, maxdirrec ? maxdirrec : INT_MAX, scan_callback, &data) == CL_EMEM)
if(optget(opts, "ExitOnOOM")->enabled)
return COMMAND_SHUTDOWN;
if (scandata.group)
thrmgr_group_waitforall(&group, &ok, &error, &total);
if (ok + error == total) {
mdprintf(desc, "%s: OK%c", conn->filename, conn->term);
}
return 0; /* no error and no 'special' command executed */
}
static int dispatch_command(const client_conn_t *conn, enum commands command, const char *argument)
{
client_conn_t *dup_conn = (client_conn_t *) malloc(sizeof(struct client_conn_tag));
if(!dup_conn) {
logg("!Can't allocate memory for client_conn\n");
return -1;
}
memcpy(dup_conn, conn, sizeof(*conn));
dup_conn->cmdtype = command;
if(cl_engine_addref(dup_conn->engine)) {
logg("!cl_engine_addref() failed\n");
return -1;
}
dup_conn->scanfd = -1;
switch (command) {
case COMMAND_FILDES:
dup_conn->scanfd = conn->scanfd;
break;
case COMMAND_SCAN:
case COMMAND_CONTSCAN:
case COMMAND_MULTISCAN:
dup_conn->filename = strdup(argument);
if (!dup_conn->filename) {
logg("!Failed to allocate memory for filename\n");
return -1;
}
break;
case COMMAND_STREAM:
case COMMAND_STATS:
/* just dispatch the command */
break;
}
if(!thrmgr_dispatch(dup_conn->thrpool, dup_conn)) {
logg("!thread dispatch failed\n");
return -2;
}
return 0;
}
/* returns:
* <0 for error
* -1 out of memory
* -2 other
* 0 for async dispatched
* 1 for command completed (connection can be closed)
*/
int execute_or_dispatch_command(client_conn_t *conn, enum commands command, const char *argument)
{
int desc = conn->sd;
char term = conn->term;
const struct cl_engine *engine = conn->engine;
/* execute commands that can be executed quickly on the recvloop thread,
* these must:
* - not involve any operation that can block for a long time, such as disk
* I/O
* - send of atomic message is allowed.
* Dispatch other commands */
switch (command) {
case COMMAND_SHUTDOWN:
pthread_mutex_lock(&exit_mutex);
progexit = 1;
pthread_mutex_unlock(&exit_mutex);
return 1;
case COMMAND_RELOAD:
pthread_mutex_lock(&reload_mutex);
reload = 1;
pthread_mutex_unlock(&reload_mutex);
mdprintf(desc, "RELOADING%c", term);
/* we set reload flag, and we'll reload before closing the
* connection */
return 1;
case COMMAND_PING:
mdprintf(desc, "PONG%c", term);
return 1;
case COMMAND_VERSION:
{
uint32_t ver;
cl_engine_get(engine, CL_ENGINE_DB_VERSION, &ver);
if(ver) {
char timestr[32];
const char *tstr;
time_t t;
cl_engine_get(engine, CL_ENGINE_DB_TIME, &t);
tstr = cli_ctime(&t, timestr, sizeof(timestr));
/* cut trailing \n */
timestr[strlen(tstr)-1] = '\0';
mdprintf(desc, "ClamAV %s/%u/%s%c", get_version(), (unsigned int) ver, tstr, term);
} else {
mdprintf(desc, "ClamAV %s%c", get_version(), conn->term);
}
return 1;
}
case COMMAND_FILDES:
case COMMAND_SCAN:
case COMMAND_CONTSCAN:
case COMMAND_STREAM:
case COMMAND_MULTISCAN:
case COMMAND_STATS:
return dispatch_command(conn, command, argument);
case COMMAND_IDSESSION:
if (conn->group) {
/* we are already inside an idsession/multiscan */
mdprintf(desc, "UNKNOWN COMMAND%c", term);
return 1;
}
conn->group = calloc(1, sizeof(*conn->group));
if (!conn->group)
return CL_EMEM;
return 0;
case COMMAND_END:
if (!conn->group) {
/* end without idsession? */
mdprintf(desc, "UNKNOWN COMMAND%c", term);
return 1;
}
return 1;
/*case COMMAND_UNKNOWN:*/
default:
mdprintf(desc, "UNKNOWN COMMAND%c", term);
return 1;
}
}

@ -28,18 +28,57 @@
#define CMD6 "CONTSCAN"
#define CMD7 "VERSION"
#define CMD8 "STREAM"
#define CMD9 "SESSION"
/*#define CMD9 "SESSION"*/
#define CMD10 "END"
#define CMD11 "SHUTDOWN"
/* #define CMD12 "FD" */
#define CMD13 "MULTISCAN"
#define CMD14 "FILDES"
#define CMD15 "STATS"
#define CMD16 "IDSESSION"
#include "libclamav/clamav.h"
#include "shared/optparser.h"
#include "server.h"
int command(client_conn_t *conn, int timeout);
enum commands {
COMMAND_UNKNOWN = 0,
COMMAND_SHUTDOWN = 1,
COMMAND_RELOAD,
COMMAND_END,
COMMAND_SESSION,
COMMAND_SCAN,
COMMAND_PING,
COMMAND_CONTSCAN,
COMMAND_VERSION,
COMMAND_STREAM,
COMMAND_MULTISCAN,
COMMAND_FILDES,
COMMAND_STATS,
/* new proto commands */
COMMAND_IDSESSION,
COMMAND_INSTREAM,
/* internal commands */
COMMAND_MULTISCANFILE
};
typedef struct client_conn_tag {
enum commands cmdtype;
char *filename;
int scanfd;
int sd;
struct fd_data *fds;
unsigned int options;
const struct optstruct *opts;
struct cl_engine *engine;
time_t engine_timestamp;
char term;
threadpool_t *thrpool;
jobgroup_t *group;
} client_conn_t;
int command(client_conn_t *conn);
enum commands parse_command(const char *cmd, const char **argument);
int execute_or_dispatch_command(client_conn_t *conn, enum commands command, const char *argument);
#endif

Loading…
Cancel
Save