back to topotato report
topotato coverage report
Current view: top level - lib - ferr.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 32 139 23.0 %
Date: 2023-11-16 17:19:14 Functions: 10 39 25.6 %

          Line data    Source code
       1             : // SPDX-License-Identifier: ISC
       2             : /*
       3             :  * Copyright (c) 2015-16  David Lamparter, for NetDEF, Inc.
       4             :  */
       5             : 
       6             : #ifdef HAVE_CONFIG_H
       7             : #include "config.h"
       8             : #endif
       9             : 
      10             : #include <stdlib.h>
      11             : #include <stdarg.h>
      12             : #include <string.h>
      13             : #include <pthread.h>
      14             : #include <signal.h>
      15             : #include <inttypes.h>
      16             : 
      17             : #include "ferr.h"
      18             : #include "vty.h"
      19             : #include "jhash.h"
      20             : #include "memory.h"
      21             : #include "hash.h"
      22             : #include "command.h"
      23             : #include "json.h"
      24             : #include "linklist.h"
      25             : #include "frr_pthread.h"
      26             : 
      27          12 : DEFINE_MTYPE_STATIC(LIB, ERRINFO, "error information");
      28             : 
      29             : /*
      30             :  * Thread-specific key for temporary storage of allocated ferr.
      31             :  */
      32             : static pthread_key_t errkey;
      33             : 
      34           0 : static void ferr_free(void *arg)
      35             : {
      36           0 :         XFREE(MTYPE_ERRINFO, arg);
      37           0 : }
      38             : 
      39             : static void err_key_init(void) __attribute__((_CONSTRUCTOR(500)));
      40           4 : static void err_key_init(void)
      41             : {
      42           4 :         pthread_key_create(&errkey, ferr_free);
      43           4 : }
      44             : 
      45             : static void err_key_fini(void) __attribute__((_DESTRUCTOR(500)));
      46           8 : static void err_key_fini(void)
      47             : {
      48           8 :         pthread_key_delete(errkey);
      49           8 : }
      50             : 
      51             : /*
      52             :  * Global shared hash table holding reference text for all defined errors.
      53             :  */
      54             : static pthread_mutex_t refs_mtx = PTHREAD_MUTEX_INITIALIZER;
      55             : struct hash *refs;
      56             : 
      57           2 : static bool ferr_hash_cmp(const void *a, const void *b)
      58             : {
      59           2 :         const struct log_ref *f_a = a;
      60           2 :         const struct log_ref *f_b = b;
      61             : 
      62           2 :         return f_a->code == f_b->code;
      63             : }
      64             : 
      65         592 : static inline unsigned int ferr_hash_key(const void *a)
      66             : {
      67         592 :         const struct log_ref *f = a;
      68             : 
      69         592 :         return f->code;
      70             : }
      71             : 
      72          14 : void log_ref_add(struct log_ref *ref)
      73             : {
      74          14 :         uint32_t i = 0;
      75             : 
      76          28 :         frr_with_mutex (&refs_mtx) {
      77         606 :                 while (ref[i].code != END_FERR) {
      78         592 :                         (void)hash_get(refs, &ref[i], hash_alloc_intern);
      79         592 :                         i++;
      80             :                 }
      81             :         }
      82          14 : }
      83             : 
      84           0 : struct log_ref *log_ref_get(uint32_t code)
      85             : {
      86           0 :         struct log_ref holder;
      87           0 :         struct log_ref *ref;
      88             : 
      89           0 :         holder.code = code;
      90           0 :         frr_with_mutex (&refs_mtx) {
      91           0 :                 ref = hash_lookup(refs, &holder);
      92             :         }
      93             : 
      94           0 :         return ref;
      95             : }
      96             : 
      97           0 : void log_ref_display(struct vty *vty, uint32_t code, bool json)
      98             : {
      99           0 :         struct log_ref *ref;
     100           0 :         struct json_object *top = NULL, *obj = NULL;
     101           0 :         struct list *errlist;
     102           0 :         struct listnode *ln;
     103             : 
     104           0 :         if (json)
     105           0 :                 top = json_object_new_object();
     106             : 
     107           0 :         frr_with_mutex (&refs_mtx) {
     108           0 :                 errlist = code ? list_new() : hash_to_list(refs);
     109             :         }
     110             : 
     111           0 :         if (code) {
     112           0 :                 ref = log_ref_get(code);
     113           0 :                 if (!ref) {
     114           0 :                         if (top)
     115           0 :                                 json_object_free(top);
     116           0 :                         list_delete(&errlist);
     117           0 :                         return;
     118             :                 }
     119           0 :                 listnode_add(errlist, ref);
     120             :         }
     121             : 
     122           0 :         for (ALL_LIST_ELEMENTS_RO(errlist, ln, ref)) {
     123           0 :                 if (json) {
     124           0 :                         char key[11];
     125             : 
     126           0 :                         snprintf(key, sizeof(key), "%u", ref->code);
     127           0 :                         obj = json_object_new_object();
     128           0 :                         json_object_string_add(obj, "title", ref->title);
     129           0 :                         json_object_string_add(obj, "description",
     130             :                                                ref->description);
     131           0 :                         json_object_string_add(obj, "suggestion",
     132             :                                                ref->suggestion);
     133           0 :                         json_object_object_add(top, key, obj);
     134             :                 } else {
     135           0 :                         char pbuf[256];
     136           0 :                         char ubuf[256];
     137             : 
     138           0 :                         snprintf(pbuf, sizeof(pbuf), "\nError %u - %s",
     139             :                                  ref->code, ref->title);
     140           0 :                         memset(ubuf, '=', strlen(pbuf));
     141           0 :                         ubuf[strlen(pbuf)] = '\0';
     142             : 
     143           0 :                         vty_out(vty, "%s\n%s\n", pbuf, ubuf);
     144           0 :                         vty_out(vty, "Description:\n%s\n\n", ref->description);
     145           0 :                         vty_out(vty, "Recommendation:\n%s\n", ref->suggestion);
     146             :                 }
     147             :         }
     148             : 
     149           0 :         vty_json(vty, top);
     150           0 :         list_delete(&errlist);
     151             : }
     152             : 
     153           0 : DEFUN_NOSH(show_error_code,
     154             :            show_error_code_cmd,
     155             :            "show error <(1-4294967295)|all> [json]",
     156             :            SHOW_STR
     157             :            "Information on errors\n"
     158             :            "Error code to get info about\n"
     159             :            "Information on all errors\n"
     160             :            JSON_STR)
     161             : {
     162           0 :         bool json = strmatch(argv[argc-1]->text, "json");
     163           0 :         uint32_t arg = 0;
     164             : 
     165           0 :         if (!strmatch(argv[2]->text, "all"))
     166           0 :                 arg = strtoul(argv[2]->arg, NULL, 10);
     167             : 
     168           0 :         log_ref_display(vty, arg, json);
     169           0 :         return CMD_SUCCESS;
     170             : }
     171             : 
     172           4 : void log_ref_init(void)
     173             : {
     174           4 :         frr_with_mutex (&refs_mtx) {
     175           4 :                 refs = hash_create(ferr_hash_key, ferr_hash_cmp,
     176             :                                    "Error Reference Texts");
     177             :         }
     178           4 : }
     179             : 
     180           4 : void log_ref_fini(void)
     181             : {
     182           8 :         frr_with_mutex (&refs_mtx) {
     183           4 :                 hash_clean_and_free(&refs, NULL);
     184             :         }
     185           4 : }
     186             : 
     187           4 : void log_ref_vty_init(void)
     188             : {
     189           4 :         install_element(VIEW_NODE, &show_error_code_cmd);
     190           4 : }
     191             : 
     192             : 
     193           0 : const struct ferr *ferr_get_last(ferr_r errval)
     194             : {
     195           0 :         struct ferr *last_error = pthread_getspecific(errkey);
     196           0 :         if (!last_error || last_error->kind == 0)
     197           0 :                 return NULL;
     198             :         return last_error;
     199             : }
     200             : 
     201           0 : ferr_r ferr_clear(void)
     202             : {
     203           0 :         struct ferr *last_error = pthread_getspecific(errkey);
     204           0 :         if (last_error)
     205           0 :                 last_error->kind = 0;
     206           0 :         return ferr_ok();
     207             : }
     208             : 
     209             : PRINTFRR(7, 0)
     210           0 : static ferr_r ferr_set_va(const char *file, int line, const char *func,
     211             :                           enum ferr_kind kind, const char *pathname,
     212             :                           int errno_val, const char *text, va_list va)
     213             : {
     214           0 :         struct ferr *error = pthread_getspecific(errkey);
     215             : 
     216           0 :         if (!error) {
     217           0 :                 error = XCALLOC(MTYPE_ERRINFO, sizeof(*error));
     218             : 
     219           0 :                 pthread_setspecific(errkey, error);
     220             :         }
     221             : 
     222           0 :         error->file = file;
     223           0 :         error->line = line;
     224           0 :         error->func = func;
     225           0 :         error->kind = kind;
     226             : 
     227           0 :         error->unique_id = jhash(text, strlen(text),
     228           0 :                                  jhash(file, strlen(file), 0xd4ed0298));
     229             : 
     230           0 :         error->errno_val = errno_val;
     231           0 :         if (pathname)
     232           0 :                 snprintf(error->pathname, sizeof(error->pathname), "%s",
     233             :                          pathname);
     234             :         else
     235           0 :                 error->pathname[0] = '\0';
     236             : 
     237           0 :         vsnprintf(error->message, sizeof(error->message), text, va);
     238           0 :         return -1;
     239             : }
     240             : 
     241           0 : ferr_r ferr_set_internal(const char *file, int line, const char *func,
     242             :                          enum ferr_kind kind, const char *text, ...)
     243             : {
     244           0 :         ferr_r rv;
     245           0 :         va_list va;
     246           0 :         va_start(va, text);
     247           0 :         rv = ferr_set_va(file, line, func, kind, NULL, 0, text, va);
     248           0 :         va_end(va);
     249           0 :         return rv;
     250             : }
     251             : 
     252           0 : ferr_r ferr_set_internal_ext(const char *file, int line, const char *func,
     253             :                              enum ferr_kind kind, const char *pathname,
     254             :                              int errno_val, const char *text, ...)
     255             : {
     256           0 :         ferr_r rv;
     257           0 :         va_list va;
     258           0 :         va_start(va, text);
     259           0 :         rv = ferr_set_va(file, line, func, kind, pathname, errno_val, text, va);
     260           0 :         va_end(va);
     261           0 :         return rv;
     262             : }
     263             : 
     264             : #define REPLACE "$ERR"
     265           0 : void vty_print_error(struct vty *vty, ferr_r err, const char *msg, ...)
     266             : {
     267           0 :         char tmpmsg[512], *replacepos;
     268           0 :         const struct ferr *last_error = ferr_get_last(err);
     269             : 
     270           0 :         va_list va;
     271           0 :         va_start(va, msg);
     272           0 :         vsnprintf(tmpmsg, sizeof(tmpmsg), msg, va);
     273           0 :         va_end(va);
     274             : 
     275           0 :         replacepos = strstr(tmpmsg, REPLACE);
     276           0 :         if (!replacepos)
     277           0 :                 vty_out(vty, "%s\n", tmpmsg);
     278             :         else {
     279           0 :                 replacepos[0] = '\0';
     280           0 :                 replacepos += sizeof(REPLACE) - 1;
     281           0 :                 vty_out(vty, "%s%s%s\n", tmpmsg,
     282             :                         last_error ? last_error->message : "(no error?)",
     283             :                         replacepos);
     284             :         }
     285           0 : }

Generated by: LCOV version v1.16-topotato