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 | } |