b151ef55 |
/* |
5c4d94a9 |
* Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm@clamav.net> |
4775d04e |
* Trog <trog@clamav.net> |
b151ef55 |
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software |
30738099 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA. |
b151ef55 |
*/
|
b3483842 |
#ifdef _MSC_VER
#include <winsock.h>
#endif
|
24791abc |
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
|
b151ef55 |
#include <pthread.h> |
4775d04e |
#include <errno.h> |
b151ef55 |
#include <signal.h> |
4775d04e |
#include <stdio.h> |
521b19b4 |
#include <string.h> |
4775d04e |
#include <time.h> |
521b19b4 |
#include <sys/types.h> |
b3483842 |
#ifndef C_WINDOWS |
521b19b4 |
#include <sys/socket.h> |
b3483842 |
#endif
#ifdef HAVE_UNISTD_H |
828266a0 |
#include <unistd.h> |
b3483842 |
#endif |
e303cf29 |
#include "libclamav/clamav.h"
#include "shared/memory.h"
#include "shared/output.h" |
b151ef55 |
#include "server.h" |
4775d04e |
#include "thrmgr.h" |
ace125c7 |
#include "session.h" |
4775d04e |
#include "clamuko.h"
#include "others.h" |
36f2038b |
#include "shared.h" |
b151ef55 |
|
b3483842 |
#ifndef C_WINDOWS
#define closesocket(s) close(s)
#endif
|
4775d04e |
#define BUFFSIZE 1024 |
b3483842 |
#ifndef FALSE |
4775d04e |
#define FALSE (0) |
b3483842 |
#endif
#ifndef TRUE |
4775d04e |
#define TRUE (1) |
b3483842 |
#endif |
b151ef55 |
|
81987d14 |
int progexit = 0;
pthread_mutex_t exit_mutex;
int reload = 0;
time_t reloaded_time = 0;
pthread_mutex_t reload_mutex;
int sighup = 0; |
0efe5820 |
static struct cl_stat *dbstat = NULL; |
90e447be |
|
4775d04e |
typedef struct client_conn_tag {
int sd;
int options;
const struct cfgstruct *copt; |
538a6756 |
struct cl_node *root;
time_t root_timestamp; |
4775d04e |
const struct cl_limits *limits; |
596b1e64 |
int *socketds;
int nsockets; |
4775d04e |
} client_conn_t; |
ace125c7 |
|
4775d04e |
void scanner_thread(void *arg) |
b151ef55 |
{ |
4775d04e |
client_conn_t *conn = (client_conn_t *) arg; |
b3483842 |
#ifndef C_WINDOWS |
b151ef55 |
sigset_t sigset; |
b3483842 |
#endif |
596b1e64 |
int ret, timeout, i, session=FALSE; |
b151ef55 |
|
4775d04e |
|
b3483842 |
#ifndef C_WINDOWS |
b151ef55 |
/* ignore all signals */
sigfillset(&sigset);
pthread_sigmask(SIG_SETMASK, &sigset, NULL); |
b3483842 |
#endif |
b151ef55 |
|
5c4d94a9 |
timeout = cfgopt(conn->copt, "ReadTimeout")->numarg; |
6fab5766 |
if(!timeout)
timeout = -1;
|
85c4356a |
do {
ret = command(conn->sd, conn->root, conn->limits, conn->options, conn->copt, timeout); |
ca43a1fd |
if (ret < 0) { |
85c4356a |
break; |
4775d04e |
} |
b151ef55 |
|
85c4356a |
switch(ret) {
case COMMAND_SHUTDOWN:
pthread_mutex_lock(&exit_mutex);
progexit = 1; |
596b1e64 |
for(i = 0; i < conn->nsockets; i++) {
shutdown(conn->socketds[i], 2); |
b3483842 |
closesocket(conn->socketds[i]); |
596b1e64 |
} |
85c4356a |
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: |
81987d14 |
session = TRUE; |
85c4356a |
break;
case COMMAND_END: |
81987d14 |
session = FALSE; |
85c4356a |
break; |
2437a101 |
}
if (session) {
pthread_mutex_lock(&exit_mutex);
if(progexit) {
session = FALSE;
}
pthread_mutex_unlock(&exit_mutex);
pthread_mutex_lock(&reload_mutex); |
538a6756 |
if (conn->root_timestamp != reloaded_time) { |
2437a101 |
session = FALSE;
}
pthread_mutex_unlock(&reload_mutex);
} |
85c4356a |
} while (session);
|
b3483842 |
closesocket(conn->sd); |
538a6756 |
cl_free(conn->root); |
4775d04e |
free(conn);
return; |
b151ef55 |
}
|
4775d04e |
void sighandler_th(int sig) |
b151ef55 |
{ |
4775d04e |
switch(sig) {
case SIGINT:
case SIGTERM:
progexit = 1; |
828266a0 |
break; |
b151ef55 |
|
b3483842 |
#ifdef SIGHUP |
828266a0 |
case SIGHUP:
sighup = 1;
break; |
b3483842 |
#endif |
9e2d6abe |
|
b3483842 |
#ifdef SIGUSR2 |
c326f0da |
case SIGUSR2:
reload = 1;
break; |
b3483842 |
#endif |
c326f0da |
|
9e2d6abe |
default:
break; /* Take no action on other signals - e.g. SIGPIPE */ |
4775d04e |
}
} |
b151ef55 |
|
0efe5820 |
static struct cl_node *reload_db(struct cl_node *root, unsigned int dboptions, const struct cfgstruct *copt, int do_check, int *ret) |
4775d04e |
{ |
5aad82e2 |
const char *dbdir; |
e303cf29 |
int retval;
unsigned int sigs = 0; |
9c1c9007 |
|
0efe5820 |
*ret = 0; |
4775d04e |
if(do_check) {
if(dbstat == NULL) {
logg("No stats for Database check - forcing reload\n");
return root; |
b151ef55 |
}
|
4775d04e |
if(cl_statchkdir(dbstat) == 1) {
logg("SelfCheck: Database modification detected. Forcing reload.\n");
return root;
} else {
logg("SelfCheck: Database status OK.\n");
return NULL; |
b151ef55 |
} |
4775d04e |
} |
b151ef55 |
|
4775d04e |
/* release old structure */
if(root) { |
f91f55e0 |
cl_free(root); |
4775d04e |
root = NULL;
} |
b151ef55 |
|
5c4d94a9 |
dbdir = cfgopt(copt, "DatabaseDirectory")->strarg; |
4775d04e |
logg("Reading databases from %s\n", dbdir); |
b151ef55 |
|
4775d04e |
if(dbstat == NULL) {
dbstat = (struct cl_stat *) mmalloc(sizeof(struct cl_stat)); |
0efe5820 |
if(!dbstat) {
logg("!Can't allocate memory for dbstat\n");
*ret = 1;
return NULL;
} |
4775d04e |
} else {
cl_statfree(dbstat);
} |
5aad47ca |
|
4775d04e |
memset(dbstat, 0, sizeof(struct cl_stat));
cl_statinidir(dbdir, dbstat); |
8eec8ae5 |
|
e303cf29 |
if((retval = cl_load(dbdir, &root, &sigs, dboptions))) { |
4775d04e |
logg("!reload db failed: %s\n", cl_strerror(retval)); |
0efe5820 |
*ret = 1;
return NULL; |
4775d04e |
} |
5aad47ca |
|
4775d04e |
if(!root) { |
0efe5820 |
logg("!reload db failed: %s\n", cl_strerror(retval));
*ret = 1;
return NULL; |
4775d04e |
} |
b151ef55 |
|
f91f55e0 |
if((retval = cl_build(root)) != 0) { |
0efe5820 |
logg("!Database initialization error: can't build engine: %s\n", cl_strerror(retval));
*ret = 1;
return NULL; |
b151ef55 |
} |
e303cf29 |
logg("Database correctly reloaded (%d signatures)\n", sigs); |
b151ef55 |
|
4775d04e |
return root; |
b151ef55 |
}
|
06d74ffa |
int acceptloop_th(int *socketds, int nsockets, struct cl_node *root, unsigned int dboptions, const struct cfgstruct *copt) |
b151ef55 |
{ |
bcb0be9c |
int new_sd, max_threads, i, ret = 0; |
511eef51 |
unsigned int options = 0; |
3afc7c49 |
threadpool_t *thr_pool; |
b3483842 |
#ifndef C_WINDOWS |
4775d04e |
struct sigaction sigact; |
b3483842 |
#endif |
4775d04e |
mode_t old_umask; |
b151ef55 |
struct cl_limits limits; |
b3483842 |
#ifndef C_WINDOWS |
b151ef55 |
sigset_t sigset; |
b3483842 |
#endif |
4775d04e |
client_conn_t *client_conn;
struct cfgstruct *cpt; |
2ce1574c |
#ifdef HAVE_STRERROR_R
char buff[BUFFSIZE + 1];
#endif |
4775d04e |
unsigned int selfchk;
time_t start_time, current_time; |
e0c86955 |
pid_t mainpid; |
a0231a19 |
int idletimeout; |
e0c86955 |
|
b151ef55 |
#if defined(C_BIGSTACK) || defined(C_BSD) |
4775d04e |
size_t stacksize; |
b151ef55 |
#endif
|
4775d04e |
#ifdef CLAMUKO
pthread_t clamuko_pid;
pthread_attr_t clamuko_attr; |
36f2038b |
struct thrarg *tharg = NULL; /* shut up gcc */ |
4775d04e |
#endif |
b3483842 |
#ifndef C_WINDOWS |
4775d04e |
memset(&sigact, 0, sizeof(struct sigaction)); |
b3483842 |
#endif |
b151ef55 |
/* save the PID */ |
e0c86955 |
mainpid = getpid(); |
5c4d94a9 |
if((cpt = cfgopt(copt, "PidFile"))->enabled) { |
b151ef55 |
FILE *fd; |
4775d04e |
old_umask = umask(0006); |
b151ef55 |
if((fd = fopen(cpt->strarg, "w")) == NULL) {
logg("!Can't save PID in file %s\n", cpt->strarg);
} else { |
e0c86955 |
fprintf(fd, "%d", (int) mainpid); |
b151ef55 |
fclose(fd);
}
umask(old_umask);
}
logg("*Listening daemon: PID: %d\n", getpid()); |
5c4d94a9 |
max_threads = cfgopt(copt, "MaxThreads")->numarg; |
b151ef55 |
|
caac94ec |
#ifdef CL_EXPERIMENTAL
if(!cfgopt(copt,"PhishingScanURLs")->enabled)
options |= CL_SCAN_NOPHISHING; |
8932ca83 |
if(cfgopt(copt,"PhishingStrictURLCheck")->enabled) |
caac94ec |
options |= CL_PHISH_NO_DOMAINLIST;
#endif
|
5c4d94a9 |
if(cfgopt(copt, "ScanArchive")->enabled || cfgopt(copt, "ClamukoScanArchive")->enabled) { |
b151ef55 |
/* set up limits */ |
18a89742 |
memset(&limits, 0, sizeof(struct cl_limits)); |
b151ef55 |
|
5c4d94a9 |
if((limits.maxfilesize = cfgopt(copt, "ArchiveMaxFileSize")->numarg)) { |
511eef51 |
logg("Archive: Archived file size limit set to %d bytes.\n", limits.maxfilesize); |
5c4d94a9 |
} else {
logg("^Archive: File size limit protection disabled.\n"); |
b151ef55 |
}
|
5c4d94a9 |
if((limits.maxreclevel = cfgopt(copt, "ArchiveMaxRecursion")->numarg)) { |
511eef51 |
logg("Archive: Recursion level limit set to %d.\n", limits.maxreclevel); |
5c4d94a9 |
} else {
logg("^Archive: Recursion level limit protection disabled.\n"); |
b151ef55 |
}
|
5c4d94a9 |
if((limits.maxfiles = cfgopt(copt, "ArchiveMaxFiles")->numarg)) { |
511eef51 |
logg("Archive: Files limit set to %d.\n", limits.maxfiles); |
5c4d94a9 |
} else {
logg("^Archive: Files limit protection disabled.\n"); |
b151ef55 |
}
|
5c4d94a9 |
if((limits.maxratio = cfgopt(copt, "ArchiveMaxCompressionRatio")->numarg)) { |
511eef51 |
logg("Archive: Compression ratio limit set to %d.\n", limits.maxratio); |
5c4d94a9 |
} else {
logg("^Archive: Compression ratio limit disabled.\n"); |
cf899a29 |
}
|
5c4d94a9 |
if(cfgopt(copt, "ArchiveLimitMemoryUsage")->enabled) { |
b151ef55 |
limits.archivememlim = 1; |
9c1c9007 |
logg("Archive: Limited memory usage.\n"); |
4775d04e |
} else { |
b151ef55 |
limits.archivememlim = 0; |
4775d04e |
} |
b151ef55 |
}
|
5c4d94a9 |
if(cfgopt(copt, "ScanArchive")->enabled) { |
b151ef55 |
logg("Archive support enabled.\n"); |
06d4e856 |
options |= CL_SCAN_ARCHIVE; |
4cd4319e |
|
5c4d94a9 |
if(cfgopt(copt, "ArchiveBlockEncrypted")->enabled) { |
728f8802 |
logg("Archive: Blocking encrypted archives.\n"); |
f852d214 |
options |= CL_SCAN_BLOCKENCRYPTED; |
510c466b |
}
|
5c4d94a9 |
if(cfgopt(copt, "ArchiveBlockMax")->enabled) { |
728f8802 |
logg("Archive: Blocking archives that exceed limits.\n"); |
06d4e856 |
options |= CL_SCAN_BLOCKMAX; |
728f8802 |
}
|
b151ef55 |
} else {
logg("Archive support disabled.\n");
}
|
f32c9757 |
if(cfgopt(copt, "AlgorithmicDetection")->enabled) { |
95345f70 |
logg("Algorithmic detection enabled.\n");
options |= CL_SCAN_ALGO;
} else {
logg("Algorithmic detection disabled.\n");
}
|
5c4d94a9 |
if(cfgopt(copt, "ScanPE")->enabled) { |
c2484690 |
logg("Portable Executable support enabled.\n"); |
06d4e856 |
options |= CL_SCAN_PE; |
600fad76 |
} else {
logg("Portable Executable support disabled.\n");
} |
f8355d13 |
|
600fad76 |
if(cfgopt(copt, "ScanELF")->enabled) {
logg("ELF support enabled.\n");
options |= CL_SCAN_ELF;
} else {
logg("ELF support disabled.\n");
}
if(cfgopt(copt, "ScanPE")->enabled || cfgopt(copt, "ScanELF")->enabled) { |
5c4d94a9 |
if(cfgopt(copt, "DetectBrokenExecutables")->enabled) { |
f8355d13 |
logg("Detection of broken executables enabled.\n"); |
ac4e01f9 |
options |= CL_SCAN_BLOCKBROKEN; |
f8355d13 |
} |
c2484690 |
}
|
5c4d94a9 |
if(cfgopt(copt, "ScanMail")->enabled) { |
b151ef55 |
logg("Mail files support enabled.\n"); |
06d4e856 |
options |= CL_SCAN_MAIL; |
94da957a |
|
5c4d94a9 |
if(cfgopt(copt, "MailFollowURLs")->enabled) { |
94da957a |
logg("Mail: URL scanning enabled.\n"); |
06d4e856 |
options |= CL_SCAN_MAILURL; |
94da957a |
}
|
b151ef55 |
} else {
logg("Mail files support disabled.\n");
}
|
5c4d94a9 |
if(cfgopt(copt, "ScanOLE2")->enabled) { |
90e447be |
logg("OLE2 support enabled.\n"); |
06d4e856 |
options |= CL_SCAN_OLE2; |
90e447be |
} else {
logg("OLE2 support disabled.\n");
}
|
5c4d94a9 |
if(cfgopt(copt, "ScanHTML")->enabled) { |
2fe19b26 |
logg("HTML support enabled.\n"); |
06d4e856 |
options |= CL_SCAN_HTML; |
2fe19b26 |
} else {
logg("HTML support disabled.\n");
}
|
5c4d94a9 |
selfchk = cfgopt(copt, "SelfCheck")->numarg; |
4775d04e |
if(!selfchk) {
logg("Self checking disabled.\n");
} else {
logg("Self checking every %d seconds.\n", selfchk);
} |
b151ef55 |
|
5c4d94a9 |
if(cfgopt(copt, "ClamukoScanOnAccess")->enabled) |
b151ef55 |
#ifdef CLAMUKO |
e6b842b3 |
{
pthread_attr_init(&clamuko_attr);
pthread_attr_setdetachstate(&clamuko_attr, PTHREAD_CREATE_JOINABLE); |
4775d04e |
|
e6b842b3 |
tharg = (struct thrarg *) mmalloc(sizeof(struct thrarg));
tharg->copt = copt;
tharg->root = root;
tharg->limits = &limits;
tharg->options = options; |
4775d04e |
|
e6b842b3 |
pthread_create(&clamuko_pid, &clamuko_attr, clamukoth, tharg);
} |
b151ef55 |
#else |
6fa27628 |
logg("Clamuko is not available.\n"); |
b151ef55 |
#endif
|
b3483842 |
#ifndef C_WINDOWS |
b151ef55 |
/* set up signal handling */
sigfillset(&sigset);
sigdelset(&sigset, SIGINT);
sigdelset(&sigset, SIGTERM); |
8d9739ce |
sigdelset(&sigset, SIGSEGV); |
3df88240 |
sigdelset(&sigset, SIGHUP); |
9e2d6abe |
sigdelset(&sigset, SIGPIPE); |
c326f0da |
sigdelset(&sigset, SIGUSR2); |
b151ef55 |
sigprocmask(SIG_SETMASK, &sigset, NULL); |
4775d04e |
|
8d9739ce |
/* SIGINT, SIGTERM, SIGSEGV */ |
3c572030 |
sigact.sa_handler = sighandler_th; |
b151ef55 |
sigemptyset(&sigact.sa_mask);
sigaddset(&sigact.sa_mask, SIGINT);
sigaddset(&sigact.sa_mask, SIGTERM); |
3df88240 |
sigaddset(&sigact.sa_mask, SIGHUP); |
9e2d6abe |
sigaddset(&sigact.sa_mask, SIGPIPE); |
c326f0da |
sigaddset(&sigact.sa_mask, SIGUSR2); |
b151ef55 |
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL); |
9e2d6abe |
sigaction(SIGHUP, &sigact, NULL);
sigaction(SIGPIPE, &sigact, NULL); |
c326f0da |
sigaction(SIGUSR2, &sigact, NULL);
if(!debug_mode) {
sigaddset(&sigact.sa_mask, SIGHUP); |
4775d04e |
sigaction(SIGSEGV, &sigact, NULL); |
c326f0da |
} |
b3483842 |
#endif |
4775d04e |
pthread_mutex_init(&exit_mutex, NULL);
pthread_mutex_init(&reload_mutex, NULL); |
b151ef55 |
|
5c4d94a9 |
idletimeout = cfgopt(copt, "IdleTimeout")->numarg; |
a0231a19 |
|
81987d14 |
if((thr_pool=thrmgr_new(max_threads, idletimeout, scanner_thread)) == NULL) { |
50c81a92 |
logg("!thrmgr_new failed\n"); |
4775d04e |
exit(-1);
} |
b151ef55 |
|
4775d04e |
time(&start_time); |
b151ef55 |
|
81987d14 |
for(;;) { |
596b1e64 |
int socketd = socketds[0];
if(nsockets > 1) {
int pollret = poll_fds(socketds, nsockets, -1);
if(pollret > 0) {
socketd = socketds[pollret - 1];
} else {
socketd = socketds[0]; /* on a poll error use the first socket */
}
} |
4775d04e |
new_sd = accept(socketd, NULL, NULL);
if((new_sd == -1) && (errno != EINTR)) { |
596b1e64 |
if(progexit) {
break;
} |
4775d04e |
/* very bad - need to exit or restart */ |
2ce1574c |
#ifdef HAVE_STRERROR_R |
50c81a92 |
logg("!accept() failed: %s\n", strerror_r(errno, buff, BUFFSIZE)); |
2ce1574c |
#else |
81987d14 |
logg("!accept() failed\n"); |
2ce1574c |
#endif |
b151ef55 |
continue;
}
|
98cd56f8 |
if (sighup) {
logg("SIGHUP caught: re-opening log file.\n");
logg_close();
sighup = 0; |
5c4d94a9 |
if(!logg_file && (cpt = cfgopt(copt, "LogFile"))->enabled) |
df4a42fe |
logg_file = cpt->strarg; |
98cd56f8 |
}
|
41d9280e |
if (!progexit && new_sd >= 0) { |
98cd56f8 |
client_conn = (client_conn_t *) mmalloc(sizeof(struct client_conn_tag));
client_conn->sd = new_sd;
client_conn->options = options;
client_conn->copt = copt; |
538a6756 |
client_conn->root = cl_dup(root);
client_conn->root_timestamp = reloaded_time; |
98cd56f8 |
client_conn->limits = &limits; |
596b1e64 |
client_conn->socketds = socketds;
client_conn->nsockets = nsockets; |
06f64aa7 |
if (!thrmgr_dispatch(thr_pool, client_conn)) {
close(client_conn->sd);
free(client_conn); |
50c81a92 |
logg("!thread dispatch failed\n"); |
06f64aa7 |
} |
98cd56f8 |
} |
4775d04e |
pthread_mutex_lock(&exit_mutex);
if(progexit) { |
41d9280e |
if (new_sd >= 0) {
close(new_sd);
} |
4775d04e |
pthread_mutex_unlock(&exit_mutex);
break; |
b151ef55 |
} |
4775d04e |
pthread_mutex_unlock(&exit_mutex); |
b151ef55 |
|
4775d04e |
if(selfchk) {
time(¤t_time); |
cfa196eb |
if((current_time - start_time) > (time_t)selfchk) { |
0efe5820 |
if(reload_db(root, dboptions, copt, TRUE, &ret)) { |
4775d04e |
pthread_mutex_lock(&reload_mutex);
reload = 1;
pthread_mutex_unlock(&reload_mutex);
}
time(&start_time);
} |
42e6f5a6 |
} |
b151ef55 |
|
4775d04e |
pthread_mutex_lock(&reload_mutex);
if(reload) {
pthread_mutex_unlock(&reload_mutex); |
0efe5820 |
root = reload_db(root, dboptions, copt, FALSE, &ret);
if(ret) {
logg("Terminating because of a fatal error.");
if(new_sd >= 0)
close(new_sd);
break;
} |
85c4356a |
pthread_mutex_lock(&reload_mutex);
reload = 0; |
81987d14 |
time(&reloaded_time); |
85c4356a |
pthread_mutex_unlock(&reload_mutex); |
4775d04e |
#ifdef CLAMUKO |
5c4d94a9 |
if(cfgopt(copt, "ClamukoScanOnAccess")->enabled) { |
e6b842b3 |
logg("Stopping and restarting Clamuko.\n");
pthread_kill(clamuko_pid, SIGUSR1);
pthread_join(clamuko_pid, NULL);
tharg->root = root;
pthread_create(&clamuko_pid, &clamuko_attr, clamukoth, tharg);
} |
e8217f5a |
#endif |
4775d04e |
} else {
pthread_mutex_unlock(&reload_mutex);
}
} |
b151ef55 |
|
538a6756 |
/* Destroy the thread manager.
* This waits for all current tasks to end
*/
thrmgr_destroy(thr_pool); |
4775d04e |
#ifdef CLAMUKO |
5c4d94a9 |
if(cfgopt(copt, "ClamukoScanOnAccess")->enabled) { |
e6b842b3 |
logg("Stopping Clamuko.\n");
pthread_kill(clamuko_pid, SIGUSR1);
pthread_join(clamuko_pid, NULL);
} |
c0eb3ceb |
#endif |
0efe5820 |
if(root)
cl_free(root);
if(dbstat)
cl_statfree(dbstat); |
596b1e64 |
logg("*Shutting down the main socket%s.\n", (nsockets > 1) ? "s" : "");
for (i = 0; i < nsockets; i++)
shutdown(socketds[i], 2);
logg("*Closing the main socket%s.\n", (nsockets > 1) ? "s" : "");
for (i = 0; i < nsockets; i++) |
b3483842 |
closesocket(socketds[i]); |
193c72c5 |
#ifndef C_OS2 |
5c4d94a9 |
if((cpt = cfgopt(copt, "LocalSocket"))->enabled) { |
6fa27628 |
if(unlink(cpt->strarg) == -1)
logg("!Can't unlink the socket file %s\n", cpt->strarg);
else
logg("Socket file removed.\n"); |
193c72c5 |
}
#endif |
6fa27628 |
|
5c4d94a9 |
if((cpt = cfgopt(copt, "PidFile"))->enabled) { |
6fa27628 |
if(unlink(cpt->strarg) == -1)
logg("!Can't unlink the pid file %s\n", cpt->strarg);
else
logg("Pid file removed.\n");
}
|
828266a0 |
time(¤t_time);
logg("--- Stopped at %s", ctime(¤t_time));
|
bcb0be9c |
return ret; |
8d9739ce |
} |