lib: Add talloc_report_str()
authorVolker Lendecke <vl@samba.org>
Wed, 11 Feb 2015 12:19:05 +0000 (12:19 +0000)
committerStefan Metzmacher <metze@samba.org>
Fri, 13 Feb 2015 22:32:07 +0000 (23:32 +0100)
This creates a talloc report into a string and will replace the code used in
source3/lib/tallocmsg.c

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
lib/util/talloc_report.c [new file with mode: 0644]
lib/util/talloc_report.h [new file with mode: 0644]
lib/util/wscript_build

diff --git a/lib/util/talloc_report.c b/lib/util/talloc_report.c
new file mode 100644 (file)
index 0000000..8d7d548
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * talloc_report into a string
+ *
+ * Copyright Volker Lendecke <vl@samba.org> 2015
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "talloc_report.h"
+
+/*
+ * talloc_vasprintf into a buffer that doubles its size. The real string
+ * length is maintained in "pstr_len".
+ */
+
+static char *talloc_vasprintf_append_largebuf(char *buf, ssize_t *pstr_len,
+                                             const char *fmt, va_list ap)
+{
+       ssize_t str_len = *pstr_len;
+       size_t buflen, needed, space;
+       char *start, *tmpbuf;
+       va_list ap2;
+       int printlen;
+
+       if (str_len == -1) {
+               return NULL;
+       }
+       if (buf == NULL) {
+               return NULL;
+       }
+       buflen = talloc_get_size(buf);
+
+       if (buflen > str_len) {
+               start = buf + str_len;
+               space = buflen - str_len;
+       } else {
+               start = NULL;
+               space = 0;
+       }
+
+       va_copy(ap2, ap);
+       printlen = vsnprintf(start, space, fmt, ap2);
+       va_end(ap2);
+
+       if (printlen < 0) {
+               goto fail;
+       }
+
+       needed = str_len + printlen + 1;
+
+       if (needed > buflen) {
+               buflen = MAX(128, buflen);
+
+               while (buflen < needed) {
+                       buflen *= 2;
+               }
+
+               tmpbuf = talloc_realloc(NULL, buf, char, buflen);
+               if (tmpbuf == NULL) {
+                       goto fail;
+               }
+               buf = tmpbuf;
+
+               va_copy(ap2, ap);
+               vsnprintf(buf + str_len, buflen - str_len, fmt, ap2);
+               va_end(ap2);
+       }
+       *pstr_len = (needed - 1);
+       return buf;
+fail:
+       *pstr_len = -1;
+       return buf;
+}
+
+static char *talloc_asprintf_append_largebuf(char *buf, ssize_t *pstr_len,
+                                            const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       buf = talloc_vasprintf_append_largebuf(buf, pstr_len, fmt, ap);
+       va_end(ap);
+       return buf;
+}
+
+struct talloc_report_str_state {
+       ssize_t str_len;
+       char *s;
+};
+
+static void talloc_report_str_helper(const void *ptr, int depth, int max_depth,
+                                    int is_ref, void *private_data)
+{
+       struct talloc_report_str_state *state = private_data;
+       const char *name = talloc_get_name(ptr);
+
+       if (ptr == state->s) {
+               return;
+       }
+
+       if (is_ref) {
+               state->s = talloc_asprintf_append_largebuf(
+                       state->s, &state->str_len,
+                       "%*sreference to: %s\n", depth*4, "", name);
+               return;
+       }
+
+       if (depth == 0) {
+               state->s = talloc_asprintf_append_largebuf(
+                       state->s, &state->str_len,
+                       "%stalloc report on '%s' "
+                       "(total %6lu bytes in %3lu blocks)\n",
+                       (max_depth < 0 ? "full " :""), name,
+                       (unsigned long)talloc_total_size(ptr),
+                       (unsigned long)talloc_total_blocks(ptr));
+               return;
+       }
+
+       if (strcmp(name, "char") == 0) {
+               /*
+                * Print out the first 50 bytes of the string
+                */
+               state->s = talloc_asprintf_append_largebuf(
+                       state->s, &state->str_len,
+                       "%*s%-30s contains %6lu bytes in %3lu blocks "
+                       "(ref %d): %*s\n", depth*4, "", name,
+                       (unsigned long)talloc_total_size(ptr),
+                       (unsigned long)talloc_total_blocks(ptr),
+                       talloc_reference_count(ptr),
+                       MIN(50, talloc_get_size(ptr)),
+                       (const char *)ptr);
+               return;
+       }
+
+       state->s = talloc_asprintf_append_largebuf(
+               state->s, &state->str_len,
+               "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
+               depth*4, "", name,
+               (unsigned long)talloc_total_size(ptr),
+               (unsigned long)talloc_total_blocks(ptr),
+               talloc_reference_count(ptr));
+}
+
+char *talloc_report_str(TALLOC_CTX *mem_ctx, TALLOC_CTX *root)
+{
+       struct talloc_report_str_state state;
+
+       state.s = talloc_strdup(mem_ctx, "");
+       if (state.s == NULL) {
+               return NULL;
+       }
+       state.str_len = 0;
+
+       talloc_report_depth_cb(root, 0, -1, talloc_report_str_helper, &state);
+
+       if (state.str_len == -1) {
+               talloc_free(state.s);
+               return NULL;
+       }
+
+       return talloc_realloc(mem_ctx, state.s, char, state.str_len+1);
+}
diff --git a/lib/util/talloc_report.h b/lib/util/talloc_report.h
new file mode 100644 (file)
index 0000000..53d0385
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * talloc_report into a string
+ *
+ * Copyright Volker Lendecke <vl@samba.org> 2015
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TALLOC_REPORT_H_
+#define _TALLOC_REPORT_H_
+
+#include <talloc.h>
+
+char *talloc_report_str(TALLOC_CTX *mem_ctx, TALLOC_CTX *root);
+
+#endif
index c0d07e70f8f4b4d3d2a4c1c9b7f1d5d628d0d77b..a1dec2a093e127306e9cfa3fdd2fa310918ce3fc 100755 (executable)
@@ -95,6 +95,13 @@ if not bld.env.SAMBA_UTIL_CORE_ONLY:
                       private_library=True
                       )
 
+    bld.SAMBA_LIBRARY('talloc_report',
+                      source='talloc_report.c',
+                      local_include=False,
+                      public_deps='talloc',
+                      private_library=True
+                      )
+
     if not bld.env.disable_ntdb:
         bld.SAMBA_LIBRARY('util_ntdb',
                           source='util_ntdb.c',