// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef NETDATA_SYSTEM_GROUPS_H
#define NETDATA_SYSTEM_GROUPS_H

#include "libnetdata/libnetdata.h"

// --------------------------------------------------------------------------------------------------------------------
// hashtable for caching uid to username mappings
// key is the uid, value is username (STRING)

#define SIMPLE_HASHTABLE_VALUE_TYPE STRING
#define SIMPLE_HASHTABLE_NAME _GROUPNAMES_CACHE
#include "libnetdata/simple_hashtable.h"

typedef struct groupnames_cache {
    SPINLOCK spinlock;
    SIMPLE_HASHTABLE_GROUPNAMES_CACHE ht;
} GROUPNAMES_CACHE;

static inline STRING *system_groupnames_cache_lookup_gid(GROUPNAMES_CACHE *gc, gid_t gid) {
    spinlock_lock(&gc->spinlock);

    SIMPLE_HASHTABLE_SLOT_GROUPNAMES_CACHE *sl = simple_hashtable_get_slot_GROUPNAMES_CACHE(&gc->ht, gid, &gid, true);
    STRING *g = SIMPLE_HASHTABLE_SLOT_DATA(sl);
    if(!g) {
        char tmp[1024 + 1];
        struct group grp, *result = NULL;

        if (getgrgid_r(gid, &grp, tmp, sizeof(tmp), &result) != 0 || !result || !grp.gr_name || !(*grp.gr_name)) {
            char name[50];
            snprintfz(name, sizeof(name), "%u", gid);
            g = string_strdupz(name);
        }
        else
            g = string_strdupz(grp.gr_name);

        simple_hashtable_set_slot_GROUPNAMES_CACHE(&gc->ht, sl, gid, g);
    }

    g = string_dup(g);
    spinlock_unlock(&gc->spinlock);
    return g;
}

static inline GROUPNAMES_CACHE *system_groupnames_cache_init(void) {
    GROUPNAMES_CACHE *gc = callocz(1, sizeof(*gc));
    spinlock_init(&gc->spinlock);
    simple_hashtable_init_GROUPNAMES_CACHE(&gc->ht, 100);
    return gc;
}

static inline void system_groupnames_cache_destroy(GROUPNAMES_CACHE *gc) {
    spinlock_lock(&gc->spinlock);

    for(SIMPLE_HASHTABLE_SLOT_GROUPNAMES_CACHE *sl = simple_hashtable_first_read_only_GROUPNAMES_CACHE(&gc->ht);
         sl;
         sl = simple_hashtable_next_read_only_GROUPNAMES_CACHE(&gc->ht, sl)) {
        STRING *u = SIMPLE_HASHTABLE_SLOT_DATA(sl);
        string_freez(u);
    }

    simple_hashtable_destroy_GROUPNAMES_CACHE(&gc->ht);
    freez(gc);
}

#endif //NETDATA_SYSTEM_GROUPS_H
