1 /* This file is part of GNU Pies.
2    Copyright (C) 2009-2020 Sergey Poznyakoff
3 
4    GNU Pies is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    GNU Pies is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with GNU Pies.  If not, see <http://www.gnu.org/licenses/>. */
16 
17 #include "pies.h"
18 
19 typedef struct
20 {
21   int open;
22   FILE *file;
23 } LOGSTREAM;
24 
25 
26 static int
syslog_printer(LOGSTREAM * str,int prio,const char * fmt,va_list ap)27 syslog_printer (LOGSTREAM *str, int prio, const char *fmt, va_list ap)
28 {
29   pies_vsyslog (prio, fmt, ap);
30   return 0;
31 }
32 
33 static int
syslog_open(int logf,LOGSTREAM * str)34 syslog_open (int logf, LOGSTREAM *str)
35 {
36   if (logf & DIAG_REOPEN_LOG)
37     {
38       pies_syslog_open ();
39       str->open = 1;
40     }
41   else
42     str->open = 0;
43   return 0;
44 }
45 
46 static void
syslog_close(LOGSTREAM * str)47 syslog_close (LOGSTREAM *str)
48 {
49   if (str->open)
50     pies_syslog_close ();
51 }
52 
53 static int
stderr_printer(LOGSTREAM * str,int prio,const char * fmt,va_list ap)54 stderr_printer (LOGSTREAM *str, int prio, const char *fmt, va_list ap)
55 {
56   FILE *fp = str->file;
57   va_list aq;
58 
59   fprintf (fp, "%s: ", program_name);
60   va_copy (aq, ap);
61   vfprintf (fp, fmt, aq);
62   va_end (aq);
63   fprintf (fp, "\n");
64   return 0;
65 }
66 
67 static int
stderr_open(int logf,LOGSTREAM * str)68 stderr_open (int logf, LOGSTREAM *str)
69 {
70   if (PIES_SYSVINIT_ENABLED && (logf & DIAG_REOPEN_LOG))
71     {
72       int fd = console_open (O_WRONLY|O_NOCTTY|O_NDELAY);
73       if (fd == -1)
74 	return -1;
75       str->file = fdopen (fd, "w");
76       if (!str->file)
77 	{
78           close (fd);
79 	  return -1;
80         }
81       str->open = 1;
82     }
83   else
84     {
85       str->file = stderr;
86       str->open = 0;
87     }
88   return 0;
89 }
90 
91 static void
stderr_close(LOGSTREAM * str)92 stderr_close (LOGSTREAM *str)
93 {
94   if (str->open)
95     fclose (str->file);
96 }
97 
98 struct logger
99 {
100   int mask;
101   int (*printer) (LOGSTREAM *, int prio, const char *fmt, va_list ap);
102   int (*open) (int flags, LOGSTREAM *);
103   void (*close) (LOGSTREAM *);
104 };
105 
106 struct logger logger[] = {
107   { DIAG_TO_STDERR, stderr_printer, stderr_open, stderr_close },
108   { DIAG_TO_SYSLOG, syslog_printer, syslog_open, syslog_close }
109 };
110 
111 void
vdiagmsg(int logf,int prio,const char * fmt,va_list ap)112 vdiagmsg (int logf, int prio, const char *fmt, va_list ap)
113 {
114   int i;
115   for (i = 0; i < ARRAY_SIZE (logger); i++)
116     {
117       if (logger[i].mask & (logf & DIAG_TO_MASK))
118 	{
119 	  LOGSTREAM stream;
120 	  if (logger[i].open (logf, &stream) == 0)
121 	    {
122 	      logger[i].printer (&stream, prio, fmt, ap);
123 	      logger[i].close (&stream);
124 	    }
125 	}
126     }
127 }
128 
129 void
diagmsg(int logf,int prio,const char * fmt,...)130 diagmsg (int logf, int prio, const char *fmt, ...)
131 {
132   va_list ap;
133   va_start (ap, fmt);
134   vdiagmsg (logf, prio, fmt, ap);
135   va_end (ap);
136 }
137 
138 unsigned debug_level;
139 int source_info_option;
140 int diag_output = DIAG_TO_STDERR;
141 
142 void
diag_setup(int flags)143 diag_setup (int flags)
144 {
145   if (flags)
146     diag_output = flags;
147   if (diag_output & DIAG_TO_SYSLOG)
148     pies_syslog_open ();
149 }
150 
151 void
vlogmsg(int prio,const char * fmt,va_list ap)152 vlogmsg (int prio, const char *fmt, va_list ap)
153 {
154   vdiagmsg (diag_output, prio, fmt, ap);
155 }
156 
157 void
logmsg(int prio,const char * fmt,...)158 logmsg (int prio, const char *fmt, ...)
159 {
160   va_list ap;
161   va_start (ap, fmt);
162   vlogmsg (prio, fmt, ap);
163   va_end (ap);
164 }
165 
166 void
debug_msg(const char * fmt,...)167 debug_msg (const char *fmt, ...)
168 {
169   va_list ap;
170   va_start (ap, fmt);
171   vlogmsg (LOG_DEBUG, fmt, ap);
172   va_end (ap);
173 }
174 
175 
176 void
logmsg_vprintf(int prio,const char * fmt,va_list ap)177 logmsg_vprintf (int prio, const char *fmt, va_list ap)
178 {
179   char *p, *t, *str;
180   static char *buf = NULL;
181   static size_t len = 0;
182   static struct grecs_txtacc *log_acc;
183 
184   if (grecs_vasprintf (&buf, &len, fmt, ap))
185     {
186       logmsg (LOG_CRIT, _("out of memory trying to log a message"));
187       return;
188     }
189   if (!log_acc)
190     log_acc = grecs_txtacc_create ();
191 
192   str = buf;
193 
194   while (str)
195     {
196       p = strchr (str, '\n');
197       if (p)
198 	{
199 	  *p++ = 0;
200 	  if (!*p)
201 	    p = NULL;
202 	  grecs_txtacc_grow_string (log_acc, str);
203 	  grecs_txtacc_grow_char (log_acc, 0);
204 	  t = grecs_txtacc_finish (log_acc, 0);
205 	  logmsg (prio, "%s", t);
206 	  grecs_txtacc_free_string (log_acc, t);
207 	}
208       else
209 	grecs_txtacc_grow_string (log_acc, str);
210       str = p;
211     }
212 }
213 
214 void
logmsg_printf(int prio,const char * fmt,...)215 logmsg_printf (int prio, const char *fmt, ...)
216 {
217   va_list ap;
218   va_start (ap, fmt);
219   logmsg_vprintf (prio, fmt, ap);
220   va_end (ap);
221 }
222 
223 void
pies_diag_printer(grecs_locus_t const * locus,int err,int errcode,const char * msg)224 pies_diag_printer (grecs_locus_t const *locus, int err, int errcode,
225 		   const char *msg)
226 {
227   if (locus)
228     {
229       char *locstr = NULL;
230       size_t locsize  = 0;
231 
232       grecs_asprint_locus (&locstr, &locsize, locus);
233 
234       if (errcode)
235 	logmsg (err ? LOG_ERR : LOG_WARNING, "%s: %s: %s",
236 		locstr, msg, strerror (errcode));
237       else
238 	logmsg (err ? LOG_ERR : LOG_WARNING, "%s: %s",
239 		locstr, msg);
240       free (locstr);
241     }
242   else
243     {
244       if (errcode)
245 	logmsg (err ? LOG_ERR : LOG_WARNING, "%s: %s", msg,
246 		strerror (errcode));
247       else
248 	logmsg (err ? LOG_ERR : LOG_WARNING, "%s", msg);
249     }
250 }
251 
252 void
logfuncall(const char * fun,const char * arg,int err)253 logfuncall (const char *fun, const char *arg, int err)
254 {
255   if (arg)
256     grecs_error (NULL, err, _("%s: %s failed"), arg, fun);
257   else
258     grecs_error (NULL, err, _("%s failed"), fun);
259 }
260