]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add custom fprintf style function for talloc binary buffers and value boxes
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 18 Nov 2016 22:57:05 +0000 (17:57 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 18 Nov 2016 22:57:05 +0000 (17:57 -0500)
src/include/libradius.h
src/include/log.h
src/include/pair.h
src/lib/print.c
src/main/log.c

index 6853c8f22f1b99510507a73b031199e33feb9c0e..7a3870596725d3d0a82103e27248472bd704faca 100644 (file)
@@ -177,6 +177,7 @@ char const          *fr_utf8_strchr(int *chr_len, char const *str, char const *chr);
 size_t         fr_snprint(char *out, size_t outlen, char const *in, ssize_t inlen, char quote);
 size_t         fr_snprint_len(char const *in, ssize_t inlen, char quote);
 char           *fr_asprint(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote);
+char           *fr_vasprintf(TALLOC_CTX *ctx, char const *fmt, va_list ap);
 
 #define                is_truncated(_ret, _max) ((_ret) >= (size_t)(_max))
 #define                truncate_len(_ret, _max) (((_ret) >= (size_t)(_max)) ? (((size_t)(_max)) - 1) : _ret)
index ffa0c6c5cd107a5855ae75e35e01aee74875a16b..46ed2bed13cabef94b21aff5a5ee559bf08ec626 100644 (file)
@@ -112,7 +112,7 @@ bool        radlog_debug_enabled(log_type_t type, log_lvl_t lvl, REQUEST *request)
        CC_HINT(nonnull);
 
 void   vradlog_request(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, va_list ap)
-       CC_HINT(format (printf, 4, 0)) CC_HINT(nonnull (3, 4));
+       CC_HINT(nonnull (3, 4));
 
 void   radlog_request(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg, ...)
        CC_HINT(format (printf, 4, 5)) CC_HINT(nonnull (3, 4));
index 70f68507d27b7419a51f24724b5787116585c49f..b7363f9eca1d074e8ddc428d381e87fd3a54a437 100644 (file)
@@ -72,13 +72,19 @@ struct value_box {
                uint8_t                 ether[6];               //!< Ethernet (MAC) address.
 
                bool                    boolean;                //!< A truth value.
-               uint8_t                 byte;                   //!< 8bit unsigned integer.
-               uint16_t                ushort;                 //!< 16bit unsigned integer.
-               uint32_t                integer;                //!< 32bit unsigned integer.
-               uint64_t                integer64;              //!< 64bit unsigned integer.
-               size_t                  size;                   //!< System specific file/memory size.
 
-               int32_t                 sinteger;               //!< 32bit signed integer.
+               struct {
+                       union {
+                               uint8_t                 byte;           //!< 8bit unsigned integer.
+                               uint16_t                ushort;         //!< 16bit unsigned integer.
+                               uint32_t                integer;        //!< 32bit unsigned integer.
+                               uint64_t                integer64;      //!< 64bit unsigned integer.
+                               size_t                  size;           //!< System specific file/memory size.
+
+                               int32_t                 sinteger;       //!< 32bit signed integer.
+                       };
+                       fr_dict_attr_t const            *enumv;         //!< Enumeration values for integer type.
+               };
 
                struct timeval          timeval;                //!< A time value with usec precision.
                double                  decimal;                //!< Double precision float.
index 20e3a4e1afed80e836aff1258108f3578b6e6e71..5fb30a07615ea7e4546c7fbd02a880f60c02318c 100644 (file)
@@ -397,3 +397,292 @@ char *fr_asprint(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote)
 
        return out;
 }
+
+DIAG_OFF(format-nonliteral)
+/** Special version of printf which supports %b and %v
+ *
+ * @todo Do something sensible with 'n$', though it's probably not actually used
+ *     anywhere in the server.
+ *
+ * - %b takes a talloced binary buffer and prints it as hex.
+ *     The length of the buffer is determined with a cal
+ */
+char *fr_vasprintf(TALLOC_CTX *ctx, char const *fmt, va_list ap)
+{
+       char const      *p = fmt, *end = p + strlen(fmt), *fmt_p = p, *fmt_q = p;
+       char            *out = NULL, *out_tmp;
+       va_list         ap_p, ap_q;
+
+       out = talloc_strdup(ctx, "");
+       va_copy(ap_p, ap);
+       va_copy(ap_q, ap_p);
+
+       do {
+
+               char            *q;
+               char            *custom;
+               char            len[2] = { '\0', '\0' };
+               long            width = 0, group = 0, precision = 0, tmp;
+
+               if ((*p != '%') || (*++p == '%')) {
+                       fmt_q = p + 1;
+                       continue;       /* literal char */
+               }
+
+               /*
+                *      Check for parameter field
+                */
+               tmp = strtoul(p, &q, 10);
+               if ((q != p) && (*q == '$')) {
+                       group = tmp;
+                       p = q + 1;
+               }
+
+               /*
+                *      Check for flags
+                */
+               do {
+                       switch (*p) {
+                       case '-':
+                               continue;
+
+                       case '+':
+                               continue;
+
+                       case ' ':
+                               continue;
+
+                       case '0':
+                               continue;
+
+                       case '#':
+                               continue;
+
+                       default:
+                               goto done_flags;
+                       }
+               } while (++p < end);
+       done_flags:
+
+               /*
+                *      Check for width field
+                */
+               if (*p == '*') {
+                       width = va_arg(ap_q, int);
+                       p++;
+               } else {
+                       width = strtoul(p, &q, 10);
+                       p = q;
+               }
+
+               /*
+                *      Check for precision field
+                */
+               if (*p == '.') {
+                       p++;
+                       precision = strtoul(p, &q, 10);
+                       p = q;
+               }
+
+               /*
+                *      Length modifiers
+                */
+               switch (*p) {
+               case 'h':
+               case 'l':
+                       len[0] = *p++;
+                       if ((*p == 'h') || (*p == 'l')) len[1] = *p++;
+                       break;
+
+               case 'L':
+               case 'z':
+               case 'j':
+               case 't':
+                       len[0] = *p++;
+                       break;
+               }
+
+               /*
+                *      Types
+                */
+               switch (*p) {
+               case 'i':                                                               /* int */
+               case 'd':                                                               /* int */
+               case 'u':                                                               /* unsigned int */
+               case 'x':                                                               /* unsigned int */
+               case 'X':                                                               /* unsigned int */
+               case 'o':                                                               /* unsigned int */
+                       switch (len[0]) {
+                       case 'h':
+                               if (len[1] == 'h') {                                    /* char (promoted to int) */
+                                       (void) va_arg(ap_q, int);
+                               } else {
+                                       (void) va_arg(ap_q, int);                       /* short (promoted to int) */
+                               }
+                               break;
+
+                       case 'L':
+                               if ((*p == 'i') || (*p == 'd')) {
+                                       if (len [1] == 'L') {
+                                               (void) va_arg(ap_q, long);              /* long */
+                                       } else {
+                                               (void) va_arg(ap_q, long long);         /* long long */
+                                       }
+                               } else {
+                                       if (len [1] == 'L') {
+                                               (void) va_arg(ap_q, unsigned long);     /* unsigned long */
+                                       } else {
+                                               (void) va_arg(ap_q, unsigned long long);/* unsigned long long */
+                                       }
+                               }
+                               break;
+
+                       case 'z':
+                               (void) va_arg(ap_q, size_t);                            /* size_t */
+                               break;
+
+                       case 'j':
+                               (void) va_arg(ap_q, intmax_t);                          /* intmax_t */
+                               break;
+
+                       case 't':
+                               (void) va_arg(ap_q, ptrdiff_t);                         /* ptrdiff_t */
+                               break;
+
+                       case '\0':      /* no length modifier */
+                               if ((*p == 'i') || (*p == 'd')) {
+                                       (void) va_arg(ap_q, int);                       /* int */
+                               } else {
+                                       (void) va_arg(ap_q, unsigned int);              /* unsigned int */
+                               }
+                       }
+                       break;
+
+               case 'f':                                                               /* double */
+               case 'F':                                                               /* double */
+               case 'e':                                                               /* double */
+               case 'E':                                                               /* double */
+               case 'g':                                                               /* double */
+               case 'G':                                                               /* double */
+               case 'a':                                                               /* double */
+               case 'A':                                                               /* double */
+                       switch (len[0]) {
+                       case 'L':
+                               (void) va_arg(ap_q, long double);                       /* long double */
+                               break;
+
+                       case 'l':       /* does nothing */
+                       default:        /* no length modifier */
+                               (void) va_arg(ap_q, double);                            /* double */
+                       }
+                       break;
+
+               case 's':
+                       (void) va_arg(ap_q, char *);                                    /* char * */
+                       break;
+
+               case 'c':
+                       (void) va_arg(ap_q, int);                                       /* char (promoted to int) */
+                       break;
+
+               case 'p':
+                       (void) va_arg(ap_q, void *);                                    /* void * */
+                       break;
+
+               case 'n':
+                       (void) va_arg(ap_q, int *);                                     /* int * */
+                       break;
+
+               /*
+                *      Custom types
+                */
+               case 'v':
+               {
+                       value_box_t const *value = va_arg(ap_q, value_box_t const *);
+
+                       /*
+                        *      Allocations that are not part of the output
+                        *      string need to occur in the NULL ctx so we don't fragment
+                        *      any pool associated with it.
+                        */
+                       custom = value_box_asprint(NULL, value->type, value->datum.enumv, value, '"');
+                       if (!custom) {
+                               talloc_free(out);
+                               return NULL;
+                       }
+
+               do_splice:
+                       /*
+                        *      Pass part of a format string to printf
+                        */
+                       if (fmt_q != fmt_p) {
+                               char *sub_fmt;
+
+                               sub_fmt = talloc_strndup(NULL, fmt_p, fmt_q - fmt_p);
+                               out_tmp = talloc_vasprintf_append_buffer(out, sub_fmt, ap_p);
+                               talloc_free(sub_fmt);
+                               if (!out_tmp) {
+                               oom:
+                                       fr_strerror_printf("Out of memory");
+                                       talloc_free(out);
+                                       talloc_free(custom);
+                                       va_end(ap_p);
+                                       va_end(ap_q);
+                                       return NULL;
+                               }
+                               out = out_tmp;
+
+                               out_tmp = talloc_strdup_append_buffer(out, custom);
+                               TALLOC_FREE(custom);
+                               if (!out_tmp) goto oom;
+                               out = out_tmp;
+
+                               va_end(ap_p);           /* one time use only */
+                               va_copy(ap_p, ap_q);    /* already advanced to the next argument */
+                       }
+
+                       fmt_p = p + 1;
+               }
+                       break;
+
+               case 'b':
+               {
+                       uint8_t const *bin = va_arg(ap_q, uint8_t *);
+
+                       /*
+                        *      Only automagically figure out the length
+                        *      if it's not specified.
+                        *
+                        *      This allows %b to be used with stack buffers,
+                        *      so long as the length is specified in the format string.
+                        */
+                       if (precision == 0) precision = talloc_array_length(bin);
+
+                       custom = talloc_array(NULL, char, (precision * 2) + 1);
+                       if (!custom) goto oom;
+                       fr_bin2hex(custom, bin, precision);
+
+                       goto do_splice;
+               }
+
+               default:
+                       break;
+               }
+               fmt_q = p + 1;
+       } while (++p < end);
+
+       /*
+        *      Print out the rest of the format string.
+        */
+       if (*fmt_p) {
+               out_tmp = talloc_vasprintf_append_buffer(out, fmt_p, ap_p);
+               if (!out_tmp) goto oom;
+               out = out_tmp;
+       }
+
+       va_end(ap_p);
+       va_end(ap_q);
+
+       return out;
+}
+DIAG_ON(format-nonliteral)
index 8fc2ae3649002892fd2a458d7c6013f39e2b28cd..51a17af4860f5634cf13cdb7ffacdfacf17f470c 100644 (file)
@@ -822,7 +822,7 @@ print_msg:
         *  running unit tests which generate errors under CI.
         */
        va_copy(aq, ap);
-       msg_exp = talloc_vasprintf(request, msg, aq);
+       msg_exp = fr_vasprintf(request, msg, aq);
        va_end(aq);
 
        /*