file.c

00001 /*
00002  * Copyright (c) 2005-2012 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: file.c,v 1.20 2007/11/09 22:06:26 tat Exp $
00009  */
00010 
00011 #include <sys/param.h>
00012 #include <sys/types.h>
00013 #include <sys/stat.h>
00014 #include <fcntl.h>
00015 #include <unistd.h>
00016 #include <u/libu.h>
00017 #include <klone/klog.h>
00018 #include <klone/klogprv.h>
00019 
00020 static void klog_close_file (klog_t *klf);
00021 static int klog_file (klog_t *klf, int level, const char *fmt, va_list ap);
00022 static int klog_flush_file (klog_t *kl);
00023 
00024 /* 
00025  * A 'file' log is physically subdivided in a certain number of files (pages)
00026  * named "<basename>.<page_id>" used as a sliding circular buffer.
00027  * A page must be thought as a fixed size array of log lines.  Each page 
00028  * in a 'file' log is of the same dimension so that each log line can be
00029  * referenced univocally.  Suppose a 'file' log made of n pages p_0, p_1, 
00030  * ..., p_n-1 of size m: the i-th line (0 <= i < n*m) will be found in page 
00031  * p_i%m at offset i%n.  We assume that at least 2 pages (n=2) exist.
00032  *
00033  * State informations are grouped into a 'head' file to be preserved between
00034  * one run and the subsequent.  Informations in 'head' (i.e. n, m, active page
00035  * id, offset in it) are used iff they correspond to actual config parameters.
00036  * Otherwise past log is discarded.
00037  *
00038  * (1) initialisation (where to start writing)
00039  * (2) append a log line
00040  * (3) termination (flush state to disk on exit)
00041  *
00042  * (1)
00043  * The 'file' log initialisation phase consists in the selection of an 
00044  * available page and an offset in it, where to start appending log messages.
00045  * The needed informations, if consistent with the supplied conf parameters, 
00046  * are gathered from the 'head' page.  If no 'head' is available (non-existent,
00047  * damaged or inconsistent with conf) the write pointer will be placed at page
00048  * zero, offset zero.
00049  */
00050 
00051 static void klog_free_file (klog_file_t *klf);
00052 static int klog_file_head_load (const char *base, klog_file_t **pklf);
00053 static int klog_file_head_dump (klog_file_t *klf);
00054 static int klog_file_head_new (const char *base, size_t npages, size_t nlines, 
00055         size_t wpageid, size_t offset, klog_file_t **pklf);
00056 static void klog_file_head_free (klog_file_t *klf);
00057 static int klog_file_append (klog_file_t *klf, const char *id, int level, 
00058         const char *ln);
00059 static int klog_file_open_page (klog_file_t *klf);
00060 static int klog_file_shift_page (klog_file_t *klf);
00061 
00062 int klog_open_file (klog_t *kl, const char *base, size_t npages, size_t nlines)
00063 {
00064     klog_file_t *klf = NULL;
00065 
00066     dbg_return_if (kl == NULL, ~0);
00067     dbg_return_if (base == NULL, ~0);
00068 
00069     /* load an existing head or create a brand new if it doesn't exist */
00070     if (klog_file_head_load(base, &klf))
00071         dbg_err_if (klog_file_head_new(base, npages, nlines, 0, 0, &klf));
00072     else
00073     {
00074         /* check consistency with the supplied values, in case there is
00075          * a delta for npages and nlines, reset everything */
00076         dbg_ifb (klf->npages != npages || klf->nlines != nlines)
00077         {
00078             klf->npages = npages;
00079             klf->nlines = nlines;
00080             klf->wpageid = 0;
00081             klf->offset = 0;
00082         }
00083     }
00084 
00085     /* open the working log page for writing */
00086     dbg_err_if (klog_file_open_page(klf));
00087 
00088     /* set private methods */
00089     kl->cb_log = klog_file;
00090     kl->cb_close = klog_close_file;
00091     kl->cb_getln = NULL;
00092     kl->cb_countln = NULL;
00093     kl->cb_clear = NULL;
00094     kl->cb_flush = klog_flush_file;
00095 
00096     kl->u.f = klf, klf = NULL;
00097 
00098     return 0;
00099 err:
00100     if (klf)
00101         klog_free_file(klf);
00102     return ~0;
00103 }
00104 
00105 static void klog_free_file (klog_file_t *klf)
00106 {
00107     U_FREE(klf);
00108 }
00109 
00110 static int klog_flush_file (klog_t *kl)
00111 {
00112     klog_file_t *klf;
00113 
00114     dbg_return_if (kl == NULL, ~0);
00115     dbg_return_if (kl->type != KLOG_TYPE_FILE, ~0);
00116     dbg_return_if (kl->u.f == NULL, ~0);
00117 
00118     klf = kl->u.f;
00119      
00120     dbg_err_if (klf->wfp == NULL);
00121     dbg_err_sif (fflush(klf->wfp) != 0);
00122 
00123     return 0;
00124 err:
00125     return ~0;
00126 }
00127 
00128 static int klog_file (klog_t *kl, int level, const char *fmt, va_list ap)
00129 {
00130     klog_file_t *klf;
00131     char ln[KLOG_LN_SZ + 1];
00132     
00133     dbg_return_if (kl == NULL, ~0);
00134     dbg_return_if (kl->type != KLOG_TYPE_FILE, ~0);
00135     dbg_return_if (kl->u.f == NULL, ~0);
00136     dbg_return_if (fmt == NULL, ~0);
00137 
00138     klf = kl->u.f;
00139 
00140     /* print log string */
00141     vsnprintf(ln, sizeof ln, fmt, ap);
00142     
00143     if (KLOG_PAGE_FULL(klf)) /* shift working page */
00144         dbg_err_if (klog_file_shift_page(klf));
00145 
00146     dbg_err_if (klog_file_append(klf, kl->ident, level, ln));
00147 
00148     return 0;
00149 err:
00150     return ~0;
00151 }
00152 
00153 static int klog_file_append (klog_file_t *klf, const char *id, int level, 
00154         const char *ln)
00155 {
00156     time_t now;
00157     char *ct;
00158 
00159     dbg_return_if (ln == NULL, ~0);
00160     dbg_return_if (id == NULL, ~0);
00161     dbg_return_if (klf == NULL, ~0);
00162     dbg_return_if (klf->wfp == NULL, ~0);
00163 
00164     dbg_err_if ((now = time(NULL)) == (time_t) -1);
00165     ct = ctime((const time_t *) &now);
00166     ct[24] = '\0';
00167 
00168     /* append line to wrk page */
00169     fprintf(klf->wfp, "[%s] %s <%s>: %s\n", 
00170             klog_to_str(level), ct, id, ln);
00171     klf->offset += 1;
00172 
00173     fflush(klf->wfp);
00174 
00175     return 0;
00176 err:
00177     return ~0;
00178 }
00179 
00180 static void klog_close_file (klog_t *kl)
00181 {
00182     klog_file_t *klf;
00183     
00184     dbg_ifb (kl == NULL) return;
00185     dbg_ifb (kl->type != KLOG_TYPE_FILE) return;
00186     dbg_ifb (kl->u.f == NULL) return;
00187 
00188     klf = kl->u.f;
00189     
00190     /* flush pending messages */
00191     U_FCLOSE(klf->wfp);
00192 
00193     /* dump head info to disk */
00194     dbg_if (klog_file_head_dump(klf));
00195 
00196     /* free resources */
00197     klog_free_file(klf), kl->u.f = NULL;
00198     
00199     return;
00200 }
00201 
00202 static int klog_file_head_load (const char *base, klog_file_t **pklf)
00203 {
00204     FILE *hfp = NULL;
00205     char hf[U_FILENAME_MAX];
00206     klog_file_t hfs, *klf = NULL;
00207 
00208     dbg_return_if (base == NULL, ~0);
00209     dbg_return_if (pklf == NULL, ~0);
00210     
00211     dbg_err_if (u_path_snprintf(hf, U_FILENAME_MAX, U_PATH_SEPARATOR, "%s%s", 
00212         base, ".head"));
00213     dbg_err_if ((hfp = fopen(hf, "r")) == NULL);
00214     dbg_err_if (fread(&hfs, sizeof hfs, 1, hfp) != 1);
00215     U_FCLOSE(hfp);
00216 
00217     dbg_err_if (klog_file_head_new(base, hfs.npages, hfs.nlines, 
00218                                    hfs.wpageid, hfs.offset, &klf));
00219     *pklf = klf;
00220 
00221     return 0;
00222 err:
00223     if (klf)
00224         klog_file_head_free(klf);
00225     U_FCLOSE(hfp);
00226     return ~0;
00227 }
00228 
00229 static int klog_file_head_dump (klog_file_t *klf)
00230 {
00231     FILE *hfp = NULL;
00232     char hf[U_FILENAME_MAX];
00233     
00234     dbg_return_if (klf == NULL, ~0);
00235 
00236     dbg_err_if (u_path_snprintf(hf, U_FILENAME_MAX, U_PATH_SEPARATOR, "%s.%s", 
00237                                 klf->basename, "head"));
00238     dbg_err_if ((hfp = fopen(hf, "w")) == NULL);
00239     dbg_err_if (fwrite(klf, sizeof(klog_file_t), 1, hfp) != 1);
00240     U_FCLOSE(hfp);
00241 
00242     return 0;
00243 err:
00244     U_FCLOSE(hfp);
00245     return ~0;
00246 }
00247 
00248 static int klog_file_head_new (const char *base, size_t npages, size_t nlines, 
00249         size_t wpageid, size_t offset, klog_file_t **pklf)
00250 {
00251     klog_file_t *klf = NULL;
00252 
00253     klf = u_zalloc(sizeof(klog_file_t));
00254     dbg_err_if (klf == NULL);
00255 
00256     u_strlcpy(klf->basename, base, sizeof klf->basename);
00257     klf->npages = npages;
00258     klf->nlines = nlines;
00259     klf->wpageid = wpageid;
00260     klf->offset = offset;
00261     klf->wfp = NULL;
00262 
00263     *pklf = klf;
00264 
00265     return 0;
00266 err:
00267     klog_file_head_free(klf);
00268     return ~0;
00269 }
00270 
00271 static void klog_file_head_free (klog_file_t *klf)
00272 {
00273     if (klf == NULL)
00274         return;
00275 
00276     U_FCLOSE(klf->wfp);
00277     U_FREE(klf);
00278     
00279     return;
00280 }
00281 
00282 static int klog_file_shift_page (klog_file_t *klf)
00283 {
00284     char wf[U_FILENAME_MAX];
00285     
00286     dbg_return_if (klf == NULL, ~0);
00287 
00288     U_FCLOSE(klf->wfp);
00289     dbg_err_if (u_path_snprintf(wf, U_FILENAME_MAX, U_PATH_SEPARATOR, "%s.%d", 
00290         klf->basename, (klf->wpageid + 1)%klf->npages));
00291     dbg_err_if ((klf->wfp = fopen(wf, "w")) == NULL);
00292 
00293     klf->offset = 0;                                /* reset offset counter */
00294     klf->wpageid = ++(klf->wpageid)%klf->npages;    /* increment page id */
00295     
00296     return 0;
00297 err:
00298     return ~0;
00299 }
00300 
00301 static int klog_file_open_page (klog_file_t *klf)
00302 {
00303     char wf[U_FILENAME_MAX];
00304 
00305     dbg_return_if (klf == NULL, ~0);
00306 
00307     dbg_err_if (u_path_snprintf(wf, U_FILENAME_MAX, U_PATH_SEPARATOR, "%s.%d", 
00308                                 klf->basename, klf->wpageid));
00309     dbg_err_if ((klf->wfp = fopen(wf, "a")) == NULL);
00310     
00311     return 0;
00312 err:
00313     return ~0;
00314 }

←Products
Copyright © 2005-2012 - KoanLogic S.r.l. - All rights reserved