129
120
mprintf_stdout = 1;
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");
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");
144
133
mprintf(" --config-file=FILE read configuration from FILE.\n");
145
134
mprintf(" --log=FILE -l FILE log into FILE\n");
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");
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");
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)
169
155
int ret = 0, try = 0, maxattempts = 0;
170
const struct optstruct *opt;
173
maxattempts = optget(opts, "MaxAttempts")->numarg;
156
struct cfgstruct *cpt;
159
maxattempts = cfgopt(copt, "MaxAttempts")->numarg;
174
160
logg("*Max retries == %d\n", maxattempts);
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");
181
ret = downloadmanager(opts, opt->strarg, try == maxattempts - 1);
166
while(cli_writelockdb(datadir, 0) == CL_ELOCKDB) {
167
logg("*Waiting to lock database directory: %s\n", datadir);
170
logg("!Can't lock database directory: %s\n", datadir);
176
ret = downloadmanager(copt, opt, cpt->strarg);
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");
192
logg("Giving up on %s...\n", opt->strarg);
193
opt = (struct optstruct *) opt->nextarg;
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;
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");
195
cli_unlockdb(datadir);
199
cli_unlockdb(datadir);
209
void msg_callback(enum cl_msg severity, const char *fullmsg, const char *msg, void *ctx)
213
logg("^[LibClamAV] %s", msg);
216
logg("~[LibClamAV] %s", msg);
218
logg("*[LibClamAV] %s", msg);
223
205
int main(int argc, char **argv)
226
const char *cfgfile, *arg = NULL, *pidfile = NULL;
228
struct optstruct *opts;
229
const struct optstruct *opt;
208
const char *newdir, *cfgfile;
209
char *pidfile = NULL;
210
struct cfgstruct *copt, *cpt;
231
212
struct sigaction sigact;
232
213
struct sigaction oldact;
215
#if !defined(C_CYGWIN) && !defined(C_OS2) && !defined(C_WINDOWS)
236
217
struct passwd *user;
238
219
struct stat statbuf;
239
220
struct mirdat mdat;
244
if((retcl = cl_init(CL_INIT_DEFAULT))) {
245
mprintf("!Can't initialize libclamav: %s\n", cl_strerror(retcl));
249
if((opts = optparse(NULL, argc, argv, 1, OPT_FRESHCLAM, 0, NULL)) == NULL) {
250
mprintf("!Can't parse command line options\n");
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[] = {
226
{"verbose", 0, 0, 'v'},
228
{"version", 0, 0, 'V'},
229
{"datadir", 1, 0, 0},
231
{"log-verbose", 0, 0, 0}, /* not used */
233
{"daemon", 0, 0, 'd'},
235
{"user", 1, 0, 'u'}, /* not used */
236
{"config-file", 1, 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},
251
opt = opt_parse(argc, argv, short_options, long_options, NULL);
253
mprintf("!Can't parse the command line\n");
257
if(opt_check(opt, "help")) {
263
if(opt_check(opt, "version")) {
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);
270
if(optget(opts, "version")->enabled) {
271
print_version(optget(opts, "DatabaseDirectory")->strarg);
276
if(optget(opts, "HTTPProxyPassword")->enabled) {
270
if((cfgfile = opt_arg(opt, "config-file"))) {
271
copt = getcfg(cfgfile, 1);
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);
279
logg("!Can't parse the config file %s\n", cfgfile);
285
if(!pthread_win32_process_attach_np()) {
286
mprintf("!Can't start the win32 pthreads layer\n");
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");
294
if(cfgopt(copt, "HTTPProxyPassword")->enabled) {
277
295
if(stat(cfgfile, &statbuf) == -1) {
278
296
logg("^Can't stat %s (critical error)\n", cfgfile);
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);
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");
315
unpuser = cfgopt(copt, "DatabaseOwner")->strarg;
297
if((user = getpwnam(dbowner)) == NULL) {
298
logg("^Can't get information about user %s.\n", dbowner);
318
if((user = getpwnam(unpuser)) == NULL) {
319
logg("^Can't get information about user %s.\n", unpuser);
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");
321
342
if(setgid(user->pw_gid)) {
322
343
logg("^setgid(%d) failed.\n", (int) user->pw_gid);
327
348
if(setuid(user->pw_uid)) {
328
349
logg("^setuid(%d) failed.\n", (int) user->pw_uid);
333
#endif /* HAVE_PWD_H */
335
356
/* initialize some important variables */
337
if(optget(opts, "Debug")->enabled || optget(opts, "debug")->enabled)
358
if(opt_check(opt, "debug") || cfgopt(copt, "Debug")->enabled)
340
if(optget(opts, "verbose")->enabled)
361
if(opt_check(opt, "verbose"))
341
362
mprintf_verbose = 1;
343
if(optget(opts, "quiet")->enabled)
364
if(opt_check(opt, "quiet"))
344
365
mprintf_quiet = 1;
346
if(optget(opts, "no-warnings")->enabled) {
351
if(optget(opts, "stdout")->enabled)
367
if(opt_check(opt, "stdout"))
352
368
mprintf_stdout = 1;
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;
359
if((opt = optget(opts, "UpdateLogFile"))->enabled) {
360
logg_file = opt->strarg;
372
if(cfgopt(copt, "LogVerbose")->enabled)
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);
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);
367
390
logg_file = NULL;
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;
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);
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);
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);
410
if(opt_check(opt, "datadir"))
411
newdir = opt_arg(opt, "datadir");
413
newdir = cfgopt(copt, "DatabaseDirectory")->strarg;
416
logg("Can't change dir to %s\n", newdir);
393
if(!getcwd(dbdir, sizeof(dbdir))) {
394
logg("!getcwd() failed\n");
398
logg("*Current working dir is %s\n", dbdir);
402
if(optget(opts, "list-mirrors")->enabled) {
420
logg("*Current working dir is %s\n", newdir);
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");
408
428
mirman_list(&mdat);
409
429
mirman_free(&mdat);
417
signal(SIGINT, sighandler);
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());
424
if(optget(opts, "daemon")->enabled) {
444
if(opt_check(opt, "daemon")) {
425
445
int bigsleep, checks;
427
447
time_t now, wakeup;
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;
434
checks = optget(opts, "Checks")->numarg;
453
if(opt_check(opt, "checks"))
454
checks = atoi(opt_arg(opt, "checks"));
456
checks = cfgopt(copt, "Checks")->numarg;
436
458
if(checks <= 0) {
437
459
logg("^Number of checks must be a positive integer.\n");
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");
450
472
bigsleep = 24 * 3600 / checks;
453
if(!optget(opts, "Foreground")->enabled) {
454
if(daemonize() == -1) {
455
logg("!daemonize() failed\n");
457
return 70; /* FIXME */
474
if(!cfgopt(copt, "Foreground")->enabled) {
460
477
mprintf_disabled = 1;
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;
466
486
writepid(pidfile);
469
489
active_children = 0;
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");
494
signal(SIGINT, daemon_sighandler);
497
sigaction(SIGTERM, &sigact, NULL);
498
sigaction(SIGHUP, &sigact, NULL);
499
sigaction(SIGINT, &sigact, NULL);
500
sigaction(SIGCHLD, &sigact, NULL);
473
503
while(!terminate) {
474
ret = download(opts, cfgfile);
477
if((opt = optget(opts, "SubmitDetectionStats"))->enabled)
478
submitstats(opt->strarg, opts);
480
if((opt = optget(opts, "OnErrorExecute"))->enabled)
504
ret = download(copt, opt, newdir);
507
const char *arg = NULL;
509
if(opt_check(opt, "on-error-execute"))
510
arg = opt_arg(opt, "on-error-execute");
511
else if((cpt = cfgopt(copt, "OnErrorExecute"))->enabled)
484
execute("OnErrorExecute", arg, opts);
515
execute("OnErrorExecute", arg);
489
518
logg("#--------------------------------------\n");
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);
532
ret = download(opts, cfgfile);
534
if((opt = optget(opts, "SubmitDetectionStats"))->enabled)
535
submitstats(opt->strarg, opts);
540
if((opt = optget(opts, "OnErrorExecute"))->enabled)
541
execute("OnErrorExecute", opt->strarg, opts);
556
ret = download(copt, opt, newdir);
558
if(opt_check(opt, "on-error-execute")) {
560
system(opt_arg(opt, "on-error-execute"));
562
} else if((cpt = cfgopt(copt, "OnErrorExecute"))->enabled) {
575
if(!pthread_win32_process_detach_np()) {
576
mprintf("!Can't stop the win32 pthreads layer\n");