Fix: getgrnam is not MT-Safe, use getgrnam_r
[lttng-tools.git] / src / common / utils.c
index 5be67c11f1e1dc896fa2e5d5e9cb7a6299903c73..aada37fe707d156bc0a22425e2c0ad04a291b81e 100644 (file)
@@ -39,6 +39,7 @@
 #include <common/compat/string.h>
 #include <common/compat/dirent.h>
 #include <common/compat/directory-handle.h>
+#include <common/dynamic-buffer.h>
 #include <lttng/constant.h>
 
 #include "utils.h"
@@ -1374,24 +1375,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;
+               }
+
+               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;
                }
-               return 0;
        }
-       return grp->gr_gid;
+       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;
+       }
+       lttng_dynamic_buffer_reset(&buffer);
+       return ret;
 }
 
 /*
This page took 0.024892 seconds and 5 git commands to generate.