log.c revision 58033
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: head/usr.sbin/ppp/log.c 58033 2000-03-14 01:46:49Z brian $
27 */
28
29#include <sys/types.h>
30
31#include <ctype.h>
32#include <stdarg.h>
33#include <stdio.h>
34#include <string.h>
35#include <syslog.h>
36#include <termios.h>
37
38#include "defs.h"
39#include "command.h"
40#include "mbuf.h"
41#include "log.h"
42#include "descriptor.h"
43#include "prompt.h"
44
45static const char * const LogNames[] = {
46  "Async",
47  "CBCP",
48  "CCP",
49  "Chat",
50  "Command",
51  "Connect",
52  "Debug",
53  "DNS",
54  "HDLC",
55  "ID0",
56  "IPCP",
57  "LCP",
58  "LQM",
59  "Phase",
60  "Physical",
61  "Sync",
62  "TCP/IP",
63  "Timer",
64  "Tun",
65  "Warning",
66  "Error",
67  "Alert"
68};
69
70#define MSK(n) (1<<((n)-1))
71
72static u_long LogMask = MSK(LogPHASE);
73static u_long LogMaskLocal = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN);
74static int LogTunno = -1;
75static struct prompt *promptlist;	/* Where to log local stuff */
76struct prompt *log_PromptContext;
77int log_PromptListChanged;
78
79struct prompt *
80log_PromptList()
81{
82  return promptlist;
83}
84
85void
86log_RegisterPrompt(struct prompt *prompt)
87{
88  prompt->next = promptlist;
89  promptlist = prompt;
90  prompt->active = 1;
91  log_DiscardAllLocal(&prompt->logmask);
92}
93
94void
95log_ActivatePrompt(struct prompt *prompt)
96{
97  prompt->active = 1;
98  LogMaskLocal |= prompt->logmask;
99}
100
101static void
102LogSetMaskLocal(void)
103{
104  struct prompt *p;
105
106  LogMaskLocal = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN);
107  for (p = promptlist; p; p = p->next)
108    LogMaskLocal |= p->logmask;
109}
110
111void
112log_DeactivatePrompt(struct prompt *prompt)
113{
114  if (prompt->active) {
115    prompt->active = 0;
116    LogSetMaskLocal();
117  }
118}
119
120void
121log_UnRegisterPrompt(struct prompt *prompt)
122{
123  if (prompt) {
124    struct prompt **p;
125
126    for (p = &promptlist; *p; p = &(*p)->next)
127      if (*p == prompt) {
128        *p = prompt->next;
129        prompt->next = NULL;
130        break;
131      }
132    LogSetMaskLocal();
133    log_PromptListChanged++;
134  }
135}
136
137void
138log_DestroyPrompts(struct server *s)
139{
140  struct prompt *p, *pn, *pl;
141
142  p = promptlist;
143  pl = NULL;
144  while (p) {
145    pn = p->next;
146    if (s && p->owner == s) {
147      if (pl)
148        pl->next = p->next;
149      else
150        promptlist = p->next;
151      p->next = NULL;
152      prompt_Destroy(p, 1);
153    } else
154      pl = p;
155    p = pn;
156  }
157}
158
159void
160log_DisplayPrompts()
161{
162  struct prompt *p;
163
164  for (p = promptlist; p; p = p->next)
165    prompt_Required(p);
166}
167
168void
169log_WritePrompts(struct datalink *dl, const char *fmt,...)
170{
171  va_list ap;
172  struct prompt *p;
173
174  va_start(ap, fmt);
175  for (p = promptlist; p; p = p->next)
176    if (prompt_IsTermMode(p, dl))
177      prompt_vPrintf(p, fmt, ap);
178  va_end(ap);
179}
180
181void
182log_SetTtyCommandMode(struct datalink *dl)
183{
184  struct prompt *p;
185
186  for (p = promptlist; p; p = p->next)
187    if (prompt_IsTermMode(p, dl))
188      prompt_TtyCommandMode(p);
189}
190
191static int
192syslogLevel(int lev)
193{
194  switch (lev) {
195  case LogDEBUG:
196  case LogTIMER:
197    return LOG_DEBUG;
198  case LogWARN:
199    return LOG_WARNING;
200  case LogERROR:
201    return LOG_ERR;
202  case LogALERT:
203    return LOG_ALERT;
204  }
205  return lev >= LogMIN && lev <= LogMAX ? LOG_INFO : 0;
206}
207
208const char *
209log_Name(int id)
210{
211  return id < LogMIN || id > LogMAX ? "Unknown" : LogNames[id - 1];
212}
213
214void
215log_Keep(int id)
216{
217  if (id >= LogMIN && id <= LogMAXCONF)
218    LogMask |= MSK(id);
219}
220
221void
222log_KeepLocal(int id, u_long *mask)
223{
224  if (id >= LogMIN && id <= LogMAXCONF) {
225    LogMaskLocal |= MSK(id);
226    *mask |= MSK(id);
227  }
228}
229
230void
231log_Discard(int id)
232{
233  if (id >= LogMIN && id <= LogMAXCONF)
234    LogMask &= ~MSK(id);
235}
236
237void
238log_DiscardLocal(int id, u_long *mask)
239{
240  if (id >= LogMIN && id <= LogMAXCONF) {
241    *mask &= ~MSK(id);
242    LogSetMaskLocal();
243  }
244}
245
246void
247log_DiscardAll()
248{
249  LogMask = 0;
250}
251
252void
253log_DiscardAllLocal(u_long *mask)
254{
255  *mask = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN);
256  LogSetMaskLocal();
257}
258
259int
260log_IsKept(int id)
261{
262  if (id < LogMIN || id > LogMAX)
263    return 0;
264  if (id > LogMAXCONF)
265    return LOG_KEPT_LOCAL | LOG_KEPT_SYSLOG;
266
267  return ((LogMaskLocal & MSK(id)) ? LOG_KEPT_LOCAL : 0) |
268    ((LogMask & MSK(id)) ? LOG_KEPT_SYSLOG : 0);
269}
270
271int
272log_IsKeptLocal(int id, u_long mask)
273{
274  if (id < LogMIN || id > LogMAX)
275    return 0;
276  if (id > LogMAXCONF)
277    return LOG_KEPT_LOCAL | LOG_KEPT_SYSLOG;
278
279  return ((mask & MSK(id)) ? LOG_KEPT_LOCAL : 0) |
280    ((LogMask & MSK(id)) ? LOG_KEPT_SYSLOG : 0);
281}
282
283void
284log_Open(const char *Name)
285{
286  openlog(Name, LOG_PID, LOG_DAEMON);
287}
288
289void
290log_SetTun(int tunno)
291{
292  LogTunno = tunno;
293}
294
295void
296log_Close()
297{
298  closelog();
299  LogTunno = -1;
300}
301
302void
303log_Printf(int lev, const char *fmt,...)
304{
305  va_list ap;
306  struct prompt *prompt;
307
308  va_start(ap, fmt);
309  if (log_IsKept(lev)) {
310    char nfmt[200];
311
312    if (promptlist && (log_IsKept(lev) & LOG_KEPT_LOCAL)) {
313      if ((log_IsKept(LogTUN) & LOG_KEPT_LOCAL) && LogTunno != -1)
314        snprintf(nfmt, sizeof nfmt, "%s%d: %s: %s", TUN_NAME,
315	         LogTunno, log_Name(lev), fmt);
316      else
317        snprintf(nfmt, sizeof nfmt, "%s: %s", log_Name(lev), fmt);
318
319      if (log_PromptContext && lev == LogWARN)
320        /* Warnings just go to the current prompt */
321        prompt_vPrintf(log_PromptContext, nfmt, ap);
322      else for (prompt = promptlist; prompt; prompt = prompt->next)
323        if (lev > LogMAXCONF || (prompt->logmask & MSK(lev)))
324          prompt_vPrintf(prompt, nfmt, ap);
325    }
326
327    if ((log_IsKept(lev) & LOG_KEPT_SYSLOG) &&
328        (lev != LogWARN || !log_PromptContext)) {
329      if ((log_IsKept(LogTUN) & LOG_KEPT_SYSLOG) && LogTunno != -1)
330        snprintf(nfmt, sizeof nfmt, "%s%d: %s: %s", TUN_NAME,
331	         LogTunno, log_Name(lev), fmt);
332      else
333        snprintf(nfmt, sizeof nfmt, "%s: %s", log_Name(lev), fmt);
334      vsyslog(syslogLevel(lev), nfmt, ap);
335    }
336  }
337  va_end(ap);
338}
339
340void
341log_DumpBp(int lev, const char *hdr, const struct mbuf *bp)
342{
343  if (log_IsKept(lev)) {
344    char buf[68];
345    char *b, *c;
346    const u_char *ptr;
347    int f;
348
349    if (hdr && *hdr)
350      log_Printf(lev, "%s\n", hdr);
351
352    b = buf;
353    c = b + 50;
354    do {
355      f = bp->m_len;
356      ptr = CONST_MBUF_CTOP(bp);
357      while (f--) {
358	sprintf(b, " %02x", (int) *ptr);
359        *c++ = isprint(*ptr) ? *ptr : '.';
360        ptr++;
361        b += 3;
362        if (b == buf + 48) {
363          memset(b, ' ', 2);
364          *c = '\0';
365          log_Printf(lev, "%s\n", buf);
366          b = buf;
367          c = b + 50;
368        }
369      }
370    } while ((bp = bp->m_next) != NULL);
371
372    if (b > buf) {
373      memset(b, ' ', 50 - (b - buf));
374      *c = '\0';
375      log_Printf(lev, "%s\n", buf);
376    }
377  }
378}
379
380void
381log_DumpBuff(int lev, const char *hdr, const u_char *ptr, int n)
382{
383  if (log_IsKept(lev)) {
384    char buf[68];
385    char *b, *c;
386
387    if (hdr && *hdr)
388      log_Printf(lev, "%s\n", hdr);
389    while (n > 0) {
390      b = buf;
391      c = b + 50;
392      for (b = buf; b != buf + 48 && n--; b += 3, ptr++) {
393	sprintf(b, " %02x", (int) *ptr);
394        *c++ = isprint(*ptr) ? *ptr : '.';
395      }
396      memset(b, ' ', 50 - (b - buf));
397      *c = '\0';
398      log_Printf(lev, "%s\n", buf);
399    }
400  }
401}
402
403int
404log_ShowLevel(struct cmdargs const *arg)
405{
406  int i;
407
408  prompt_Printf(arg->prompt, "Log:  ");
409  for (i = LogMIN; i <= LogMAX; i++)
410    if (log_IsKept(i) & LOG_KEPT_SYSLOG)
411      prompt_Printf(arg->prompt, " %s", log_Name(i));
412
413  prompt_Printf(arg->prompt, "\nLocal:");
414  for (i = LogMIN; i <= LogMAX; i++)
415    if (log_IsKeptLocal(i, arg->prompt->logmask) & LOG_KEPT_LOCAL)
416      prompt_Printf(arg->prompt, " %s", log_Name(i));
417
418  prompt_Printf(arg->prompt, "\n");
419
420  return 0;
421}
422
423int
424log_SetLevel(struct cmdargs const *arg)
425{
426  int i, res, argc, local;
427  char const *const *argv, *argp;
428
429  argc = arg->argc - arg->argn;
430  argv = arg->argv + arg->argn;
431  res = 0;
432
433  if (argc == 0 || strcasecmp(argv[0], "local"))
434    local = 0;
435  else {
436    if (arg->prompt == NULL) {
437      log_Printf(LogWARN, "set log local: Only available on the command line\n");
438      return 1;
439    }
440    argc--;
441    argv++;
442    local = 1;
443  }
444
445  if (argc == 0 || (argv[0][0] != '+' && argv[0][0] != '-')) {
446    if (local)
447      log_DiscardAllLocal(&arg->prompt->logmask);
448    else
449      log_DiscardAll();
450  }
451
452  while (argc--) {
453    argp = **argv == '+' || **argv == '-' ? *argv + 1 : *argv;
454    for (i = LogMIN; i <= LogMAX; i++)
455      if (strcasecmp(argp, log_Name(i)) == 0) {
456	if (**argv == '-') {
457          if (local)
458            log_DiscardLocal(i, &arg->prompt->logmask);
459          else
460	    log_Discard(i);
461	} else if (local)
462          log_KeepLocal(i, &arg->prompt->logmask);
463        else
464          log_Keep(i);
465	break;
466      }
467    if (i > LogMAX) {
468      log_Printf(LogWARN, "%s: Invalid log value\n", argp);
469      res = -1;
470    }
471    argv++;
472  }
473  return res;
474}
475
476int
477log_ShowWho(struct cmdargs const *arg)
478{
479  struct prompt *p;
480
481  for (p = promptlist; p; p = p->next) {
482    prompt_Printf(arg->prompt, "%s (%s)", p->src.type, p->src.from);
483    if (p == arg->prompt)
484      prompt_Printf(arg->prompt, " *");
485    if (!p->active)
486      prompt_Printf(arg->prompt, " ^Z");
487    prompt_Printf(arg->prompt, "\n");
488  }
489
490  return 0;
491}
492