Browse code

refactor error handlers in clamdscan

git-svn: trunk@4907

aCaB authored on 2009/03/07 10:55:07
Showing 4 changed files
... ...
@@ -1,3 +1,7 @@
1
+Sat Mar  7 02:52:32 CET 2009 (acab)
2
+-----------------------------------
3
+ * clamdscan: refactor error handling
4
+
1 5
 Fri Mar  6 17:41:15 CET 2009 (tk)
2 6
 ---------------------------------
3 7
  * libclamav, sigtool: use .gdb extension for safebrowsing dbs
... ...
@@ -144,16 +144,16 @@ static char *makeabs(const char *basepath) {
144 144
 
145 145
 /* Recursively scans a path with the given scantype
146 146
  * Returns non zero for serious errors, zero otherwise */
147
-static int client_scan(const char *file, int scantype, int *infected, int *errors, int maxlevel, int session, int flags) {
147
+static int client_scan(const char *file, int scantype, int *infected, int maxlevel, int session, int flags) {
148 148
     int ret;
149 149
     char *fullpath = makeabs(file);
150 150
 
151 151
     if(!fullpath)
152 152
 	return 0;
153 153
     if (!session)
154
-	ret = serial_client_scan(fullpath, scantype, infected, errors, maxlevel, flags);
154
+	ret = serial_client_scan(fullpath, scantype, infected, maxlevel, flags);
155 155
     else
156
-	ret = parallel_client_scan(fullpath, scantype, infected, errors, maxlevel, flags);
156
+	ret = parallel_client_scan(fullpath, scantype, infected, maxlevel, flags);
157 157
     free(fullpath);
158 158
     return ret;
159 159
 }
... ...
@@ -260,19 +260,19 @@ int client(const struct optstruct *opts, int *infected)
260 260
 	if((sockd = dconnect()) >= 0 && (ret = dsresult(sockd, scantype, NULL)) >= 0)
261 261
 	    *infected = ret;
262 262
 	else
263
-	    errors++;
263
+	    errors = 1;
264 264
 	if(sockd >= 0) close(sockd);
265 265
     } else if(opts->filename) {
266 266
 	unsigned int i;
267
-	for (i = 0; opts->filename[i]; i++) {
267
+	for (i = 0; !errors && opts->filename[i]; i++) {
268 268
 	    if(!strcmp(opts->filename[i], "-")) {
269 269
 		logg("!Scanning from standard input requires \"-\" to be the only file argument\n");
270 270
 		continue;
271 271
 	    }
272
-	    if(client_scan(opts->filename[i], scantype, infected, &errors, maxrec, session, flags)) break;
272
+	    errors = client_scan(opts->filename[i], scantype, infected, maxrec, session, flags);
273 273
 	}
274 274
     } else {
275
-	client_scan("", scantype, infected, &errors, maxrec, session, flags);
275
+	errors = client_scan("", scantype, infected, maxrec, session, flags);
276 276
     }
277 277
     return *infected ? 1 : (errors ? 2 : 0);
278 278
 }
... ...
@@ -78,7 +78,7 @@ int sendln(int sockd, const char *line, unsigned int len) {
78 78
 	int sent = send(sockd, line, len, 0);
79 79
 	if(sent <= 0) {
80 80
 	    if(sent && errno == EINTR) continue;
81
-	    logg("!Can't send request to clamd: %s\n", strerror(errno));
81
+	    logg("!Can't send to clamd: %s\n", strerror(errno));
82 82
 	    return 1;
83 83
 	}
84 84
 	line += sent;
... ...
@@ -118,13 +118,10 @@ int recvln(struct RCVLN *s, char **rbol, char **reol) {
118 118
 		    *s->cur = '\0';
119 119
 		    if(strcmp(s->buf, "UNKNOWN COMMAND\n"))
120 120
 			logg("!Communication error\n");
121
-		    else {
121
+		    else
122 122
 			logg("!Command rejected by clamd (wrong clamd version?)\n");
123
-			exit(2);
124
-		    }
125 123
 		    return -1;
126 124
 		}
127
-		*rbol = NULL;
128 125
 	        return 0;
129 126
 	    }
130 127
 	}
... ...
@@ -177,7 +174,6 @@ static int send_stream(int sockd, const char *filename) {
177 177
 	if((unsigned int)len > todo) len = todo;
178 178
 	buf[0] = htonl(len);
179 179
 	if(sendln(sockd, (const char *)buf, len+sizeof(uint32_t))) {
180
-	    logg("!Can't write to the socket.\n");
181 180
 	    close(fd);
182 181
 	    return 1;
183 182
 	}
... ...
@@ -189,7 +185,7 @@ static int send_stream(int sockd, const char *filename) {
189 189
     }
190 190
     close(fd);
191 191
     if(len) {
192
-	logg("!Failed to read from %s.\n", filename);
192
+	logg("!Failed to read from %s.\n", filename ? filename : "STDIN");
193 193
 	return 1;
194 194
     }
195 195
     *buf=0;
... ...
@@ -245,9 +241,9 @@ static int send_fdpass(int sockd, const char *filename) {
245 245
  * This is used only in non IDSESSION mode
246 246
  * Returns the number of infected files or -1 on error */
247 247
 int dsresult(int sockd, int scantype, const char *filename) {
248
-	int infected = 0, waserror = 0, len, beenthere = 0;
249
-	char *bol, *eol;
250
-	struct RCVLN rcv;
248
+    int infected = 0, len, beenthere = 0;
249
+    char *bol, *eol;
250
+    struct RCVLN rcv;
251 251
 
252 252
     recvlninit(&rcv, sockd);
253 253
 
... ...
@@ -277,17 +273,14 @@ int dsresult(int sockd, int scantype, const char *filename) {
277 277
     }
278 278
 
279 279
     while((len = recvln(&rcv, &bol, &eol))) {
280
-	if(len == -1) {
281
-	    waserror = 1;
282
-	    break;
283
-	}
280
+	if(len == -1) return -1;
284 281
 	beenthere = 1;
285 282
 	if(!filename) logg("~%s\n", bol);
286 283
 	if(len > 7) {
287 284
 	    char *colon = strrchr(bol, ':');
288 285
 	    if(!colon) {
289 286
 		logg("Failed to parse reply\n");
290
-		waserror = 1;
287
+		return -1;
291 288
 	    } else if(!memcmp(eol - 7, " FOUND", 6)) {
292 289
 		infected++;
293 290
 		if(filename) {
... ...
@@ -308,15 +301,14 @@ int dsresult(int sockd, int scantype, const char *filename) {
308 308
 		    else
309 309
 			logg("~%s\n", bol);
310 310
 		}
311
-		waserror = 1;
312 311
 	    }
313 312
 	}
314 313
     }
315 314
     if(!beenthere) {
316 315
 	logg("~%s: no reply from clamd\n", filename ? filename : "STDIN");
317
-	waserror = 1;
316
+	return -1;
318 317
     }
319
-    return infected ? infected : (waserror ? -1 : 0);
318
+    return infected;
320 319
 }
321 320
 
322 321
 
... ...
@@ -324,9 +316,7 @@ int dsresult(int sockd, int scantype, const char *filename) {
324 324
 /* Used by serial_callback() */
325 325
 struct client_serial_data {
326 326
     int infected;
327
-    int errors;
328 327
     int scantype;
329
-    int spam;
330 328
 };
331 329
 
332 330
 /* FTW callback for scanning in non IDSESSION mode
... ...
@@ -349,27 +339,25 @@ static int serial_callback(struct stat *sb, char *filename, const char *path, en
349 349
 	return CL_SUCCESS;
350 350
     case warning_skipped_special:
351 351
 	logg("~%s: Not supported file type. ERROR\n", path);
352
-	c->errors++;
353 352
 	return CL_SUCCESS;
354 353
     case visit_directory_toplev:
355
-	c->spam = 1;
356 354
 	if(c->scantype >= STREAM)
357 355
 	    return CL_SUCCESS;
358 356
 	f = path;
359
-    default:
357
+	filename = NULL;
358
+    case visit_file:
360 359
 	break;
361 360
     }
362 361
 
363 362
     if((sockd = dconnect()) < 0) {
364
-	free(filename);
363
+	if(filename) free(filename);
365 364
 	return CL_EOPEN;
366 365
     }
367
-    if((ret = dsresult(sockd, c->scantype, f)) >= 0)
368
-	c->infected += ret;
369
-    else
370
-	c->errors++;
366
+    ret = dsresult(sockd, c->scantype, f);
367
+    if(filename) free(filename);
371 368
     close(sockd);
372
-    free(filename);
369
+    if(ret < 0) return CL_VIRUS;
370
+    c->infected += ret;
373 371
     if(reason == visit_directory_toplev)
374 372
 	return CL_BREAK;
375 373
     return CL_SUCCESS;
... ...
@@ -377,23 +365,20 @@ static int serial_callback(struct stat *sb, char *filename, const char *path, en
377 377
 
378 378
 /* Non-IDSESSION handler
379 379
  * Returns non zero for serious errors, zero otherwise */
380
-int serial_client_scan(char *file, int scantype, int *infected, int *errors, int maxlevel, int flags) {
380
+int serial_client_scan(char *file, int scantype, int *infected, int maxlevel, int flags) {
381 381
     struct cli_ftw_cbdata data;
382 382
     struct client_serial_data cdata;
383 383
     int ftw;
384 384
 
385 385
     cdata.infected = 0;
386
-    cdata.errors = 0;
387 386
     cdata.scantype = scantype;
388
-    cdata.spam = 0;
389 387
     data.data = &cdata;
390 388
 
391 389
     ftw = cli_ftw(file, flags, maxlevel ? maxlevel : INT_MAX, serial_callback, &data);
392 390
     *infected += cdata.infected;
393
-    *errors += cdata.errors;
394 391
 
395 392
     if(ftw == CL_SUCCESS || ftw == CL_BREAK) {
396
-	if(!printinfected && !cdata.infected && (!cdata.errors || cdata.spam))
393
+	if(!printinfected && !cdata.infected)
397 394
 	    logg("~%s: OK\n", file);
398 395
 	return 0;
399 396
     }
... ...
@@ -403,9 +388,7 @@ int serial_client_scan(char *file, int scantype, int *infected, int *errors, int
403 403
 /* Used in IDSESSION mode */
404 404
 struct client_parallel_data {
405 405
     int infected;
406
-    int errors;
407 406
     int scantype;
408
-    int spam;
409 407
     int sockd;
410 408
     int lastid;
411 409
     struct SCANID {
... ...
@@ -429,11 +412,8 @@ static int dspresult(struct client_parallel_data *c) {
429 429
     recvlninit(&rcv, c->sockd);
430 430
     do {
431 431
 	len = recvln(&rcv, &bol, &eol);
432
-	if(!bol || len == -1) {
433
-	    c->errors++;
434
-	    return 1;
435
-	}
436
-	if(!bol) return 0;
432
+	if(len < 0) return 1;
433
+	if(!len) return 0;
437 434
 	if((rid = atoi(bol))) {
438 435
 	    id = &c->ids;
439 436
 	    while(*id) {
... ...
@@ -443,7 +423,6 @@ static int dspresult(struct client_parallel_data *c) {
443 443
 	    if(!*id) id = NULL;
444 444
 	}
445 445
 	if(!id) {
446
-	    c->errors++;
447 446
 	    logg("!Bogus session id from clamd\n");
448 447
 	    return 1;
449 448
 	}
... ...
@@ -451,16 +430,15 @@ static int dspresult(struct client_parallel_data *c) {
451 451
 	if(len > 7) {
452 452
 	    char *colon = strrchr(bol, ':');
453 453
 	    if(!colon) {
454
-		c->errors++;
455
-		logg("Failed to parse reply\n");
454
+		logg("!Failed to parse reply\n");
455
+		free((void *)filename);
456
+		return 1;
456 457
 	    } else if(!memcmp(eol - 7, " FOUND", 6)) {
457 458
 		c->infected++;
458 459
 		logg("~%s%s\n", filename, colon);
459 460
 		if(action) action(filename);
460 461
 	    } else if(!memcmp(eol-7, " ERROR", 6)) {
461
-		c->errors++;
462
-		if(filename)
463
-		    logg("~%s%s\n", filename, colon);
462
+		logg("~%s%s\n", filename, colon);
464 463
 	    }
465 464
 	}
466 465
 	free((void *)filename);
... ...
@@ -473,7 +451,7 @@ static int dspresult(struct client_parallel_data *c) {
473 473
 }
474 474
 
475 475
 /* FTW callback for scanning in IDSESSION mode
476
- * Returns SUCCESS or BREAK on success, CL_EXXX on error */
476
+ * Returns SUCCESS on success, CL_EXXX or BREAK on error */
477 477
 static int parallel_callback(struct stat *sb, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data) {
478 478
     struct client_parallel_data *c = (struct client_parallel_data *)data->data;
479 479
     struct SCANID **id = &c->ids, *cid;
... ...
@@ -490,12 +468,10 @@ static int parallel_callback(struct stat *sb, char *filename, const char *path,
490 490
 	return CL_SUCCESS;
491 491
     case warning_skipped_special:
492 492
 	logg("~%s: Not supported file type. ERROR\n", path);
493
-	c->errors++;
494
-	return CL_SUCCESS;
493
+    case warning_skipped_link:
495 494
     case visit_directory_toplev:
496
-	c->spam = 1;
497 495
 	return CL_SUCCESS;
498
-    default:
496
+    case visit_file:
499 497
 	break;
500 498
     }
501 499
 
... ...
@@ -510,9 +486,8 @@ static int parallel_callback(struct stat *sb, char *filename, const char *path,
510 510
 	FD_SET(c->sockd, &wfds);
511 511
 	if(select(c->sockd + 1, &rfds, &wfds, NULL, NULL) < 0) {
512 512
 	    if(errno == EINTR) continue;
513
-	    c->errors++;
514 513
 	    free(filename);
515
-	    logg("!select failed during session\n");
514
+	    logg("!select() failed during session\n");
516 515
 	    return CL_BREAK;
517 516
 	}
518 517
 	if(FD_ISSET(c->sockd, &rfds)) {
... ...
@@ -554,7 +529,7 @@ static int parallel_callback(struct stat *sb, char *filename, const char *path,
554 554
 
555 555
 /* IDSESSION handler
556 556
  * Returns non zero for serious errors, zero otherwise */
557
-int parallel_client_scan(char *file, int scantype, int *infected, int *errors, int maxlevel, int flags) {
557
+int parallel_client_scan(char *file, int scantype, int *infected, int maxlevel, int flags) {
558 558
     struct cli_ftw_cbdata data;
559 559
     struct client_parallel_data cdata;
560 560
     int ftw;
... ...
@@ -568,18 +543,15 @@ int parallel_client_scan(char *file, int scantype, int *infected, int *errors, i
568 568
     }
569 569
 
570 570
     cdata.infected = 0;
571
-    cdata.errors = 0;
572 571
     cdata.scantype = scantype;
573
-    cdata.spam = 0;
574 572
     cdata.lastid = 0;
575 573
     cdata.ids = NULL;
576 574
     data.data = &cdata;
577 575
 
578 576
     ftw = cli_ftw(file, flags, maxlevel ? maxlevel : INT_MAX, parallel_callback, &data);
579 577
 
580
-    if(ftw != CL_SUCCESS && ftw != CL_BREAK) {
578
+    if(ftw != CL_SUCCESS) {
581 579
 	*infected += cdata.infected;
582
-	*errors += cdata.errors;
583 580
 	close(cdata.sockd);
584 581
 	return 1;
585 582
     }
... ...
@@ -589,13 +561,12 @@ int parallel_client_scan(char *file, int scantype, int *infected, int *errors, i
589 589
     close(cdata.sockd);
590 590
 
591 591
     *infected += cdata.infected;
592
-    *errors += cdata.errors;
593 592
 
594 593
     if(cdata.ids) {
595
-	logg("!Clamd closed connection before scanning all files.\n");
594
+	logg("!Clamd closed the connection before scanning all files.\n");
596 595
 	return 1;
597 596
     }
598
-    if(!printinfected && !cdata.infected && (!cdata.errors || cdata.spam))
597
+    if(!printinfected && !cdata.infected)
599 598
 	logg("~%s: OK\n", file);
600 599
     return 0;
601 600
 }
... ...
@@ -34,7 +34,7 @@ int dconnect(void);
34 34
 int sendln(int sockd, const char *line, unsigned int len);
35 35
 void recvlninit(struct RCVLN *s, int sockd);
36 36
 int recvln(struct RCVLN *s, char **rbol, char **reol);
37
-int serial_client_scan(char *file, int scantype, int *infected, int *errors, int maxlevel, int flags);
38
-int parallel_client_scan(char *file, int scantype, int *infected, int *errors, int maxlevel, int flags);
37
+int serial_client_scan(char *file, int scantype, int *infected, int maxlevel, int flags);
38
+int parallel_client_scan(char *file, int scantype, int *infected, int maxlevel, int flags);
39 39
 int dsresult(int sockd, int scantype, const char *filename);
40 40
 #endif