~ubuntu-branches/ubuntu/feisty/clamav/feisty

« back to all changes in this revision

Viewing changes to freshclam/freshclam.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2007-02-20 10:33:44 UTC
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20070220103344-zgcu2psnx9d98fpa
Tags: upstream-0.90
ImportĀ upstreamĀ versionĀ 0.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 *  Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm@clamav.net>
3
3
 *
4
4
 *  This program is free software; you can redistribute it and/or modify
5
 
 *  it under the terms of the GNU General Public License version 2 as
6
 
 *  published by the Free Software Foundation.
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation; either version 2 of the License, or
 
7
 *  (at your option) any later version.
7
8
 *
8
9
 *  This program is distributed in the hope that it will be useful,
9
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
16
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16
17
 *  MA 02110-1301, USA.
17
18
 */
 
19
#ifdef  _MSC_VER
 
20
#include <winsock.h>
 
21
#endif
18
22
 
19
23
#if HAVE_CONFIG_H
20
24
#include "clamav-config.h"
30
34
#include <signal.h>
31
35
#include <time.h>
32
36
#include <sys/types.h>
33
 
#ifndef _WIN32
 
37
#ifndef C_WINDOWS
34
38
#include <sys/wait.h>
35
39
#endif
36
40
#include <sys/stat.h>
37
41
#include <fcntl.h>
38
 
#ifdef  HAVE_PWD_H
 
42
#ifndef C_WINDOWS
39
43
#include <pwd.h>
40
 
#endif
41
 
#ifdef HAVE_GRP_H
42
44
#include <grp.h>
43
45
#endif
44
46
 
49
51
#include "target.h"
50
52
#include "clamav.h"
51
53
 
52
 
#include "libclamav/others.h"
53
 
 
54
 
#include "shared/optparser.h"
 
54
#include "shared/options.h"
55
55
#include "shared/output.h"
56
56
#include "shared/misc.h"
57
57
 
 
58
#include "libclamav/lockdb.h"
 
59
 
58
60
#include "execute.h"
59
61
#include "manager.h"
60
62
#include "mirman.h"
63
65
extern int active_children;
64
66
 
65
67
static short foreground = 1;
66
 
char updtmpdir[512], dbdir[512];
67
 
int sigchld_wait = 1;
68
68
 
69
 
static void sighandler(int sig) {
 
69
static void daemon_sighandler(int sig) {
70
70
 
71
71
    switch(sig) {
72
72
#ifdef  SIGCHLD
73
73
        case SIGCHLD:
74
 
            if (sigchld_wait)
75
 
                waitpid(-1, NULL, WNOHANG);
 
74
            waitpid(-1, NULL, WNOHANG);
76
75
            active_children--;
77
76
            break;
78
77
#endif
79
78
 
80
 
#ifdef SIGPIPE
81
 
        case SIGPIPE:
82
 
            /* no action, app will get EPIPE */
83
 
            break;
84
 
#endif
85
 
 
86
79
#ifdef  SIGALRM
87
80
        case SIGALRM:
88
81
                terminate = -1;
101
94
#endif
102
95
 
103
96
        default:
104
 
            if(*updtmpdir)
105
 
                cli_rmdirs(updtmpdir);
106
 
            logg("Update process interrupted\n");
107
 
            exit(2);
 
97
            terminate = 1;
 
98
            break;
108
99
    }
109
100
 
110
101
    return;
111
102
}
112
103
 
113
 
static void writepid(const char *pidfile)
 
104
static void writepid(char *pidfile)
114
105
{
115
106
        FILE *fd;
116
107
        int old_umask;
129
120
    mprintf_stdout = 1;
130
121
 
131
122
    mprintf("\n");
132
 
    mprintf("                   Clam AntiVirus: freshclam  %s\n", get_version());
133
 
    printf("           By The ClamAV Team: http://www.clamav.net/team\n");
134
 
    printf("           (C) 2007-2009 Sourcefire, Inc. et al.\n\n");
 
123
    mprintf("                   Clam AntiVirus: freshclam  "VERSION"\n");
 
124
    mprintf("    (C) 2002 - 2007 ClamAV Team - http://www.clamav.net/team\n\n");
135
125
 
136
126
    mprintf("    --help               -h              show help\n");
137
127
    mprintf("    --version            -V              print version number and exit\n");
138
128
    mprintf("    --verbose            -v              be verbose\n");
139
129
    mprintf("    --debug                              enable debug messages\n");
140
130
    mprintf("    --quiet                              only output error messages\n");
141
 
    mprintf("    --no-warnings                        don't print and log warnings\n");
142
131
    mprintf("    --stdout                             write to stdout instead of stderr\n");
143
132
    mprintf("\n");
144
133
    mprintf("    --config-file=FILE                   read configuration from FILE.\n");
145
134
    mprintf("    --log=FILE           -l FILE         log into FILE\n");
146
 
#ifndef _WIN32
147
135
    mprintf("    --daemon             -d              run in daemon mode\n");
148
136
    mprintf("    --pid=FILE           -p FILE         save daemon's pid in FILE\n");
149
137
    mprintf("    --user=USER          -u USER         run as USER\n");
150
 
#endif
151
138
    mprintf("    --no-dns                             force old non-DNS verification method\n");
152
139
    mprintf("    --checks=#n          -c #n           number of checks per day, 1 <= n <= 50\n");
153
140
    mprintf("    --datadir=DIRECTORY                  download new databases into DIRECTORY\n");
159
146
    mprintf("    --on-error-execute=COMMAND           execute COMMAND if errors occured\n");
160
147
    mprintf("    --on-outdated-execute=COMMAND        execute COMMAND when software is outdated\n");
161
148
    mprintf("    --list-mirrors                       print mirrors from mirrors.dat\n");
162
 
    mprintf("    --submit-stats[=/path/clamd.conf]    only submit detection statistics\n");
163
149
 
164
150
    mprintf("\n");
165
151
}
166
152
 
167
 
static int download(const struct optstruct *opts, const char *cfgfile)
 
153
static int download(const struct cfgstruct *copt, const struct optstruct *opt, const char *datadir)
168
154
{
169
155
        int ret = 0, try = 0, maxattempts = 0;
170
 
        const struct optstruct *opt;
171
 
 
172
 
 
173
 
    maxattempts = optget(opts, "MaxAttempts")->numarg;
 
156
        struct cfgstruct *cpt;
 
157
 
 
158
 
 
159
    maxattempts = cfgopt(copt, "MaxAttempts")->numarg;
174
160
    logg("*Max retries == %d\n", maxattempts);
175
161
 
176
 
    if(!(opt = optget(opts, "DatabaseMirror"))->enabled) {
177
 
        logg("^You must specify at least one database mirror in %s\n", cfgfile);
 
162
    if(!(cpt = cfgopt(copt, "DatabaseMirror"))->enabled) {
 
163
        logg("^You must specify at least one database mirror.\n");
178
164
        return 56;
179
165
    } else {
180
 
        while(opt) {
181
 
            ret = downloadmanager(opts, opt->strarg, try == maxattempts - 1);
182
 
#ifndef _WIN32
 
166
        while(cli_writelockdb(datadir, 0) == CL_ELOCKDB) {
 
167
            logg("*Waiting to lock database directory: %s\n", datadir);
 
168
            sleep(5);
 
169
            if(++try > 12) {
 
170
                logg("!Can't lock database directory: %s\n", datadir);
 
171
                return 61; 
 
172
            }
 
173
        }
 
174
        try = 0;
 
175
        while(cpt) {
 
176
            ret = downloadmanager(copt, opt, cpt->strarg);
183
177
            alarm(0);
184
 
#endif
 
178
 
185
179
            if(ret == 52 || ret == 54 || ret == 58 || ret == 59) {
186
180
                if(try < maxattempts - 1) {
187
181
                    logg("Trying again in 5 secs...\n");
189
183
                    sleep(5);
190
184
                    continue;
191
185
                } else {
192
 
                    logg("Giving up on %s...\n", opt->strarg);
193
 
                    opt = (struct optstruct *) opt->nextarg;
194
 
                    if(!opt) {
195
 
                        logg("Update failed. Your network may be down or none of the mirrors listed in %s is working. Check http://www.clamav.net/support/mirror-problem for possible reasons.\n", cfgfile);
 
186
                    logg("Giving up on %s...\n", cpt->strarg);
 
187
                    cpt = (struct cfgstruct *) cpt->nextarg;
 
188
                    if(!cpt) {
 
189
                        logg("Update failed. Your network may be down or none of the mirrors listed in freshclam.conf is working. Check http://www.clamav.net/support/mirror-problem for possible reasons.\n");
196
190
                    }
197
191
                    try = 0;
198
192
                }
199
193
 
200
194
            } else {
 
195
                cli_unlockdb(datadir);
201
196
                return ret;
202
197
            }
203
198
        }
 
199
        cli_unlockdb(datadir);
204
200
    }
205
201
 
206
202
    return ret;
207
203
}
208
204
 
209
 
void msg_callback(enum cl_msg severity, const char *fullmsg, const char *msg, void *ctx)
210
 
{
211
 
    switch (severity) {
212
 
        case CL_MSG_ERROR:
213
 
            logg("^[LibClamAV] %s", msg);
214
 
            break;
215
 
        case CL_MSG_WARN:
216
 
            logg("~[LibClamAV] %s", msg);
217
 
        default:
218
 
            logg("*[LibClamAV] %s", msg);
219
 
            break;
220
 
    }
221
 
}
222
 
 
223
205
int main(int argc, char **argv)
224
206
{
225
 
        int ret = 52, retcl;
226
 
        const char *cfgfile, *arg = NULL, *pidfile = NULL;
227
 
        char *pt;
228
 
        struct optstruct *opts;
229
 
        const struct optstruct *opt;
230
 
#ifndef _WIN32
 
207
        int ret = 52;
 
208
        const char *newdir, *cfgfile;
 
209
        char *pidfile = NULL;
 
210
        struct cfgstruct *copt, *cpt;
 
211
#ifndef C_WINDOWS
231
212
        struct sigaction sigact;
232
213
        struct sigaction oldact;
233
214
#endif
234
 
#ifdef HAVE_PWD_H
235
 
        const char *dbowner;
 
215
#if !defined(C_CYGWIN)  && !defined(C_OS2) && !defined(C_WINDOWS)
 
216
        char *unpuser;
236
217
        struct passwd *user;
237
218
#endif
238
219
        struct stat statbuf;
239
220
        struct mirdat mdat;
240
 
 
241
 
    if(check_flevel())
242
 
        exit(40);
243
 
 
244
 
    if((retcl = cl_init(CL_INIT_DEFAULT))) {
245
 
        mprintf("!Can't initialize libclamav: %s\n", cl_strerror(retcl));
246
 
        return 40;
247
 
    }
248
 
 
249
 
    if((opts = optparse(NULL, argc, argv, 1, OPT_FRESHCLAM, 0, NULL)) == NULL) {
250
 
        mprintf("!Can't parse command line options\n");
251
 
        return 40;
252
 
    }
253
 
 
254
 
    if(optget(opts, "help")->enabled) {
 
221
        struct optstruct *opt;
 
222
        const char *short_options = "hvdp:Vl:c:u:a:";
 
223
        static struct option long_options[] = {
 
224
            {"help", 0, 0, 'h'},
 
225
            {"quiet", 0, 0, 0},
 
226
            {"verbose", 0, 0, 'v'},
 
227
            {"debug", 0, 0, 0},
 
228
            {"version", 0, 0, 'V'},
 
229
            {"datadir", 1, 0, 0},
 
230
            {"log", 1, 0, 'l'},
 
231
            {"log-verbose", 0, 0, 0}, /* not used */
 
232
            {"stdout", 0, 0, 0},
 
233
            {"daemon", 0, 0, 'd'},
 
234
            {"pid", 1, 0, 'p'},
 
235
            {"user", 1, 0, 'u'}, /* not used */
 
236
            {"config-file", 1, 0, 0},
 
237
            {"no-dns", 0, 0, 0},
 
238
            {"checks", 1, 0, 'c'},
 
239
            {"http-proxy", 1, 0, 0},
 
240
            {"local-address", 1, 0, 'a'},
 
241
            {"proxy-user", 1, 0, 0},
 
242
            {"daemon-notify", 2, 0, 0},
 
243
            {"on-update-execute", 1, 0, 0},
 
244
            {"on-error-execute", 1, 0, 0},
 
245
            {"on-outdated-execute", 1, 0, 0},
 
246
            {"list-mirrors", 0, 0, 0},
 
247
            {0, 0, 0, 0}
 
248
        };
 
249
 
 
250
 
 
251
    opt = opt_parse(argc, argv, short_options, long_options, NULL);
 
252
    if(!opt) {
 
253
        mprintf("!Can't parse the command line\n");
 
254
        return 40;
 
255
    }
 
256
 
 
257
    if(opt_check(opt, "help")) {
255
258
        help();
256
 
        optfree(opts);
 
259
        opt_free(opt);
 
260
        return 0;
 
261
    }
 
262
 
 
263
    if(opt_check(opt, "version")) {
 
264
        print_version();
 
265
        opt_free(opt);
257
266
        return 0;
258
267
    }
259
268
 
260
269
    /* parse the config file */
261
 
    cfgfile = optget(opts, "config-file")->strarg;
262
 
    pt = strdup(cfgfile);
263
 
    if((opts = optparse(cfgfile, 0, NULL, 1, OPT_FRESHCLAM, 0, opts)) == NULL) {
264
 
        fprintf(stderr, "ERROR: Can't open/parse the config file %s\n", pt);
265
 
        free(pt);
266
 
        return 40;
267
 
    }
268
 
    free(pt);
269
 
 
270
 
    if(optget(opts, "version")->enabled) {
271
 
        print_version(optget(opts, "DatabaseDirectory")->strarg);
272
 
        optfree(opts);
273
 
        return 0;
274
 
    }
275
 
 
276
 
    if(optget(opts, "HTTPProxyPassword")->enabled) {
 
270
    if((cfgfile = opt_arg(opt, "config-file"))) {
 
271
        copt = getcfg(cfgfile, 1);
 
272
    } else {
 
273
        /* TODO: force strict permissions on freshclam.conf */
 
274
        if((copt = getcfg((cfgfile = CONFDIR"/freshclam.conf"), 1)) == NULL)
 
275
            copt = getcfg((cfgfile = CONFDIR"/clamd.conf"), 1);
 
276
    }
 
277
 
 
278
    if(!copt) {
 
279
        logg("!Can't parse the config file %s\n", cfgfile);
 
280
        opt_free(opt);
 
281
        return 56;
 
282
    }
 
283
 
 
284
#ifdef C_WINDOWS
 
285
    if(!pthread_win32_process_attach_np()) {
 
286
        mprintf("!Can't start the win32 pthreads layer\n");
 
287
        return 63;
 
288
    }
 
289
#endif
 
290
 
 
291
    if(opt_check(opt, "http-proxy") || opt_check(opt, "proxy-user"))
 
292
        logg("WARNING: Proxy settings are now only configurable in the config file.\n");
 
293
 
 
294
    if(cfgopt(copt, "HTTPProxyPassword")->enabled) {
277
295
        if(stat(cfgfile, &statbuf) == -1) {
278
296
            logg("^Can't stat %s (critical error)\n", cfgfile);
279
 
            optfree(opts);
 
297
            opt_free(opt);
280
298
            return 56;
281
299
        }
282
300
 
283
 
#ifndef _WIN32
 
301
#if !defined(C_CYGWIN) && !defined(C_WINDOWS)
284
302
        if(statbuf.st_mode & (S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH)) {
285
303
            logg("^Insecure permissions (for HTTPProxyPassword): %s must have no more than 0700 permissions.\n", cfgfile);
286
 
            optfree(opts);
 
304
            opt_free(opt);
287
305
            return 56;
288
306
        }
289
307
#endif
290
308
    }
291
309
 
292
 
#ifdef HAVE_PWD_H
 
310
#if !defined(C_CYGWIN)  && !defined(C_OS2) && !defined(C_WINDOWS)
293
311
    /* freshclam shouldn't work with root privileges */
294
 
    dbowner = optget(opts, "DatabaseOwner")->strarg;
 
312
    if(opt_check(opt, "user"))
 
313
        unpuser = opt_arg(opt, "user");
 
314
    else
 
315
        unpuser = cfgopt(copt, "DatabaseOwner")->strarg;
295
316
 
296
317
    if(!geteuid()) {
297
 
        if((user = getpwnam(dbowner)) == NULL) {
298
 
            logg("^Can't get information about user %s.\n", dbowner);
299
 
            optfree(opts);
 
318
        if((user = getpwnam(unpuser)) == NULL) {
 
319
            logg("^Can't get information about user %s.\n", unpuser);
 
320
            opt_free(opt);
300
321
            return 60;
301
322
        }
302
323
 
303
 
        if(optget(opts, "AllowSupplementaryGroups")->enabled) {
 
324
        if(cfgopt(copt, "AllowSupplementaryGroups")->enabled) {
304
325
#ifdef HAVE_INITGROUPS
305
 
            if(initgroups(dbowner, user->pw_gid)) {
 
326
            if(initgroups(unpuser, user->pw_gid)) {
306
327
                logg("^initgroups() failed.\n");
307
 
                optfree(opts);
 
328
                opt_free(opt);
308
329
                return 61;
309
330
            }
310
331
#endif
312
333
#ifdef HAVE_SETGROUPS
313
334
            if(setgroups(1, &user->pw_gid)) {
314
335
                logg("^setgroups() failed.\n");
315
 
                optfree(opts);
 
336
                opt_free(opt);
316
337
                return 61;
317
338
            }
318
339
#endif
320
341
 
321
342
        if(setgid(user->pw_gid)) {
322
343
            logg("^setgid(%d) failed.\n", (int) user->pw_gid);
323
 
            optfree(opts);
 
344
            opt_free(opt);
324
345
            return 61;
325
346
        }
326
347
 
327
348
        if(setuid(user->pw_uid)) {
328
349
            logg("^setuid(%d) failed.\n", (int) user->pw_uid);
329
 
            optfree(opts);
 
350
            opt_free(opt);
330
351
            return 61;
331
352
        }
332
353
    }
333
 
#endif /* HAVE_PWD_H */
 
354
#endif
334
355
 
335
356
    /* initialize some important variables */
336
357
 
337
 
    if(optget(opts, "Debug")->enabled || optget(opts, "debug")->enabled)
 
358
    if(opt_check(opt, "debug") || cfgopt(copt, "Debug")->enabled)
338
359
        cl_debug();
339
360
 
340
 
    if(optget(opts, "verbose")->enabled)
 
361
    if(opt_check(opt, "verbose"))
341
362
        mprintf_verbose = 1;
342
363
 
343
 
    if(optget(opts, "quiet")->enabled)
 
364
    if(opt_check(opt, "quiet"))
344
365
        mprintf_quiet = 1;
345
366
 
346
 
    if(optget(opts, "no-warnings")->enabled) {
347
 
        mprintf_nowarn = 1;
348
 
        logg_nowarn = 1;
349
 
    }
350
 
 
351
 
    if(optget(opts, "stdout")->enabled)
 
367
    if(opt_check(opt, "stdout"))
352
368
        mprintf_stdout = 1;
353
369
 
354
370
    /* initialize logger */
355
 
    logg_verbose = mprintf_verbose ? 1 : optget(opts, "LogVerbose")->enabled;
356
 
    logg_time = optget(opts, "LogTime")->enabled;
357
 
    logg_size = optget(opts, "LogFileMaxSize")->numarg;
358
 
 
359
 
    if((opt = optget(opts, "UpdateLogFile"))->enabled) {
360
 
        logg_file = opt->strarg; 
 
371
 
 
372
    if(cfgopt(copt, "LogVerbose")->enabled)
 
373
        logg_verbose = 1;
 
374
 
 
375
    if(opt_check(opt, "log")) {
 
376
        logg_file = opt_arg(opt, "log");
 
377
        if(logg("#--------------------------------------\n")) {
 
378
            mprintf("!Problem with internal logger (--log=%s).\n", logg_file);
 
379
            opt_free(opt);
 
380
            return 62;
 
381
        }
 
382
    } else if((cpt = cfgopt(copt, "UpdateLogFile"))->enabled) {
 
383
        logg_file = cpt->strarg; 
361
384
        if(logg("#--------------------------------------\n")) {
362
385
            mprintf("!Problem with internal logger (UpdateLogFile = %s).\n", logg_file);
363
 
            optfree(opts);
 
386
            opt_free(opt);
364
387
            return 62;
365
388
        }
366
389
    } else
367
390
        logg_file = NULL;
368
391
 
369
392
#if defined(USE_SYSLOG) && !defined(C_AIX)
370
 
    if(optget(opts, "LogSyslog")->enabled) {
 
393
    if(cfgopt(copt, "LogSyslog")->enabled) {
371
394
            int fac = LOG_LOCAL6;
372
395
 
373
 
        if((opt = optget(opts, "LogFacility"))->enabled) {
374
 
            if((fac = logg_facility(opt->strarg)) == -1) {
375
 
                mprintf("!LogFacility: %s: No such facility.\n", opt->strarg);
376
 
                optfree(opts);
 
396
        if((cpt = cfgopt(copt, "LogFacility"))->enabled) {
 
397
            if((fac = logg_facility(cpt->strarg)) == -1) {
 
398
                mprintf("!LogFacility: %s: No such facility.\n", cpt->strarg);
 
399
                opt_free(opt);
377
400
                return 62;
378
401
            }
379
402
        }
383
406
    }
384
407
#endif
385
408
 
386
 
    cl_set_clcb_msg(msg_callback);
387
409
    /* change the current working directory */
388
 
    if(chdir(optget(opts, "DatabaseDirectory")->strarg)) {
389
 
        logg("!Can't change dir to %s\n", optget(opts, "DatabaseDirectory")->strarg);
390
 
        optfree(opts);
 
410
    if(opt_check(opt, "datadir"))
 
411
        newdir = opt_arg(opt, "datadir");
 
412
    else
 
413
        newdir = cfgopt(copt, "DatabaseDirectory")->strarg;
 
414
 
 
415
    if(chdir(newdir)) {
 
416
        logg("Can't change dir to %s\n", newdir);
 
417
        opt_free(opt);
391
418
        return 50;
392
 
    } else {
393
 
        if(!getcwd(dbdir, sizeof(dbdir))) {
394
 
            logg("!getcwd() failed\n");
395
 
            optfree(opts);
396
 
            return 50;
397
 
        }
398
 
        logg("*Current working dir is %s\n", dbdir);
399
 
    }
400
 
 
401
 
 
402
 
    if(optget(opts, "list-mirrors")->enabled) {
 
419
    } else
 
420
        logg("*Current working dir is %s\n", newdir);
 
421
 
 
422
 
 
423
    if(opt_check(opt, "list-mirrors")) {
403
424
        if(mirman_read("mirrors.dat", &mdat, 1) == -1) {
404
425
            printf("Can't read mirrors.dat\n");
405
 
            optfree(opts);
406
426
            return 55;
407
427
        }
408
428
        mirman_list(&mdat);
409
429
        mirman_free(&mdat);
410
 
        optfree(opts);
411
430
        return 0;
412
431
    }
413
432
 
414
 
    *updtmpdir = 0;
 
433
#ifdef  C_WINDOWS
 
434
    {
 
435
            WSADATA wsaData;
415
436
 
416
 
#ifdef _WIN32
417
 
    signal(SIGINT, sighandler);
418
 
#else
419
 
    memset(&sigact, 0, sizeof(struct sigaction));
420
 
    sigact.sa_handler = sighandler;
421
 
    sigaction(SIGINT, &sigact, NULL);
422
 
    sigaction(SIGPIPE, &sigact, NULL);
 
437
        if(WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR) {
 
438
            logg("!Error at WSAStartup(): %d\n", WSAGetLastError());
 
439
            return 1;
 
440
        }
 
441
    }
423
442
#endif
424
 
    if(optget(opts, "daemon")->enabled) {
 
443
 
 
444
    if(opt_check(opt, "daemon")) {
425
445
            int bigsleep, checks;
426
 
#ifndef _WIN32
 
446
#ifndef C_WINDOWS
427
447
            time_t now, wakeup;
428
448
 
429
 
        sigaction(SIGTERM, &sigact, NULL);
430
 
        sigaction(SIGHUP, &sigact, NULL);
431
 
        sigaction(SIGCHLD, &sigact, NULL);
 
449
        memset(&sigact, 0, sizeof(struct sigaction));
 
450
        sigact.sa_handler = daemon_sighandler;
432
451
#endif
433
452
 
434
 
        checks = optget(opts, "Checks")->numarg;
 
453
        if(opt_check(opt, "checks"))
 
454
            checks = atoi(opt_arg(opt, "checks"));
 
455
        else
 
456
            checks = cfgopt(copt, "Checks")->numarg;
435
457
 
436
458
        if(checks <= 0) {
437
459
            logg("^Number of checks must be a positive integer.\n");
438
 
            optfree(opts);
 
460
            opt_free(opt);
439
461
            return 41;
440
462
        }
441
463
 
442
 
        if(!optget(opts, "DNSDatabaseInfo")->enabled || optget(opts, "no-dns")->enabled) {
 
464
        if(!cfgopt(copt, "DNSDatabaseInfo")->enabled || opt_check(opt, "no-dns")) {
443
465
            if(checks > 50) {
444
466
                logg("^Number of checks must be between 1 and 50.\n");
445
 
                optfree(opts);
 
467
                opt_free(opt);
446
468
                return 41;
447
469
            }
448
470
        }
449
471
 
450
472
        bigsleep = 24 * 3600 / checks;
451
473
 
452
 
#ifndef _WIN32
453
 
        if(!optget(opts, "Foreground")->enabled) {
454
 
            if(daemonize() == -1) {
455
 
                logg("!daemonize() failed\n");
456
 
                optfree(opts);
457
 
                return 70; /* FIXME */
458
 
            }
 
474
        if(!cfgopt(copt, "Foreground")->enabled) {
459
475
            foreground = 0;
 
476
            daemonize();
460
477
            mprintf_disabled = 1;
461
478
        }
462
 
#endif
463
479
 
464
 
        if((opt = optget(opts, "PidFile"))->enabled) {
465
 
            pidfile = opt->strarg;
 
480
        if(opt_check(opt, "pid")) {
 
481
            pidfile = opt_arg(opt, "pid");
 
482
        } else if ((cpt = cfgopt(copt, "PidFile"))->enabled) {
 
483
            pidfile = cpt->strarg;
 
484
        }
 
485
        if (pidfile) {
466
486
            writepid(pidfile);
467
487
        }
468
488
 
469
489
        active_children = 0;
470
490
 
471
 
        logg("#freshclam daemon %s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")\n", get_version());
 
491
        logg("#freshclam daemon "VERSION" (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")\n");
 
492
 
 
493
#ifdef  C_WINDOWS
 
494
        signal(SIGINT, daemon_sighandler);
 
495
        terminate = 0;
 
496
#else
 
497
        sigaction(SIGTERM, &sigact, NULL);
 
498
        sigaction(SIGHUP, &sigact, NULL);
 
499
        sigaction(SIGINT, &sigact, NULL);
 
500
        sigaction(SIGCHLD, &sigact, NULL);
 
501
#endif
472
502
 
473
503
        while(!terminate) {
474
 
            ret = download(opts, cfgfile);
475
 
 
476
 
            if(ret <= 1) {
477
 
                if((opt = optget(opts, "SubmitDetectionStats"))->enabled)
478
 
                    submitstats(opt->strarg, opts);
479
 
            } else  {
480
 
                if((opt = optget(opts, "OnErrorExecute"))->enabled)
481
 
                    arg = opt->strarg;
 
504
            ret = download(copt, opt, newdir);
 
505
 
 
506
            if(ret > 1) {
 
507
                    const char *arg = NULL;
 
508
 
 
509
                if(opt_check(opt, "on-error-execute"))
 
510
                    arg = opt_arg(opt, "on-error-execute");
 
511
                else if((cpt = cfgopt(copt, "OnErrorExecute"))->enabled)
 
512
                    arg = cpt->strarg;
482
513
 
483
514
                if(arg)
484
 
                    execute("OnErrorExecute", arg, opts);
485
 
 
486
 
                arg = NULL;
 
515
                    execute("OnErrorExecute", arg);
487
516
            }
488
517
 
489
518
            logg("#--------------------------------------\n");
494
523
            sigaction(SIGUSR1, &sigact, &oldact);
495
524
#endif
496
525
 
497
 
#ifdef  _WIN32
 
526
#ifdef  C_WINDOWS
498
527
            sleep(bigsleep);
499
528
#else   
500
529
            time(&wakeup);
523
552
#endif      
524
553
        }
525
554
 
526
 
    } else {
527
 
        if((opt = optget(opts, "submit-stats"))->active) {
528
 
            if(!optget(opts, "no-warnings")->enabled)
529
 
                logg(" *** Virus databases are not updated in this mode ***\n");
530
 
            ret = submitstats(opt->strarg, opts);
531
 
        } else {
532
 
            ret = download(opts, cfgfile);
533
 
 
534
 
            if((opt = optget(opts, "SubmitDetectionStats"))->enabled)
535
 
                submitstats(opt->strarg, opts);
536
 
        }
537
 
    }
538
 
 
539
 
    if(ret > 1) {
540
 
        if((opt = optget(opts, "OnErrorExecute"))->enabled)
541
 
            execute("OnErrorExecute", opt->strarg, opts);
542
 
    }
543
 
 
 
555
    } else
 
556
        ret = download(copt, opt, newdir);
 
557
 
 
558
    if(opt_check(opt, "on-error-execute")) {
 
559
        if(ret > 1)
 
560
            system(opt_arg(opt, "on-error-execute"));
 
561
 
 
562
    } else if((cpt = cfgopt(copt, "OnErrorExecute"))->enabled) {
 
563
        if(ret > 1)
 
564
            system(cpt->strarg);
 
565
    }
544
566
    if (pidfile) {
545
567
        unlink(pidfile);
546
568
    }
547
569
 
548
 
    optfree(opts);
 
570
    opt_free(opt);
 
571
 
 
572
#ifdef C_WINDOWS
 
573
    WSACleanup();
 
574
 
 
575
    if(!pthread_win32_process_detach_np()) {
 
576
        mprintf("!Can't stop the win32 pthreads layer\n");
 
577
        return 63;
 
578
    }
 
579
#endif
549
580
 
550
581
    return(ret);
551
582
}