3 * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #define FRR_DEFINE_DESC_TABLE
30 #include "lib_errors.h"
33 #include "frr_pthread.h"
36 #define UNW_LOCAL_ONLY
37 #include <libunwind.h>
42 * Looks up a message in a message list by key.
44 * If the message is not found, returns the provided error message.
46 * Terminates when it hits a struct message that's all zeros.
48 * @param mz the message list
49 * @param kz the message key
50 * @param nf the message to return if not found
53 const char *lookup_msg(const struct message
*mz
, int kz
, const char *nf
)
55 static struct message nt
= {0};
56 const char *rz
= nf
? nf
: "(no message found)";
57 const struct message
*pnt
;
58 for (pnt
= mz
; memcmp(pnt
, &nt
, sizeof(struct message
)); pnt
++)
60 rz
= pnt
->str
? pnt
->str
: rz
;
66 /* For time string format. */
67 size_t quagga_timestamp(int timestamp_precision
, char *buf
, size_t buflen
)
76 gettimeofday(&clock
, NULL
);
78 /* first, we update the cache if the time has changed */
79 if (cache
.last
!= clock
.tv_sec
) {
81 cache
.last
= clock
.tv_sec
;
82 localtime_r(&cache
.last
, &tm
);
83 cache
.len
= strftime(cache
.buf
, sizeof(cache
.buf
),
84 "%Y/%m/%d %H:%M:%S", &tm
);
86 /* note: it's not worth caching the subsecond part, because
87 chances are that back-to-back calls are not sufficiently close
89 for the clock not to have ticked forward */
91 if (buflen
> cache
.len
) {
92 memcpy(buf
, cache
.buf
, cache
.len
);
93 if ((timestamp_precision
> 0)
94 && (buflen
> cache
.len
+ 1 + timestamp_precision
)) {
95 /* should we worry about locale issues? */
96 static const int divisor
[] = {0, 100000, 10000, 1000,
99 char *p
= buf
+ cache
.len
+ 1
100 + (prec
= timestamp_precision
);
103 /* this is unlikely to happen, but protect anyway */
108 clock
.tv_usec
/= divisor
[prec
];
110 *p
-- = '0' + (clock
.tv_usec
% 10);
112 } while (--prec
> 0);
114 return cache
.len
+ 1 + timestamp_precision
;
116 buf
[cache
.len
] = '\0';
127 * NB: only AS-Safe (async-signal) functions can be used here!
130 /* Note: the goal here is to use only async-signal-safe functions. */
131 void zlog_signal(int signo
, const char *action
, void *siginfo_v
,
132 void *program_counter
)
134 siginfo_t
*siginfo
= siginfo_v
;
136 char buf
[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")
138 struct fbuf fb
= { .buf
= buf
, .pos
= buf
, .len
= sizeof(buf
) };
142 bprintfrr(&fb
, "Received signal %d at %lld", signo
, (long long)now
);
144 bprintfrr(&fb
, " (si_addr 0x%tx, PC 0x%tx)",
145 (ptrdiff_t)siginfo
->si_addr
,
146 (ptrdiff_t)program_counter
);
148 bprintfrr(&fb
, " (si_addr 0x%tx)",
149 (ptrdiff_t)siginfo
->si_addr
);
150 bprintfrr(&fb
, "; %s\n", action
);
152 zlog_sigsafe(fb
.buf
, fb
.pos
- fb
.buf
);
154 zlog_backtrace_sigsafe(LOG_CRIT
, program_counter
);
159 tc
= pthread_getspecific(thread_current
);
162 bprintfrr(&fb
, "no thread information available\n");
164 bprintfrr(&fb
, "in thread %s scheduled from %s:%d\n",
165 tc
->funcname
, tc
->schedfrom
, tc
->schedfrom_line
);
167 zlog_sigsafe(fb
.buf
, fb
.pos
- fb
.buf
);
170 /* Log a backtrace using only async-signal-safe functions.
171 Needs to be enhanced to support syslog logging. */
172 void zlog_backtrace_sigsafe(int priority
, void *program_counter
)
174 #ifdef HAVE_LIBUNWIND
176 struct fbuf fb
= { .buf
= buf
, .len
= sizeof(buf
) };
179 unw_word_t ip
, off
, sp
;
183 unw_init_local(&cursor
, &uc
);
184 while (unw_step(&cursor
) > 0) {
185 char name
[128] = "?";
187 unw_get_reg(&cursor
, UNW_REG_IP
, &ip
);
188 unw_get_reg(&cursor
, UNW_REG_SP
, &sp
);
190 if (!unw_get_proc_name(&cursor
, buf
, sizeof(buf
), &off
))
191 snprintfrr(name
, sizeof(name
), "%s+%#lx",
195 if (unw_is_signal_frame(&cursor
))
196 bprintfrr(&fb
, " ---- signal ----\n");
197 bprintfrr(&fb
, "%-30s %16lx %16lx", name
, (long)ip
, (long)sp
);
198 if (dladdr((void *)ip
, &dlinfo
))
199 bprintfrr(&fb
, " %s (mapped at %p)",
200 dlinfo
.dli_fname
, dlinfo
.dli_fbase
);
201 bprintfrr(&fb
, "\n");
202 zlog_sigsafe(fb
.buf
, fb
.pos
- fb
.buf
);
204 #elif defined(HAVE_GLIBC_BACKTRACE)
208 struct fbuf fb
= { .buf
= buf
, .pos
= buf
, .len
= sizeof(buf
) };
211 size
= backtrace(array
, array_size(array
));
212 if (size
<= 0 || (size_t)size
> array_size(array
))
215 bprintfrr(&fb
, "Backtrace for %d stack frames:", size
);
216 zlog_sigsafe(fb
.pos
, fb
.buf
- fb
.pos
);
218 bt
= backtrace_symbols(array
, size
);
220 for (i
= 0; i
< size
; i
++) {
223 bprintfrr(&fb
, "%s", bt
[i
]);
225 bprintfrr(&fb
, "[bt %d] 0x%tx", i
,
226 (ptrdiff_t)(array
[i
]));
227 zlog_sigsafe(fb
.buf
, fb
.pos
- fb
.buf
);
231 #endif /* HAVE_STRACK_TRACE */
234 void zlog_backtrace(int priority
)
236 #ifdef HAVE_LIBUNWIND
240 unw_word_t ip
, off
, sp
;
244 unw_init_local(&cursor
, &uc
);
245 zlog(priority
, "Backtrace:");
246 while (unw_step(&cursor
) > 0) {
247 char name
[128] = "?";
249 unw_get_reg(&cursor
, UNW_REG_IP
, &ip
);
250 unw_get_reg(&cursor
, UNW_REG_SP
, &sp
);
252 if (unw_is_signal_frame(&cursor
))
253 zlog(priority
, " ---- signal ----");
255 if (!unw_get_proc_name(&cursor
, buf
, sizeof(buf
), &off
))
256 snprintf(name
, sizeof(name
), "%s+%#lx",
259 if (dladdr((void *)ip
, &dlinfo
))
260 zlog(priority
, "%-30s %16lx %16lx %s (mapped at %p)",
261 name
, (long)ip
, (long)sp
,
262 dlinfo
.dli_fname
, dlinfo
.dli_fbase
);
264 zlog(priority
, "%-30s %16lx %16lx",
265 name
, (long)ip
, (long)sp
);
267 #elif defined(HAVE_GLIBC_BACKTRACE)
272 size
= backtrace(array
, array_size(array
));
273 if (size
<= 0 || (size_t)size
> array_size(array
)) {
276 "Cannot get backtrace, returned invalid # of frames %d "
277 "(valid range is between 1 and %lu)",
278 size
, (unsigned long)(array_size(array
)));
281 zlog(priority
, "Backtrace for %d stack frames:", size
);
282 if (!(strings
= backtrace_symbols(array
, size
))) {
283 flog_err_sys(EC_LIB_SYSTEM_CALL
,
284 "Cannot get backtrace symbols (out of memory?)");
285 for (i
= 0; i
< size
; i
++)
286 zlog(priority
, "[bt %d] %p", i
, array
[i
]);
288 for (i
= 0; i
< size
; i
++)
289 zlog(priority
, "[bt %d] %s", i
, strings
[i
]);
292 #else /* !HAVE_GLIBC_BACKTRACE && !HAVE_LIBUNWIND */
293 zlog(priority
, "No backtrace available on this platform.");
297 void zlog_thread_info(int log_level
)
300 tc
= pthread_getspecific(thread_current
);
304 "Current thread function %s, scheduled from "
306 tc
->funcname
, tc
->schedfrom
, tc
->schedfrom_line
);
308 zlog(log_level
, "Current thread not known/applicable");
311 void _zlog_assert_failed(const char *assertion
, const char *file
,
312 unsigned int line
, const char *function
)
314 zlog(LOG_CRIT
, "Assertion `%s' failed in file %s, line %u, function %s",
315 assertion
, file
, line
, (function
? function
: "?"));
316 zlog_backtrace(LOG_CRIT
);
317 zlog_thread_info(LOG_CRIT
);
318 log_memstats(stderr
, "log");
322 void memory_oom(size_t size
, const char *name
)
325 "out of memory: failed to allocate %zu bytes for %s object",
327 zlog_backtrace(LOG_CRIT
);
328 log_memstats(stderr
, "log");
332 /* Wrapper around strerror to handle case where it returns NULL. */
333 const char *safe_strerror(int errnum
)
335 const char *s
= strerror(errnum
);
336 return (s
!= NULL
) ? s
: "Unknown error";
339 #define DESC_ENTRY(T) [(T)] = { (T), (#T), '\0' }
340 static const struct zebra_desc_table command_types
[] = {
341 DESC_ENTRY(ZEBRA_INTERFACE_ADD
),
342 DESC_ENTRY(ZEBRA_INTERFACE_DELETE
),
343 DESC_ENTRY(ZEBRA_INTERFACE_ADDRESS_ADD
),
344 DESC_ENTRY(ZEBRA_INTERFACE_ADDRESS_DELETE
),
345 DESC_ENTRY(ZEBRA_INTERFACE_UP
),
346 DESC_ENTRY(ZEBRA_INTERFACE_DOWN
),
347 DESC_ENTRY(ZEBRA_INTERFACE_SET_MASTER
),
348 DESC_ENTRY(ZEBRA_ROUTE_ADD
),
349 DESC_ENTRY(ZEBRA_ROUTE_DELETE
),
350 DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_OWNER
),
351 DESC_ENTRY(ZEBRA_REDISTRIBUTE_ADD
),
352 DESC_ENTRY(ZEBRA_REDISTRIBUTE_DELETE
),
353 DESC_ENTRY(ZEBRA_REDISTRIBUTE_DEFAULT_ADD
),
354 DESC_ENTRY(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE
),
355 DESC_ENTRY(ZEBRA_ROUTER_ID_ADD
),
356 DESC_ENTRY(ZEBRA_ROUTER_ID_DELETE
),
357 DESC_ENTRY(ZEBRA_ROUTER_ID_UPDATE
),
358 DESC_ENTRY(ZEBRA_HELLO
),
359 DESC_ENTRY(ZEBRA_CAPABILITIES
),
360 DESC_ENTRY(ZEBRA_NEXTHOP_REGISTER
),
361 DESC_ENTRY(ZEBRA_NEXTHOP_UNREGISTER
),
362 DESC_ENTRY(ZEBRA_NEXTHOP_UPDATE
),
363 DESC_ENTRY(ZEBRA_INTERFACE_NBR_ADDRESS_ADD
),
364 DESC_ENTRY(ZEBRA_INTERFACE_NBR_ADDRESS_DELETE
),
365 DESC_ENTRY(ZEBRA_INTERFACE_BFD_DEST_UPDATE
),
366 DESC_ENTRY(ZEBRA_IMPORT_ROUTE_REGISTER
),
367 DESC_ENTRY(ZEBRA_IMPORT_ROUTE_UNREGISTER
),
368 DESC_ENTRY(ZEBRA_IMPORT_CHECK_UPDATE
),
369 DESC_ENTRY(ZEBRA_BFD_DEST_REGISTER
),
370 DESC_ENTRY(ZEBRA_BFD_DEST_DEREGISTER
),
371 DESC_ENTRY(ZEBRA_BFD_DEST_UPDATE
),
372 DESC_ENTRY(ZEBRA_BFD_DEST_REPLAY
),
373 DESC_ENTRY(ZEBRA_REDISTRIBUTE_ROUTE_ADD
),
374 DESC_ENTRY(ZEBRA_REDISTRIBUTE_ROUTE_DEL
),
375 DESC_ENTRY(ZEBRA_VRF_UNREGISTER
),
376 DESC_ENTRY(ZEBRA_VRF_ADD
),
377 DESC_ENTRY(ZEBRA_VRF_DELETE
),
378 DESC_ENTRY(ZEBRA_VRF_LABEL
),
379 DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE
),
380 DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER
),
381 DESC_ENTRY(ZEBRA_BFD_CLIENT_DEREGISTER
),
382 DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV
),
383 DESC_ENTRY(ZEBRA_INTERFACE_DISABLE_RADV
),
384 DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB
),
385 DESC_ENTRY(ZEBRA_INTERFACE_LINK_PARAMS
),
386 DESC_ENTRY(ZEBRA_MPLS_LABELS_ADD
),
387 DESC_ENTRY(ZEBRA_MPLS_LABELS_DELETE
),
388 DESC_ENTRY(ZEBRA_MPLS_LABELS_REPLACE
),
389 DESC_ENTRY(ZEBRA_IPMR_ROUTE_STATS
),
390 DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT
),
391 DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC
),
392 DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK
),
393 DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK
),
394 DESC_ENTRY(ZEBRA_FEC_REGISTER
),
395 DESC_ENTRY(ZEBRA_FEC_UNREGISTER
),
396 DESC_ENTRY(ZEBRA_FEC_UPDATE
),
397 DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI
),
398 DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW
),
399 DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP
),
400 DESC_ENTRY(ZEBRA_ADVERTISE_SUBNET
),
401 DESC_ENTRY(ZEBRA_LOCAL_ES_ADD
),
402 DESC_ENTRY(ZEBRA_LOCAL_ES_DEL
),
403 DESC_ENTRY(ZEBRA_VNI_ADD
),
404 DESC_ENTRY(ZEBRA_VNI_DEL
),
405 DESC_ENTRY(ZEBRA_L3VNI_ADD
),
406 DESC_ENTRY(ZEBRA_L3VNI_DEL
),
407 DESC_ENTRY(ZEBRA_REMOTE_VTEP_ADD
),
408 DESC_ENTRY(ZEBRA_REMOTE_VTEP_DEL
),
409 DESC_ENTRY(ZEBRA_MACIP_ADD
),
410 DESC_ENTRY(ZEBRA_MACIP_DEL
),
411 DESC_ENTRY(ZEBRA_IP_PREFIX_ROUTE_ADD
),
412 DESC_ENTRY(ZEBRA_IP_PREFIX_ROUTE_DEL
),
413 DESC_ENTRY(ZEBRA_REMOTE_MACIP_ADD
),
414 DESC_ENTRY(ZEBRA_REMOTE_MACIP_DEL
),
415 DESC_ENTRY(ZEBRA_DUPLICATE_ADDR_DETECTION
),
416 DESC_ENTRY(ZEBRA_PW_ADD
),
417 DESC_ENTRY(ZEBRA_PW_DELETE
),
418 DESC_ENTRY(ZEBRA_PW_SET
),
419 DESC_ENTRY(ZEBRA_PW_UNSET
),
420 DESC_ENTRY(ZEBRA_PW_STATUS_UPDATE
),
421 DESC_ENTRY(ZEBRA_RULE_ADD
),
422 DESC_ENTRY(ZEBRA_RULE_DELETE
),
423 DESC_ENTRY(ZEBRA_RULE_NOTIFY_OWNER
),
424 DESC_ENTRY(ZEBRA_TABLE_MANAGER_CONNECT
),
425 DESC_ENTRY(ZEBRA_GET_TABLE_CHUNK
),
426 DESC_ENTRY(ZEBRA_RELEASE_TABLE_CHUNK
),
427 DESC_ENTRY(ZEBRA_IPSET_CREATE
),
428 DESC_ENTRY(ZEBRA_IPSET_DESTROY
),
429 DESC_ENTRY(ZEBRA_IPSET_ENTRY_ADD
),
430 DESC_ENTRY(ZEBRA_IPSET_ENTRY_DELETE
),
431 DESC_ENTRY(ZEBRA_IPSET_NOTIFY_OWNER
),
432 DESC_ENTRY(ZEBRA_IPSET_ENTRY_NOTIFY_OWNER
),
433 DESC_ENTRY(ZEBRA_IPTABLE_ADD
),
434 DESC_ENTRY(ZEBRA_IPTABLE_DELETE
),
435 DESC_ENTRY(ZEBRA_IPTABLE_NOTIFY_OWNER
),
436 DESC_ENTRY(ZEBRA_VXLAN_FLOOD_CONTROL
),
437 DESC_ENTRY(ZEBRA_VXLAN_SG_ADD
),
438 DESC_ENTRY(ZEBRA_VXLAN_SG_DEL
),
439 DESC_ENTRY(ZEBRA_VXLAN_SG_REPLAY
),
440 DESC_ENTRY(ZEBRA_MLAG_PROCESS_UP
),
441 DESC_ENTRY(ZEBRA_MLAG_PROCESS_DOWN
),
442 DESC_ENTRY(ZEBRA_MLAG_CLIENT_REGISTER
),
443 DESC_ENTRY(ZEBRA_MLAG_CLIENT_UNREGISTER
),
444 DESC_ENTRY(ZEBRA_MLAG_FORWARD_MSG
),
445 DESC_ENTRY(ZEBRA_ERROR
),
446 DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES
)};
449 static const struct zebra_desc_table unknown
= {0, "unknown", '?'};
451 static const struct zebra_desc_table
*zroute_lookup(unsigned int zroute
)
455 if (zroute
>= array_size(route_types
)) {
456 flog_err(EC_LIB_DEVELOPMENT
, "unknown zebra route type: %u",
460 if (zroute
== route_types
[zroute
].type
)
461 return &route_types
[zroute
];
462 for (i
= 0; i
< array_size(route_types
); i
++) {
463 if (zroute
== route_types
[i
].type
) {
465 "internal error: route type table out of order "
466 "while searching for %u, please notify developers",
468 return &route_types
[i
];
471 flog_err(EC_LIB_DEVELOPMENT
,
472 "internal error: cannot find route type %u in table!", zroute
);
476 const char *zebra_route_string(unsigned int zroute
)
478 return zroute_lookup(zroute
)->string
;
481 char zebra_route_char(unsigned int zroute
)
483 return zroute_lookup(zroute
)->chr
;
486 const char *zserv_command_string(unsigned int command
)
488 if (command
>= array_size(command_types
)) {
489 flog_err(EC_LIB_DEVELOPMENT
, "unknown zserv command type: %u",
491 return unknown
.string
;
493 return command_types
[command
].string
;
496 int proto_name2num(const char *s
)
500 for (i
= 0; i
< array_size(route_types
); ++i
)
501 if (strcasecmp(s
, route_types
[i
].string
) == 0)
502 return route_types
[i
].type
;
506 int proto_redistnum(int afi
, const char *s
)
512 if (strmatch(s
, "kernel"))
513 return ZEBRA_ROUTE_KERNEL
;
514 else if (strmatch(s
, "connected"))
515 return ZEBRA_ROUTE_CONNECT
;
516 else if (strmatch(s
, "static"))
517 return ZEBRA_ROUTE_STATIC
;
518 else if (strmatch(s
, "rip"))
519 return ZEBRA_ROUTE_RIP
;
520 else if (strmatch(s
, "eigrp"))
521 return ZEBRA_ROUTE_EIGRP
;
522 else if (strmatch(s
, "ospf"))
523 return ZEBRA_ROUTE_OSPF
;
524 else if (strmatch(s
, "isis"))
525 return ZEBRA_ROUTE_ISIS
;
526 else if (strmatch(s
, "bgp"))
527 return ZEBRA_ROUTE_BGP
;
528 else if (strmatch(s
, "table"))
529 return ZEBRA_ROUTE_TABLE
;
530 else if (strmatch(s
, "vnc"))
531 return ZEBRA_ROUTE_VNC
;
532 else if (strmatch(s
, "vnc-direct"))
533 return ZEBRA_ROUTE_VNC_DIRECT
;
534 else if (strmatch(s
, "nhrp"))
535 return ZEBRA_ROUTE_NHRP
;
536 else if (strmatch(s
, "babel"))
537 return ZEBRA_ROUTE_BABEL
;
538 else if (strmatch(s
, "sharp"))
539 return ZEBRA_ROUTE_SHARP
;
540 else if (strmatch(s
, "openfabric"))
541 return ZEBRA_ROUTE_OPENFABRIC
;
543 if (afi
== AFI_IP6
) {
544 if (strmatch(s
, "kernel"))
545 return ZEBRA_ROUTE_KERNEL
;
546 else if (strmatch(s
, "connected"))
547 return ZEBRA_ROUTE_CONNECT
;
548 else if (strmatch(s
, "static"))
549 return ZEBRA_ROUTE_STATIC
;
550 else if (strmatch(s
, "ripng"))
551 return ZEBRA_ROUTE_RIPNG
;
552 else if (strmatch(s
, "ospf6"))
553 return ZEBRA_ROUTE_OSPF6
;
554 else if (strmatch(s
, "isis"))
555 return ZEBRA_ROUTE_ISIS
;
556 else if (strmatch(s
, "bgp"))
557 return ZEBRA_ROUTE_BGP
;
558 else if (strmatch(s
, "table"))
559 return ZEBRA_ROUTE_TABLE
;
560 else if (strmatch(s
, "vnc"))
561 return ZEBRA_ROUTE_VNC
;
562 else if (strmatch(s
, "vnc-direct"))
563 return ZEBRA_ROUTE_VNC_DIRECT
;
564 else if (strmatch(s
, "nhrp"))
565 return ZEBRA_ROUTE_NHRP
;
566 else if (strmatch(s
, "babel"))
567 return ZEBRA_ROUTE_BABEL
;
568 else if (strmatch(s
, "sharp"))
569 return ZEBRA_ROUTE_SHARP
;
570 else if (strmatch(s
, "openfabric"))
571 return ZEBRA_ROUTE_OPENFABRIC
;
576 void zlog_hexdump(const void *mem
, size_t len
)
579 const uint8_t *src
= mem
;
580 const uint8_t *end
= src
+ len
;
583 zlog_debug("%016lx: (zero length / no data)", (long)src
);
593 const uint8_t *lineend
= src
+ 8;
594 unsigned line_bytes
= 0;
596 bprintfrr(&fb
, "%016lx: ", (long)src
);
598 while (src
< lineend
&& src
< end
) {
599 bprintfrr(&fb
, "%02x ", *src
++);
603 bprintfrr(&fb
, "%*s", (8 - line_bytes
) * 3, "");
606 while (src
< lineend
&& src
< end
&& fb
.pos
< fb
.buf
+ fb
.len
) {
607 uint8_t byte
= *src
++;
615 zlog_debug("%.*s", (int)(fb
.pos
- fb
.buf
), fb
.buf
);
619 const char *zlog_sanitize(char *buf
, size_t bufsz
, const void *in
, size_t inlen
)
621 const char *inbuf
= in
;
622 char *pos
= buf
, *end
= buf
+ bufsz
;
623 const char *iend
= inbuf
+ inlen
;
625 memset(buf
, 0, bufsz
);
626 for (; inbuf
< iend
; inbuf
++) {
627 /* don't write partial escape sequence */
632 snprintf(pos
, end
- pos
, "\\n");
633 else if (*inbuf
== '\r')
634 snprintf(pos
, end
- pos
, "\\r");
635 else if (*inbuf
== '\t')
636 snprintf(pos
, end
- pos
, "\\t");
637 else if (*inbuf
< ' ' || *inbuf
== '"' || *inbuf
>= 127)
638 snprintf(pos
, end
- pos
, "\\x%02hhx", *inbuf
);