bt_common_abort(): optionally execute a custom command before aborting
[babeltrace.git] / src / common / common.c
index 4aa8fcd2a70e3ec9a890182fbf7f89350c97936f..3acad47cfd88a2671293442f0f3f89894be5a967 100644 (file)
@@ -22,8 +22,9 @@
  * SOFTWARE.
  */
 
+#define BT_LOG_OUTPUT_LEVEL log_level
 #define BT_LOG_TAG "COMMON"
-#include "logging.h"
+#include "logging/log.h"
 
 #include <unistd.h>
 #include <string.h>
 
 #ifndef __MINGW32__
 #include <pwd.h>
+#include <sys/ioctl.h>
 #endif
 
-#define SYSTEM_PLUGIN_PATH     INSTALL_LIBDIR "/babeltrace2/plugins"
+#define SYSTEM_PLUGIN_PATH     BABELTRACE_PLUGINS_DIR
 #define HOME_ENV_VAR           "HOME"
 #define HOME_PLUGIN_SUBPATH    "/.local/lib/babeltrace2/plugins"
 
@@ -115,8 +117,15 @@ bool bt_common_is_setuid_setgid(void)
 }
 #endif /* __MINGW32__ */
 
+#ifdef __MINGW32__
+static
+const char *bt_get_home_dir(int log_level)
+{
+       return g_get_home_dir();
+}
+#else /* __MINGW32__ */
 static
-char *bt_secure_getenv(const char *name)
+char *bt_secure_getenv(const char *name, int log_level)
 {
        if (bt_common_is_setuid_setgid()) {
                BT_LOGD("Disregarding environment variable for setuid/setgid binary: "
@@ -126,20 +135,13 @@ char *bt_secure_getenv(const char *name)
        return getenv(name);
 }
 
-#ifdef __MINGW32__
-static
-const char *bt_get_home_dir(void)
-{
-       return g_get_home_dir();
-}
-#else /* __MINGW32__ */
 static
-const char *bt_get_home_dir(void)
+const char *bt_get_home_dir(int log_level)
 {
        char *val = NULL;
        struct passwd *pwd;
 
-       val = bt_secure_getenv(HOME_ENV_VAR);
+       val = bt_secure_getenv(HOME_ENV_VAR, log_level);
        if (val) {
                goto end;
        }
@@ -155,13 +157,13 @@ end:
 #endif /* __MINGW32__ */
 
 BT_HIDDEN
-char *bt_common_get_home_plugin_path(void)
+char *bt_common_get_home_plugin_path(int log_level)
 {
        char *path = NULL;
        const char *home_dir;
        size_t length;
 
-       home_dir = bt_get_home_dir();
+       home_dir = bt_get_home_dir(log_level);
        if (!home_dir) {
                goto end;
        }
@@ -169,8 +171,8 @@ char *bt_common_get_home_plugin_path(void)
        length = strlen(home_dir) + strlen(HOME_PLUGIN_SUBPATH) + 1;
 
        if (length >= PATH_MAX) {
-               BT_LOGW("Home directory path is too long: length=%zu",
-                       length);
+               BT_LOGW("Home directory path is too long: "
+                       "length=%zu, max-length=%u", length, PATH_MAX);
                goto end;
        }
 
@@ -510,6 +512,7 @@ set_end_pos:
 error:
        if (output) {
                g_string_free(output, TRUE);
+               output = NULL;
        }
 
 end:
@@ -577,7 +580,7 @@ bool bt_common_string_is_printable(const char *input)
 {
        const char *ch;
        bool printable = true;
-       BT_ASSERT(input);
+       BT_ASSERT_DBG(input);
 
        for (ch = input; *ch != '\0'; ch++) {
                if (!isprint(*ch) && *ch != '\n' && *ch != '\r' &&
@@ -670,7 +673,7 @@ struct bt_common_lttng_live_url_parts bt_common_parse_lttng_live_url(
 
        at += end_pos;
 
-       /* :// */
+       /* `://` */
        if (strncmp(at, "://", 3) != 0) {
                if (error_buf) {
                        snprintf(error_buf, error_buf_size,
@@ -680,6 +683,7 @@ struct bt_common_lttng_live_url_parts bt_common_parse_lttng_live_url(
                goto error;
        }
 
+       /* Skip `://` */
        at += 3;
 
        /* Hostname */
@@ -729,12 +733,13 @@ struct bt_common_lttng_live_url_parts bt_common_parse_lttng_live_url(
        }
 
        if (at[end_pos] == '\0') {
+               /* Relay daemon hostname and ports provided only */
                goto end;
        }
 
        at += end_pos;
 
-       /* /host/ */
+       /* `/host/` */
        if (strncmp(at, "/host/", 6) != 0) {
                if (error_buf) {
                        snprintf(error_buf, error_buf_size,
@@ -758,9 +763,16 @@ struct bt_common_lttng_live_url_parts bt_common_parse_lttng_live_url(
        }
 
        if (at[end_pos] == '\0') {
-               goto end;
+               if (error_buf) {
+                       snprintf(error_buf, error_buf_size,
+                               "Missing `/` after target hostname (`%s`)",
+                               parts.target_hostname->str);
+               }
+
+               goto error;
        }
 
+       /* Skip `/` */
        at += end_pos + 1;
 
        /* Session name */
@@ -1087,6 +1099,36 @@ end_of_pattern:
        return p[-1] == '*' && at_end_of_pattern(p, pattern, pattern_len);
 }
 
+#ifdef __MINGW32__
+BT_HIDDEN
+GString *bt_common_normalize_path(const char *path, const char *wd)
+{
+       char *tmp;
+       GString *norm_path = NULL;
+
+       BT_ASSERT(path);
+
+       tmp = _fullpath(NULL, path, PATH_MAX);
+       if (!tmp) {
+               goto error;
+       }
+
+       norm_path = g_string_new(tmp);
+       if (!norm_path) {
+               goto error;
+       }
+
+       goto end;
+error:
+       if (norm_path) {
+               g_string_free(norm_path, TRUE);
+               norm_path = NULL;
+       }
+end:
+       free(tmp);
+       return norm_path;
+}
+#else
 static
 void append_path_parts(const char *path, GPtrArray *parts)
 {
@@ -1120,38 +1162,6 @@ void destroy_gstring(void *gstring)
        (void) g_string_free(gstring, TRUE);
 }
 
-#ifdef __MINGW32__
-BT_HIDDEN
-GString *bt_common_normalize_path(const char *path, const char *wd)
-{
-       char *tmp;
-       GString *norm_path = NULL;
-
-       BT_ASSERT(path);
-
-       tmp = _fullpath(NULL, path, PATH_MAX);
-       if (!tmp) {
-               goto error;
-       }
-
-       norm_path = g_string_new(tmp);
-       if (!norm_path) {
-               goto error;
-       }
-
-       goto end;
-error:
-       if (norm_path) {
-               g_string_free(norm_path, TRUE);
-               norm_path = NULL;
-       }
-end:
-       if (tmp) {
-               free(tmp);
-       }
-       return norm_path;
-}
-#else
 BT_HIDDEN
 GString *bt_common_normalize_path(const char *path, const char *wd)
 {
@@ -1238,7 +1248,7 @@ end:
 #endif
 
 BT_HIDDEN
-size_t bt_common_get_page_size(void)
+size_t bt_common_get_page_size(int log_level)
 {
        int page_size;
 
@@ -1246,7 +1256,7 @@ size_t bt_common_get_page_size(void)
        if (page_size < 0) {
                BT_LOGF("Cannot get system's page size: ret=%d",
                        page_size);
-               abort();
+               bt_common_abort();
        }
 
        return page_size;
@@ -1261,7 +1271,7 @@ size_t bt_common_get_page_size(void)
                strncpy(_tmp_fmt, *out_fmt_ch, _tmp_fmt_size);          \
                _tmp_fmt[_tmp_fmt_size] = '\0';                         \
                _count = snprintf(*buf_ch, _size, _tmp_fmt, __VA_ARGS__); \
-               BT_ASSERT(_count >= 0);                                 \
+               BT_ASSERT_DBG(_count >= 0);                                     \
                *buf_ch += MIN(_count, _size);                          \
        } while (0)
 
@@ -1403,13 +1413,11 @@ static inline void handle_conversion_specifier_std(char *buf, char **buf_ch,
 
                switch (length_mod) {
                case LENGTH_MOD_NONE:
-                       BUF_STD_APPEND_SINGLE_ARG(int);
-                       break;
                case LENGTH_MOD_LOW_L:
-                       BUF_STD_APPEND_SINGLE_ARG(wint_t);
+                       BUF_STD_APPEND_SINGLE_ARG(int);
                        break;
                default:
-                       abort();
+                       bt_common_abort();
                }
                break;
        }
@@ -1424,7 +1432,7 @@ static inline void handle_conversion_specifier_std(char *buf, char **buf_ch,
                        BUF_STD_APPEND_SINGLE_ARG(wchar_t *);
                        break;
                default:
-                       abort();
+                       bt_common_abort();
                }
                break;
        case 'd':
@@ -1447,7 +1455,7 @@ static inline void handle_conversion_specifier_std(char *buf, char **buf_ch,
                        BUF_STD_APPEND_SINGLE_ARG(size_t);
                        break;
                default:
-                       abort();
+                       bt_common_abort();
                }
                break;
        case 'o':
@@ -1472,7 +1480,7 @@ static inline void handle_conversion_specifier_std(char *buf, char **buf_ch,
                        BUF_STD_APPEND_SINGLE_ARG(size_t);
                        break;
                default:
-                       abort();
+                       bt_common_abort();
                }
                break;
        case 'f':
@@ -1491,7 +1499,7 @@ static inline void handle_conversion_specifier_std(char *buf, char **buf_ch,
                        BUF_STD_APPEND_SINGLE_ARG(long double);
                        break;
                default:
-                       abort();
+                       bt_common_abort();
                }
                break;
        case 'p':
@@ -1500,11 +1508,11 @@ static inline void handle_conversion_specifier_std(char *buf, char **buf_ch,
                if (length_mod == LENGTH_MOD_NONE) {
                        BUF_STD_APPEND_SINGLE_ARG(void *);
                } else {
-                       abort();
+                       bt_common_abort();
                }
                break;
        default:
-               abort();
+               bt_common_abort();
        }
 
 update_rw_fmt:
@@ -1520,13 +1528,13 @@ void bt_common_custom_vsnprintf(char *buf, size_t buf_size,
        const char *fmt_ch = fmt;
        char *buf_ch = buf;
 
-       BT_ASSERT(buf);
-       BT_ASSERT(fmt);
+       BT_ASSERT_DBG(buf);
+       BT_ASSERT_DBG(fmt);
 
        while (*fmt_ch != '\0') {
                switch (*fmt_ch) {
                case '%':
-                       BT_ASSERT(fmt_ch[1] != '\0');
+                       BT_ASSERT_DBG(fmt_ch[1] != '\0');
 
                        if (fmt_ch[1] == intro) {
                                handle_specifier(priv_data, &buf_ch,
@@ -1578,12 +1586,12 @@ void bt_common_sep_digits(char *str, unsigned int digits_per_group, char sep)
        uint64_t sep_count;
        uint64_t new_len;
 
-       BT_ASSERT(digits_per_group > 0);
-       BT_ASSERT(sep != '\0');
+       BT_ASSERT_DBG(digits_per_group > 0);
+       BT_ASSERT_DBG(sep != '\0');
 
        /* Compute new length of `str` */
        orig_len = strlen(str);
-       BT_ASSERT(orig_len > 0);
+       BT_ASSERT_DBG(orig_len > 0);
        sep_count = (orig_len - 1) / digits_per_group;
        new_len = strlen(str) + sep_count;
 
@@ -1670,3 +1678,247 @@ void bt_common_sep_digits(char *str, unsigned int digits_per_group, char sep)
                i++;
        }
 }
+
+BT_HIDDEN
+GString *bt_common_fold(const char *str, unsigned int total_length,
+               unsigned int indent)
+{
+       const unsigned int content_length = total_length - indent;
+       GString *folded = g_string_new(NULL);
+       GString *tmp_line = g_string_new(NULL);
+       gchar **lines = NULL;
+       gchar **line_words = NULL;
+       gchar * const *line;
+       unsigned int i;
+
+       BT_ASSERT_DBG(str);
+       BT_ASSERT_DBG(indent < total_length);
+       BT_ASSERT_DBG(tmp_line);
+       BT_ASSERT_DBG(folded);
+
+       if (strlen(str) == 0) {
+               /* Empty input string: empty output string */
+               goto end;
+       }
+
+       /* Split lines */
+       lines = g_strsplit(str, "\n", 0);
+       BT_ASSERT_DBG(lines);
+
+       /* For each source line */
+       for (line = lines; *line; line++) {
+               gchar * const *word;
+
+               /*
+                * Append empty line without indenting if source line is
+                * empty.
+                */
+               if (strlen(*line) == 0) {
+                       g_string_append_c(folded, '\n');
+                       continue;
+               }
+
+               /* Split words */
+               line_words = g_strsplit(*line, " ", 0);
+               BT_ASSERT_DBG(line_words);
+
+               /*
+                * Indent for first line (we know there's at least one
+                * word at this point).
+                */
+               for (i = 0; i < indent; i++) {
+                       g_string_append_c(folded, ' ');
+               }
+
+               /* Append words, folding when necessary */
+               g_string_assign(tmp_line, "");
+
+               for (word = line_words; *word; word++) {
+                       /*
+                        * `tmp_line->len > 0` is in the condition so
+                        * that words that are larger than
+                        * `content_length` are at least written on
+                        * their own line.
+                        *
+                        * `tmp_line->len - 1` because the temporary
+                        * line always contains a trailing space which
+                        * won't be part of the line if we fold.
+                        */
+                       if (tmp_line->len > 0 &&
+                                       tmp_line->len - 1 + strlen(*word) >= content_length) {
+                               /* Fold (without trailing space) */
+                               g_string_append_len(folded,
+                                       tmp_line->str, tmp_line->len - 1);
+                               g_string_append_c(folded, '\n');
+
+                               /* Indent new line */
+                               for (i = 0; i < indent; i++) {
+                                       g_string_append_c(folded, ' ');
+                               }
+
+                               g_string_assign(tmp_line, "");
+                       }
+
+                       /* Append current word and space to temporary line */
+                       g_string_append(tmp_line, *word);
+                       g_string_append_c(tmp_line, ' ');
+               }
+
+               /* Append last line if any, without trailing space */
+               if (tmp_line->len > 0) {
+                       g_string_append_len(folded, tmp_line->str,
+                               tmp_line->len - 1);
+               }
+
+               /* Append source newline */
+               g_string_append_c(folded, '\n');
+
+               /* Free array of this line's words */
+               g_strfreev(line_words);
+               line_words = NULL;
+       }
+
+       /* Remove trailing newline if any */
+       if (folded->str[folded->len - 1] == '\n') {
+               g_string_truncate(folded, folded->len - 1);
+       }
+
+end:
+       if (lines) {
+               g_strfreev(lines);
+       }
+
+       BT_ASSERT_DBG(!line_words);
+
+       if (tmp_line) {
+               g_string_free(tmp_line, TRUE);
+       }
+
+       return folded;
+}
+
+#ifdef __MINGW32__
+BT_HIDDEN
+int bt_common_get_term_size(unsigned int *width, unsigned int *height)
+{
+       /* Not supported on Windows yet */
+       return -1;
+}
+#else /* __MINGW32__ */
+BT_HIDDEN
+int bt_common_get_term_size(unsigned int *width, unsigned int *height)
+{
+       int ret = 0;
+       struct winsize winsize;
+
+       if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) < 0) {
+               ret = -1;
+               goto end;
+       }
+
+       if (width) {
+               *width = (unsigned int) winsize.ws_col;
+       }
+
+       if (height) {
+               *height = (unsigned int) winsize.ws_row;
+       }
+
+end:
+       return ret;
+}
+#endif /* __MINGW32__ */
+
+BT_HIDDEN
+int bt_common_g_string_append_printf(GString *str, const char *fmt, ...)
+{
+       va_list ap;
+       gsize len, allocated_len, available_len;
+       int print_len;
+
+       /* str->len excludes \0. */
+       len = str->len;
+       /* Explicitly exclude \0. */
+       allocated_len = str->allocated_len - 1;
+       available_len = allocated_len - len;
+
+       str->len = allocated_len;
+       va_start(ap, fmt);
+       print_len = vsnprintf(str->str + len, available_len + 1, fmt, ap);
+       va_end(ap);
+       if (print_len < 0) {
+               return print_len;
+       }
+       if (G_UNLIKELY(available_len < print_len)) {
+               /* Resize. */
+               g_string_set_size(str, len + print_len);
+               va_start(ap, fmt);
+               print_len = vsprintf(str->str + len, fmt, ap);
+               va_end(ap);
+       } else {
+               str->len = len + print_len;
+       }
+       return print_len;
+}
+
+BT_HIDDEN
+int bt_common_append_file_content_to_g_string(GString *str, FILE *fp)
+{
+       const size_t chunk_size = 4096;
+       int ret = 0;
+       char *buf;
+       size_t read_len;
+       gsize orig_len = str->len;
+
+       BT_ASSERT(str);
+       BT_ASSERT(fp);
+       buf = g_malloc(chunk_size);
+       if (!buf) {
+               ret = -1;
+               goto end;
+       }
+
+       while (true) {
+               if (ferror(fp)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               if (feof(fp)) {
+                       break;
+               }
+
+               read_len = fread(buf, 1, chunk_size, fp);
+               g_string_append_len(str, buf, read_len);
+       }
+
+end:
+       if (ret) {
+               /* Remove what was appended */
+               g_string_truncate(str, orig_len);
+       }
+
+       g_free(buf);
+       return ret;
+}
+
+BT_HIDDEN
+void bt_common_abort(void)
+{
+       static const char * const exec_on_abort_env_name =
+               "BABELTRACE_EXEC_ON_ABORT";
+       const char *env_exec_on_abort;
+
+       env_exec_on_abort = getenv(exec_on_abort_env_name);
+       if (env_exec_on_abort) {
+               if (bt_common_is_setuid_setgid()) {
+                       goto do_abort;
+               }
+
+               (void) g_spawn_command_line_sync(env_exec_on_abort,
+                           NULL, NULL, NULL, NULL);
+       }
+
+do_abort:
+       abort();
+}
This page took 0.029867 seconds and 4 git commands to generate.