libexplain  1.4.D001
libexplain/output/syslog.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2010-2013 Peter Miller
00004  * Written by Peter Miller <pmiller@opensource.org.au>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as
00008  * published by the Free Software Foundation; either version 3 of the
00009  * License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include <libexplain/ac/string.h>
00021 #include <libexplain/ac/syslog.h>
00022 
00023 #include <libexplain/output.h>
00024 #include <libexplain/program_name.h>
00025 
00026 
00027 typedef struct explain_output_syslog_t explain_output_syslog_t;
00028 struct explain_output_syslog_t
00029 {
00030     explain_output_t inherited;
00031     int priority;
00032 };
00033 
00034 static int openlog_has_been_called;
00035 
00036 
00037 static void
00038 message(explain_output_t *op, const char *text)
00039 {
00040     explain_output_syslog_t *p;
00041     const char      *prog;
00042     size_t          text_size;
00043 
00044     text_size = strlen(text);
00045     while (text_size > 0 && text[text_size - 1] == '\n')
00046         --text_size;
00047 
00048     /*
00049      * The syslog implementation in glibc is determined to have the "ident"
00050      * in the error message.  Contrary to the man page, if "ident" is NULL,
00051      * instead of no program name (as documented), it inserts its own idea of
00052      * the program name.  To have it use libexplain's idea of the program
00053      * name, we provide it to openlog(), and remove it (if present) from the
00054      * string passed to syslog().  Plus, an empty "ident" string makes for an
00055      * inconsistent {ugly} syslog format.
00056      */
00057     prog = explain_program_name_get();
00058     if (prog && *prog)
00059     {
00060         size_t prog_size = strlen(prog);
00061         size_t delta = prog_size + 2;
00062         if
00063         (
00064             text_size >= delta
00065         &&
00066             memcmp(text, prog, prog_size) == 0
00067         &&
00068             memcmp(text + prog_size, ": ", 2) == 0
00069         )
00070         {
00071             text += delta;
00072             text_size -= delta;
00073         }
00074     }
00075     if (text_size == 0)
00076         return;
00077 
00078     p = (explain_output_syslog_t *)op;
00079     syslog(p->priority, "%.*s\n", (int)text_size, text);
00080 }
00081 
00082 
00083 static const explain_output_vtable_t vtable =
00084 {
00085     0, /* destructor */
00086     message,
00087     0, /* exit */
00088     sizeof(explain_output_t)
00089 };
00090 
00091 
00092 explain_output_t *
00093 explain_output_syslog_new(void)
00094 {
00095     int level = LOG_ERR;
00096     return explain_output_syslog_new1(level);
00097 }
00098 
00099 
00100 explain_output_t *
00101 explain_output_syslog_new1(int level)
00102 {
00103     int option = 0;
00104     int facility = LOG_USER;
00105     return explain_output_syslog_new3(option, facility, level);
00106 }
00107 
00108 
00109 explain_output_t *
00110 explain_output_syslog_new3(int option, int facility, int level)
00111 {
00112     explain_output_t *result;
00113 
00114     result = explain_output_new(&vtable);
00115     if (result)
00116     {
00117         explain_output_syslog_t *p;
00118         const char      *ident;
00119 
00120         /*
00121          * The syslog implementation in glibc is determined to have the "ident"
00122          * in the error message.  Contrary to the man page, if "ident" is NULL,
00123          * instead of no program name (as documented), it inserts its own idea
00124          * of the program name.  To have it use libexplain's idea of the
00125          * program name, we provide it to openlog(), and remove it (if present)
00126          * from the string passed to syslog().  Plus, an empty "ident" string
00127          * makes for an inconsistent {ugly} syslog format.
00128          */
00129         ident = explain_program_name_get();
00130         if (ident && !*ident)
00131             ident = NULL;
00132 
00133         if (!openlog_has_been_called)
00134         {
00135             openlog_has_been_called = 1;
00136             openlog(ident, option, facility);
00137         }
00138         p = (explain_output_syslog_t *)result;
00139         p->priority = facility | level;
00140     }
00141     return result;
00142 }
00143 
00144 
00145 /* vim: set ts=8 sw=4 et : */