* Sync comment with code's reality.
[dragonfly.git] / usr.sbin / ppp / log.c
1 /*-
2  * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/usr.sbin/ppp/log.c,v 1.44.2.5 2002/09/01 02:12:28 brian Exp $
27  * $DragonFly: src/usr.sbin/ppp/log.c,v 1.2 2003/06/17 04:30:00 dillon Exp $
28  */
29
30 #include <sys/types.h>
31
32 #include <ctype.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <syslog.h>
37 #include <termios.h>
38
39 #include "defs.h"
40 #include "command.h"
41 #include "mbuf.h"
42 #include "log.h"
43 #include "descriptor.h"
44 #include "prompt.h"
45
46 static const char *const LogNames[] = {
47   "Async",
48   "CBCP",
49   "CCP",
50   "Chat",
51   "Command",
52   "Connect",
53   "Debug",
54   "DNS",
55   "Filter",                     /* Log discarded packets */
56   "HDLC",
57   "ID0",
58   "IPCP",
59   "IPV6CP",
60   "LCP",
61   "LQM",
62   "Phase",
63   "Physical",
64   "Sync",
65   "TCP/IP",
66   "Timer",
67   "Tun",
68   "Warning",
69   "Error",
70   "Alert"
71 };
72
73 #define MSK(n) (1<<((n)-1))
74
75 static u_long LogMask = MSK(LogPHASE);
76 static u_long LogMaskLocal = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN);
77 static int LogTunno = -1;
78 static struct prompt *promptlist;       /* Where to log local stuff */
79 struct prompt *log_PromptContext;
80 int log_PromptListChanged;
81
82 struct prompt *
83 log_PromptList()
84 {
85   return promptlist;
86 }
87
88 void
89 log_RegisterPrompt(struct prompt *prompt)
90 {
91   prompt->next = promptlist;
92   promptlist = prompt;
93   prompt->active = 1;
94   log_DiscardAllLocal(&prompt->logmask);
95 }
96
97 void
98 log_ActivatePrompt(struct prompt *prompt)
99 {
100   prompt->active = 1;
101   LogMaskLocal |= prompt->logmask;
102 }
103
104 static void
105 LogSetMaskLocal(void)
106 {
107   struct prompt *p;
108
109   LogMaskLocal = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN);
110   for (p = promptlist; p; p = p->next)
111     LogMaskLocal |= p->logmask;
112 }
113
114 void
115 log_DeactivatePrompt(struct prompt *prompt)
116 {
117   if (prompt->active) {
118     prompt->active = 0;
119     LogSetMaskLocal();
120   }
121 }
122
123 void
124 log_UnRegisterPrompt(struct prompt *prompt)
125 {
126   if (prompt) {
127     struct prompt **p;
128
129     for (p = &promptlist; *p; p = &(*p)->next)
130       if (*p == prompt) {
131         *p = prompt->next;
132         prompt->next = NULL;
133         break;
134       }
135     LogSetMaskLocal();
136     log_PromptListChanged++;
137   }
138 }
139
140 void
141 log_DestroyPrompts(struct server *s)
142 {
143   struct prompt *p, *pn, *pl;
144
145   p = promptlist;
146   pl = NULL;
147   while (p) {
148     pn = p->next;
149     if (s && p->owner == s) {
150       if (pl)
151         pl->next = p->next;
152       else
153         promptlist = p->next;
154       p->next = NULL;
155       prompt_Destroy(p, 1);
156     } else
157       pl = p;
158     p = pn;
159   }
160 }
161
162 void
163 log_DisplayPrompts()
164 {
165   struct prompt *p;
166
167   for (p = promptlist; p; p = p->next)
168     prompt_Required(p);
169 }
170
171 void
172 log_WritePrompts(struct datalink *dl, const char *fmt,...)
173 {
174   va_list ap;
175   struct prompt *p;
176
177   va_start(ap, fmt);
178   for (p = promptlist; p; p = p->next)
179     if (prompt_IsTermMode(p, dl))
180       prompt_vPrintf(p, fmt, ap);
181   va_end(ap);
182 }
183
184 void
185 log_SetTtyCommandMode(struct datalink *dl)
186 {
187   struct prompt *p;
188
189   for (p = promptlist; p; p = p->next)
190     if (prompt_IsTermMode(p, dl))
191       prompt_TtyCommandMode(p);
192 }
193
194 static int
195 syslogLevel(int lev)
196 {
197   switch (lev) {
198   case LogLOG:
199     return LOG_INFO;
200   case LogDEBUG:
201   case LogTIMER:
202     return LOG_DEBUG;
203   case LogWARN:
204     return LOG_WARNING;
205   case LogERROR:
206     return LOG_ERR;
207   case LogALERT:
208     return LOG_ALERT;
209   }
210   return lev >= LogMIN && lev <= LogMAX ? LOG_INFO : 0;
211 }
212
213 const char *
214 log_Name(int id)
215 {
216   if (id == LogLOG)
217     return "LOG";
218   return id < LogMIN || id > LogMAX ? "Unknown" : LogNames[id - 1];
219 }
220
221 void
222 log_Keep(int id)
223 {
224   if (id >= LogMIN && id <= LogMAXCONF)
225     LogMask |= MSK(id);
226 }
227
228 void
229 log_KeepLocal(int id, u_long *mask)
230 {
231   if (id >= LogMIN && id <= LogMAXCONF) {
232     LogMaskLocal |= MSK(id);
233     *mask |= MSK(id);
234   }
235 }
236
237 void
238 log_Discard(int id)
239 {
240   if (id >= LogMIN && id <= LogMAXCONF)
241     LogMask &= ~MSK(id);
242 }
243
244 void
245 log_DiscardLocal(int id, u_long *mask)
246 {
247   if (id >= LogMIN && id <= LogMAXCONF) {
248     *mask &= ~MSK(id);
249     LogSetMaskLocal();
250   }
251 }
252
253 void
254 log_DiscardAll()
255 {
256   LogMask = 0;
257 }
258
259 void
260 log_DiscardAllLocal(u_long *mask)
261 {
262   *mask = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN);
263   LogSetMaskLocal();
264 }
265
266 int
267 log_IsKept(int id)
268 {
269   if (id == LogLOG)
270     return LOG_KEPT_SYSLOG;
271   if (id < LogMIN || id > LogMAX)
272     return 0;
273   if (id > LogMAXCONF)
274     return LOG_KEPT_LOCAL | LOG_KEPT_SYSLOG;
275
276   return ((LogMaskLocal & MSK(id)) ? LOG_KEPT_LOCAL : 0) |
277     ((LogMask & MSK(id)) ? LOG_KEPT_SYSLOG : 0);
278 }
279
280 int
281 log_IsKeptLocal(int id, u_long mask)
282 {
283   if (id < LogMIN || id > LogMAX)
284     return 0;
285   if (id > LogMAXCONF)
286     return LOG_KEPT_LOCAL | LOG_KEPT_SYSLOG;
287
288   return ((mask & MSK(id)) ? LOG_KEPT_LOCAL : 0) |
289     ((LogMask & MSK(id)) ? LOG_KEPT_SYSLOG : 0);
290 }
291
292 void
293 log_Open(const char *Name)
294 {
295   openlog(Name, LOG_PID, LOG_DAEMON);
296 }
297
298 void
299 log_SetTun(int tunno)
300 {
301   LogTunno = tunno;
302 }
303
304 void
305 log_Close()
306 {
307   closelog();
308   LogTunno = -1;
309 }
310
311 void
312 log_Printf(int lev, const char *fmt,...)
313 {
314   va_list ap;
315   struct prompt *prompt;
316
317   if (log_IsKept(lev)) {
318     char nfmt[200];
319
320     va_start(ap, fmt);
321     if (promptlist && (log_IsKept(lev) & LOG_KEPT_LOCAL)) {
322       if ((log_IsKept(LogTUN) & LOG_KEPT_LOCAL) && LogTunno != -1)
323         snprintf(nfmt, sizeof nfmt, "%s%d: %s: %s", TUN_NAME,
324                  LogTunno, log_Name(lev), fmt);
325       else
326         snprintf(nfmt, sizeof nfmt, "%s: %s", log_Name(lev), fmt);
327
328       if (log_PromptContext && lev == LogWARN)
329         /* Warnings just go to the current prompt */
330         prompt_vPrintf(log_PromptContext, nfmt, ap);
331       else for (prompt = promptlist; prompt; prompt = prompt->next)
332         if (lev > LogMAXCONF || (prompt->logmask & MSK(lev)))
333           prompt_vPrintf(prompt, nfmt, ap);
334     }
335     va_end(ap);
336
337     va_start(ap, fmt);
338     if ((log_IsKept(lev) & LOG_KEPT_SYSLOG) &&
339         (lev != LogWARN || !log_PromptContext)) {
340       if ((log_IsKept(LogTUN) & LOG_KEPT_SYSLOG) && LogTunno != -1)
341         snprintf(nfmt, sizeof nfmt, "%s%d: %s: %s", TUN_NAME,
342                  LogTunno, log_Name(lev), fmt);
343       else
344         snprintf(nfmt, sizeof nfmt, "%s: %s", log_Name(lev), fmt);
345       vsyslog(syslogLevel(lev), nfmt, ap);
346     }
347     va_end(ap);
348   }
349 }
350
351 void
352 log_DumpBp(int lev, const char *hdr, const struct mbuf *bp)
353 {
354   if (log_IsKept(lev)) {
355     char buf[68];
356     char *b, *c;
357     const u_char *ptr;
358     int f;
359
360     if (hdr && *hdr)
361       log_Printf(lev, "%s\n", hdr);
362
363     b = buf;
364     c = b + 50;
365     do {
366       f = bp->m_len;
367       ptr = CONST_MBUF_CTOP(bp);
368       while (f--) {
369         sprintf(b, " %02x", (int) *ptr);
370         *c++ = isprint(*ptr) ? *ptr : '.';
371         ptr++;
372         b += 3;
373         if (b == buf + 48) {
374           memset(b, ' ', 2);
375           *c = '\0';
376           log_Printf(lev, "%s\n", buf);
377           b = buf;
378           c = b + 50;
379         }
380       }
381     } while ((bp = bp->m_next) != NULL);
382
383     if (b > buf) {
384       memset(b, ' ', 50 - (b - buf));
385       *c = '\0';
386       log_Printf(lev, "%s\n", buf);
387     }
388   }
389 }
390
391 void
392 log_DumpBuff(int lev, const char *hdr, const u_char *ptr, int n)
393 {
394   if (log_IsKept(lev)) {
395     char buf[68];
396     char *b, *c;
397
398     if (hdr && *hdr)
399       log_Printf(lev, "%s\n", hdr);
400     while (n > 0) {
401       b = buf;
402       c = b + 50;
403       for (b = buf; b != buf + 48 && n--; b += 3, ptr++) {
404         sprintf(b, " %02x", (int) *ptr);
405         *c++ = isprint(*ptr) ? *ptr : '.';
406       }
407       memset(b, ' ', 50 - (b - buf));
408       *c = '\0';
409       log_Printf(lev, "%s\n", buf);
410     }
411   }
412 }
413
414 int
415 log_ShowLevel(struct cmdargs const *arg)
416 {
417   int i;
418
419   prompt_Printf(arg->prompt, "Log:  ");
420   for (i = LogMIN; i <= LogMAX; i++)
421     if (log_IsKept(i) & LOG_KEPT_SYSLOG)
422       prompt_Printf(arg->prompt, " %s", log_Name(i));
423
424   prompt_Printf(arg->prompt, "\nLocal:");
425   for (i = LogMIN; i <= LogMAX; i++)
426     if (log_IsKeptLocal(i, arg->prompt->logmask) & LOG_KEPT_LOCAL)
427       prompt_Printf(arg->prompt, " %s", log_Name(i));
428
429   prompt_Printf(arg->prompt, "\n");
430
431   return 0;
432 }
433
434 int
435 log_SetLevel(struct cmdargs const *arg)
436 {
437   int i, res, argc, local;
438   char const *const *argv, *argp;
439
440   argc = arg->argc - arg->argn;
441   argv = arg->argv + arg->argn;
442   res = 0;
443
444   if (argc == 0 || strcasecmp(argv[0], "local"))
445     local = 0;
446   else {
447     if (arg->prompt == NULL) {
448       log_Printf(LogWARN, "set log local: Only available on the"
449                  " command line\n");
450       return 1;
451     }
452     argc--;
453     argv++;
454     local = 1;
455   }
456
457   if (argc == 0 || (argv[0][0] != '+' && argv[0][0] != '-')) {
458     if (local)
459       log_DiscardAllLocal(&arg->prompt->logmask);
460     else
461       log_DiscardAll();
462   }
463
464   while (argc--) {
465     argp = **argv == '+' || **argv == '-' ? *argv + 1 : *argv;
466     /* Special case 'all' */
467     if (strcasecmp(argp, "all") == 0) {
468         if (**argv == '-') {
469           if (local)
470             for (i = LogMIN; i <= LogMAX; i++)
471               log_DiscardLocal(i, &arg->prompt->logmask);
472           else
473             for (i = LogMIN; i <= LogMAX; i++)
474               log_Discard(i);
475         } else if (local)
476           for (i = LogMIN; i <= LogMAX; i++)
477             log_KeepLocal(i, &arg->prompt->logmask);
478         else
479           for (i = LogMIN; i <= LogMAX; i++)
480             log_Keep(i);
481         argv++;
482         continue;
483     }
484     for (i = LogMIN; i <= LogMAX; i++)
485       if (strcasecmp(argp, log_Name(i)) == 0) {
486         if (**argv == '-') {
487           if (local)
488             log_DiscardLocal(i, &arg->prompt->logmask);
489           else
490             log_Discard(i);
491         } else if (local)
492           log_KeepLocal(i, &arg->prompt->logmask);
493         else
494           log_Keep(i);
495         break;
496       }
497     if (i > LogMAX) {
498       log_Printf(LogWARN, "%s: Invalid log value\n", argp);
499       res = -1;
500     }
501     argv++;
502   }
503   return res;
504 }
505
506 int
507 log_ShowWho(struct cmdargs const *arg)
508 {
509   struct prompt *p;
510
511   for (p = promptlist; p; p = p->next) {
512     prompt_Printf(arg->prompt, "%s (%s)", p->src.type, p->src.from);
513     if (p == arg->prompt)
514       prompt_Printf(arg->prompt, " *");
515     if (!p->active)
516       prompt_Printf(arg->prompt, " ^Z");
517     prompt_Printf(arg->prompt, "\n");
518   }
519
520   return 0;
521 }