Browse code

Freshclam improvements. Some simplification and cleanup of mirror management functions. Reduced mirror blacklist timeouts. Added ignore time-remaining output to --list-mirrors option. Made freshclam lenient when the database version is 1 behind what was advertised by DNS. Database updates will still fail if the hosted version is more than 1 version out of date.

Micah Snyder (micasnyd) authored on 2018/10/10 22:09:58
Showing 6 changed files
... ...
@@ -63,15 +63,10 @@ Example
63 63
 # Default: current.cvd.clamav.net
64 64
 #DNSDatabaseInfo current.cvd.clamav.net
65 65
 
66
-# Uncomment the following line and replace XY with your country
67
-# code. See https://www.iana.org/domains/root/db for the full list.
68
-# You can use db.XY.ipv6.clamav.net for IPv6 connections.
69
-#DatabaseMirror db.XY.clamav.net
70
-
71
-# database.clamav.net is a round-robin record which points to our most 
72
-# reliable mirrors. It's used as a fall back in case db.XY.clamav.net is 
73
-# not working. DO NOT TOUCH the following line unless you know what you
74
-# are doing.
66
+# database.clamav.net is now the primary domain name to be used world-wide.
67
+# Now that CloudFlare is being used as our Content Delivery Network (CDN),
68
+# this one domain name works world-wide to direct freshclam to the closest
69
+# geographic endpoint.
75 70
 DatabaseMirror database.clamav.net
76 71
 
77 72
 # How many attempts to make before giving up.
... ...
@@ -186,9 +186,13 @@ help (void)
186 186
 static int
187 187
 download (const struct optstruct *opts, const char *cfgfile)
188 188
 {
189
+    time_t currtime;
189 190
     int ret = 0, try = 1, maxattempts = 0;
190 191
     const struct optstruct *opt;
191 192
 
193
+    time(&currtime);
194
+    logg("ClamAV update process started at %s", ctime(&currtime));
195
+    logg("*Using IPv6 aware code\n");
192 196
 
193 197
     maxattempts = optget (opts, "MaxAttempts")->numarg;
194 198
     logg ("*Max retries == %d\n", maxattempts);
... ...
@@ -225,6 +229,7 @@ download (const struct optstruct *opts, const char *cfgfile)
225 225
                     {
226 226
                         logg ("Update failed. Your network may be down or none of the mirrors listed in %s is working. Check https://www.clamav.net/documents/official-mirror-faq for possible reasons.\n", cfgfile);
227 227
                     }
228
+                    try = 1;
228 229
                 }
229 230
 
230 231
             }
... ...
@@ -299,7 +304,7 @@ main (int argc, char **argv)
299 299
     {
300 300
         help ();
301 301
         optfree (opts);
302
-        return 0;
302
+        return FC_SUCCESS;
303 303
     }
304 304
 
305 305
     /* check foreground option from command line to override config file */
... ...
@@ -337,7 +342,7 @@ main (int argc, char **argv)
337 337
     {
338 338
         print_version (optget (opts, "DatabaseDirectory")->strarg);
339 339
         optfree (opts);
340
-        return 0;
340
+        return FC_SUCCESS;
341 341
     }
342 342
 
343 343
     if (optget (opts, "HTTPProxyPassword")->enabled)
... ...
@@ -492,7 +497,7 @@ main (int argc, char **argv)
492 492
 
493 493
     if (optget (opts, "list-mirrors")->enabled)
494 494
     {
495
-        if (mirman_read ("mirrors.dat", &mdat, 1) == -1)
495
+        if (mirman_read("mirrors.dat", &mdat, 1) != FC_SUCCESS)
496 496
         {
497 497
             printf ("Can't read mirrors.dat\n");
498 498
             optfree (opts);
... ...
@@ -501,7 +506,7 @@ main (int argc, char **argv)
501 501
         mirman_list (&mdat);
502 502
         mirman_free (&mdat);
503 503
         optfree (opts);
504
-        return 0;
504
+        return FC_SUCCESS;
505 505
     }
506 506
 
507 507
     if ((opt = optget (opts, "PrivateMirror"))->enabled)
... ...
@@ -20,29 +20,34 @@
20 20
 #ifndef __FRESHCLAMCODES_H
21 21
 #define __FRESHCLAMCODES_H
22 22
 
23
-#define FC_UPTODATE        1
23
+typedef enum fc_error_tag {
24
+    FC_SUCCESS          = 0,
25
+    FC_UPTODATE         = 1,
24 26
 
25
-#define FCE_INIT          40
26
-#define FCE_CHECKS        41
27
-#define FCE_PRIVATEMIRROR 45
27
+    FCE_INIT            = 40,
28
+    FCE_CHECKS          = 41,
29
+    FCE_PRIVATEMIRROR   = 45,
28 30
 
29
-#define FCE_DIRECTORY     50
30
-#define FCE_CONNECTION    52
31
-#define FCE_EMPTYFILE     53
32
-#define FCE_BADCVD        54
33
-#define FCE_FILE          55
31
+    FCE_DIRECTORY       = 50,
32
+    FCE_CONNECTION      = 52,
33
+    FCE_EMPTYFILE       = 53,
34
+    FCE_BADCVD          = 54,
35
+    FCE_FILE            = 55,
34 36
 /* TESTFAIL is also 55, consider moving to new value */
35
-#define FCE_TESTFAIL      55
36
-#define FCE_CONFIG        56
37
-#define FCE_DBDIRACCESS   57
38
-#define FCE_FAILEDGET     58
39
-#define FCE_MIRRORNOTSYNC 59
37
+    FCE_TESTFAIL        = 55,
38
+    FCE_CONFIG          = 56,
39
+    FCE_DBDIRACCESS     = 57,
40
+    FCE_FAILEDGET       = 58,
41
+    FCE_MIRRORNOTSYNC   = 59,
40 42
 
41
-#define FCE_USERINFO      60
42
-#define FCE_USERORGROUP   61
43
-#define FCE_LOGGING       62
43
+    FCE_USERINFO        = 60,
44
+    FCE_USERORGROUP     = 61,
45
+    FCE_LOGGING         = 62,
44 46
 
45
-#define FCE_FAILEDUPDATE  70
46
-#define FCE_MEM           75
47
+    FCE_FAILEDUPDATE    = 70,
48
+    FCE_MEM             = 75,
49
+    FCE_ARG             = 76,
50
+    FCE_OPEN            = 77
51
+} fc_error_t;
47 52
 
48 53
 #endif
... ...
@@ -186,6 +186,7 @@ wwwconnect (const char *server, const char *proxy, int pport, char *ip,
186 186
             const char *localip, int ctimeout, struct mirdat *mdat,
187 187
             int logerr, unsigned int can_whitelist, unsigned int attempt)
188 188
 {
189
+    mir_status_t mirror_status = MIRROR_OK;
189 190
     int socketfd, port, ret;
190 191
     unsigned int ips = 0, ignored = 0, i;
191 192
     struct addrinfo hints, *res = NULL, *rp, *loadbal_rp = NULL, *addrs[128];
... ...
@@ -193,7 +194,7 @@ wwwconnect (const char *server, const char *proxy, int pport, char *ip,
193 193
     uint32_t loadbal = 1, minsucc = 0xffffffff, minfail =
194 194
         0xffffffff, addrnum = 0;
195 195
     int ipv4start = -1, ipv4end = -1;
196
-    struct mirdat_ip *md;
196
+    struct mirdat_ip *md = NULL;
197 197
     char ipaddr[46];
198 198
     const char *hostpt;
199 199
 
... ...
@@ -288,25 +289,32 @@ wwwconnect (const char *server, const char *proxy, int pport, char *ip,
288 288
             return -1;
289 289
         }
290 290
 
291
-        if (mdat && (ret = mirman_check (addr, rp->ai_family, mdat, &md)))
291
+        if (mdat)
292 292
         {
293
-            if (ret == 1)
294
-                logg ("*Ignoring mirror %s (due to previous errors)\n",
295
-                      ipaddr);
296
-            else
297
-                logg ("*Ignoring mirror %s (has connected too many times with an outdated version)\n", ipaddr);
298
-
299
-            ignored++;
300
-            if (!loadbal || i + 1 < addrnum)
293
+            if (FC_SUCCESS != (ret = mirman_check (addr, rp->ai_family, mdat, &md, &mirror_status)))
301 294
             {
302
-                i++;
303
-                continue;
295
+                logg ("!Failed to check mirrors.dat!\n");
296
+                return -1;
297
+            }
298
+            else if (MIRROR_OK != mirror_status)
299
+            {
300
+                if (MIRROR_IGNORE__PREV_ERRS == mirror_status)
301
+                    logg ("*Ignoring mirror %s (due to previous errors)\n", ipaddr);
302
+                else if (MIRROR_IGNORE__OUTDATED_VERSION == mirror_status)
303
+                    logg ("*Ignoring mirror %s (has connected too many times with an outdated version)\n", ipaddr);
304
+
305
+                ignored++;
306
+                if (!loadbal || i + 1 < addrnum)
307
+                {
308
+                    i++;
309
+                    continue;
310
+                }
304 311
             }
305 312
         }
306 313
 
307 314
         if (mdat && loadbal)
308 315
         {
309
-            if (!ret)
316
+            if (MIRROR_OK == mirror_status)
310 317
             {
311 318
                 if (!md)
312 319
                 {
... ...
@@ -387,7 +395,7 @@ wwwconnect (const char *server, const char *proxy, int pport, char *ip,
387 387
             else
388 388
                 i++;
389 389
             if (mdat)
390
-                mirman_update (addr, rp->ai_family, mdat, 2);
390
+                mirman_update (addr, rp->ai_family, mdat, FCE_CONNECTION);
391 391
             continue;
392 392
         }
393 393
         else
... ...
@@ -647,7 +655,7 @@ remote_cvdhead (const char *cvdfile, const char *localfile,
647 647
     {
648 648
         logg ("%cremote_cvdhead: Error while reading CVD header from %s\n",
649 649
               logerr ? '!' : '^', hostname);
650
-        mirman_update (mdat->currip, mdat->af, mdat, 1);
650
+        mirman_update (mdat->currip, mdat->af, mdat, FCE_FAILEDGET);
651 651
         return NULL;
652 652
     }
653 653
 
... ...
@@ -656,7 +664,7 @@ remote_cvdhead (const char *cvdfile, const char *localfile,
656 656
     {
657 657
         logg ("%c%s not found on remote server\n", logerr ? '!' : '^',
658 658
               cvdfile);
659
-        mirman_update (mdat->currip, mdat->af, mdat, 2);
659
+        mirman_update (mdat->currip, mdat->af, mdat, FCE_FAILEDGET);
660 660
         return NULL;
661 661
     }
662 662
 
... ...
@@ -667,7 +675,7 @@ remote_cvdhead (const char *cvdfile, const char *localfile,
667 667
         /* mirror status: up to date */
668 668
         *ims = 0;
669 669
         logg ("OK (IMS)\n");
670
-        mirman_update (mdat->currip, mdat->af, mdat, 0);
670
+        mirman_update (mdat->currip, mdat->af, mdat, FC_SUCCESS);
671 671
         return NULL;
672 672
     }
673 673
     else
... ...
@@ -680,8 +688,18 @@ remote_cvdhead (const char *cvdfile, const char *localfile,
680 680
         && !strstr (buffer, "HTTP/1.1 206")
681 681
         && !strstr (buffer, "HTTP/1.0 206"))
682 682
     {
683
-        logg ("%cUnknown response from remote server\n", logerr ? '!' : '^');
684
-        mirman_update (mdat->currip, mdat->af, mdat, 1);
683
+        char * respcode = NULL;
684
+        if ((NULL != (respcode = strstr (buffer, "HTTP/1.0 "))) ||
685
+            (NULL != (respcode = strstr (buffer, "HTTP/1.1 ")))) {
686
+            /* There was some sort of response code...*/
687
+            char * httpcode = calloc(MIN(FILEBUFF - (size_t)(respcode - buffer), 13) + 1, 1);
688
+            memcpy(httpcode, respcode, MIN(FILEBUFF - (size_t)(respcode - buffer), 13));
689
+            logg ("%cremote_cvdhead: Unknown response from %s (IP: %s): %s\n", logerr ? '!' : '^', hostname, ipaddr, httpcode);
690
+            free (httpcode);
691
+        } else {
692
+            logg ("%cremote_cvdhead: Unknown response from %s (IP: %s)\n", logerr ? '!' : '^', hostname, ipaddr);
693
+        }
694
+        mirman_update (mdat->currip, mdat->af, mdat, FCE_FAILEDGET);
685 695
         return NULL;
686 696
     }
687 697
 
... ...
@@ -704,7 +722,7 @@ remote_cvdhead (const char *cvdfile, const char *localfile,
704 704
     {
705 705
         logg ("%cremote_cvdhead: Malformed CVD header (too short)\n",
706 706
               logerr ? '!' : '^');
707
-        mirman_update (mdat->currip, mdat->af, mdat, 1);
707
+        mirman_update (mdat->currip, mdat->af, mdat, FCE_BADCVD);
708 708
         return NULL;
709 709
     }
710 710
 
... ...
@@ -716,7 +734,7 @@ remote_cvdhead (const char *cvdfile, const char *localfile,
716 716
         {
717 717
             logg ("%cremote_cvdhead: Malformed CVD header (bad chars)\n",
718 718
                   logerr ? '!' : '^');
719
-            mirman_update (mdat->currip, mdat->af, mdat, 1);
719
+            mirman_update (mdat->currip, mdat->af, mdat, FCE_BADCVD);
720 720
             return NULL;
721 721
         }
722 722
         head[j] = ch[j];
... ...
@@ -726,18 +744,18 @@ remote_cvdhead (const char *cvdfile, const char *localfile,
726 726
     {
727 727
         logg ("%cremote_cvdhead: Malformed CVD header (can't parse)\n",
728 728
               logerr ? '!' : '^');
729
-        mirman_update (mdat->currip, mdat->af, mdat, 1);
729
+        mirman_update (mdat->currip, mdat->af, mdat, FCE_BADCVD);
730 730
     }
731 731
     else
732 732
     {
733 733
         logg ("OK\n");
734
-        mirman_update (mdat->currip, mdat->af, mdat, 0);
734
+        mirman_update (mdat->currip, mdat->af, mdat, FC_SUCCESS);
735 735
     }
736 736
 
737 737
     return cvd;
738 738
 }
739 739
 
740
-static int
740
+static fc_error_t
741 741
 getfile_mirman (const char *srcfile, const char *destfile,
742 742
                 const char *hostname, char *ip, const char *localip,
743 743
                 const char *proxy, int port, const char *user,
... ...
@@ -757,6 +775,8 @@ getfile_mirman (const char *srcfile, const char *destfile,
757 757
     UNUSEDPARAM(ctimeout);
758 758
     UNUSEDPARAM(can_whitelist);
759 759
 
760
+    memset (buffer, 0, sizeof(FILEBUFF));
761
+
760 762
     if (proxy)
761 763
     {
762 764
         remotename = malloc (strlen (hostname) + 8);
... ...
@@ -842,7 +862,7 @@ getfile_mirman (const char *srcfile, const char *destfile,
842 842
             else
843 843
                 logg ("%cgetfile: Error while reading database from %s (IP: %s): %s\n", logerr ? '!' : '^', hostname, ipaddr, strerror (errno));
844 844
             if (mdat)
845
-                mirman_update (mdat->currip, mdat->af, mdat, 1);
845
+                mirman_update (mdat->currip, mdat->af, mdat, FCE_FAILEDGET);
846 846
             return FCE_CONNECTION;
847 847
         }
848 848
 
... ...
@@ -869,7 +889,7 @@ getfile_mirman (const char *srcfile, const char *destfile,
869 869
                   ipaddr);
870 870
 
871 871
         if (mdat)
872
-            mirman_update (mdat->currip, mdat->af, mdat, 2);
872
+            mirman_update (mdat->currip, mdat->af, mdat, FCE_FAILEDGET);
873 873
         return FCE_FAILEDGET;
874 874
     }
875 875
 
... ...
@@ -877,7 +897,7 @@ getfile_mirman (const char *srcfile, const char *destfile,
877 877
     if (strstr (buffer, "HTTP/1.1 304") || strstr (buffer, "HTTP/1.0 304"))
878 878
     {
879 879
         if (mdat)
880
-            mirman_update (mdat->currip, mdat->af, mdat, 0);
880
+            mirman_update (mdat->currip, mdat->af, mdat, FC_SUCCESS);
881 881
         return FC_UPTODATE;
882 882
     }
883 883
 
... ...
@@ -885,14 +905,30 @@ getfile_mirman (const char *srcfile, const char *destfile,
885 885
         && !strstr (buffer, "HTTP/1.1 206")
886 886
         && !strstr (buffer, "HTTP/1.0 206"))
887 887
     {
888
-        if (proxy)
889
-            logg ("%cgetfile: Unknown response from %s\n",
890
-                  logerr ? '!' : '^', hostname);
891
-        else
892
-            logg ("%cgetfile: Unknown response from %s (IP: %s)\n",
893
-                  logerr ? '!' : '^', hostname, ipaddr);
888
+        char * respcode = NULL;
889
+        if ((NULL != (respcode = strstr (buffer, "HTTP/1.0 "))) ||
890
+            (NULL != (respcode = strstr (buffer, "HTTP/1.1 ")))) {
891
+            /* There was some sort of response code...*/
892
+            char * httpcode = calloc(MIN(FILEBUFF - (size_t)(respcode - buffer), 13) + 1, 1);
893
+            memcpy(httpcode, respcode, MIN(FILEBUFF - (size_t)(respcode - buffer), 13));
894
+            if (proxy)
895
+                logg ("%cgetfile: Unknown response from %s: %s\n",
896
+                    logerr ? '!' : '^', hostname, httpcode);
897
+            else
898
+                logg ("%cgetfile: Unknown response from %s (IP: %s): %s\n",
899
+                    logerr ? '!' : '^', hostname, ipaddr, httpcode);
900
+            free (httpcode);
901
+        }
902
+        else {
903
+            if (proxy)
904
+                logg ("%cgetfile: Unknown response from %s\n",
905
+                    logerr ? '!' : '^', hostname);
906
+            else
907
+                logg ("%cgetfile: Unknown response from %s (IP: %s)\n",
908
+                    logerr ? '!' : '^', hostname, ipaddr);
909
+        }
894 910
         if (mdat)
895
-            mirman_update (mdat->currip, mdat->af, mdat, 1);
911
+            mirman_update (mdat->currip, mdat->af, mdat, FCE_FAILEDGET);
896 912
         return FCE_FAILEDGET;
897 913
     }
898 914
 
... ...
@@ -983,7 +1019,7 @@ getfile_mirman (const char *srcfile, const char *destfile,
983 983
             logg ("%cgetfile: Download interrupted: %s (IP: %s)\n",
984 984
                   logerr ? '!' : '^', strerror (errno), ipaddr);
985 985
         if (mdat)
986
-            mirman_update (mdat->currip, mdat->af, mdat, 2);
986
+            mirman_update (mdat->currip, mdat->af, mdat, FCE_CONNECTION);
987 987
         return FCE_CONNECTION;
988 988
     }
989 989
 
... ...
@@ -996,8 +1032,8 @@ getfile_mirman (const char *srcfile, const char *destfile,
996 996
         logg ("Downloading %s [*]\n", fname);
997 997
 
998 998
     if (mdat)
999
-        mirman_update (mdat->currip, mdat->af, mdat, 0);
1000
-    return 0;
999
+        mirman_update (mdat->currip, mdat->af, mdat, FC_SUCCESS);
1000
+    return FC_SUCCESS;
1001 1001
 }
1002 1002
 
1003 1003
 static int
... ...
@@ -1024,23 +1060,13 @@ getfile (const char *srcfile, const char *destfile, const char *hostname,
1024 1024
     if (sd < 0)
1025 1025
         return FCE_CONNECTION;
1026 1026
 
1027
-    if (mdat)
1028
-    {
1029
-        mirman_update_sf (mdat->currip, mdat->af, mdat, 0, 1);
1030
-        mirman_write ("mirrors.dat", dbdir, mdat);
1031
-    }
1032
-
1033
-    ret =
1034
-        getfile_mirman (srcfile, destfile, hostname, ip, localip, proxy, port,
1027
+    ret = getfile_mirman (srcfile, destfile, hostname, ip, localip, proxy, port,
1035 1028
                         user, pass, uas, ctimeout, rtimeout, mdat, logerr,
1036 1029
                         can_whitelist, ims, ipaddr, sd);
1037 1030
     closesocket (sd);
1038 1031
 
1039
-    if (mdat)
1040
-    {
1041
-        mirman_update_sf (mdat->currip, mdat->af, mdat, 0, -1);
1042
-        mirman_write ("mirrors.dat", dbdir, mdat);
1043
-    }
1032
+    /* Update mirrors.dat */
1033
+    (void) mirman_write ("mirrors.dat", dbdir, mdat);
1044 1034
 
1045 1035
     return ret;
1046 1036
 }
... ...
@@ -1118,14 +1144,21 @@ getcvd (const char *cvdfile, const char *newfile, const char *hostname,
1118 1118
     if (cvd->version < newver)
1119 1119
     {
1120 1120
         logg ("^Mirror %s is not synchronized.\n", ip);
1121
-        mirman_update (mdat->currip, mdat->af, mdat, 2);
1122
-        cl_cvdfree (cvd);
1123 1121
         unlink (newfile);
1124
-        return FCE_MIRRORNOTSYNC;
1122
+        if (cvd->version < newver - 1)
1123
+        {
1124
+            logg ("^Mirror is more than 1 version out of date. Recording mirror failure.\n");
1125
+            mirman_update (mdat->currip, mdat->af, mdat, FCE_MIRRORNOTSYNC);
1126
+            cl_cvdfree (cvd);
1127
+            return FCE_MIRRORNOTSYNC;
1128
+        }
1129
+
1130
+        cl_cvdfree (cvd);
1131
+        return FC_UPTODATE;
1125 1132
     }
1126 1133
 
1127 1134
     cl_cvdfree (cvd);
1128
-    return 0;
1135
+    return FC_SUCCESS;
1129 1136
 }
1130 1137
 
1131 1138
 static int
... ...
@@ -1251,7 +1284,7 @@ getpatch (const char *dbname, const char *tmpdir, int version,
1251 1251
         logg ("!getpatch: Can't chdir to %s\n", olddir);
1252 1252
         return FCE_DIRECTORY;
1253 1253
     }
1254
-    return 0;
1254
+    return FC_SUCCESS;
1255 1255
 }
1256 1256
 
1257 1257
 static struct cl_cvd *
... ...
@@ -1508,7 +1541,7 @@ test_database (const char *newfile, const char *newdb, int bytecode)
1508 1508
         && engine->domainlist_matcher->sha256_pfx_set.keys)
1509 1509
         cli_hashset_destroy (&engine->domainlist_matcher->sha256_pfx_set);
1510 1510
     cl_engine_free (engine);
1511
-    return 0;
1511
+    return FC_SUCCESS;
1512 1512
 }
1513 1513
 
1514 1514
 #ifndef WIN32
... ...
@@ -1582,7 +1615,7 @@ test_database_wrap (const char *file, const char *newdb, int bytecode)
1582 1582
             }
1583 1583
             if (firstline[0])
1584 1584
                 logg ("^Database successfully loaded, but there is stderr output\n");
1585
-            return 0;
1585
+            return FC_SUCCESS;
1586 1586
         }
1587 1587
         if (WIFSIGNALED (status))
1588 1588
         {
... ...
@@ -2260,7 +2293,7 @@ updatedb (const char *dbname, const char *hostname, char *ip, int *signo,
2260 2260
     }
2261 2261
 #endif
2262 2262
     cl_cvdfree (current);
2263
-    return 0;
2263
+    return FC_SUCCESS;
2264 2264
 }
2265 2265
 
2266 2266
 static int
... ...
@@ -2480,14 +2513,13 @@ updatecustomdb (const char *url, int *signo, const struct optstruct *opts,
2480 2480
 
2481 2481
     logg ("%s updated (version: custom database, sigs: %u)\n", dbname, sigs);
2482 2482
     *signo += sigs;
2483
-    return 0;
2483
+    return FC_SUCCESS;
2484 2484
 }
2485 2485
 
2486 2486
 int
2487 2487
 downloadmanager (const struct optstruct *opts, const char *hostname,
2488 2488
                  unsigned int attempt)
2489 2489
 {
2490
-    time_t currtime;
2491 2490
     int ret, custret = 0, updated = 0, outdated = 0, signo = 0, logerr;
2492 2491
     unsigned int ttl;
2493 2492
     char ipaddr[46], *dnsreply = NULL, *pt, *localip = NULL, *newver = NULL;
... ...
@@ -2512,10 +2544,6 @@ downloadmanager (const struct optstruct *opts, const char *hostname,
2512 2512
         return FCE_DBDIRACCESS;
2513 2513
     }
2514 2514
 
2515
-    time (&currtime);
2516
-    logg ("ClamAV update process started at %s", ctime (&currtime));
2517
-    logg ("*Using IPv6 aware code\n");
2518
-
2519 2515
 #ifdef HAVE_RESOLV_H
2520 2516
     dnsdbinfo = optget (opts, "DNSDatabaseInfo")->strarg;
2521 2517
 
... ...
@@ -2635,7 +2663,7 @@ downloadmanager (const struct optstruct *opts, const char *hostname,
2635 2635
                 }
2636 2636
                 free (dnsreply);
2637 2637
                 free (newver);
2638
-                mirman_write ("mirrors.dat", dbdir, &mdat);
2638
+                (void) mirman_write ("mirrors.dat", dbdir, &mdat);
2639 2639
                 mirman_free (&mdat);
2640 2640
                 cli_rmdirs (updtmpdir);
2641 2641
                 return custret;
... ...
@@ -2663,7 +2691,7 @@ downloadmanager (const struct optstruct *opts, const char *hostname,
2663 2663
                     free (dnsreply);
2664 2664
                 if (newver)
2665 2665
                     free (newver);
2666
-                mirman_write ("mirrors.dat", dbdir, &mdat);
2666
+                (void) mirman_write ("mirrors.dat", dbdir, &mdat);
2667 2667
                 mirman_free (&mdat);
2668 2668
                 cli_rmdirs (updtmpdir);
2669 2669
                 return ret;
... ...
@@ -2685,7 +2713,7 @@ downloadmanager (const struct optstruct *opts, const char *hostname,
2685 2685
                 free (dnsreply);
2686 2686
             if (newver)
2687 2687
                 free (newver);
2688
-            mirman_write ("mirrors.dat", dbdir, &mdat);
2688
+            (void) mirman_write ("mirrors.dat", dbdir, &mdat);
2689 2689
             mirman_free (&mdat);
2690 2690
             cli_rmdirs (updtmpdir);
2691 2691
             return ret;
... ...
@@ -2702,7 +2730,7 @@ downloadmanager (const struct optstruct *opts, const char *hostname,
2702 2702
                 free (dnsreply);
2703 2703
             if (newver)
2704 2704
                 free (newver);
2705
-            mirman_write ("mirrors.dat", dbdir, &mdat);
2705
+            (void) mirman_write ("mirrors.dat", dbdir, &mdat);
2706 2706
             mirman_free (&mdat);
2707 2707
             cli_rmdirs (updtmpdir);
2708 2708
             return ret;
... ...
@@ -2736,7 +2764,7 @@ downloadmanager (const struct optstruct *opts, const char *hostname,
2736 2736
                 free (dnsreply);
2737 2737
             if (newver)
2738 2738
                 free (newver);
2739
-            mirman_write ("mirrors.dat", dbdir, &mdat);
2739
+            (void) mirman_write ("mirrors.dat", dbdir, &mdat);
2740 2740
             mirman_free (&mdat);
2741 2741
             cli_rmdirs (updtmpdir);
2742 2742
             return ret;
... ...
@@ -2771,7 +2799,7 @@ downloadmanager (const struct optstruct *opts, const char *hostname,
2771 2771
                 free (dnsreply);
2772 2772
             if (newver)
2773 2773
                 free (newver);
2774
-            mirman_write ("mirrors.dat", dbdir, &mdat);
2774
+            (void) mirman_write ("mirrors.dat", dbdir, &mdat);
2775 2775
             mirman_free (&mdat);
2776 2776
             cli_rmdirs (updtmpdir);
2777 2777
             return ret;
... ...
@@ -2793,7 +2821,7 @@ downloadmanager (const struct optstruct *opts, const char *hostname,
2793 2793
                         free (dnsreply);
2794 2794
                     if (newver)
2795 2795
                         free (newver);
2796
-                    mirman_write ("mirrors.dat", dbdir, &mdat);
2796
+                    (void) mirman_write ("mirrors.dat", dbdir, &mdat);
2797 2797
                     mirman_free (&mdat);
2798 2798
                     cli_rmdirs (updtmpdir);
2799 2799
                     return ret;
... ...
@@ -2808,7 +2836,7 @@ downloadmanager (const struct optstruct *opts, const char *hostname,
2808 2808
     if (dnsreply)
2809 2809
         free (dnsreply);
2810 2810
 
2811
-    mirman_write ("mirrors.dat", dbdir, &mdat);
2811
+    (void) mirman_write ("mirrors.dat", dbdir, &mdat);
2812 2812
     mirman_free (&mdat);
2813 2813
 
2814 2814
     cli_rmdirs (updtmpdir);
... ...
@@ -50,11 +50,11 @@
50 50
 #endif
51 51
 #endif
52 52
 
53
-#define IGNORE_LONG	3 * 86400
54
-#define IGNORE_SHORT	6 * 3600
53
+#define IGNORE_SHORT    (3600)              /* 1 hour */
54
+#define IGNORE_LONG     (6 * IGNORE_SHORT)  /* 6 hours */
55 55
 
56 56
 void
57
-mirman_free (struct mirdat *mdat)
57
+mirman_free(struct mirdat *mdat)
58 58
 {
59 59
     if (mdat && mdat->num)
60 60
     {
... ...
@@ -63,34 +63,32 @@ mirman_free (struct mirdat *mdat)
63 63
     }
64 64
 }
65 65
 
66
-int
67
-mirman_read (const char *file, struct mirdat *mdat, uint8_t active)
66
+fc_error_t mirman_read(const char *file, struct mirdat *mdat, uint8_t active)
68 67
 {
69 68
     struct mirdat_ip mip;
70 69
     int fd, bread;
71 70
 
72
-
73
-    memset (mdat, 0, sizeof (struct mirdat));
71
+    memset (mdat, 0, sizeof(struct mirdat));
74 72
 
75 73
     if (!(mdat->active = active))
76
-        return 0;
74
+        return FC_SUCCESS;
77 75
 
78 76
     if ((fd = open (file, O_RDONLY | O_BINARY)) == -1)
79
-        return -1;
77
+        return FCE_OPEN;
80 78
 
81
-    while ((bread = read (fd, &mip, sizeof (mip))) == sizeof (mip))
79
+    while ((bread = read (fd, &mip, sizeof(mip))) == sizeof(mip))
82 80
     {
83 81
         mdat->mirtab =
84 82
             (struct mirdat_ip *) realloc (mdat->mirtab,
85
-                                          (mdat->num + 1) * sizeof (mip));
83
+                                          (mdat->num + 1) * sizeof(mip));
86 84
         if (!mdat->mirtab)
87 85
         {
88
-            logg ("!Can't allocate memory for mdat->mirtab\n");
86
+            logg("!Can't allocate memory for mdat->mirtab\n");
89 87
             mirman_free (mdat);
90 88
             close (fd);
91
-            return -1;
89
+            return FCE_MEM;
92 90
         }
93
-        memcpy (&mdat->mirtab[mdat->num], &mip, sizeof (mip));
91
+        memcpy (&mdat->mirtab[mdat->num], &mip, sizeof(mip));
94 92
         mdat->num++;
95 93
     }
96 94
 
... ...
@@ -98,156 +96,136 @@ mirman_read (const char *file, struct mirdat *mdat, uint8_t active)
98 98
 
99 99
     if (bread)
100 100
     {
101
-        logg ("^Removing broken %s file.\n", file);
101
+        logg("^Removing broken %s file.\n", file);
102 102
         unlink (file);
103 103
         mirman_free (mdat);
104
-        return -1;
104
+        return FCE_FILE;
105 105
     }
106 106
 
107
-    return 0;
107
+    return FC_SUCCESS;
108 108
 }
109 109
 
110
-int
111
-mirman_check (uint32_t * ip, int af, struct mirdat *mdat,
112
-              struct mirdat_ip **md)
110
+fc_error_t mirman_check(uint32_t * ip, int af, struct mirdat *mdat,
111
+                        struct mirdat_ip **md, mir_status_t *mirror_status)
113 112
 {
114
-    unsigned int i, flevel = cl_retflevel ();
113
+    fc_error_t status = FC_SUCCESS;
114
+    unsigned int i;
115
+    unsigned int flevel = cl_retflevel ();
115 116
 
117
+    if (NULL == md || NULL == mdat || NULL == ip) {
118
+        logg("!mirman_check: Invalid arguments.\n");
119
+        status = FCE_ARG;
120
+        goto done;
121
+    }
116 122
 
117
-    if (md)
118
-        *md = NULL;
123
+    *md = NULL;
119 124
 
120 125
     if (!mdat->active)
121
-        return 0;
126
+    {
127
+        *mirror_status = MIRROR_OK;
128
+        goto done;
129
+    }
122 130
 
123 131
     for (i = 0; i < mdat->num; i++)
124 132
     {
125
-
126
-        if ((af == AF_INET && mdat->mirtab[i].ip4 == *ip)
127
-            || (af == AF_INET6
128
-                && !memcmp (mdat->mirtab[i].ip6, ip, 4 * sizeof (uint32_t))))
133
+        if ((af == AF_INET && mdat->mirtab[i].ip4 == *ip) ||
134
+            ((af == AF_INET6) && (!memcmp (mdat->mirtab[i].ip6, ip, 4 * sizeof(uint32_t)))))
129 135
         {
136
+            /*
137
+             * Mirror found in mirror table.
138
+             */
130 139
 
131
-            if (!mdat->mirtab[i].atime && !mdat->mirtab[i].ignore)
140
+            if (mdat->dbflevel && (mdat->dbflevel > flevel) && (mdat->dbflevel - flevel > 3))
132 141
             {
133
-                if (md)
134
-                    *md = &mdat->mirtab[i];
135
-                return 0;
142
+                /* Functionality level of database is lower than
143
+                 * level of the database we already have */
144
+                if (difftime(time(NULL), mdat->mirtab[i].atime) < (mdat->dbflevel - flevel) * 3600)
145
+                {
146
+                    *mirror_status = MIRROR_IGNORE__OUTDATED_VERSION;
147
+                    goto done;
148
+                }
136 149
             }
137 150
 
138
-            if (mdat->dbflevel && (mdat->dbflevel > flevel)
139
-                && (mdat->dbflevel - flevel > 3))
140
-                if (time (NULL) - mdat->mirtab[i].atime <
141
-                    (mdat->dbflevel - flevel) * 3600)
142
-                    return 2;
143
-
144
-            if (mdat->mirtab[i].ignore)
151
+            if ((mdat->mirtab[i].atime > 0) &&
152
+                (IGNORE_NO != mdat->mirtab[i].ignore))
145 153
             {
146
-                if (!mdat->mirtab[i].atime)
147
-                    return 1;
148
-
149
-                if (time (NULL) - mdat->mirtab[i].atime > IGNORE_LONG)
154
+                /*
155
+                 * Found, but the ignore flag is set.
156
+                 */
157
+                if (difftime(time(NULL), mdat->mirtab[i].atime) > IGNORE_LONG)
150 158
                 {
151
-                    mdat->mirtab[i].ignore = 0;
152
-                    if (md)
153
-                        *md = &mdat->mirtab[i];
154
-                    return 0;
159
+                    /* Long-Ignore timeout expired,
160
+                     * the mirror can be attempted again */
161
+                    mdat->mirtab[i].ignore = IGNORE_NO;
162
+                }
163
+                else if ((mdat->mirtab[i].ignore == IGNORE_SHORTTERM) &&
164
+                        (difftime(time(NULL), mdat->mirtab[i].atime) > IGNORE_SHORT))
165
+                {
166
+                    /* Mirror was only set to Short-Term ignore...
167
+                     * the Short-Ignore timeout expired,
168
+                     * the mirror can be attempted again */
169
+                    mdat->mirtab[i].ignore = IGNORE_NO;
155 170
                 }
156 171
                 else
157 172
                 {
158
-                    if (mdat->mirtab[i].ignore == 2
159
-                        && (time (NULL) - mdat->mirtab[i].atime >
160
-                            IGNORE_SHORT))
161
-                    {
162
-                        if (md)
163
-                            *md = &mdat->mirtab[i];
164
-                        return 0;
165
-                    }
166
-                    return 1;
173
+                    *mirror_status = MIRROR_IGNORE__PREV_ERRS;
174
+                    goto done;
167 175
                 }
168 176
             }
169 177
 
170
-            if (md)
171
-                *md = &mdat->mirtab[i];
172
-            return 0;
178
+            /* Mirror found, and is ok to try. */
179
+            *md = &mdat->mirtab[i];
180
+            *mirror_status = MIRROR_OK;
181
+            goto done;
173 182
         }
174 183
     }
175 184
 
176
-    return 0;
185
+    /* Mirror wasn't in mirror table. */
186
+    *mirror_status = MIRROR_OK;
187
+
188
+done:
189
+
190
+    return status;
177 191
 }
178 192
 
179
-static int
180
-mirman_update_int (uint32_t * ip, int af, struct mirdat *mdat, uint8_t broken,
181
-                   int succ, int fail)
193
+fc_error_t mirman_update(uint32_t * ip, int af, struct mirdat *mdat, fc_error_t error)
182 194
 {
183
-    unsigned int i, found = 0;
184
-
195
+    fc_error_t status = FCE_ARG;
196
+    unsigned int i = 0;
197
+    struct mirdat_ip *mirror = NULL;
185 198
 
186
-    if (!mdat->active)
187
-        return 0;
199
+    if (!mdat->active) {
200
+        /* Disable mirrors.dat management when using a proxy. */
201
+        return FC_SUCCESS;
202
+    }
188 203
 
204
+    /*
205
+     * Attempt to find the ip in the mirror table.
206
+     */
189 207
     for (i = 0; i < mdat->num; i++)
190 208
     {
191
-        if ((af == AF_INET && mdat->mirtab[i].ip4 == *ip)
192
-            || (af == AF_INET6
193
-                && !memcmp (mdat->mirtab[i].ip6, ip, 4 * sizeof (uint32_t))))
209
+        if (((af == AF_INET) && (mdat->mirtab[i].ip4 == *ip)) ||
210
+            ((af == AF_INET6) && (!memcmp(mdat->mirtab[i].ip6, ip, 4 * sizeof(uint32_t)))))
194 211
         {
195
-            found = 1;
212
+            mirror = &mdat->mirtab[i];
196 213
             break;
197 214
         }
198 215
     }
199 216
 
200
-    if (found)
201
-    {
202
-        mdat->mirtab[i].atime = 0;  /* will be updated in mirman_write() */
203
-        if (succ || fail)
204
-        {
205
-            if ((int) mdat->mirtab[i].fail + fail < 0)
206
-                mdat->mirtab[i].fail = 0;
207
-            else
208
-                mdat->mirtab[i].fail += fail;
209
-
210
-            if ((int) mdat->mirtab[i].succ + succ < 0)
211
-                mdat->mirtab[i].succ = 0;
212
-            else
213
-                mdat->mirtab[i].succ += succ;
214
-        }
215
-        else
216
-        {
217
-            if (broken)
218
-                mdat->mirtab[i].fail++;
219
-            else
220
-                mdat->mirtab[i].succ++;
221
-
222
-            if (broken == 2)
223
-            {
224
-                mdat->mirtab[i].ignore = 2;
225
-            }
226
-            else
227
-            {
228
-                /*
229
-                 * If the total number of failures is less than 3 then never
230
-                 * mark a permanent failure, in other case use the real status.
231
-                 */
232
-                if (mdat->mirtab[i].fail < 3)
233
-                    mdat->mirtab[i].ignore = 0;
234
-                else
235
-                    mdat->mirtab[i].ignore = broken;
236
-            }
237
-        }
238
-    }
239
-    else
217
+    if (NULL == mirror)
240 218
     {
219
+        /*
220
+         * Allocate space in the mirror table for the new mirror IP
221
+         */
241 222
         mdat->mirtab =
242
-            (struct mirdat_ip *) realloc (mdat->mirtab,
243
-                                          (mdat->num +
244
-                                           1) * sizeof (struct mirdat_ip));
223
+            (struct mirdat_ip *) realloc(mdat->mirtab,
224
+                                        (mdat->num + 1) * sizeof(struct mirdat_ip));
245 225
         if (!mdat->mirtab)
246 226
         {
247
-            logg ("!Can't allocate memory for new element in mdat->mirtab\n");
248
-            return -1;
227
+            logg("!Can't allocate memory for new element in mdat->mirtab\n");
228
+            return FCE_MEM;
249 229
         }
250
-        memset (&mdat->mirtab[mdat->num], 0, sizeof (struct mirdat_ip));
230
+        memset (&mdat->mirtab[mdat->num], 0, sizeof(struct mirdat_ip));
251 231
         if (af == AF_INET)
252 232
         {
253 233
             mdat->mirtab[mdat->num].ip4 = *ip;
... ...
@@ -255,116 +233,163 @@ mirman_update_int (uint32_t * ip, int af, struct mirdat *mdat, uint8_t broken,
255 255
         else
256 256
         {
257 257
             mdat->mirtab[mdat->num].ip4 = 0;
258
-            memcpy (mdat->mirtab[mdat->num].ip6, ip, 4 * sizeof (uint32_t));
258
+            memcpy (mdat->mirtab[mdat->num].ip6, ip, 4 * sizeof(uint32_t));
259 259
         }
260 260
         mdat->mirtab[mdat->num].atime = 0;
261
-        mdat->mirtab[mdat->num].succ = (succ > 0) ? succ : 0;
262
-        mdat->mirtab[mdat->num].fail = (fail > 0) ? fail : 0;
263
-        mdat->mirtab[mdat->num].ignore = (broken == 2) ? 2 : 0;
264
-        if (!succ && !fail)
265
-        {
266
-            if (broken)
267
-                mdat->mirtab[mdat->num].fail++;
268
-            else
269
-                mdat->mirtab[mdat->num].succ++;
270
-        }
261
+        mdat->mirtab[mdat->num].succ = 0;
262
+        mdat->mirtab[mdat->num].fail = 0;
263
+        mdat->mirtab[mdat->num].ignore = 0;
264
+
265
+        mirror = &mdat->mirtab[mdat->num];
271 266
         mdat->num++;
272 267
     }
273 268
 
274
-    return 0;
275
-}
269
+    mirror->atime = 0;  /* will be updated in mirman_write() */
276 270
 
277
-int
278
-mirman_update (uint32_t * ip, int af, struct mirdat *mdat, uint8_t broken)
279
-{
280
-    return mirman_update_int (ip, af, mdat, broken, 0, 0);
281
-}
271
+    if (FC_SUCCESS == error) {
272
+        mirror->succ++;
273
+        mirror->fail = 0;
274
+    }
275
+    else
276
+    {
277
+        mirror->succ = 0;
278
+        mirror->fail++;
279
+    }
282 280
 
283
-int
284
-mirman_update_sf (uint32_t * ip, int af, struct mirdat *mdat, int succ,
285
-                  int fail)
286
-{
287
-    return mirman_update_int (ip, af, mdat, 0, succ, fail);
281
+    if (mirror->fail >= 6)
282
+    {
283
+        mirror->ignore = IGNORE_LONGTERM;
284
+    }
285
+    else if (mirror->fail >= 3)
286
+    {
287
+        mirror->ignore = IGNORE_SHORTTERM;
288
+    }
289
+    else
290
+    {
291
+        mirror->ignore = IGNORE_NO;
292
+    }
293
+
294
+    return FC_SUCCESS;
288 295
 }
289 296
 
290
-void
291
-mirman_list (const struct mirdat *mdat)
297
+void mirman_list(const struct mirdat *mdat)
292 298
 {
293 299
     unsigned int i;
294 300
     time_t tm;
295 301
     char ip[46];
296 302
 
297
-
298 303
     for (i = 0; i < mdat->num; i++)
299 304
     {
300
-        printf ("Mirror #%u\n", i + 1);
305
+        printf("Mirror #%u\n", i + 1);
301 306
 #ifdef HAVE_GETADDRINFO
302 307
         if (mdat->mirtab[i].ip4)
303
-            printf ("IP: %s\n",
304
-                    inet_ntop (AF_INET, &mdat->mirtab[i].ip4, ip,
305
-                               sizeof (ip)));
308
+            printf("IP: %s\n",
309
+                inet_ntop(AF_INET, &mdat->mirtab[i].ip4, ip, sizeof(ip)));
306 310
         else
307
-            printf ("IP: %s\n",
308
-                    inet_ntop (AF_INET6, mdat->mirtab[i].ip6, ip,
309
-                               sizeof (ip)));
311
+            printf("IP: %s\n",
312
+                inet_ntop(AF_INET6, mdat->mirtab[i].ip6, ip, sizeof(ip)));
310 313
 #else
311 314
         if (mdat->mirtab[i].ip4)
312
-            printf ("IP: %s\n",
313
-                    inet_ntoa (*(struct in_addr *) &mdat->mirtab[i].ip4));
315
+            printf("IP: %s\n",
316
+                inet_ntoa(*(struct in_addr *)&mdat->mirtab[i].ip4));
314 317
 #endif
315
-        printf ("Successes: %u\n", mdat->mirtab[i].succ);
316
-        printf ("Failures: %u\n", mdat->mirtab[i].fail);
318
+        printf("Successes: %u\n", mdat->mirtab[i].succ);
319
+        printf("Failures: %u\n", mdat->mirtab[i].fail);
317 320
         tm = mdat->mirtab[i].atime;
318
-        printf ("Last access: %s", ctime ((const time_t *) &tm));
319
-        printf ("Ignore: %s\n", mdat->mirtab[i].ignore ? "Yes" : "No");
321
+        printf("Last access: %s", ctime((const time_t *) &tm));
322
+        if (mdat->mirtab[i].ignore) {
323
+            time_t ignore_expires = tm + ((mdat->mirtab[i].ignore == IGNORE_LONGTERM) ? IGNORE_LONG
324
+                                                                                      : IGNORE_SHORT);
325
+            double difference = difftime(ignore_expires, time(NULL));
326
+            if (difference > 0) {
327
+                uint32_t remaining = difference;
328
+                uint32_t seconds, minutes, hours;
329
+                seconds = remaining % 60;
330
+                remaining = remaining / 60;
331
+                minutes = remaining % 60;
332
+                remaining = remaining / 60;
333
+                hours = remaining % 60;
334
+
335
+                printf("Ignore: Yes,  %d hours %d minutes %d seconds remaining.\n",
336
+                    hours, minutes, seconds);
337
+            } else {
338
+                printf("Ignore: No\n");
339
+            }
340
+        } else {
341
+            printf("Ignore: No\n");
342
+        }
320 343
         if (i != mdat->num - 1)
321
-            printf ("-------------------------------------\n");
344
+            printf("-------------------------------------\n");
322 345
     }
323 346
 }
324 347
 
325
-void
326
-mirman_whitelist (struct mirdat *mdat, unsigned int mode)
348
+void mirman_whitelist(struct mirdat *mdat, unsigned int mode)
327 349
 {
328 350
     unsigned int i;
329 351
 
330
-    logg ("*Whitelisting %s blacklisted mirrors\n",
331
-          mode == 1 ? "all" : "short-term");
352
+    if (NULL == mdat) {
353
+        logg("!mirman_whitelist: Invalid arguments!\n");
354
+        return;
355
+    }
356
+
357
+    switch (mode)
358
+    {
359
+    case 1:
360
+        logg("*Whitelisting all blacklisted mirrors\n");
361
+        break;
362
+    case 2:
363
+        logg("*Whitelisting short-term blacklisted mirrors\n");
364
+        break;
365
+    default:
366
+        logg("!mirman_whitelist: Unexpected mode argument: %u\n", mode);
367
+        return;
368
+    }
369
+
332 370
     for (i = 0; i < mdat->num; i++)
333
-        if (mode == 1 || (mode == 2 && mdat->mirtab[i].ignore == 2))
334
-            mdat->mirtab[i].ignore = 0;
371
+    {
372
+        if (mode == 1)
373
+        {
374
+            mdat->mirtab[i].ignore = IGNORE_NO;
375
+        }
376
+        else if ((mode == 2) && (IGNORE_SHORTTERM == mdat->mirtab[i].ignore))
377
+        {
378
+            mdat->mirtab[i].ignore = IGNORE_NO;
379
+        }
380
+    }
381
+
382
+    return;
335 383
 }
336 384
 
337
-int
338
-mirman_write (const char *file, const char *dir, struct mirdat *mdat)
385
+fc_error_t mirman_write(const char *file, const char *dir, struct mirdat *mdat)
339 386
 {
340 387
     int fd;
341 388
     unsigned int i;
342 389
     char path[512];
343 390
 
344
-    snprintf (path, sizeof (path), "%s/%s", dir, file);
345
-    path[sizeof (path) - 1] = 0;
391
+    snprintf(path, sizeof(path), "%s/%s", dir, file);
392
+    path[sizeof(path) - 1] = 0;
346 393
 
347 394
     if (!mdat->num)
348
-        return 0;
395
+        return FC_SUCCESS;
349 396
 
350 397
     if ((fd =
351
-         open (path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600)) == -1)
398
+         open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600)) == -1)
352 399
     {
353
-        logg ("!Can't open %s for writing\n", path);
354
-        return -1;
400
+        logg("!Can't open %s for writing\n", path);
401
+        return FCE_OPEN;
355 402
     }
356 403
 
357 404
     for (i = 0; i < mdat->num; i++)
358 405
         if (!mdat->mirtab[i].atime)
359
-            mdat->mirtab[i].atime = (uint32_t) time (NULL);
406
+            mdat->mirtab[i].atime = (uint32_t) time(NULL);
360 407
 
361
-    if (write (fd, mdat->mirtab, mdat->num * sizeof (struct mirdat_ip)) == -1)
408
+    if (write(fd, mdat->mirtab, mdat->num * sizeof(struct mirdat_ip)) == -1)
362 409
     {
363
-        logg ("!Can't write to %s\n", path);
364
-        close (fd);
365
-        return -1;
410
+        logg("!Can't write to %s\n", path);
411
+        close(fd);
412
+        return FCE_FILE;
366 413
     }
367 414
 
368
-    close (fd);
369
-    return 0;
415
+    close(fd);
416
+    return FC_SUCCESS;
370 417
 }
... ...
@@ -20,11 +20,25 @@
20 20
 #define __MIRMAN_H
21 21
 
22 22
 #include "libclamav/cltypes.h"
23
+#include "freshclamcodes.h"
24
+
25
+typedef enum mir_status_tag {
26
+    MIRROR_OK=0,
27
+    MIRROR_FAILURE,
28
+    MIRROR_IGNORE__PREV_ERRS,
29
+    MIRROR_IGNORE__OUTDATED_VERSION
30
+} mir_status_t;
31
+
32
+typedef enum mir_ignore_tag {
33
+    IGNORE_NO=0,
34
+    IGNORE_LONGTERM,
35
+    IGNORE_SHORTTERM
36
+} mir_ignore_t;
23 37
 
24 38
 struct mirdat_ip
25 39
 {
26 40
     uint32_t ip4;               /* IPv4 address */
27
-    uint32_t atime;             /* last access time */
41
+    time_t atime;             /* last access time */
28 42
     uint32_t succ;              /* number of successful downloads from this ip */
29 43
     uint32_t fail;              /* number of failures */
30 44
     uint8_t ignore;             /* ignore flag */
... ...
@@ -34,24 +48,85 @@ struct mirdat_ip
34 34
 
35 35
 struct mirdat
36 36
 {
37
-    uint8_t active;
38
-    unsigned int num;
39
-    uint32_t currip[4];
40
-    uint32_t af;
41
-    uint32_t dbflevel;
42
-    struct mirdat_ip *mirtab;
37
+    uint8_t active;             /* 1 if active, 2 if disabled */
38
+    unsigned int num;           /* number of mirrors */
39
+    uint32_t currip[4];         /* IP currently attempting */
40
+    uint32_t af;                /* AF_INET or AF_INET6 for current IP */
41
+    uint32_t dbflevel;          /* functionality level of current database */
42
+    struct mirdat_ip *mirtab;   /* mirror table of known mirror IP addresses */
43 43
 };
44 44
 
45
-int mirman_read (const char *file, struct mirdat *mdat, uint8_t active);
46
-int mirman_check (uint32_t * ip, int af, struct mirdat *mdat,
47
-                  struct mirdat_ip **md);
48
-int mirman_update (uint32_t * ip, int af, struct mirdat *mdat,
49
-                   uint8_t broken);
50
-int mirman_update_sf (uint32_t * ip, int af, struct mirdat *mdat, int succ,
51
-                      int fail);
52
-void mirman_list (const struct mirdat *mdat);
53
-void mirman_whitelist (struct mirdat *mdat, unsigned int mode);
54
-int mirman_write (const char *file, const char *dir, struct mirdat *mdat);
55
-void mirman_free (struct mirdat *mdat);
45
+/**
46
+ * @brief   Read mirrors.dat into an existing mirdat structur.
47
+ *
48
+ * @param file          The filename (probably mirrors.dat).
49
+ * @param mdat          An existing mirdat structure. Must not be NULL.
50
+ * @param active        1 - active, 0 - inactive (e.g. when using private mirrors or proxies).
51
+ * @return fc_error_t   FC_SUCCESS or an error code.
52
+ */
53
+fc_error_t mirman_read(const char *file, struct mirdat *mdat, uint8_t active);
54
+
55
+/**
56
+ * @brief   Check if a mirror is should be ignored, if it's in the mirror table.
57
+ *
58
+ * Will add the mirror to the table if it isn't in the table.
59
+ *
60
+ * @param ip                    The mirror in question.
61
+ * @param af                    AF_INET or AF_INET6.
62
+ * @param mdat                  The mirrors.dat structure.
63
+ * @param[out] md               A pointer to the mirror in mdat
64
+ * @param[out] mirror_status    MIRROR_OK  or an ignore reason, such as:
65
+ *                              MIRROR_IGNORE__PREV_ERRS  or
66
+ *                              MIRROR_IGNORE__OUTDATED_VERSION
67
+ * @return fc_error_t           FC_SUCCESS or an FCE error code.
68
+ */
69
+fc_error_t mirman_check(uint32_t * ip, int af, struct mirdat *mdat,
70
+                        struct mirdat_ip **md, mir_status_t *mirror_status);
71
+
72
+/**
73
+ * @brief   Update the mirdat structure with the current mirror status
74
+ *
75
+ * @param ip            IP of current mirror.
76
+ * @param af            AF_INET or AF_INET6.
77
+ * @param mdat          The mirrors.dat structure.
78
+ * @param error         FC_SUCCESS or an FCE error code.
79
+ * @return fc_error_t   FC_SUCCESS or an FCE error code.
80
+ */
81
+fc_error_t mirman_update(uint32_t * ip, int af, struct mirdat *mdat, fc_error_t mirror_status);
82
+
83
+/**
84
+ * @brief   Print out the mirror info.
85
+ *
86
+ * @param mdat  The mirdat struct.
87
+ */
88
+void mirman_list(const struct mirdat *mdat);
89
+
90
+/**
91
+ * @brief   Remove "ignore" flag on mirrors.
92
+ *
93
+ * @param mdat  Structure
94
+ * @param mode  1: Whitelist _all_ mirrors.
95
+ *              2: Whitelist only mirrors that were in Short-Term ignore.
96
+ */
97
+void mirman_whitelist(struct mirdat *mdat, unsigned int mode);
98
+
99
+/**
100
+ * @brief   Update mirrors.dat with the current mirdat struct info.
101
+ *
102
+ * @param file          The filename to write to (probably "mirrors.dat")
103
+ * @param dir           The database directory to store the file in.
104
+ * @param mdat          The mirdat struct to write to disk.
105
+ * @return fc_error_t   FC_SUCCESS or an error code.
106
+ */
107
+fc_error_t mirman_write(const char *file, const char *dir, struct mirdat *mdat);
108
+
109
+/**
110
+ * @brief   Free up the mirror table in the mirdat structure.
111
+ *
112
+ * Does not attempt to free mdat itself.
113
+ *
114
+ * @param mdat  The mirdat structure.
115
+ */
116
+void mirman_free(struct mirdat *mdat);
56 117
 
57 118
 #endif