Browse code

clamscan: properly report errors from libclamav; simplify error codes

Tomasz Kojm authored on 2010/02/05 05:33:03
Showing 6 changed files
... ...
@@ -1,3 +1,8 @@
1
+Thu Feb  4 21:31:27 CET 2010 (tk)
2
+---------------------------------
3
+ * clamscan: properly report errors from libclamav; simplify
4
+	     error codes
5
+
1 6
 Wed Feb  3 18:23:08 CET 2010 (tk)
2 7
 ---------------------------------
3 8
  * clamdscan: fix error logic once again
... ...
@@ -145,7 +145,7 @@ int main(int argc, char **argv)
145 145
 	logg("\n----------- SCAN SUMMARY -----------\n");
146 146
 	logg("Infected files: %d\n", infected);
147 147
 	if(err)
148
-	    logg("Errors: %d\n", err);
148
+	    logg("Total errors: %d\n", err);
149 149
 	if(notremoved) {
150 150
 	    logg("Not removed: %d\n", notremoved);
151 151
 	}
... ...
@@ -75,7 +75,7 @@ int main(int argc, char **argv)
75 75
 
76 76
     if((opts = optparse(NULL, argc, argv, 1, OPT_CLAMSCAN, 0, NULL)) == NULL) {
77 77
 	mprintf("!Can't parse command line options\n");
78
-	return 40;
78
+	return 2;
79 79
     }
80 80
 
81 81
     if(optget(opts, "verbose")->enabled) {
... ...
@@ -129,7 +129,7 @@ int main(int argc, char **argv)
129 129
 	if(logg("#\n-------------------------------------------------------------------------------\n\n")) {
130 130
 	    mprintf("!Problem with internal logger.\n");
131 131
 	    optfree(opts);
132
-	    return 62;
132
+	    return 2;
133 133
 	}
134 134
     } else 
135 135
 	logg_file = NULL;
... ...
@@ -159,6 +159,8 @@ int main(int argc, char **argv)
159 159
 	logg("Scanned directories: %u\n", info.dirs);
160 160
 	logg("Scanned files: %u\n", info.files);
161 161
 	logg("Infected files: %u\n", info.ifiles);
162
+	if(info.errors)
163
+	    logg("Total errors: %u\n", info.errors);
162 164
 	if(notremoved) {
163 165
 	    logg("Not removed: %u\n", notremoved);
164 166
 	}
... ...
@@ -26,6 +26,7 @@ struct s_info {
26 26
     unsigned int dirs;		/* number of scanned directories */
27 27
     unsigned int files;		/* number of scanned files */
28 28
     unsigned int ifiles;	/* number of infected files */
29
+    unsigned int errors;	/* number of errors */
29 30
     unsigned long int blocks;	/* number of *scanned* 16kb blocks */
30 31
     unsigned long int rblocks;	/* number of *read* 16kb blocks */
31 32
 };
... ...
@@ -64,10 +64,10 @@
64 64
 dev_t procdev;
65 65
 #endif
66 66
 
67
-static int scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, unsigned int options)
67
+void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, unsigned int options)
68 68
 {
69
-  int ret = 0, fd, included, printclean = 1;
70
-  unsigned int fsize;
69
+	int ret = 0, fd, included, printclean = 1;
70
+	unsigned int fsize;
71 71
 	const struct optstruct *opt;
72 72
 	const char *virname;
73 73
 #ifdef C_LINUX
... ...
@@ -79,7 +79,7 @@ static int scanfile(const char *filename, struct cl_engine *engine, const struct
79 79
 	    if(sb.st_dev == procdev) {
80 80
 		if(!printinfected)
81 81
 		    logg("~%s: Excluded (/proc)\n", filename);
82
-		return 0;
82
+		return;
83 83
 	    }
84 84
 #endif    
85 85
 
... ...
@@ -88,7 +88,7 @@ static int scanfile(const char *filename, struct cl_engine *engine, const struct
88 88
 	    if(match_regex(filename, opt->strarg) == 1) {
89 89
 		if(!printinfected)
90 90
 		    logg("~%s: Excluded\n", filename);
91
-		return 0;
91
+		return;
92 92
 	    }
93 93
 	    opt = opt->nextarg;
94 94
 	}
... ...
@@ -106,7 +106,7 @@ static int scanfile(const char *filename, struct cl_engine *engine, const struct
106 106
 	if(!included) {
107 107
 	    if(!printinfected)
108 108
 		logg("~%s: Excluded\n", filename);
109
-	    return 0;
109
+	    return;
110 110
 	}
111 111
     }
112 112
 
... ...
@@ -114,7 +114,7 @@ static int scanfile(const char *filename, struct cl_engine *engine, const struct
114 114
     if(fsize == 0) {
115 115
 	if(!printinfected)
116 116
 	    logg("~%s: Empty file\n", filename);
117
-	return 0;
117
+	return;
118 118
     }
119 119
     info.rblocks += fsize / CL_COUNT_PRECISION;
120 120
 #ifndef _WIN32
... ...
@@ -122,7 +122,8 @@ static int scanfile(const char *filename, struct cl_engine *engine, const struct
122 122
 	if(checkaccess(filename, NULL, R_OK) != 1) {
123 123
 	    if(!printinfected)
124 124
 		logg("~%s: Access denied\n", filename);
125
-	    return 0;
125
+	    info.errors++;
126
+	    return;
126 127
 	}
127 128
 #endif
128 129
 
... ...
@@ -130,13 +131,13 @@ static int scanfile(const char *filename, struct cl_engine *engine, const struct
130 130
 
131 131
     if((fd = safe_open(filename, O_RDONLY|O_BINARY)) == -1) {
132 132
 	logg("^Can't open file %s: %s\n", filename, strerror(errno));
133
-	return 54;
133
+	info.errors++;
134
+	return;
134 135
     }
135 136
 
136
-    info.files++;
137
-
138 137
     if((ret = cl_scandesc(fd, &virname, &info.blocks, engine, options)) == CL_VIRUS) {
139 138
 	logg("~%s: %s FOUND\n", filename, virname);
139
+	info.files++;
140 140
 	info.ifiles++;
141 141
 
142 142
 	if(bell)
... ...
@@ -145,25 +146,26 @@ static int scanfile(const char *filename, struct cl_engine *engine, const struct
145 145
     } else if(ret == CL_CLEAN) {
146 146
 	if(!printinfected && printclean)
147 147
 	    mprintf("~%s: OK\n", filename);
148
-    } else
148
+	info.files++;
149
+    } else {
149 150
 	if(!printinfected)
150 151
 	    logg("~%s: %s ERROR\n", filename, cl_strerror(ret));
152
+	info.errors++;
153
+    }
151 154
 
152 155
     close(fd);
153 156
 
154 157
     if(ret == CL_VIRUS && action)
155 158
 	action(filename);
156
-
157
-    return ret;
158 159
 }
159 160
 
160
-static int scandirs(const char *dirname, struct cl_engine *engine, const struct optstruct *opts, unsigned int options, unsigned int depth, dev_t dev)
161
+void scandirs(const char *dirname, struct cl_engine *engine, const struct optstruct *opts, unsigned int options, unsigned int depth, dev_t dev)
161 162
 {
162 163
 	DIR *dd;
163 164
 	struct dirent *dent;
164 165
 	struct stat statbuf;
165 166
 	char *fname;
166
-	int scanret = 0, included;
167
+	int included;
167 168
 	const struct optstruct *opt;
168 169
 
169 170
 
... ...
@@ -172,7 +174,7 @@ static int scandirs(const char *dirname, struct cl_engine *engine, const struct
172 172
 	    if(match_regex(dirname, opt->strarg) == 1) {
173 173
 		if(!printinfected)
174 174
 		    logg("~%s: Excluded\n", dirname);
175
-		return 0;
175
+		return;
176 176
 	    }
177 177
 	    opt = opt->nextarg;
178 178
 	}
... ...
@@ -190,17 +192,16 @@ static int scandirs(const char *dirname, struct cl_engine *engine, const struct
190 190
 	if(!included) {
191 191
 	    if(!printinfected)
192 192
 		logg("~%s: Excluded\n", dirname);
193
-	    return 0;
193
+	    return;
194 194
 	}
195 195
     }
196 196
 
197 197
     if(depth > (unsigned int) optget(opts, "max-dir-recursion")->numarg)
198
-	return 0;
199
-
200
-    info.dirs++;
201
-    depth++;
198
+	return;
202 199
 
203 200
     if((dd = opendir(dirname)) != NULL) {
201
+	info.dirs++;
202
+	depth++;
204 203
 	while((dent = readdir(dd))) {
205 204
 	    if(dent->d_ino)
206 205
 	    {
... ...
@@ -222,13 +223,10 @@ static int scandirs(const char *dirname, struct cl_engine *engine, const struct
222 222
 				continue;
223 223
 			    }
224 224
 			}
225
-			if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode) && recursion) {
226
-			    if(scandirs(fname, engine, opts, options, depth, dev) == 1)
227
-				scanret++;
228
-			} else {
229
-			    if(S_ISREG(statbuf.st_mode))
230
-				scanret += scanfile(fname, engine, opts, options);
231
-			}
225
+			if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode) && recursion)
226
+			    scandirs(fname, engine, opts, options, depth, dev);
227
+			else if(S_ISREG(statbuf.st_mode))
228
+			    scanfile(fname, engine, opts, options);
232 229
 		    }
233 230
 		    free(fname);
234 231
 		}
... ...
@@ -237,16 +235,10 @@ static int scandirs(const char *dirname, struct cl_engine *engine, const struct
237 237
     } else {
238 238
 	if(!printinfected)
239 239
 	    logg("~%s: Can't open directory.\n", dirname);
240
-	return 53;
240
+	info.errors++;
241 241
     }
242 242
 
243 243
     closedir(dd);
244
-
245
-    if(scanret)
246
-	return 1;
247
-    else
248
-	return 0;
249
-
250 244
 }
251 245
 
252 246
 static int scanstdin(const struct cl_engine *engine, const struct optstruct *opts, int options)
... ...
@@ -266,7 +258,7 @@ static int scanstdin(const struct cl_engine *engine, const struct optstruct *opt
266 266
 
267 267
     if(checkaccess(tmpdir, CLAMAVUSER, W_OK) != 1) {
268 268
 	logg("!Can't write to temporary directory\n");
269
-	return 64;
269
+	return 2;
270 270
     }
271 271
 
272 272
     file = cli_gentemp(tmpdir);
... ...
@@ -274,7 +266,7 @@ static int scanstdin(const struct cl_engine *engine, const struct optstruct *opt
274 274
     if(!(fs = fopen(file, "wb"))) {
275 275
 	logg("!Can't open %s for writing\n", file);
276 276
 	free(file);
277
-	return 63;
277
+	return 2;
278 278
     }
279 279
 
280 280
     while((bread = fread(buff, 1, FILEBUFF, stdin))) {
... ...
@@ -282,7 +274,7 @@ static int scanstdin(const struct cl_engine *engine, const struct optstruct *opt
282 282
 	if(fwrite(buff, 1, bread, fs) < bread) {
283 283
 	    logg("!Can't write to %s\n", file);
284 284
 	    free(file);
285
-	    return 58;
285
+	    return 2;
286 286
 	}
287 287
     }
288 288
     fclose(fs);
... ...
@@ -338,12 +330,12 @@ int scanmanager(const struct optstruct *opts)
338 338
 
339 339
     if((ret = cl_init(CL_INIT_DEFAULT))) {
340 340
 	logg("!Can't initialize libclamav: %s\n", cl_strerror(ret));
341
-	return 50;
341
+	return 2;
342 342
     }
343 343
 
344 344
     if(!(engine = cl_engine_new())) {
345 345
 	logg("!Can't initialize antivirus engine\n");
346
-	return 50;
346
+	return 2;
347 347
     }
348 348
 
349 349
     if(optget(opts, "detect-pua")->enabled) {
... ...
@@ -355,7 +347,7 @@ int scanmanager(const struct optstruct *opts)
355 355
 		if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) {
356 356
 		    logg("!Can't allocate memory for pua_cats\n");
357 357
 		    cl_engine_free(engine);
358
-		    return 70;
358
+		    return 2;
359 359
 		}
360 360
 		sprintf(pua_cats + i, ".%s", opt->strarg);
361 361
 		i += strlen(opt->strarg) + 1;
... ...
@@ -371,14 +363,14 @@ int scanmanager(const struct optstruct *opts)
371 371
 		logg("!--exclude-pua and --include-pua cannot be used at the same time\n");
372 372
 		cl_engine_free(engine);
373 373
 		free(pua_cats);
374
-		return 40;
374
+		return 2;
375 375
 	    }
376 376
 	    dboptions |= CL_DB_PUA_INCLUDE;
377 377
 	    i = 0;
378 378
 	    while(opt) {
379 379
 		if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) {
380 380
 		    logg("!Can't allocate memory for pua_cats\n");
381
-		    return 70;
381
+		    return 2;
382 382
 		}
383 383
 		sprintf(pua_cats + i, ".%s", opt->strarg);
384 384
 		i += strlen(opt->strarg) + 1;
... ...
@@ -394,7 +386,7 @@ int scanmanager(const struct optstruct *opts)
394 394
 		logg("!cli_engine_set_str(CL_ENGINE_PUA_CATEGORIES) failed: %s\n", cl_strerror(ret));
395 395
 		free(pua_cats);
396 396
 		cl_engine_free(engine);
397
-		return 50;
397
+		return 2;
398 398
 	    }
399 399
 	    free(pua_cats);
400 400
 	}
... ...
@@ -413,7 +405,7 @@ int scanmanager(const struct optstruct *opts)
413 413
 	if((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, opt->strarg))) {
414 414
 	    logg("!cli_engine_set_str(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret));
415 415
 	    cl_engine_free(engine);
416
-	    return 50;
416
+	    return 2;
417 417
 	}
418 418
     }
419 419
 
... ...
@@ -421,7 +413,7 @@ int scanmanager(const struct optstruct *opts)
421 421
 	if((ret = cl_load(opt->strarg, engine, &info.sigs, dboptions))) {
422 422
 	    logg("!%s\n", cl_strerror(ret));
423 423
 	    cl_engine_free(engine);
424
-	    return 50;
424
+	    return 2;
425 425
 	}
426 426
 
427 427
     } else {
... ...
@@ -431,7 +423,7 @@ int scanmanager(const struct optstruct *opts)
431 431
 	    logg("!%s\n", cl_strerror(ret));
432 432
 	    free(dbdir);
433 433
 	    cl_engine_free(engine);
434
-	    return 50;
434
+	    return 2;
435 435
 	}
436 436
 	free(dbdir);
437 437
     }
... ...
@@ -439,7 +431,7 @@ int scanmanager(const struct optstruct *opts)
439 439
     if((ret = cl_engine_compile(engine)) != 0) {
440 440
 	logg("!Database initialization error: %s\n", cl_strerror(ret));;
441 441
 	cl_engine_free(engine);
442
-	return 50;
442
+	return 2;
443 443
     }
444 444
 
445 445
     /* set limits */
... ...
@@ -448,7 +440,7 @@ int scanmanager(const struct optstruct *opts)
448 448
 	if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_SCANSIZE, opt->numarg))) {
449 449
 	    logg("!cli_engine_set_num(CL_ENGINE_MAX_SCANSIZE) failed: %s\n", cl_strerror(ret));
450 450
 	    cl_engine_free(engine);
451
-	    return 50;
451
+	    return 2;
452 452
 	}
453 453
     }
454 454
 
... ...
@@ -456,7 +448,7 @@ int scanmanager(const struct optstruct *opts)
456 456
 	if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_FILESIZE, opt->numarg))) {
457 457
 	    logg("!cli_engine_set_num(CL_ENGINE_MAX_FILESIZE) failed: %s\n", cl_strerror(ret));
458 458
 	    cl_engine_free(engine);
459
-	    return 50;
459
+	    return 2;
460 460
 	}
461 461
     }
462 462
 
... ...
@@ -475,7 +467,7 @@ int scanmanager(const struct optstruct *opts)
475 475
 	if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_FILES, opt->numarg))) {
476 476
 	    logg("!cli_engine_set_num(CL_ENGINE_MAX_FILES) failed: %s\n", cl_strerror(ret));
477 477
 	    cl_engine_free(engine);
478
-	    return 50;
478
+	    return 2;
479 479
 	}
480 480
     }
481 481
 
... ...
@@ -483,7 +475,7 @@ int scanmanager(const struct optstruct *opts)
483 483
 	if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_RECURSION, opt->numarg))) {
484 484
 	    logg("!cli_engine_set_num(CL_ENGINE_MAX_RECURSION) failed: %s\n", cl_strerror(ret));
485 485
 	    cl_engine_free(engine);
486
-	    return 50;
486
+	    return 2;
487 487
 	}
488 488
     }
489 489
 
... ...
@@ -543,7 +535,7 @@ int scanmanager(const struct optstruct *opts)
543 543
 		    break;
544 544
 		default:
545 545
 		    logg("!Invalid argument for --structured-ssn-format\n");
546
-		    return 40;
546
+		    return 2;
547 547
 	    }
548 548
 	} else {
549 549
 	    options |= CL_SCAN_STRUCTURED_SSN_NORMAL;
... ...
@@ -553,7 +545,7 @@ int scanmanager(const struct optstruct *opts)
553 553
 	    if((ret = cl_engine_set_num(engine, CL_ENGINE_MIN_SSN_COUNT, opt->numarg))) {
554 554
 		logg("!cli_engine_set_num(CL_ENGINE_MIN_SSN_COUNT) failed: %s\n", cl_strerror(ret));
555 555
 		cl_engine_free(engine);
556
-		return 50;
556
+		return 2;
557 557
 	    }
558 558
 	}
559 559
 
... ...
@@ -561,7 +553,7 @@ int scanmanager(const struct optstruct *opts)
561 561
 	    if((ret = cl_engine_set_num(engine, CL_ENGINE_MIN_CC_COUNT, opt->numarg))) {
562 562
 		logg("!cli_engine_set_num(CL_ENGINE_MIN_CC_COUNT) failed: %s\n", cl_strerror(ret));
563 563
 		cl_engine_free(engine);
564
-		return 50;
564
+		return 2;
565 565
 	    }
566 566
 	}
567 567
 
... ...
@@ -580,10 +572,10 @@ int scanmanager(const struct optstruct *opts)
580 580
 	/* we need full path for some reasons (eg. archive handling) */
581 581
 	if(!getcwd(cwd, sizeof(cwd))) {
582 582
 	    logg("!Can't get absolute pathname of current working directory\n");
583
-	    ret = 57;
583
+	    ret = 2;
584 584
 	} else {
585 585
 	    stat(cwd, &sb);
586
-	    ret = scandirs(cwd, engine, opts, options, 1, sb.st_dev);
586
+	    scandirs(cwd, engine, opts, options, 1, sb.st_dev);
587 587
 	}
588 588
 
589 589
     } else if(opts->filename && !optget(opts, "file-list")->enabled && !strcmp(opts->filename[0], "-")) { /* read data from stdin */
... ...
@@ -597,7 +589,7 @@ int scanmanager(const struct optstruct *opts)
597 597
 	    if((fmodeint = fileinfo(file, 2)) == -1) {
598 598
 		logg("^Can't access file %s\n", file);
599 599
 		perror(file);
600
-		ret = 56;
600
+		ret = 2;
601 601
 	    } else {
602 602
 		for(i = strlen(file) - 1; i > 0; i--) {
603 603
 		    if(file[i] == *PATHSEP)
... ...
@@ -610,17 +602,17 @@ int scanmanager(const struct optstruct *opts)
610 610
 
611 611
 		switch(fmode & S_IFMT) {
612 612
 		    case S_IFREG:
613
-			ret = scanfile(file, engine, opts, options);
613
+			scanfile(file, engine, opts, options);
614 614
 			break;
615 615
 
616 616
 		    case S_IFDIR:
617 617
 			stat(file, &sb);
618
-			ret = scandirs(file, engine, opts, options, 1, sb.st_dev);
618
+			scandirs(file, engine, opts, options, 1, sb.st_dev);
619 619
 			break;
620 620
 
621 621
 		    default:
622 622
 			logg("!Not supported file type (%s)\n", file);
623
-			ret = 52;
623
+			ret = 2;
624 624
 		}
625 625
 	    }
626 626
 	    free(file);
... ...
@@ -630,11 +622,11 @@ int scanmanager(const struct optstruct *opts)
630 630
     /* free the engine */
631 631
     cl_engine_free(engine);
632 632
 
633
-    /* overwrite return code */
633
+    /* overwrite return code - infection takes priority */
634 634
     if(info.ifiles)
635 635
 	ret = 1;
636
-    else if(ret < 50) /* hopefully no error detected */ 
637
-	ret = 0; /* just make sure it's 0 */
636
+    else if(info.errors)
637
+	ret = 2;
638 638
 
639 639
     return ret;
640 640
 }
... ...
@@ -186,39 +186,11 @@ Maximum depth directories are scanned at (default: 15).
186 186
 \fBclamscan \-r /var/spool/mail\fR
187 187
 .SH "RETURN CODES"
188 188
 .LP 
189
-Note: some return codes may only appear in a single file mode (when clamscan is started with a single argument). Those are marked with \fB(ofm)\fR.
190
-
191 189
 0 : No virus found.
192 190
 .TP 
193 191
 1 : Virus(es) found.
194 192
 .TP 
195
-40: Unknown option passed.
196
-.TP 
197
-50: Database initialization error.
198
-.TP 
199
-52: Not supported file type.
200
-.TP 
201
-53: Can't open directory.
202
-.TP 
203
-54: Can't open file. (ofm)
204
-.TP 
205
-55: Error reading file. (ofm)
206
-.TP 
207
-56: Can't stat input file / directory.
208
-.TP 
209
-57: Can't get absolute path name of current working directory.
210
-.TP 
211
-58: I/O error, please check your file system.
212
-.TP 
213
-62: Can't initialize logger.
214
-.TP 
215
-63: Can't create temporary files/directories (check permissions).
216
-.TP 
217
-64: Can't write to temporary directory (please specify another one).
218
-.TP 
219
-70: Can't allocate memory (calloc).
220
-.TP 
221
-71: Can't allocate memory (malloc).
193
+2 : Some error(s) occured.
222 194
 .SH "CREDITS"
223 195
 Please check the full documentation for credits.
224 196
 .SH "AUTHOR"