1 /*
2     AWFFull - A Webalizer Fork, Full o' features
3 
4     preserve.c
5         preserve 'state' between runs
6 
7     Copyright (C) 1997-2001  Bradford L. Barrett (brad@mrunix.net)
8     Copyright (C) 2004-2008 by Stephen McInerney (spm@stedee.id.au)
9     Copyright (C) 2006 by Alexander Lazic (al-awffull@none.at)
10 
11     This file is part of AWFFull.
12 
13     AWFFull is free software: you can redistribute it and/or modify
14     it under the terms of the GNU General Public License as published by
15     the Free Software Foundation, either version 3 of the License, or
16     (at your option) any later version.
17 
18     AWFFull is distributed in the hope that it will be useful,
19     but WITHOUT ANY WARRANTY; without even the implied warranty of
20     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21     GNU General Public License for more details.
22 
23     You should have received a copy of the GNU General Public License
24     along with AWFFull.  If not, see <http://www.gnu.org/licenses/>.
25 
26     This software uses the gd graphics library, which is copyright by
27     Quest Protein Database Center, Cold Spring Harbor Labs.  Please
28     see the documentation supplied with the library for additional
29     information and license terms, or visit www.boutell.com/gd/ for the
30     most recent version of the library and supporting documentation.
31 
32 */
33 
34 #include "awffull.h"                            /* main header              */
35 
36 /* local variables */
37 struct history history_list[MAXHISTLEN];        /* Complete Array for the history */
38 
39 int hist_month[12], hist_year[12];              /* arrays for monthly total */
40 unsigned long hist_hit[12];                     /* calculations: used to    */
41 unsigned long hist_files[12];                   /* produce index.html       */
42 unsigned long hist_site[12];                    /* these are read and saved */
43 double hist_xfer[12];                           /* in the history file      */
44 unsigned long hist_page[12];
45 unsigned long hist_visit[12];
46 
47 int hist_fday[12], hist_lday[12];               /* first/last day arrays    */
48 
49 /************************************************
50  * cmp_history                                  *
51  *   submit to qsort for sorting the history    *
52  *   sorts by year & month, oldest first        *
53  ************************************************/
54 int
cmp_history(const void * h1,const void * h2)55 cmp_history(const void *h1, const void *h2)
56 {
57     struct history *history1 = (struct history *) h1;
58     struct history *history2 = (struct history *) h2;
59     int cmp_rtn = 0;                            /* Value to return */
60 
61     if (history1->year < history2->year) {
62         cmp_rtn = -1;
63     } else if (history1->year > history2->year) {
64         cmp_rtn = 1;
65     } else {
66         /* Same year, compare for month */
67         if (history1->month < history2->month) {
68             cmp_rtn = -1;
69         } else if (history1->month > history2->month) {
70             cmp_rtn = 1;
71         }
72     }
73     return (cmp_rtn);
74 }
75 
76 
77 /*********************************************
78  * GET_HISTORY - load in history file        *
79  *********************************************/
80 void
get_history()81 get_history()
82 {
83     int i = 0;
84     int numfields = 0;                          /* Number of fields returned from each line */
85 
86     /*  Used to verify if an older history file */
87     int nbr_hist_entries = 0;                   /* How many lines out of the history file have been read */
88 
89     FILE *hist_fp;
90     char buffer[BUFSIZE];
91 
92     /* first initalize the history array */
93     for (i = 0; i < MAXHISTLEN; i++) {
94         history_list[i].year = 0;
95         history_list[i].month = 0;
96         history_list[i].hit = 0;
97         history_list[i].file = 0;
98         history_list[i].site = 0;
99         history_list[i].xfer = 0.0;
100         history_list[i].page = 0;
101         history_list[i].visit = 0;
102         history_list[i].first_day = 0;
103         history_list[i].last_day = 0;
104     }
105 
106     /* Open History file and Process */
107     hist_fp = fopen(g_settings.settings.history_filename, "r");
108     if (hist_fp) {
109         VPRINT(VERBOSE1, "%s %s\n", _("Reading history file..."), g_settings.settings.history_filename);
110         while ((fgets(buffer, BUFSIZE, hist_fp)) != NULL) {
111             /* month# year# requests files sites xfer firstday lastday */
112             numfields = sscanf(buffer, "%d %d %lu %lu %lu %lf %d %d %lu %lu",
113                                &history_list[nbr_hist_entries].month,
114                                &history_list[nbr_hist_entries].year,
115                                &history_list[nbr_hist_entries].hit,
116                                &history_list[nbr_hist_entries].file,
117                                &history_list[nbr_hist_entries].site,
118                                &history_list[nbr_hist_entries].xfer, &history_list[nbr_hist_entries].first_day, &history_list[nbr_hist_entries].last_day,
119                                &history_list[nbr_hist_entries].page, &history_list[nbr_hist_entries].visit);
120             if (numfields == 8) {               /* kludge for reading 1.20.xx history files */
121                 history_list[nbr_hist_entries].page = 0;
122                 history_list[nbr_hist_entries].visit = 0;
123             }
124 
125             nbr_hist_entries++;
126             if (nbr_hist_entries > MAXHISTLEN) {
127                 ERRVPRINT(VERBOSE1, "%s (mth=%d)\n", _("Error: Ignoring invalid history record"), nbr_hist_entries + 1);
128                 break;
129             }
130         }
131         fclose(hist_fp);
132         /* Sort the history array. We only need to sort those entries we've just received */
133         qsort(history_list, nbr_hist_entries, sizeof(struct history), cmp_history);
134         if (nbr_hist_entries > 0) {
135             g_counters.month.first_day = history_list[nbr_hist_entries - 1].first_day;
136             g_counters.month.last_day = history_list[nbr_hist_entries - 1].last_day;
137         }
138         VPRINT(VERBOSE2, "History Read. %d Entries\n", nbr_hist_entries);
139     } else {
140         VPRINT(VERBOSE1, "%s\n", _("History file not found..."));
141     }
142 }
143 
144 
145 /*********************************************
146  * PUT_HISTORY - write out history file      *
147  *********************************************/
148 void
put_history()149 put_history()
150 {
151     int i;
152     FILE *hist_fp;
153 
154     hist_fp = fopen(g_settings.settings.history_filename, "w");
155 
156     if (hist_fp) {
157         VPRINT(VERBOSE1, "%s\n", _("Saving history information..."));
158         for (i = 0; i < MAXHISTLEN && i < (g_settings.settings.history_index + 1); i++) {
159             fprintf(hist_fp, "%d %d %lu %lu %lu %.0f %d %d %lu %lu\n",
160                     history_list[i].month, history_list[i].year, history_list[i].hit, history_list[i].file, history_list[i].site, history_list[i].xfer, history_list[i].first_day,
161                     history_list[i].last_day, history_list[i].page, history_list[i].visit);
162         }
163         fclose(hist_fp);
164     } else {
165         ERRVPRINT(VERBOSE1, "%s %s\n", _("Error: Unable to write history file"), g_settings.settings.history_filename);
166     }
167 }
168 
169 
170 /************************************************************************
171  * update_history_array                                                 *
172  *                                                                      *
173  * Updates the history Structure Array.                                 *
174  * Should be run at the end of every month processed.                   *
175  *                                                                      *
176  ************************************************************************/
177 void
update_history_array(void)178 update_history_array(void)
179 {
180     unsigned int year_index, month_index, history_index;
181     unsigned int i, j;
182 
183     VPRINT(VERBOSE2, "Updating History \"by month\" structure\n");
184     g_settings.settings.history_index = 0;
185     if (history_list[0].year == 0) {
186         VPRINT(VERBOSE2, "History Init!\n");
187         /* Empty History; Create 1st entry. */
188         history_list[0].year = g_cur_year;
189         history_list[0].month = g_cur_month;
190         history_list[0].hit = g_counters.month.hit;
191         history_list[0].file = g_counters.month.file;
192         history_list[0].site = g_counters.month.site;
193         history_list[0].xfer = g_counters.month.vol / VOLUMEBASE;
194         history_list[0].first_day = g_counters.month.first_day;
195         history_list[0].last_day = g_counters.month.last_day;
196         history_list[0].page = g_counters.month.page;
197         history_list[0].visit = g_counters.month.visit;
198     } else {
199         history_index = ((g_cur_year - history_list[0].year) * 12) + g_cur_month - history_list[0].month;
200         if (history_index >= MAXHISTLEN) {
201             /* We've managed to exceed the size of the history list!
202              * shuffle everything down */
203             VPRINT(VERBOSE2, "History Shuffle! Max: %u --> %u\n", MAXHISTLEN, history_index);
204             j = history_index - MAXHISTLEN + 1;
205             for (i = 0; i < MAXHISTLEN; i++) {
206 //                VPRINT(0, "Index %u - %u  From: %d/%d ", i,j,history_list[i].year, history_list[i].month);
207                 if ((i + j) >= MAXHISTLEN) {
208 //                    VPRINT(0, " to %d/%d  ZERO\n", 0, 0);
209                     history_list[i].year = 0;
210                     history_list[i].month = 0;
211                     history_list[i].hit = 0;
212                     history_list[i].file = 0;
213                     history_list[i].site = 0;
214                     history_list[i].xfer = 0;
215                     history_list[i].first_day = 0;
216                     history_list[i].last_day = 0;
217                     history_list[i].page = 0;
218                     history_list[i].visit = 0;
219                 } else {
220 //                    VPRINT(0, " to %d/%d  COPY\n", history_list[i + j].year, history_list[i + j].month);
221                     history_list[i].year = history_list[i + j].year;
222                     history_list[i].month = history_list[i + j].month;
223                     history_list[i].hit = history_list[i + j].hit;
224                     history_list[i].file = history_list[i + j].file;
225                     history_list[i].site = history_list[i + j].site;
226                     history_list[i].xfer = history_list[i + j].xfer;
227                     history_list[i].first_day = history_list[i + j].first_day;
228                     history_list[i].last_day = history_list[i + j].last_day;
229                     history_list[i].page = history_list[i + j].page;
230                     history_list[i].visit = history_list[i + j].visit;
231                 }
232             }
233             history_index = MAXHISTLEN - 1;
234         }
235 //        VPRINT(0, " DONE!\n");
236         history_list[history_index].year = g_cur_year;
237         history_list[history_index].month = g_cur_month;
238         history_list[history_index].hit = g_counters.month.hit;
239         history_list[history_index].file = g_counters.month.file;
240         history_list[history_index].site = g_counters.month.site;
241         history_list[history_index].xfer = g_counters.month.vol / VOLUMEBASE;
242         history_list[history_index].first_day = g_counters.month.first_day;
243         history_list[history_index].last_day = g_counters.month.last_day;
244         history_list[history_index].page = g_counters.month.page;
245         history_list[history_index].visit = g_counters.month.visit;
246 
247         g_settings.settings.history_index = history_index;
248     }
249 
250     history_index = 0;
251     month_index = history_list[0].month;
252     year_index = history_list[0].year;
253     for (i = 0; i < MAXHISTLEN; i++) {
254         history_list[i].year = year_index;
255         history_list[i].month = month_index;
256         month_index++;
257         if (month_index > 12) {
258             month_index = 1;
259             year_index++;
260         }
261     }
262 
263     if (g_settings.settings.verbosity >= VERBOSE3) {
264         VPRINT(VERBOSE3, "History Table Dump: --\n");
265         for (i = 0; i < MAXHISTLEN; i++) {
266             VPRINT(VERBOSE3, "%d %d %lu %lu %lu %.0f %d %d %lu %lu\n",
267                    history_list[i].month, history_list[i].year, history_list[i].hit, history_list[i].file, history_list[i].site, history_list[i].xfer, history_list[i].first_day,
268                    history_list[i].last_day, history_list[i].page, history_list[i].visit);
269         }
270         VPRINT(VERBOSE3, " --\n");
271     }
272 }
273 
274 
275 /*********************************************/
276 /* SAVE_STATE - save internal data structs   */
277 /*********************************************/
278 int
save_state()279 save_state()
280 {
281     HNODEPTR hptr;
282     UNODEPTR uptr;
283     RNODEPTR rptr;
284     ANODEPTR aptr;
285     SNODEPTR sptr;
286     INODEPTR iptr;
287     ENODEPTR eptr;
288     SEGNODEPTR segptr;
289 
290     FILE *fp;
291     int i;
292 
293     char buffer[BUFSIZE];
294 
295     /* Open data file for write */
296     fp = fopen(g_settings.settings.state_filename, "w");
297     if (fp == NULL)
298         return 1;
299 
300     /* Saving current run data... */
301     snprintf(buffer, sizeof(buffer), "%04d/%02d/%02d %02d:%02d:%02d", g_cur_year, g_cur_month, g_cur_day, g_cur_hour, g_cur_min, g_cur_sec);
302     VPRINT(VERBOSE1, "%s [%s]\n", _("Saving current run data..."), buffer);
303 
304     /* first, save the easy stuff */
305     /* Header record */
306     snprintf(buffer, sizeof(buffer), "# AWFFull V%s Incremental Data - %02d/%02d/%04d %02d:%02d:%02d\n", version, g_cur_month, g_cur_day, g_cur_year, g_cur_hour, g_cur_min,
307              g_cur_sec);
308     if (fputs(buffer, fp) == EOF)
309         return 1;                               /* error exit */
310 
311     /* Current date/time          */
312     snprintf(buffer, sizeof(buffer), "%d %d %d %d %d %d\n", g_cur_year, g_cur_month, g_cur_day, g_cur_hour, g_cur_min, g_cur_sec);
313     if (fputs(buffer, fp) == EOF)
314         return 1;                               /* error exit */
315 
316     /* Monthly totals for sites, urls, etc... */
317     snprintf(buffer, sizeof(buffer), "%lu %lu %lu %lu %lu %lu %llu %lu %lu %lu %d %lu %lu\n", g_counters.month.hit, g_counters.month.file, g_counters.month.site,
318              g_counters.month.url, g_counters.month.ref, g_counters.month.agent, g_counters.month.vol, g_counters.month.page, g_counters.month.visit, g_counters.month.user, 0,
319              g_counters.generic.bad_month, g_counters.generic.ignored_month);
320     if (fputs(buffer, fp) == EOF)
321         return 1;                               /* error exit */
322 
323     /* Daily totals for sites, urls, etc... */
324     snprintf(buffer, sizeof(buffer), "%u %lu %lu %d %d\n", 0, ht_hit, mh_hit, g_counters.month.first_day, g_counters.month.last_day);
325     if (fputs(buffer, fp) == EOF)
326         return 1;                               /* error exit */
327 
328     /* Monthly (by day) total array */
329     for (i = 0; i < 31; i++) {
330         snprintf(buffer, sizeof(buffer), "%lu %lu %llu %lu %lu %lu %d\n", g_counters.day.hit[i], g_counters.day.file[i], g_counters.day.vol[i], g_counters.day.site[i],
331                  g_counters.day.page[i], g_counters.day.visit[i], 0);
332         if (fputs(buffer, fp) == EOF)
333             return 1;                           /* error exit */
334     }
335 
336     /* Daily (by hour) total array */
337     for (i = 0; i < 24; i++) {
338         snprintf(buffer, sizeof(buffer), "%lu %lu %llu %lu %lu\n", g_counters.hour.hit[i], g_counters.hour.file[i], g_counters.hour.vol[i], g_counters.hour.page[i],
339                  g_counters.hour.site[i]);
340         if (fputs(buffer, fp) == EOF)
341             return 1;                           /* error exit */
342     }
343 
344     /* Response codes */
345     for (i = 0; i < TOTAL_RC; i++) {
346         snprintf(buffer, sizeof(buffer), "%lu\n", response[i].count);
347         if (fputs(buffer, fp) == EOF)
348             return 1;                           /* error exit */
349     }
350 
351     /* now we need to save our linked lists */
352     /* URL list */
353     if (fputs("# -urls- \n", fp) == EOF)
354         return 1;                               /* error exit */
355     for (i = 0; i < MAXHASH; i++) {
356         uptr = um_htab[i];
357         while (uptr != NULL) {
358             snprintf(buffer, sizeof(buffer), "%s\n%d %lu %lu %llu %lu %lu %lu %llu %lu\n", uptr->string, uptr->flag, uptr->count, uptr->files, uptr->xfer, uptr->entry, uptr->exit,
359                      uptr->pcount, uptr->pxfer, uptr->single_access);
360             if (fputs(buffer, fp) == EOF)
361                 return 1;
362             uptr = uptr->next;
363         }
364     }
365     if (fputs("# End Of Table - urls\n", fp) == EOF)
366         return 1;                               /* error exit */
367 
368     /* daily hostname list */
369     if (fputs("# -sites- (monthly)\n", fp) == EOF)
370         return 1;                               /* error exit */
371 
372     for (i = 0; i < MAXHASH; i++) {
373         hptr = sm_htab[i];
374         while (hptr != NULL) {
375             snprintf(buffer, sizeof(buffer), "%s\n%d %lu %lu %llu %lu %lu %lu %d\n%s\n", hptr->string, hptr->flag, hptr->count, hptr->files, hptr->xfer, hptr->visit, hptr->pages,
376                      hptr->tstamp, hptr->lasturl_is_entry, (hptr->lasturl == blank_str) ? "-" : hptr->lasturl);
377             if (fputs(buffer, fp) == EOF)
378                 return 1;                       /* error exit */
379             hptr = hptr->next;
380         }
381     }
382     if (fputs("# End Of Table - sites (monthly)\n", fp) == EOF)
383         return 1;
384 
385     /* hourly hostname list */
386     if (fputs("# -sites- (daily)\n", fp) == EOF)
387         return 1;                               /* error exit */
388     for (i = 0; i < MAXHASH; i++) {
389         hptr = sd_htab[i];
390         while (hptr != NULL) {
391             snprintf(buffer, sizeof(buffer), "%s\n%d %lu %lu %llu %lu %lu %lu %d\n%s\n", hptr->string, hptr->flag, hptr->count, hptr->files, hptr->xfer, hptr->visit, hptr->pages,
392                      hptr->tstamp, hptr->lasturl_is_entry, (hptr->lasturl == blank_str) ? "-" : hptr->lasturl);
393             if (fputs(buffer, fp) == EOF)
394                 return 1;
395             hptr = hptr->next;
396         }
397     }
398     if (fputs("# End Of Table - sites (daily)\n", fp) == EOF)
399         return 1;
400 
401     /* Referrer list */
402     if (fputs("# -referrers- \n", fp) == EOF)
403         return 1;                               /* error exit */
404     if (g_counters.month.ref != 0) {
405         for (i = 0; i < MAXHASH; i++) {
406             rptr = rm_htab[i];
407             while (rptr != NULL) {
408                 snprintf(buffer, sizeof(buffer), "%s\n%d %lu\n", rptr->string, rptr->flag, rptr->count);
409                 if (fputs(buffer, fp) == EOF)
410                     return 1;                   /* error exit */
411                 rptr = rptr->next;
412             }
413         }
414     }
415     if (fputs("# End Of Table - referrers\n", fp) == EOF)
416         return 1;
417 
418     /* User agent list */
419     if (fputs("# -agents- \n", fp) == EOF)
420         return 1;                               /* error exit */
421     if (g_counters.month.agent != 0) {
422         for (i = 0; i < MAXHASH; i++) {
423             aptr = am_htab[i];
424             while (aptr != NULL) {
425                 snprintf(buffer, sizeof(buffer), "%s\n%d %lu\n", aptr->string, aptr->flag, aptr->count);
426                 if (fputs(buffer, fp) == EOF)
427                     return 1;                   /* error exit */
428                 aptr = aptr->next;
429             }
430         }
431     }
432     if (fputs("# End Of Table - agents\n", fp) == EOF)
433         return 1;
434 
435     /* Search String list */
436     if (fputs("# -search strings- \n", fp) == EOF)
437         return 1;                               /* error exit */
438     for (i = 0; i < MAXHASH; i++) {
439         sptr = sr_htab[i];
440         while (sptr != NULL) {
441             snprintf(buffer, sizeof(buffer), "%s\n%lu\n", sptr->string, sptr->count);
442             if (fputs(buffer, fp) == EOF)
443                 return 1;                       /* error exit */
444             sptr = sptr->next;
445         }
446     }
447     if (fputs("# End Of Table - search strings\n", fp) == EOF)
448         return 1;
449 
450     /* username list */
451     if (fputs("# -usernames- \n", fp) == EOF)
452         return 1;                               /* error exit */
453 
454     for (i = 0; i < MAXHASH; i++) {
455         iptr = im_htab[i];
456         while (iptr != NULL) {
457             snprintf(buffer, sizeof(buffer), "%s\n%d %lu %lu %llu %lu %lu\n", iptr->string, iptr->flag, iptr->count, iptr->files, iptr->xfer, iptr->visit, iptr->tstamp);
458             if (fputs(buffer, fp) == EOF)
459                 return 1;                       /* error exit */
460             iptr = iptr->next;
461         }
462     }
463     if (fputs("# End Of Table - usernames\n", fp) == EOF)
464         return 1;
465 
466     /* ErrorPages list */
467     if (fputs("# -404errors- \n", fp) == EOF)
468         return 1;                               /* error exit */
469 
470     for (i = 0; i < MAXHASH; i++) {
471         eptr = ep_htab[i];
472         while (eptr != NULL) {
473             snprintf(buffer, sizeof(buffer), "%s\n%lu\n%s\n", eptr->url, eptr->count, eptr->referer);
474             if (fputs(buffer, fp) == EOF)
475                 return 1;
476             eptr = eptr->next;
477         }
478     }
479     if (fputs("# End Of Table - 404errors\n", fp) == EOF)
480         return 1;                               /* error exit */
481 
482     /* Save Segmenting Data. */
483     if (fputs("# -segmenting_referers- \n", fp) == EOF)
484         return 1;                               /* error exit */
485 
486     for (i = 0; i < MAXHASH; i++) {
487         segptr = seg_ref_htab[i];
488         while (segptr != NULL) {
489             snprintf(buffer, sizeof(buffer), "%s\n%lu\n", segptr->string, segptr->tstamp);
490             if (fputs(buffer, fp) == EOF)
491                 return 1;                       /* error exit */
492             segptr = segptr->next;
493         }
494     }
495     if (fputs("# End Of Table - segmenting_referers\n", fp) == EOF)
496         return 1;
497 
498     fclose(fp);                                 /* close data file...                            */
499     return 0;                                   /* successful, return with good return code      */
500 }
501 
502 
503 /*********************************************
504  * RESTORE_STATE - reload internal run data
505  *
506  * Returns:
507  * 0 on successful load
508  * -1 on no file too load
509  * > 0 on any error in the load
510  *********************************************/
511 int
restore_state()512 restore_state()
513 {
514     FILE *fp;
515     int i;
516     struct hnode t_hnode;                       /* Temporary hash nodes */
517     struct unode t_unode;
518     struct rnode t_rnode;
519     struct anode t_anode;
520     struct snode t_snode;
521     struct inode t_inode;
522     struct enode t_enode;
523     struct seg_node t_segnode;
524 
525     char buffer[BUFSIZE];
526     char buffer2[BUFSIZE], buffer3[BUFSIZE];
527 
528     struct tm time_rec;                         /* Gotta convert that string'ed time into a timerec first */
529 
530     unsigned long ul_bogus = 0;
531 
532     unsigned int tmp_version_major = 0;         /* Scan in the version of the Current Run Data file. Use int's as a float scan was not consistant */
533     unsigned int tmp_version_minor = 0;
534     unsigned int tmp_version_micro = 0;
535     unsigned long rundata_version = 0;          /* The webalizer version from the file header */
536     int ssout;                                  /* sscanf return result for checking */
537 
538     unsigned long ignore_this_value = 0;        /* Ignore this value - was old save, now dropped */
539     bool ignore_this_bool = false;
540 
541     fp = fopen(g_settings.settings.state_filename, "r");
542     if (fp == NULL) {
543         /* Previous run data not found... */
544         VPRINT(VERBOSE1, "%s\n", _("Previous run data not found..."));
545         return -1;                              /* return with Not Found code */
546     }
547 
548     /* Reading previous run data... */
549     VPRINT(VERBOSE1, "%s %s\n", _("Reading previous run data.."), g_settings.settings.state_filename);
550 
551     /* get easy stuff */
552     /* Header record */
553     if ((fgets(buffer, BUFSIZE, fp)) != NULL) {
554         ssout = sscanf(buffer, "# AWFFull V%u.%u.%u", &tmp_version_major, &tmp_version_minor, &tmp_version_micro);
555         if (ssout <= 0) {
556             /* Possibly Webalizer format header? */
557             ssout = sscanf(buffer, "# Webalizer V%u.%u", &tmp_version_major, &tmp_version_minor);
558             if (ssout <= 0) {
559                 return (1);
560             }
561         }
562         /* Version level = Major x 10,000 + Minor x 100 + Micro
563          *      Micro is *always* > 0
564          *      Gives us 99 levels in Minor and Micro
565          *   3.3.1 = 30301
566          */
567         if (tmp_version_micro == 0) {           /* Old Webalizer Format, early awffull */
568             rundata_version = tmp_version_major * 100 + tmp_version_minor;
569         } else {
570             rundata_version = tmp_version_major * 10000 + tmp_version_minor * 100 + tmp_version_micro;
571         }
572 
573         VPRINT(VERBOSE1, "%s %lu\n", _("Previous Run Version:"), rundata_version);
574         if (rundata_version < 201) {            /* Check for version compatibility */
575             return 99;
576         }
577         if (rundata_version < 301) {
578             ERRVPRINT(VERBOSE0, "%s\n", _("Warning: Changes to Referrals & User Agents count methods. See README!"));
579         }
580     } /* bad magic? */
581     else
582         return 98;                              /* error exit */
583 
584     /* Current date/time          */
585     if ((fgets(buffer, BUFSIZE, fp)) != NULL) {
586         memset(&time_rec, 0, sizeof(time_rec));
587         strptime(buffer, "%Y %m %d %H %M %S", &time_rec);
588         /* calculate current timestamp (seconds since epoch) and setup current time globals */
589         time_rec.tm_isdst = -1;                 /* stop mktime from resetting for daylight savings */
590         cur_tstamp = mktime(&time_rec);
591         VPRINT(VERBOSE1, "%s %lu", _("Previous Final Timestamp:"), cur_tstamp);
592         g_cur_year = time_rec.tm_year + 1900;
593         g_cur_month = time_rec.tm_mon + 1;
594         g_cur_day = time_rec.tm_mday;
595         g_cur_hour = time_rec.tm_hour;
596         g_cur_min = time_rec.tm_min;
597         g_cur_sec = time_rec.tm_sec;
598         VPRINT(VERBOSE1, " %d-%d-%d:%d:%d:%d\n", g_cur_year, g_cur_month, g_cur_day, g_cur_hour, g_cur_min, g_cur_sec);
599     } else
600         return 2;                               /* error exit */
601 
602     /* Monthly totals for sites, urls, etc... */
603     if ((fgets(buffer, BUFSIZE, fp)) != NULL) {
604         if (rundata_version < 302) {
605             sscanf(buffer, "%lu %lu %lu %lu %lu %lu %llu %lu %lu %lu", &g_counters.month.hit, &g_counters.month.file, &g_counters.month.site, &g_counters.month.url,
606                    &g_counters.month.ref, &g_counters.month.agent, &g_counters.month.vol, &g_counters.month.page, &g_counters.month.visit, &g_counters.month.user);
607         } else {
608             sscanf(buffer, "%lu %lu %lu %lu %lu %lu %llu %lu %lu %lu %lu %lu %lu", &g_counters.month.hit, &g_counters.month.file, &g_counters.month.site, &g_counters.month.url,
609                    &g_counters.month.ref, &g_counters.month.agent, &g_counters.month.vol, &g_counters.month.page, &g_counters.month.visit, &g_counters.month.user,
610                    &ignore_this_value, &g_counters.generic.bad_month, &g_counters.generic.ignored_month);
611         }
612     } else
613         return 3;                               /* error exit */
614 
615     /* Daily totals for sites, urls, etc... */
616     if ((fgets(buffer, BUFSIZE, fp)) != NULL) {
617         sscanf(buffer, "%lu %lu %lu %d %d", &ignore_this_value, &ht_hit, &mh_hit, &g_counters.month.first_day, &g_counters.month.last_day);
618     } else
619         return 4;                               /* error exit */
620 
621     /* Monthly (by day) total array */
622     for (i = 0; i < 31; i++) {
623         if ((fgets(buffer, BUFSIZE, fp)) != NULL) {
624             if (rundata_version < 302) {
625                 sscanf(buffer, "%lu %lu %llu %lu %lu %lu", &g_counters.day.hit[i], &g_counters.day.file[i], &g_counters.day.vol[i], &g_counters.day.site[i],
626                        &g_counters.day.page[i], &g_counters.day.visit[i]);
627             } else {
628                 sscanf(buffer, "%lu %lu %llu %lu %lu %lu %lu", &g_counters.day.hit[i], &g_counters.day.file[i], &g_counters.day.vol[i], &g_counters.day.site[i],
629                        &g_counters.day.page[i], &g_counters.day.visit[i], &ignore_this_value);
630             }
631         } else
632             return 5;                           /* error exit */
633     }
634 
635     /* Daily (by hour) total array */
636     for (i = 0; i < 24; i++) {
637         if ((fgets(buffer, BUFSIZE, fp)) != NULL) {
638             if (rundata_version < 302) {
639                 sscanf(buffer, "%lu %lu %llu %lu", &g_counters.hour.hit[i], &g_counters.hour.file[i], &g_counters.hour.vol[i], &g_counters.hour.page[i]);
640             } else if (rundata_version < 30801) {
641                 sscanf(buffer, "%lu %lu %llu %lu %lu", &g_counters.hour.hit[i], &g_counters.hour.file[i], &g_counters.hour.vol[i], &g_counters.hour.page[i], &ignore_this_value);
642             } else {
643                 sscanf(buffer, "%lu %lu %llu %lu %lu", &g_counters.hour.hit[i], &g_counters.hour.file[i], &g_counters.hour.vol[i], &g_counters.hour.page[i],
644                        &g_counters.hour.site[i]);
645             }
646         } else
647             return 6;                           /* error exit */
648     }
649 
650     /* Response codes */
651     for (i = 0; i < TOTAL_RC; i++) {
652         if ((fgets(buffer, BUFSIZE, fp)) != NULL)
653             sscanf(buffer, "%lu", &response[i].count);
654         else
655             return 7;                           /* error exit */
656     }
657 
658 
659     /* now we need to restore our linked lists */
660     /* URL list */
661 
662     /* Kludge for V2.01-06 TOTAL_RC off by one bug */
663     if (!strncmp(buffer, "# -urls- ", 9))
664         response[TOTAL_RC - 1].count = 0;
665     else {
666         /* now do hash tables */
667 
668         /* url table */
669         if ((fgets(buffer, BUFSIZE, fp)) != NULL) {     /* Table header */
670             if (strncmp(buffer, "# -urls- ", 9))
671                 return 8;
672         } /* (url)        */
673         else
674             return 8;                           /* error exit */
675     }
676 
677     while ((fgets(buffer2, BUFSIZE, fp)) != NULL) {
678         if (!strncmp(buffer2, "# End Of Table ", 15))
679             break;
680         buffer2[strlen(buffer2) - 1] = '\0';    /* Chop off trailing newline */
681 
682         if ((fgets(buffer, BUFSIZE, fp)) == NULL)
683             return 9;                           /* error exit */
684         if (!isdigit((int) buffer[0]))
685             return 9;                           /* error exit */
686 
687         /* Zero values not used in loads of older data */
688         t_unode.single_access = 0;
689         t_unode.pcount = 0;
690         t_unode.pxfer = 0;
691         /* load temporary node data */
692         if (rundata_version >= 30801) {
693             sscanf(buffer, "%d %lu %lu %llu %lu %lu %lu %llu %lu", &t_unode.flag, &t_unode.count, &t_unode.files, &t_unode.xfer, &t_unode.entry, &t_unode.exit, &t_unode.pcount,
694                    &t_unode.pxfer, &t_unode.single_access);
695         } else if (rundata_version > 30403) {
696             sscanf(buffer, "%d %lu %lu %llu %lu %lu %lu %llu", &t_unode.flag, &t_unode.count, &t_unode.files, &t_unode.xfer, &t_unode.entry, &t_unode.exit, &t_unode.pcount,
697                    &t_unode.pxfer);
698         } else {
699             sscanf(buffer, "%d %lu %lu %llu %lu %lu", &t_unode.flag, &t_unode.count, &t_unode.files, &t_unode.xfer, &t_unode.entry, &t_unode.exit);
700         }
701 
702         /* Good record, insert into hash table */
703         if (put_unode(buffer2, t_unode.flag, t_unode.count, t_unode.xfer, &ul_bogus, t_unode.entry, t_unode.exit, t_unode.single_access, 0, um_htab)) {
704             /* Error adding URL node, skipping ... */
705             ERRVPRINT(VERBOSE1, "%s %s\n", _("Error adding URL node, skipping"), buffer2);
706         }
707     }
708 
709     /* daily hostname list */
710     if ((fgets(buffer, BUFSIZE, fp)) != NULL) { /* Table header */
711         if (strncmp(buffer, "# -sites- ", 10))
712             return 10;
713     } /* (monthly)    */
714     else
715         return 10;                              /* error exit */
716 
717     while ((fgets(buffer2, BUFSIZE, fp)) != NULL) {
718         /* Check for end of table */
719         if (!strncmp(buffer2, "# End Of Table ", 15))
720             break;
721         buffer2[strlen(buffer2) - 1] = '\0';    /* Chop off trailing newline */
722 
723         if ((fgets(buffer, BUFSIZE, fp)) == NULL)
724             return 11;                          /* error exit */
725         if (!isdigit((int) buffer[0]))
726             return 11;                          /* error exit */
727 
728         /* Zero values not used in loads of older data */
729         t_hnode.pages = 0;
730         t_hnode.lasturl_is_entry = false;
731         /* load temporary node data */
732         if (rundata_version < 300) {
733             sscanf(buffer, "%d %lu %lu %llu %lu %lu", &t_hnode.flag, &t_hnode.count, &t_hnode.files, &t_hnode.xfer, &t_hnode.visit, &t_hnode.tstamp);
734             t_hnode.pages = 0;
735         } else if (rundata_version < 30801) {
736             sscanf(buffer, "%d %lu %lu %llu %lu %lu %lu", &t_hnode.flag, &t_hnode.count, &t_hnode.files, &t_hnode.xfer, &t_hnode.visit, &t_hnode.pages, &t_hnode.tstamp);
737         } else {                                /* version 3.00, aka 300, included t_hnode.pages in the output */
738             sscanf(buffer, "%d %lu %lu %llu %lu %lu %lu %hhd", &t_hnode.flag, &t_hnode.count, &t_hnode.files, &t_hnode.xfer, &t_hnode.visit, &t_hnode.pages, &t_hnode.tstamp,
739                    &t_hnode.lasturl_is_entry);
740         }
741 
742         /* get last url */
743         if ((fgets(buffer, BUFSIZE, fp)) == NULL)
744             return 11;                          /* error exit */
745         if (buffer[0] == '-')
746             t_hnode.lasturl = blank_str;
747         else {
748             buffer[strlen(buffer) - 1] = 0;
749             t_hnode.lasturl = find_url(buffer);
750         }
751 
752         /* Good record, insert into hash table */
753         if (put_hnode
754             (buffer2, t_hnode.flag, t_hnode.count, t_hnode.files, t_hnode.xfer, &ul_bogus, t_hnode.visit, t_hnode.pages, t_hnode.tstamp, "", t_hnode.lasturl, sm_htab,
755              t_hnode.lasturl_is_entry, false, &ignore_this_bool)) {
756             /* Error adding host node (monthly), skipping .... */
757             ERRVPRINT(VERBOSE1, "%s %s\n", _("Error adding Host node (monthly), skipping"), buffer2);
758         }
759     }
760 
761     /* hourly hostname list */
762     if ((fgets(buffer, BUFSIZE, fp)) != NULL) { /* Table header */
763         if (strncmp(buffer, "# -sites- ", 10))
764             return 12;
765     } /* (daily)      */
766     else
767         return 12;                              /* error exit */
768 
769     while ((fgets(buffer2, BUFSIZE, fp)) != NULL) {
770         /* Check for end of table */
771         if (!strncmp(buffer2, "# End Of Table ", 15))
772             break;
773         buffer2[strlen(buffer2) - 1] = '\0';    /* Chop off trailing newline */
774 
775         if ((fgets(buffer, BUFSIZE, fp)) == NULL)
776             return 13;                          /* error exit */
777         if (!isdigit((int) buffer[0]))
778             return 13;                          /* error exit */
779 
780         /* Zero values not used in loads of older data */
781         t_hnode.pages = 0;
782         t_hnode.lasturl_is_entry = false;
783         /* load temporary node data */
784         if (rundata_version < 300) {
785             sscanf(buffer, "%d %lu %lu %llu %lu %lu", &t_hnode.flag, &t_hnode.count, &t_hnode.files, &t_hnode.xfer, &t_hnode.visit, &t_hnode.tstamp);
786             t_hnode.pages = 0;
787         } else if (rundata_version < 30801) {   /* version 3.00, aka 300, included t_hnode.pages in the output */
788             sscanf(buffer, "%d %lu %lu %llu %lu %lu %lu", &t_hnode.flag, &t_hnode.count, &t_hnode.files, &t_hnode.xfer, &t_hnode.visit, &t_hnode.pages, &t_hnode.tstamp);
789         } else {                                /* version 3.8.1, aka 30801, included t_hnode.lasturl_is_entry in the output */
790             sscanf(buffer, "%d %lu %lu %llu %lu %lu %lu %hhd", &t_hnode.flag, &t_hnode.count, &t_hnode.files, &t_hnode.xfer, &t_hnode.visit, &t_hnode.pages, &t_hnode.tstamp,
791                    &(t_hnode.lasturl_is_entry));
792         }
793 
794 
795         /* get last url */
796         if ((fgets(buffer, BUFSIZE, fp)) == NULL)
797             return 13;                          /* error exit */
798         if (buffer[0] == '-')
799             t_hnode.lasturl = blank_str;
800         else {
801             buffer[strlen(buffer) - 1] = 0;
802             t_hnode.lasturl = find_url(buffer);
803         }
804 
805         /* Good record, insert into hash table */
806         if (put_hnode
807             (buffer2, t_hnode.flag, t_hnode.count, t_hnode.files, t_hnode.xfer, &ul_bogus, t_hnode.visit, t_hnode.pages, t_hnode.tstamp, "", t_hnode.lasturl, sd_htab,
808              t_hnode.lasturl_is_entry, false, &ignore_this_bool)) {
809             /* Error adding host node (daily), skipping .... */
810             ERRVPRINT(VERBOSE1, "%s %s\n", _("Error adding Host node (daily), skipping"), buffer2);
811         }
812     }
813 
814     /* Referrer list */
815     if ((fgets(buffer, BUFSIZE, fp)) != NULL) { /* Table header */
816         if (strncmp(buffer, "# -referrers- ", 14))
817             return 14;
818     } else
819         return 14;                              /* error exit */
820 
821     while ((fgets(buffer2, BUFSIZE, fp)) != NULL) {
822         if (!strncmp(buffer2, "# End Of Table ", 15))
823             break;
824         buffer2[strlen(buffer2) - 1] = '\0';    /* Chop off trailing newline */
825 
826         if ((fgets(buffer, BUFSIZE, fp)) == NULL)
827             return 15;                          /* error exit */
828         if (!isdigit((int) buffer[0]))
829             return 15;                          /* error exit */
830 
831         /* load temporary node data */
832         sscanf(buffer, "%d %lu", &t_rnode.flag, &t_rnode.count);
833 
834         /* insert node */
835         if (put_rnode(buffer2, t_rnode.flag, t_rnode.count, &ul_bogus, rm_htab)) {
836             ERRVPRINT(VERBOSE1, "%s %s\n", _("Error adding Referrer node, skipping"), buffer2);
837         }
838     }
839 
840     /* User agent list */
841     if ((fgets(buffer, BUFSIZE, fp)) != NULL) { /* Table header */
842         if (strncmp(buffer, "# -agents- ", 11))
843             return 16;
844     } else
845         return 16;                              /* error exit */
846 
847     while ((fgets(buffer2, BUFSIZE, fp)) != NULL) {
848         if (!strncmp(buffer2, "# End Of Table ", 15))
849             break;
850         buffer2[strlen(buffer2) - 1] = '\0';    /* Chop off trailing newline */
851 
852         if ((fgets(buffer, BUFSIZE, fp)) == NULL)
853             return 17;                          /* error exit */
854         if (!isdigit((int) buffer[0]))
855             return 17;                          /* error exit */
856 
857         /* load temporary node data */
858         sscanf(buffer, "%d %lu", &t_anode.flag, &t_anode.count);
859 
860         /* insert node */
861         if (put_anode(buffer2, t_anode.flag, t_anode.count, &ul_bogus, am_htab)) {
862             ERRVPRINT(VERBOSE1, "%s %s\n", _("Error adding User Agent node, skipping"), buffer2);
863         }
864     }
865 
866     /* Search Strings table */
867     if ((fgets(buffer, BUFSIZE, fp)) != NULL) { /* Table header */
868         if (strncmp(buffer, "# -search string", 16))
869             return 18;
870     } else
871         return 18;                              /* error exit */
872 
873     while ((fgets(buffer2, BUFSIZE, fp)) != NULL) {
874         if (!strncmp(buffer2, "# End Of Table ", 15))
875             break;
876         buffer2[strlen(buffer2) - 1] = '\0';    /* Chop off trailing newline */
877 
878         if ((fgets(buffer, BUFSIZE, fp)) == NULL)
879             return 19;                          /* error exit */
880         if (!isdigit((int) buffer[0]))
881             return 19;                          /* error exit */
882 
883         /* load temporary node data */
884         sscanf(buffer, "%lu", &t_snode.count);
885 
886         /* insert node */
887         if (put_snode(buffer2, t_snode.count, sr_htab)) {
888             ERRVPRINT(VERBOSE1, "%s %s\n", _("Error adding Search String Node, skipping"), buffer2);
889         }
890     }
891 
892     /* usernames table */
893     if ((fgets(buffer, BUFSIZE, fp)) != NULL) { /* Table header */
894         if (strncmp(buffer, "# -usernames- ", 10))
895             return 20;
896     } else
897         return 20;                              /* error exit */
898 
899     while ((fgets(buffer2, BUFSIZE, fp)) != NULL) {
900         /* Check for end of table */
901         if (!strncmp(buffer2, "# End Of Table ", 15))
902             break;
903         buffer2[strlen(buffer2) - 1] = '\0';    /* Chop off trailing newline */
904 
905         if ((fgets(buffer, BUFSIZE, fp)) == NULL)
906             return 21;                          /* error exit */
907         if (!isdigit((int) buffer[0]))
908             return 21;                          /* error exit */
909 
910         /* load temporary node data */
911         sscanf(buffer, "%d %lu %lu %llu %lu %lu", &t_inode.flag, &t_inode.count, &t_inode.files, &t_inode.xfer, &t_inode.visit, &t_inode.tstamp);
912 
913         /* Good record, insert into hash table */
914         if (put_inode(buffer2, t_inode.flag, t_inode.count, t_inode.files, t_inode.xfer, &ul_bogus, t_inode.visit, t_inode.tstamp, im_htab, false)) {
915             /* Error adding username node, skipping .... */
916             ERRVPRINT(VERBOSE1, "%s %s\n", _("Error adding Username node, skipping"), buffer2);
917         }
918     }
919 
920     if (rundata_version > 302) {
921         /* 404 table */
922         if ((fgets(buffer, BUFSIZE, fp)) != NULL) {     /* Table header */
923             if (strncmp(buffer, "# -404errors- ", 14))
924                 return 22;
925         } else
926             return 22;                          /* error exit */
927 
928         while ((fgets(buffer2, BUFSIZE, fp)) != NULL) {
929             if (!strncmp(buffer2, "# End Of Table ", 15))
930                 break;
931             buffer2[strlen(buffer2) - 1] = '\0';        /* Chop off trailing newline */
932 
933             if ((fgets(buffer, BUFSIZE, fp)) == NULL)
934                 return 23;                      /* error exit */
935             if (!isdigit((int) buffer[0]))
936                 return 23;                      /* error exit */
937 
938             /* load temporary node data */
939             sscanf(buffer, "%lu", &t_enode.count);
940 
941             if ((fgets(buffer3, BUFSIZE, fp)) == NULL)
942                 return 23;                      /* error exit */
943             buffer3[strlen(buffer3) - 1] = '\0';        /* Chop off trailing newline */
944 
945             /* Good record, insert into hash table */
946             if (put_enode(buffer2, buffer3, OBJ_REG, t_enode.count, &g_counters.generic.error_month, ep_htab)) {
947                 /* Error adding URL node, skipping ... */
948                 ERRVPRINT(VERBOSE1, "%s %s\n", _("Error adding URL node, skipping"), buffer2);
949             }
950         }
951     }
952 
953 
954     /* Restore Segmenting Data. */
955     if (rundata_version >= 30901) {
956         if ((fgets(buffer, BUFSIZE, fp)) != NULL) {     /* Table header */
957             if (strncmp(buffer, "# -segmenting_referers- ", 10))
958                 return 24;
959         } else
960             return 24;                          /* error exit */
961 
962         while ((fgets(buffer2, BUFSIZE, fp)) != NULL) {
963             /* Check for end of table */
964             if (!strncmp(buffer2, "# End Of Table ", 15))
965                 break;
966             buffer2[strlen(buffer2) - 1] = '\0';        /* Chop off trailing newline */
967 
968             if ((fgets(buffer, BUFSIZE, fp)) == NULL)
969                 return 25;                      /* error exit */
970             if (!isdigit((int) buffer[0]))
971                 return 25;                      /* error exit */
972 
973             /* load temporary node data */
974             sscanf(buffer, "%lu", &t_segnode.tstamp);
975 
976             /* Good record, insert into hash table */
977             if (!put_segnode(buffer2, t_segnode.tstamp, seg_ref_htab)) {
978                 /* Error adding segmenting by referrer node, skipping .... */
979                 ERRVPRINT(VERBOSE1, "%s %s\n", _("Error adding Segmenting By Referrer node, skipping"), buffer2);
980             }
981         }
982     }
983 
984     fclose(fp);
985     g_settings.flags.is_first_run = false;      /* First run is false, as we're effectively mid-run */
986     return 0;                                   /* return with ok code       */
987 }
988 
989 
990 /************************************************************************
991  ************************************************************************
992  *                      END OF FILE                                     *
993  ************************************************************************
994  ************************************************************************/
995