back to topotato report
topotato coverage report
Current view: top level - lib - ferr.c (source / functions) Hit Total Coverage
Test: test_bgp_dont_capability_negotiate.py::BGPDontCapabilityNegotiate Lines: 34 141 24.1 %
Date: 2023-02-24 18:37:16 Functions: 10 20 50.0 %

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

Generated by: LCOV version v1.16-topotato