Fix: sessiond: occasional badfd error on repeated SIGTERM
[lttng-tools.git] / src / common / utils.c
index 6e772671451aec4e90e9943dd4c78eddd087c083..69d0ab16ef7a26cb542b8ad6c6f96b95e1141fd5 100644 (file)
 #include <common/compat/getenv.h>
 #include <common/compat/string.h>
 #include <common/compat/dirent.h>
+#include <common/dynamic-buffer.h>
 #include <lttng/constant.h>
 
 #include "utils.h"
 #include "defaults.h"
+#include "time.h"
 
 /*
  * Return a partial realpath(3) of the path even if the full path does not
@@ -189,6 +191,10 @@ char *utils_partial_realpath(const char *path, char *resolved_path, size_t size)
 error:
        free(resolved_path);
        free(cut_path);
+       free(try_path);
+       if (try_path_prev != try_path) {
+               free(try_path_prev);
+       }
        return NULL;
 }
 
@@ -426,6 +432,7 @@ void utils_close_pipe(int *src)
                if (ret) {
                        PERROR("close pipe");
                }
+               src[i] = -1;
        }
 }
 
@@ -524,7 +531,7 @@ int utils_create_lock_file(const char *filepath)
                S_IRGRP | S_IWGRP);
        if (fd < 0) {
                PERROR("open lock file %s", filepath);
-               ret = -1;
+               fd = -1;
                goto error;
        }
 
@@ -843,7 +850,6 @@ int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size,
 {
        int ret;
 
-       assert(new_count);
        assert(stream_fd);
 
        ret = close(out_fd);
@@ -851,6 +857,7 @@ int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size,
                PERROR("Closing tracefile");
                goto error;
        }
+       *stream_fd = -1;
 
        if (count > 0) {
                /*
@@ -866,18 +873,22 @@ int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size,
                 * Unlinking the old file rather than overwriting it
                 * achieves this.
                 */
-               *new_count = (*new_count + 1) % count;
-               ret = utils_unlink_stream_file(path_name, file_name,
-                               size, *new_count, uid, gid, 0);
+               if (new_count) {
+                       *new_count = (*new_count + 1) % count;
+               }
+               ret = utils_unlink_stream_file(path_name, file_name, size,
+                               new_count ? *new_count : 0, uid, gid, 0);
                if (ret < 0 && errno != ENOENT) {
                        goto error;
                }
        } else {
-               (*new_count)++;
+               if (new_count) {
+                       (*new_count)++;
+               }
        }
 
-       ret = utils_create_stream_file(path_name, file_name, size, *new_count,
-                       uid, gid, 0);
+       ret = utils_create_stream_file(path_name, file_name, size,
+                       new_count ? *new_count : 0, uid, gid, 0);
        if (ret < 0) {
                goto error;
        }
@@ -1009,6 +1020,59 @@ static inline unsigned int fls_u32(uint32_t x)
 #define HAS_FLS_U32
 #endif
 
+#if defined(__x86_64)
+static inline
+unsigned int fls_u64(uint64_t x)
+{
+       long r;
+
+       asm("bsrq %1,%0\n\t"
+           "jnz 1f\n\t"
+           "movq $-1,%0\n\t"
+           "1:\n\t"
+           : "=r" (r) : "rm" (x));
+       return r + 1;
+}
+#define HAS_FLS_U64
+#endif
+
+#ifndef HAS_FLS_U64
+static __attribute__((unused))
+unsigned int fls_u64(uint64_t x)
+{
+       unsigned int r = 64;
+
+       if (!x)
+               return 0;
+
+       if (!(x & 0xFFFFFFFF00000000ULL)) {
+               x <<= 32;
+               r -= 32;
+       }
+       if (!(x & 0xFFFF000000000000ULL)) {
+               x <<= 16;
+               r -= 16;
+       }
+       if (!(x & 0xFF00000000000000ULL)) {
+               x <<= 8;
+               r -= 8;
+       }
+       if (!(x & 0xF000000000000000ULL)) {
+               x <<= 4;
+               r -= 4;
+       }
+       if (!(x & 0xC000000000000000ULL)) {
+               x <<= 2;
+               r -= 2;
+       }
+       if (!(x & 0x8000000000000000ULL)) {
+               x <<= 1;
+               r -= 1;
+       }
+       return r;
+}
+#endif
+
 #ifndef HAS_FLS_U32
 static __attribute__((unused)) unsigned int fls_u32(uint32_t x)
 {
@@ -1055,6 +1119,20 @@ int utils_get_count_order_u32(uint32_t x)
        return fls_u32(x - 1);
 }
 
+/*
+ * Return the minimum order for which x <= (1UL << order).
+ * Return -1 if x is 0.
+ */
+LTTNG_HIDDEN
+int utils_get_count_order_u64(uint64_t x)
+{
+       if (!x) {
+               return -1;
+       }
+
+       return fls_u64(x - 1);
+}
+
 /**
  * Obtain the value of LTTNG_HOME environment variable, if exists.
  * Otherwise returns the value of HOME.
@@ -1127,26 +1205,6 @@ end:
        return home_dir;
 }
 
-/*
- * Obtain the value of LTTNG_KMOD_PROBES environment variable, if exists.
- * Otherwise returns NULL.
- */
-LTTNG_HIDDEN
-char *utils_get_kmod_probes_list(void)
-{
-       return lttng_secure_getenv(DEFAULT_LTTNG_KMOD_PROBES);
-}
-
-/*
- * Obtain the value of LTTNG_EXTRA_KMOD_PROBES environment variable, if
- * exists. Otherwise returns NULL.
- */
-LTTNG_HIDDEN
-char *utils_get_extra_kmod_probes_list(void)
-{
-       return lttng_secure_getenv(DEFAULT_LTTNG_EXTRA_KMOD_PROBES);
-}
-
 /*
  * With the given format, fill dst with the time of len maximum siz.
  *
@@ -1175,24 +1233,77 @@ size_t utils_get_current_time_str(const char *format, char *dst, size_t len)
 }
 
 /*
- * Return the group ID matching name, else 0 if it cannot be found.
+ * Return 0 on success and set *gid to the group_ID matching the passed name.
+ * Else -1 if it cannot be found or an error occurred.
  */
 LTTNG_HIDDEN
-gid_t utils_get_group_id(const char *name)
+int utils_get_group_id(const char *name, bool warn, gid_t *gid)
 {
-       struct group *grp;
+       static volatile int warn_once;
+       int ret;
+       long sys_len;
+       size_t len;
+       struct group grp;
+       struct group *result;
+       struct lttng_dynamic_buffer buffer;
+
+       /* Get the system limit, if it exists. */
+       sys_len = sysconf(_SC_GETGR_R_SIZE_MAX);
+       if (sys_len == -1) {
+               len = 1024;
+       } else {
+               len = (size_t) sys_len;
+       }
+
+       lttng_dynamic_buffer_init(&buffer);
+       ret = lttng_dynamic_buffer_set_size(&buffer, len);
+       if (ret) {
+               ERR("Failed to allocate group info buffer");
+               ret = -1;
+               goto error;
+       }
 
-       grp = getgrnam(name);
-       if (!grp) {
-               static volatile int warn_once;
+       while ((ret = getgrnam_r(name, &grp, buffer.data, buffer.size, &result)) == ERANGE) {
+               const size_t new_len = 2 * buffer.size;
 
-               if (!warn_once) {
-                       WARN("No tracing group detected");
-                       warn_once = 1;
+               /* Buffer is not big enough, increase its size. */
+               if (new_len < buffer.size) {
+                       ERR("Group info buffer size overflow");
+                       ret = -1;
+                       goto error;
                }
-               return 0;
+
+               ret = lttng_dynamic_buffer_set_size(&buffer, new_len);
+               if (ret) {
+                       ERR("Failed to grow group info buffer to %zu bytes",
+                                       new_len);
+                       ret = -1;
+                       goto error;
+               }
+       }
+       if (ret) {
+               PERROR("Failed to get group file entry for group name \"%s\"",
+                               name);
+               ret = -1;
+               goto error;
+       }
+
+       /* Group not found. */
+       if (!result) {
+               ret = -1;
+               goto error;
+       }
+
+       *gid = result->gr_gid;
+       ret = 0;
+
+error:
+       if (ret && warn && !warn_once) {
+               WARN("No tracing group detected");
+               warn_once = 1;
        }
-       return grp->gr_gid;
+       lttng_dynamic_buffer_reset(&buffer);
+       return ret;
 }
 
 /*
@@ -1322,3 +1433,101 @@ end:
        }
        return ret;
 }
+
+LTTNG_HIDDEN
+int utils_truncate_stream_file(int fd, off_t length)
+{
+       int ret;
+       off_t lseek_ret;
+
+       ret = ftruncate(fd, length);
+       if (ret < 0) {
+               PERROR("ftruncate");
+               goto end;
+       }
+       lseek_ret = lseek(fd, length, SEEK_SET);
+       if (lseek_ret < 0) {
+               PERROR("lseek");
+               ret = -1;
+               goto end;
+       }
+end:
+       return ret;
+}
+
+static const char *get_man_bin_path(void)
+{
+       char *env_man_path = lttng_secure_getenv(DEFAULT_MAN_BIN_PATH_ENV);
+
+       if (env_man_path) {
+               return env_man_path;
+       }
+
+       return DEFAULT_MAN_BIN_PATH;
+}
+
+LTTNG_HIDDEN
+int utils_show_help(int section, const char *page_name,
+               const char *help_msg)
+{
+       char section_string[8];
+       const char *man_bin_path = get_man_bin_path();
+       int ret = 0;
+
+       if (help_msg) {
+               printf("%s", help_msg);
+               goto end;
+       }
+
+       /* Section integer -> section string */
+       ret = sprintf(section_string, "%d", section);
+       assert(ret > 0 && ret < 8);
+
+       /*
+        * Execute man pager.
+        *
+        * We provide -M to man here because LTTng-tools can
+        * be installed outside /usr, in which case its man pages are
+        * not located in the default /usr/share/man directory.
+        */
+       ret = execlp(man_bin_path, "man", "-M", MANPATH,
+               section_string, page_name, NULL);
+
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+int timespec_to_ms(struct timespec ts, unsigned long *ms)
+{
+       unsigned long res, remain_ms;
+
+       if (ts.tv_sec > ULONG_MAX / MSEC_PER_SEC) {
+               errno = EOVERFLOW;
+               return -1;      /* multiplication overflow */
+       }
+       res = ts.tv_sec * MSEC_PER_SEC;
+       remain_ms = ULONG_MAX - res;
+       if (ts.tv_nsec / NSEC_PER_MSEC > remain_ms) {
+               errno = EOVERFLOW;
+               return -1;      /* addition overflow */
+       }
+       res += ts.tv_nsec / NSEC_PER_MSEC;
+       *ms = res;
+       return 0;
+}
+
+LTTNG_HIDDEN
+struct timespec timespec_abs_diff(struct timespec t1, struct timespec t2)
+{
+       uint64_t ts1 = (uint64_t) t1.tv_sec * (uint64_t) NSEC_PER_SEC +
+                       (uint64_t) t1.tv_nsec;
+       uint64_t ts2 = (uint64_t) t2.tv_sec * (uint64_t) NSEC_PER_SEC +
+                       (uint64_t) t2.tv_nsec;
+       uint64_t diff = max(ts1, ts2) - min(ts1, ts2);
+       struct timespec res;
+
+       res.tv_sec = diff / (uint64_t) NSEC_PER_SEC;
+       res.tv_nsec = diff % (uint64_t) NSEC_PER_SEC;
+       return res;
+}
This page took 0.026829 seconds and 4 git commands to generate.