Coverage Report

Created: 2026-10-17 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/lib/log_vty.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Logging - VTY code
4
 * Copyright (C) 2019 Cumulus Networks, Inc.
5
 *                    Stephen Worley
6
 */
7
8
#include <zebra.h>
9
10
#include "lib/log_vty.h"
11
#include "command.h"
12
#include "lib/log.h"
13
#include "lib/zlog_targets.h"
14
#include "lib/zlog_5424.h"
15
#include "lib/lib_errors.h"
16
#include "lib/printfrr.h"
17
#include "lib/systemd.h"
18
19
#include "lib/log_vty_clippy.c"
20
21
0
#define ZLOG_MAXLVL(a, b) MAX(a, b)
22
23
DEFINE_HOOK(zlog_rotate, (), ());
24
DEFINE_HOOK(zlog_cli_show, (struct vty * vty), (vty));
25
26
static unsigned logmsgs_with_persist_bt;
27
28
static const int log_default_lvl = LOG_DEBUG;
29
30
static int log_config_stdout_lvl = ZLOG_DISABLED;
31
static int log_config_syslog_lvl = ZLOG_DISABLED;
32
static int log_cmdline_stdout_lvl = ZLOG_DISABLED;
33
static int log_cmdline_syslog_lvl = ZLOG_DISABLED;
34
35
static struct zlog_cfg_file zt_file_cmdline = {
36
  .prio_min = ZLOG_DISABLED,
37
  .ts_subsec = LOG_TIMESTAMP_PRECISION,
38
};
39
static struct zlog_cfg_file zt_file = {
40
  .prio_min = ZLOG_DISABLED,
41
  .ts_subsec = LOG_TIMESTAMP_PRECISION,
42
};
43
static struct zlog_cfg_filterfile zt_filterfile = {
44
  .parent =
45
    {
46
      .prio_min = ZLOG_DISABLED,
47
      .ts_subsec = LOG_TIMESTAMP_PRECISION,
48
    },
49
};
50
51
static struct zlog_cfg_file zt_stdout_file = {
52
  .prio_min = ZLOG_DISABLED,
53
  .ts_subsec = LOG_TIMESTAMP_PRECISION,
54
};
55
static struct zlog_cfg_5424 zt_stdout_journald = {
56
  .prio_min = ZLOG_DISABLED,
57
58
  .fmt = ZLOG_FMT_JOURNALD,
59
  .dst = ZLOG_5424_DST_UNIX,
60
  .filename = "/run/systemd/journal/socket",
61
62
  /* this can't be changed through config since this target substitutes
63
   * in for the "plain" stdout target
64
   */
65
  .facility = LOG_DAEMON,
66
  .kw_version = false,
67
  .kw_location = true,
68
  .kw_uid = true,
69
  .kw_ec = true,
70
  .kw_args = true,
71
};
72
static bool stdout_journald_in_use;
73
74
const char *zlog_progname;
75
static const char *zlog_protoname;
76
77
static const struct facility_map {
78
  int facility;
79
  const char *name;
80
  size_t match;
81
} syslog_facilities[] = {
82
  {LOG_KERN, "kern", 1},
83
  {LOG_USER, "user", 2},
84
  {LOG_MAIL, "mail", 1},
85
  {LOG_DAEMON, "daemon", 1},
86
  {LOG_AUTH, "auth", 1},
87
  {LOG_SYSLOG, "syslog", 1},
88
  {LOG_LPR, "lpr", 2},
89
  {LOG_NEWS, "news", 1},
90
  {LOG_UUCP, "uucp", 2},
91
  {LOG_CRON, "cron", 1},
92
#ifdef LOG_FTP
93
  {LOG_FTP, "ftp", 1},
94
#endif
95
  {LOG_LOCAL0, "local0", 6},
96
  {LOG_LOCAL1, "local1", 6},
97
  {LOG_LOCAL2, "local2", 6},
98
  {LOG_LOCAL3, "local3", 6},
99
  {LOG_LOCAL4, "local4", 6},
100
  {LOG_LOCAL5, "local5", 6},
101
  {LOG_LOCAL6, "local6", 6},
102
  {LOG_LOCAL7, "local7", 6},
103
  {0, NULL, 0},
104
};
105
106
static const char * const zlog_priority[] = {
107
  "emergencies",   "alerts",  "critical",  "errors", "warnings",
108
  "notifications", "informational", "debugging", NULL,
109
};
110
111
const char *zlog_priority_str(int priority)
112
0
{
113
0
  if (priority > LOG_DEBUG)
114
0
    return "???";
115
0
  return zlog_priority[priority];
116
0
}
117
118
const char *facility_name(int facility)
119
0
{
120
0
  const struct facility_map *fm;
121
122
0
  for (fm = syslog_facilities; fm->name; fm++)
123
0
    if (fm->facility == facility)
124
0
      return fm->name;
125
0
  return "";
126
0
}
127
128
int facility_match(const char *str)
129
0
{
130
0
  const struct facility_map *fm;
131
132
0
  for (fm = syslog_facilities; fm->name; fm++)
133
0
    if (!strncmp(str, fm->name, fm->match))
134
0
      return fm->facility;
135
0
  return -1;
136
0
}
137
138
int log_level_match(const char *s)
139
0
{
140
0
  int level;
141
142
0
  for (level = 0; zlog_priority[level] != NULL; level++)
143
0
    if (!strncmp(s, zlog_priority[level], 2))
144
0
      return level;
145
0
  return ZLOG_DISABLED;
146
0
}
147
148
void zlog_rotate(void)
149
0
{
150
0
  zlog_file_rotate(&zt_file);
151
0
  zlog_file_rotate(&zt_filterfile.parent);
152
0
  zlog_file_rotate(&zt_file_cmdline);
153
0
  hook_call(zlog_rotate);
154
0
}
155
156
157
void log_show_syslog(struct vty *vty)
158
0
{
159
0
  int level = zlog_syslog_get_prio_min();
160
161
0
  vty_out(vty, "Syslog logging: ");
162
0
  if (level == ZLOG_DISABLED)
163
0
    vty_out(vty, "disabled\n");
164
0
  else
165
0
    vty_out(vty, "level %s, facility %s, ident %s\n",
166
0
      zlog_priority[level],
167
0
      facility_name(zlog_syslog_get_facility()),
168
0
      zlog_progname);
169
0
}
170
171
DEFUN_NOSH (show_logging,
172
      show_logging_cmd,
173
      "show logging",
174
      SHOW_STR
175
      "Show current logging configuration\n")
176
0
{
177
0
  int stdout_prio;
178
179
0
  log_show_syslog(vty);
180
181
0
  stdout_prio = stdout_journald_in_use ? zt_stdout_journald.prio_min
182
0
               : zt_stdout_file.prio_min;
183
184
0
  vty_out(vty, "Stdout logging: ");
185
0
  if (stdout_prio == ZLOG_DISABLED)
186
0
    vty_out(vty, "disabled");
187
0
  else
188
0
    vty_out(vty, "level %s", zlog_priority[stdout_prio]);
189
0
  vty_out(vty, "\n");
190
191
0
  vty_out(vty, "File logging: ");
192
0
  if (zt_file.prio_min == ZLOG_DISABLED || !zt_file.filename)
193
0
    vty_out(vty, "disabled");
194
0
  else
195
0
    vty_out(vty, "level %s, filename %s",
196
0
      zlog_priority[zt_file.prio_min], zt_file.filename);
197
0
  vty_out(vty, "\n");
198
199
0
  if (zt_filterfile.parent.prio_min != ZLOG_DISABLED
200
0
      && zt_filterfile.parent.filename)
201
0
    vty_out(vty, "Filtered-file logging: level %s, filename %s\n",
202
0
      zlog_priority[zt_filterfile.parent.prio_min],
203
0
      zt_filterfile.parent.filename);
204
205
0
  if (log_cmdline_syslog_lvl != ZLOG_DISABLED)
206
0
    vty_out(vty,
207
0
      "From command line: \"--log syslog --log-level %s\"\n",
208
0
      zlog_priority[log_cmdline_syslog_lvl]);
209
0
  if (log_cmdline_stdout_lvl != ZLOG_DISABLED)
210
0
    vty_out(vty,
211
0
      "From command line: \"--log stdout --log-level %s\"\n",
212
0
      zlog_priority[log_cmdline_stdout_lvl]);
213
0
  if (zt_file_cmdline.prio_min != ZLOG_DISABLED)
214
0
    vty_out(vty,
215
0
      "From command line: \"--log file:%s --log-level %s\"\n",
216
0
      zt_file_cmdline.filename,
217
0
      zlog_priority[zt_file_cmdline.prio_min]);
218
219
0
  vty_out(vty, "Protocol name: %s\n", zlog_protoname);
220
0
  vty_out(vty, "Record priority: %s\n",
221
0
    (zt_file.record_priority ? "enabled" : "disabled"));
222
0
  vty_out(vty, "Timestamp precision: %d\n", zt_file.ts_subsec);
223
224
0
  hook_call(zlog_cli_show, vty);
225
0
  return CMD_SUCCESS;
226
0
}
227
228
static void log_stdout_apply_level(void)
229
0
{
230
0
  int maxlvl;
231
232
0
  maxlvl = ZLOG_MAXLVL(log_config_stdout_lvl, log_cmdline_stdout_lvl);
233
234
0
  if (stdout_journald_in_use) {
235
0
    zt_stdout_journald.prio_min = maxlvl;
236
0
    zlog_5424_apply_meta(&zt_stdout_journald);
237
0
  } else {
238
0
    zt_stdout_file.prio_min = maxlvl;
239
0
    zlog_file_set_other(&zt_stdout_file);
240
0
  }
241
0
}
242
243
DEFPY (config_log_stdout,
244
       config_log_stdout_cmd,
245
       "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
246
       "Logging control\n"
247
       "Set stdout logging level\n"
248
       LOG_LEVEL_DESC)
249
0
{
250
0
  int level;
251
252
0
  if (levelarg) {
253
0
    level = log_level_match(levelarg);
254
0
    if (level == ZLOG_DISABLED)
255
0
      return CMD_ERR_NO_MATCH;
256
0
  } else
257
0
    level = log_default_lvl;
258
259
0
  log_config_stdout_lvl = level;
260
0
  log_stdout_apply_level();
261
0
  return CMD_SUCCESS;
262
0
}
263
264
DEFUN (no_config_log_stdout,
265
       no_config_log_stdout_cmd,
266
       "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
267
       NO_STR
268
       "Logging control\n"
269
       "Cancel logging to stdout\n"
270
       LOG_LEVEL_DESC)
271
0
{
272
0
  log_config_stdout_lvl = ZLOG_DISABLED;
273
0
  log_stdout_apply_level();
274
0
  return CMD_SUCCESS;
275
0
}
276
277
DEFUN_HIDDEN (config_log_monitor,
278
       config_log_monitor_cmd,
279
       "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
280
       "Logging control\n"
281
       "Set terminal line (monitor) logging level\n"
282
       LOG_LEVEL_DESC)
283
0
{
284
0
  vty_out(vty, "%% \"log monitor\" is deprecated and does nothing.\n");
285
0
  return CMD_SUCCESS;
286
0
}
287
288
DEFUN_HIDDEN (no_config_log_monitor,
289
       no_config_log_monitor_cmd,
290
       "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
291
       NO_STR
292
       "Logging control\n"
293
       "Disable terminal line (monitor) logging\n"
294
       LOG_LEVEL_DESC)
295
0
{
296
0
  return CMD_SUCCESS;
297
0
}
298
299
DEFPY_NOSH (debug_uid_backtrace,
300
      debug_uid_backtrace_cmd,
301
      "[no] debug unique-id UID backtrace",
302
      NO_STR
303
      DEBUG_STR
304
      "Options per individual log message, by unique ID\n"
305
      "Log message unique ID (XXXXX-XXXXX)\n"
306
      "Add backtrace to log when message is printed\n")
307
0
{
308
0
  struct xrefdata search, *xrd;
309
0
  struct xrefdata_logmsg *xrdl;
310
0
  uint8_t flag;
311
312
0
  strlcpy(search.uid, uid, sizeof(search.uid));
313
0
  xrd = xrefdata_uid_find(&xrefdata_uid, &search);
314
315
0
  if (!xrd)
316
0
    return CMD_ERR_NOTHING_TODO;
317
318
0
  if (xrd->xref->type != XREFT_LOGMSG) {
319
0
    vty_out(vty, "%% ID \"%s\" is not a log message\n", uid);
320
0
    return CMD_WARNING;
321
0
  }
322
0
  xrdl = container_of(xrd, struct xrefdata_logmsg, xrefdata);
323
324
0
  flag = (vty->node == CONFIG_NODE) ? LOGMSG_FLAG_PERSISTENT
325
0
            : LOGMSG_FLAG_EPHEMERAL;
326
327
0
  if ((xrdl->fl_print_bt & flag) == (no ? 0 : flag))
328
0
    return CMD_SUCCESS;
329
0
  if (flag == LOGMSG_FLAG_PERSISTENT)
330
0
    logmsgs_with_persist_bt += no ? -1 : 1;
331
332
0
  xrdl->fl_print_bt ^= flag;
333
0
  return CMD_SUCCESS;
334
0
}
335
336
static int set_log_file(struct zlog_cfg_file *target, struct vty *vty,
337
      const char *fname, int loglevel)
338
0
{
339
0
  char path[MAXPATHLEN + 1];
340
0
  const char *fullpath;
341
0
  bool ok;
342
343
344
  /* Path detection. */
345
0
  if (!IS_DIRECTORY_SEP(*fname)) {
346
0
    char cwd[MAXPATHLEN + 1];
347
348
0
    cwd[MAXPATHLEN] = '\0';
349
350
0
    if (getcwd(cwd, MAXPATHLEN) == NULL) {
351
0
      flog_err_sys(EC_LIB_SYSTEM_CALL,
352
0
             "config_log_file: Unable to alloc mem!");
353
0
      return CMD_WARNING_CONFIG_FAILED;
354
0
    }
355
356
0
    int pr = snprintf(path, sizeof(path), "%s/%s", cwd, fname);
357
0
    if (pr < 0 || (unsigned int)pr >= sizeof(path)) {
358
0
      flog_err_sys(
359
0
        EC_LIB_SYSTEM_CALL,
360
0
        "%s: Path too long ('%s/%s'); system maximum is %u",
361
0
        __func__, cwd, fname, MAXPATHLEN);
362
0
      return CMD_WARNING_CONFIG_FAILED;
363
0
    }
364
365
0
    fullpath = path;
366
0
  } else
367
0
    fullpath = fname;
368
369
0
  target->prio_min = loglevel;
370
0
  ok = zlog_file_set_filename(target, fullpath);
371
372
0
  if (!ok) {
373
0
    if (vty)
374
0
      vty_out(vty, "can't open logfile %s\n", fname);
375
0
    return CMD_WARNING_CONFIG_FAILED;
376
0
  }
377
0
  return CMD_SUCCESS;
378
0
}
379
380
void command_setup_early_logging(const char *dest, const char *level)
381
0
{
382
0
  int nlevel;
383
0
  char *sep;
384
0
  int len;
385
0
  char type[8];
386
387
0
  if (level) {
388
0
    nlevel = log_level_match(level);
389
390
0
    if (nlevel == ZLOG_DISABLED) {
391
0
      fprintf(stderr, "invalid log level \"%s\"\n", level);
392
0
      exit(1);
393
0
    }
394
0
  } else
395
0
    nlevel = log_default_lvl;
396
397
0
  if (!dest)
398
0
    return;
399
400
0
  sep = strchr(dest, ':');
401
0
  len = sep ? (int)(sep - dest) : (int)strlen(dest);
402
403
0
  snprintfrr(type, sizeof(type), "%.*s", len, dest);
404
405
0
  if (strcmp(type, "stdout") == 0) {
406
0
    log_cmdline_stdout_lvl = nlevel;
407
0
    log_stdout_apply_level();
408
0
    return;
409
0
  }
410
0
  if (strcmp(type, "syslog") == 0) {
411
0
    log_cmdline_syslog_lvl = nlevel;
412
0
    zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl,
413
0
                 log_cmdline_syslog_lvl));
414
0
    return;
415
0
  }
416
0
  if (strcmp(type, "file") == 0 && sep) {
417
0
    sep++;
418
0
    set_log_file(&zt_file_cmdline, NULL, sep, nlevel);
419
0
    return;
420
0
  }
421
0
  if (strcmp(type, "monitor") == 0 && sep) {
422
0
    struct zlog_live_cfg cfg = {};
423
0
    unsigned long fd;
424
0
    char *endp;
425
426
0
    sep++;
427
0
    fd = strtoul(sep, &endp, 10);
428
0
    if (!*sep || *endp) {
429
0
      fprintf(stderr, "invalid monitor fd \"%s\"\n", sep);
430
0
      exit(1);
431
0
    }
432
433
0
    zlog_live_open_fd(&cfg, nlevel, fd);
434
0
    zlog_live_disown(&cfg);
435
0
    return;
436
0
  }
437
438
0
  fprintf(stderr, "invalid log target \"%s\" (\"%s\")\n", type, dest);
439
0
  exit(1);
440
0
}
441
442
DEFUN (clear_log_cmdline,
443
       clear_log_cmdline_cmd,
444
       "clear log cmdline-targets",
445
       CLEAR_STR
446
       "Logging control\n"
447
       "Disable log targets specified at startup by --log option\n")
448
0
{
449
0
  zt_file_cmdline.prio_min = ZLOG_DISABLED;
450
0
  zlog_file_set_other(&zt_file_cmdline);
451
452
0
  log_cmdline_syslog_lvl = ZLOG_DISABLED;
453
0
  zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl,
454
0
               log_cmdline_syslog_lvl));
455
456
0
  log_cmdline_stdout_lvl = ZLOG_DISABLED;
457
0
  log_stdout_apply_level();
458
459
0
  return CMD_SUCCESS;
460
0
}
461
462
DEFPY (config_log_file,
463
       config_log_file_cmd,
464
       "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
465
       "Logging control\n"
466
       "Logging to file\n"
467
       "Logging filename\n"
468
       LOG_LEVEL_DESC)
469
0
{
470
0
  int level = log_default_lvl;
471
472
0
  if (levelarg) {
473
0
    level = log_level_match(levelarg);
474
0
    if (level == ZLOG_DISABLED)
475
0
      return CMD_ERR_NO_MATCH;
476
0
  }
477
0
  return set_log_file(&zt_file, vty, filename, level);
478
0
}
479
480
DEFUN (no_config_log_file,
481
       no_config_log_file_cmd,
482
       "no log file [FILENAME [LEVEL]]",
483
       NO_STR
484
       "Logging control\n"
485
       "Cancel logging to file\n"
486
       "Logging file name\n"
487
       "Logging level\n")
488
0
{
489
0
  zt_file.prio_min = ZLOG_DISABLED;
490
0
  zlog_file_set_other(&zt_file);
491
0
  return CMD_SUCCESS;
492
0
}
493
494
DEFPY (config_log_syslog,
495
       config_log_syslog_cmd,
496
       "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
497
       "Logging control\n"
498
       "Set syslog logging level\n"
499
       LOG_LEVEL_DESC)
500
0
{
501
0
  int level;
502
503
0
  if (levelarg) {
504
0
    level = log_level_match(levelarg);
505
506
0
    if (level == ZLOG_DISABLED)
507
0
      return CMD_ERR_NO_MATCH;
508
0
  } else
509
0
    level = log_default_lvl;
510
511
0
  log_config_syslog_lvl = level;
512
0
  zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl,
513
0
               log_cmdline_syslog_lvl));
514
0
  return CMD_SUCCESS;
515
0
}
516
517
DEFUN (no_config_log_syslog,
518
       no_config_log_syslog_cmd,
519
       "no log syslog [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>] [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
520
       NO_STR
521
       "Logging control\n"
522
       "Cancel logging to syslog\n"
523
       LOG_FACILITY_DESC
524
       LOG_LEVEL_DESC)
525
0
{
526
0
  log_config_syslog_lvl = ZLOG_DISABLED;
527
0
  zlog_syslog_set_prio_min(ZLOG_MAXLVL(log_config_syslog_lvl,
528
0
               log_cmdline_syslog_lvl));
529
0
  return CMD_SUCCESS;
530
0
}
531
532
DEFPY (config_log_facility,
533
       config_log_facility_cmd,
534
       "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>$facilityarg",
535
       "Logging control\n"
536
       "Facility parameter for syslog messages\n"
537
       LOG_FACILITY_DESC)
538
0
{
539
0
  int facility = facility_match(facilityarg);
540
541
0
  zlog_syslog_set_facility(facility);
542
0
  return CMD_SUCCESS;
543
0
}
544
545
DEFUN (no_config_log_facility,
546
       no_config_log_facility_cmd,
547
       "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
548
       NO_STR
549
       "Logging control\n"
550
       "Reset syslog facility to default (daemon)\n"
551
       LOG_FACILITY_DESC)
552
0
{
553
0
  zlog_syslog_set_facility(LOG_DAEMON);
554
0
  return CMD_SUCCESS;
555
0
}
556
557
DEFUN (config_log_record_priority,
558
       config_log_record_priority_cmd,
559
       "log record-priority",
560
       "Logging control\n"
561
       "Log the priority of the message within the message\n")
562
0
{
563
0
  zt_file.record_priority = true;
564
0
  zlog_file_set_other(&zt_file);
565
0
  if (!stdout_journald_in_use) {
566
0
    zt_stdout_file.record_priority = true;
567
0
    zlog_file_set_other(&zt_stdout_file);
568
0
  }
569
0
  zt_filterfile.parent.record_priority = true;
570
0
  zlog_file_set_other(&zt_filterfile.parent);
571
0
  return CMD_SUCCESS;
572
0
}
573
574
DEFUN (no_config_log_record_priority,
575
       no_config_log_record_priority_cmd,
576
       "no log record-priority",
577
       NO_STR
578
       "Logging control\n"
579
       "Do not log the priority of the message within the message\n")
580
0
{
581
0
  zt_file.record_priority = false;
582
0
  zlog_file_set_other(&zt_file);
583
0
  if (!stdout_journald_in_use) {
584
0
    zt_stdout_file.record_priority = false;
585
0
    zlog_file_set_other(&zt_stdout_file);
586
0
  }
587
0
  zt_filterfile.parent.record_priority = false;
588
0
  zlog_file_set_other(&zt_filterfile.parent);
589
0
  return CMD_SUCCESS;
590
0
}
591
592
DEFPY (config_log_timestamp_precision,
593
       config_log_timestamp_precision_cmd,
594
       "log timestamp precision (0-6)",
595
       "Logging control\n"
596
       "Timestamp configuration\n"
597
       "Set the timestamp precision\n"
598
       "Number of subsecond digits\n")
599
0
{
600
0
  zt_file.ts_subsec = precision;
601
0
  zlog_file_set_other(&zt_file);
602
0
  if (!stdout_journald_in_use) {
603
0
    zt_stdout_file.ts_subsec = precision;
604
0
    zlog_file_set_other(&zt_stdout_file);
605
0
  }
606
0
  zt_filterfile.parent.ts_subsec = precision;
607
0
  zlog_file_set_other(&zt_filterfile.parent);
608
0
  return CMD_SUCCESS;
609
0
}
610
611
DEFUN (no_config_log_timestamp_precision,
612
       no_config_log_timestamp_precision_cmd,
613
       "no log timestamp precision [(0-6)]",
614
       NO_STR
615
       "Logging control\n"
616
       "Timestamp configuration\n"
617
       "Reset the timestamp precision to the default value of 0\n"
618
       "Number of subsecond digits\n")
619
0
{
620
0
  zt_file.ts_subsec = 0;
621
0
  zlog_file_set_other(&zt_file);
622
0
  if (!stdout_journald_in_use) {
623
0
    zt_stdout_file.ts_subsec = 0;
624
0
    zlog_file_set_other(&zt_stdout_file);
625
0
  }
626
0
  zt_filterfile.parent.ts_subsec = 0;
627
0
  zlog_file_set_other(&zt_filterfile.parent);
628
0
  return CMD_SUCCESS;
629
0
}
630
631
DEFPY (config_log_ec,
632
       config_log_ec_cmd,
633
       "[no] log error-category",
634
       NO_STR
635
       "Logging control\n"
636
       "Prefix log message text with [EC 9999] code\n")
637
0
{
638
0
  zlog_set_prefix_ec(!no);
639
0
  return CMD_SUCCESS;
640
0
}
641
642
DEFPY (config_log_xid,
643
       config_log_xid_cmd,
644
       "[no] log unique-id",
645
       NO_STR
646
       "Logging control\n"
647
       "Prefix log message text with [XXXXX-XXXXX] identifier\n")
648
0
{
649
0
  zlog_set_prefix_xid(!no);
650
0
  return CMD_SUCCESS;
651
0
}
652
653
DEFPY (config_log_filterfile,
654
       config_log_filterfile_cmd,
655
       "log filtered-file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
656
       "Logging control\n"
657
       "Logging to file with string filter\n"
658
       "Logging filename\n"
659
       LOG_LEVEL_DESC)
660
0
{
661
0
  int level = log_default_lvl;
662
663
0
  if (levelarg) {
664
0
    level = log_level_match(levelarg);
665
0
    if (level == ZLOG_DISABLED)
666
0
      return CMD_ERR_NO_MATCH;
667
0
  }
668
0
  return set_log_file(&zt_filterfile.parent, vty, filename, level);
669
0
}
670
671
DEFUN (no_config_log_filterfile,
672
       no_config_log_filterfile_cmd,
673
       "no log filtered-file [FILENAME [LEVEL]]",
674
       NO_STR
675
       "Logging control\n"
676
       "Cancel logging to file with string filter\n"
677
       "Logging file name\n"
678
       "Logging level\n")
679
0
{
680
0
  zt_filterfile.parent.prio_min = ZLOG_DISABLED;
681
0
  zlog_file_set_other(&zt_filterfile.parent);
682
0
  return CMD_SUCCESS;
683
0
}
684
685
DEFPY (log_filter,
686
       log_filter_cmd,
687
       "[no] log filter-text WORD$filter",
688
       NO_STR
689
       "Logging control\n"
690
       FILTER_LOG_STR
691
       "String to filter by\n")
692
0
{
693
0
  int ret = 0;
694
695
0
  if (no)
696
0
    ret = zlog_filter_del(filter);
697
0
  else
698
0
    ret = zlog_filter_add(filter);
699
700
0
  if (ret == 1) {
701
0
    vty_out(vty, "%% filter table full\n");
702
0
    return CMD_WARNING;
703
0
  } else if (ret != 0) {
704
0
    vty_out(vty, "%% failed to %s log filter\n",
705
0
      (no ? "remove" : "apply"));
706
0
    return CMD_WARNING;
707
0
  }
708
709
0
  vty_out(vty, " %s\n", filter);
710
0
  return CMD_SUCCESS;
711
0
}
712
713
/* Clear all log filters */
714
DEFPY (log_filter_clear,
715
       log_filter_clear_cmd,
716
       "clear log filter-text",
717
       CLEAR_STR
718
       "Logging control\n"
719
       FILTER_LOG_STR)
720
0
{
721
0
  zlog_filter_clear();
722
0
  return CMD_SUCCESS;
723
0
}
724
725
/* Show log filter */
726
DEFPY (show_log_filter,
727
       show_log_filter_cmd,
728
       "show logging filter-text",
729
       SHOW_STR
730
       "Show current logging configuration\n"
731
       FILTER_LOG_STR)
732
0
{
733
0
  char log_filters[ZLOG_FILTERS_MAX * (ZLOG_FILTER_LENGTH_MAX + 3)] = "";
734
0
  int len = 0;
735
736
0
  len = zlog_filter_dump(log_filters, sizeof(log_filters));
737
738
0
  if (len == -1) {
739
0
    vty_out(vty, "%% failed to get filters\n");
740
0
    return CMD_WARNING;
741
0
  }
742
743
0
  if (len != 0)
744
0
    vty_out(vty, "%s", log_filters);
745
746
0
  return CMD_SUCCESS;
747
0
}
748
749
/* Enable/disable 'immediate' mode, with no output buffering */
750
DEFPY (log_immediate_mode,
751
       log_immediate_mode_cmd,
752
       "[no] log immediate-mode",
753
       NO_STR
754
       "Logging control\n"
755
       "Output immediately, without buffering\n")
756
0
{
757
0
  zlog_set_immediate(!no);
758
0
  return CMD_SUCCESS;
759
0
}
760
761
void log_config_write(struct vty *vty)
762
0
{
763
0
  bool show_cmdline_hint = false;
764
765
0
  if (zt_file.prio_min != ZLOG_DISABLED && zt_file.filename) {
766
0
    vty_out(vty, "log file %s", zt_file.filename);
767
768
0
    if (zt_file.prio_min != log_default_lvl)
769
0
      vty_out(vty, " %s", zlog_priority[zt_file.prio_min]);
770
0
    vty_out(vty, "\n");
771
0
  }
772
773
0
  if (zt_filterfile.parent.prio_min != ZLOG_DISABLED
774
0
      && zt_filterfile.parent.filename) {
775
0
    vty_out(vty, "log filtered-file %s",
776
0
      zt_filterfile.parent.filename);
777
778
0
    if (zt_filterfile.parent.prio_min != log_default_lvl)
779
0
      vty_out(vty, " %s",
780
0
        zlog_priority[zt_filterfile.parent.prio_min]);
781
0
    vty_out(vty, "\n");
782
0
  }
783
784
0
  if (log_config_stdout_lvl != ZLOG_DISABLED) {
785
0
    vty_out(vty, "log stdout");
786
787
0
    if (log_config_stdout_lvl != log_default_lvl)
788
0
      vty_out(vty, " %s",
789
0
        zlog_priority[log_config_stdout_lvl]);
790
0
    vty_out(vty, "\n");
791
0
  }
792
793
0
  if (log_config_syslog_lvl != ZLOG_DISABLED) {
794
0
    vty_out(vty, "log syslog");
795
796
0
    if (log_config_syslog_lvl != log_default_lvl)
797
0
      vty_out(vty, " %s",
798
0
        zlog_priority[log_config_syslog_lvl]);
799
0
    vty_out(vty, "\n");
800
0
  }
801
802
0
  if (log_cmdline_syslog_lvl != ZLOG_DISABLED) {
803
0
    vty_out(vty,
804
0
      "! \"log syslog %s\" enabled by \"--log\" startup option\n",
805
0
      zlog_priority[log_cmdline_syslog_lvl]);
806
0
    show_cmdline_hint = true;
807
0
  }
808
0
  if (log_cmdline_stdout_lvl != ZLOG_DISABLED) {
809
0
    vty_out(vty,
810
0
      "! \"log stdout %s\" enabled by \"--log\" startup option\n",
811
0
      zlog_priority[log_cmdline_stdout_lvl]);
812
0
    show_cmdline_hint = true;
813
0
  }
814
0
  if (zt_file_cmdline.prio_min != ZLOG_DISABLED) {
815
0
    vty_out(vty,
816
0
      "! \"log file %s %s\" enabled by \"--log\" startup option\n",
817
0
      zt_file_cmdline.filename,
818
0
      zlog_priority[zt_file_cmdline.prio_min]);
819
0
    show_cmdline_hint = true;
820
0
  }
821
0
  if (show_cmdline_hint)
822
0
    vty_out(vty,
823
0
      "! use \"clear log cmdline-targets\" to remove this target\n");
824
825
0
  if (zlog_syslog_get_facility() != LOG_DAEMON)
826
0
    vty_out(vty, "log facility %s\n",
827
0
      facility_name(zlog_syslog_get_facility()));
828
829
0
  if (zt_file.record_priority == 1)
830
0
    vty_out(vty, "log record-priority\n");
831
832
0
  if (zt_file.ts_subsec > 0)
833
0
    vty_out(vty, "log timestamp precision %d\n",
834
0
      zt_file.ts_subsec);
835
836
0
  if (!zlog_get_prefix_ec())
837
0
    vty_out(vty, "no log error-category\n");
838
0
  if (!zlog_get_prefix_xid())
839
0
    vty_out(vty, "no log unique-id\n");
840
841
0
  if (logmsgs_with_persist_bt) {
842
0
    struct xrefdata *xrd;
843
0
    struct xrefdata_logmsg *xrdl;
844
845
0
    vty_out(vty, "!\n");
846
847
0
    frr_each (xrefdata_uid, &xrefdata_uid, xrd) {
848
0
      if (xrd->xref->type != XREFT_LOGMSG)
849
0
        continue;
850
851
0
      xrdl = container_of(xrd, struct xrefdata_logmsg,
852
0
              xrefdata);
853
0
      if (xrdl->fl_print_bt & LOGMSG_FLAG_PERSISTENT)
854
0
        vty_out(vty, "debug unique-id %s backtrace\n",
855
0
          xrd->uid);
856
0
    }
857
0
  }
858
0
}
859
860
static int log_vty_init(const char *progname, const char *protoname,
861
       unsigned short instance, uid_t uid, gid_t gid)
862
4
{
863
4
  zlog_progname = progname;
864
4
  zlog_protoname = protoname;
865
866
4
  zlog_set_prefix_ec(true);
867
4
  zlog_set_prefix_xid(true);
868
869
4
  zlog_filterfile_init(&zt_filterfile);
870
871
4
  if (sd_stdout_is_journal) {
872
0
    stdout_journald_in_use = true;
873
0
    zlog_5424_init(&zt_stdout_journald);
874
0
    zlog_5424_apply_dst(&zt_stdout_journald);
875
0
  } else
876
4
    zlog_file_set_fd(&zt_stdout_file, STDOUT_FILENO);
877
4
  return 0;
878
4
}
879
880
__attribute__((_CONSTRUCTOR(475))) static void log_vty_preinit(void)
881
8
{
882
8
  hook_register(zlog_init, log_vty_init);
883
8
}
884
885
void log_cmd_init(void)
886
4
{
887
4
  install_element(VIEW_NODE, &show_logging_cmd);
888
4
  install_element(ENABLE_NODE, &clear_log_cmdline_cmd);
889
890
4
  install_element(CONFIG_NODE, &config_log_stdout_cmd);
891
4
  install_element(CONFIG_NODE, &no_config_log_stdout_cmd);
892
4
  install_element(CONFIG_NODE, &config_log_monitor_cmd);
893
4
  install_element(CONFIG_NODE, &no_config_log_monitor_cmd);
894
4
  install_element(CONFIG_NODE, &config_log_file_cmd);
895
4
  install_element(CONFIG_NODE, &no_config_log_file_cmd);
896
4
  install_element(CONFIG_NODE, &config_log_syslog_cmd);
897
4
  install_element(CONFIG_NODE, &no_config_log_syslog_cmd);
898
4
  install_element(CONFIG_NODE, &config_log_facility_cmd);
899
4
  install_element(CONFIG_NODE, &no_config_log_facility_cmd);
900
4
  install_element(CONFIG_NODE, &config_log_record_priority_cmd);
901
4
  install_element(CONFIG_NODE, &no_config_log_record_priority_cmd);
902
4
  install_element(CONFIG_NODE, &config_log_timestamp_precision_cmd);
903
4
  install_element(CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
904
4
  install_element(CONFIG_NODE, &config_log_ec_cmd);
905
4
  install_element(CONFIG_NODE, &config_log_xid_cmd);
906
907
4
  install_element(VIEW_NODE, &show_log_filter_cmd);
908
4
  install_element(CONFIG_NODE, &log_filter_cmd);
909
4
  install_element(CONFIG_NODE, &log_filter_clear_cmd);
910
4
  install_element(CONFIG_NODE, &config_log_filterfile_cmd);
911
4
  install_element(CONFIG_NODE, &no_config_log_filterfile_cmd);
912
4
  install_element(CONFIG_NODE, &log_immediate_mode_cmd);
913
914
4
  install_element(ENABLE_NODE, &debug_uid_backtrace_cmd);
915
4
  install_element(CONFIG_NODE, &debug_uid_backtrace_cmd);
916
917
4
  log_5424_cmd_init();
918
4
}