summaryrefslogtreecommitdiffstats
path: root/src/libnetdata/os/system-maps/cache-host-users-and-groups.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnetdata/os/system-maps/cache-host-users-and-groups.c')
-rw-r--r--src/libnetdata/os/system-maps/cache-host-users-and-groups.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/src/libnetdata/os/system-maps/cache-host-users-and-groups.c b/src/libnetdata/os/system-maps/cache-host-users-and-groups.c
new file mode 100644
index 000000000..53825fd35
--- /dev/null
+++ b/src/libnetdata/os/system-maps/cache-host-users-and-groups.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "libnetdata/libnetdata.h"
+
+static bool file_changed(const struct stat *statbuf __maybe_unused, struct timespec *last_modification_time __maybe_unused) {
+#if defined(OS_MACOS) || defined(OS_WINDOWS)
+ return false;
+#else
+ if(likely(statbuf->st_mtim.tv_sec == last_modification_time->tv_sec &&
+ statbuf->st_mtim.tv_nsec == last_modification_time->tv_nsec)) return false;
+
+ last_modification_time->tv_sec = statbuf->st_mtim.tv_sec;
+ last_modification_time->tv_nsec = statbuf->st_mtim.tv_nsec;
+
+ return true;
+#endif
+}
+
+static size_t read_passwd_or_group(const char *filename, struct timespec *last_modification_time, void (*cb)(uint32_t gid, const char *name, uint32_t version), uint32_t version) {
+ struct stat statbuf;
+ if(unlikely(stat(filename, &statbuf) || !file_changed(&statbuf, last_modification_time)))
+ return 0;
+
+ procfile *ff = procfile_open(filename, " :\t", PROCFILE_FLAG_DEFAULT);
+ if(unlikely(!ff)) return 0;
+
+ ff = procfile_readall(ff);
+ if(unlikely(!ff)) return 0;
+
+ size_t line, lines = procfile_lines(ff);
+
+ size_t added = 0;
+ for(line = 0; line < lines ;line++) {
+ size_t words = procfile_linewords(ff, line);
+ if(unlikely(words < 3)) continue;
+
+ char *name = procfile_lineword(ff, line, 0);
+ if(unlikely(!name || !*name)) continue;
+
+ char *id_string = procfile_lineword(ff, line, 2);
+ if(unlikely(!id_string || !*id_string)) continue;
+
+ uint32_t id = str2ull(id_string, NULL);
+
+ cb(id, name, version);
+ added++;
+ }
+
+ procfile_close(ff);
+ return added;
+}
+
+void update_cached_host_users(void) {
+ if(!netdata_configured_host_prefix || !*netdata_configured_host_prefix) return;
+
+ static SPINLOCK spinlock = NETDATA_SPINLOCK_INITIALIZER;
+ if(!spinlock_trylock(&spinlock)) return;
+
+ char filename[FILENAME_MAX];
+ static bool initialized = false;
+
+ size_t added = 0;
+
+ if(!initialized) {
+ initialized = true;
+ cached_usernames_init();
+ }
+
+ static uint32_t passwd_version = 0;
+ static struct timespec passwd_ts = { 0 };
+ snprintfz(filename, FILENAME_MAX, "%s/etc/passwd", netdata_configured_host_prefix);
+ added = read_passwd_or_group(filename, &passwd_ts, cached_username_populate_by_uid, ++passwd_version);
+ if(added) cached_usernames_delete_old_versions(passwd_version);
+
+ spinlock_unlock(&spinlock);
+}
+
+void update_cached_host_groups(void) {
+ if(!netdata_configured_host_prefix || !*netdata_configured_host_prefix) return;
+
+ static SPINLOCK spinlock = NETDATA_SPINLOCK_INITIALIZER;
+ if(!spinlock_trylock(&spinlock)) return;
+
+ char filename[FILENAME_MAX];
+ static bool initialized = false;
+
+ size_t added = 0;
+
+ if(!initialized) {
+ initialized = true;
+ cached_groupnames_init();
+ }
+
+ static uint32_t group_version = 0;
+ static struct timespec group_ts = { 0 };
+ snprintfz(filename, FILENAME_MAX, "%s/etc/group", netdata_configured_host_prefix);
+ added = read_passwd_or_group(filename, &group_ts, cached_groupname_populate_by_gid, ++group_version);
+ if(added) cached_groupnames_delete_old_versions(group_version);
+
+ spinlock_unlock(&spinlock);
+}