LibC: Implement getgrnam and getgrgid

This commit is contained in:
Bananymous 2024-01-03 00:14:49 +02:00
parent d2bc399770
commit 668c4c8976
2 changed files with 163 additions and 0 deletions

View File

@ -7,6 +7,7 @@ set(LIBC_SOURCES
ctype.cpp ctype.cpp
dirent.cpp dirent.cpp
fcntl.cpp fcntl.cpp
grp.cpp
malloc.cpp malloc.cpp
printf_impl.cpp printf_impl.cpp
pwd.cpp pwd.cpp

162
libc/grp.cpp Normal file
View File

@ -0,0 +1,162 @@
#include <BAN/StringView.h>
#include <BAN/Vector.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
static struct stat s_group_st;
static char* s_group_mmap = nullptr;
static int s_group_fd = -1;
static struct group s_group;
id_t parse_id(BAN::StringView string)
{
id_t id = 0;
for (char c : string)
{
if (!isdigit(c))
return -1;
id = (id * 10) + (c - '0');
}
return id;
}
static bool open_group_file()
{
if (s_group_fd == -1)
s_group_fd = open("/etc/group", O_RDONLY);
if (s_group_fd == -1)
return false;
if (fstat(s_group_fd, &s_group_st) == -1)
return false;
if (s_group_mmap == nullptr || s_group_mmap == MAP_FAILED)
s_group_mmap = (char*)mmap(nullptr, s_group_st.st_size, PROT_READ, MAP_PRIVATE, s_group_fd, 0);
if (s_group_mmap == MAP_FAILED)
return false;
s_group.gr_name = nullptr;
s_group.gr_mem = nullptr;
return true;
}
struct group* fill_group(const BAN::Vector<BAN::StringView>& parts)
{
if (parts.size() != 4)
return nullptr;
if (s_group.gr_name)
{
free(s_group.gr_name);
s_group.gr_name = nullptr;
}
if (s_group.gr_mem)
{
for (size_t i = 0; s_group.gr_mem && s_group.gr_mem[i]; i++)
free(s_group.gr_mem[i]);
free(s_group.gr_mem);
s_group.gr_mem = nullptr;
}
auto groups_or_error = parts[3].split(',');
if (groups_or_error.is_error())
return nullptr;
auto groups = groups_or_error.release_value();
s_group.gr_gid = parse_id(parts[2]);
if (s_group.gr_gid == -1)
return nullptr;
s_group.gr_name = (char*)malloc(parts[0].size() + 1);
if (s_group.gr_name == nullptr)
return nullptr;
memcpy(s_group.gr_name, parts[0].data(), parts[0].size());
s_group.gr_name[parts[0].size()] = '\0';
s_group.gr_mem = (char**)malloc((groups.size() + 1) * sizeof(char*));
if (s_group.gr_mem == nullptr)
return nullptr;
for (size_t i = 0; i < groups.size(); i++)
{
s_group.gr_mem[i] = (char*)malloc(groups[i].size() + 1);
if (s_group.gr_mem[i] == nullptr)
{
for (size_t j = 0; j < i; j++)
free(s_group.gr_mem[j]);
free(s_group.gr_mem);
s_group.gr_mem = nullptr;
return nullptr;
}
memcpy(s_group.gr_mem[i], groups[i].data(), groups[i].size());
s_group.gr_mem[i][groups[i].size()] = '\0';
}
s_group.gr_mem[groups.size()] = nullptr;
return &s_group;
}
struct group* getgrnam(const char* name)
{
if (s_group_mmap == nullptr || s_group_mmap == MAP_FAILED)
if (!open_group_file())
return nullptr;
off_t start = 0;
off_t end = 0;
while (start < s_group_st.st_size)
{
while (end < s_group_st.st_size && s_group_mmap[end] != '\n')
end++;
BAN::StringView line(s_group_mmap + start, end - start);
start = ++end;
auto parts_or_error = line.split(':', true);
if (parts_or_error.is_error())
return nullptr;
auto parts = parts_or_error.release_value();
if (parts.size() == 4 && parts[0] == name)
return fill_group(parts);
}
return nullptr;
}
struct group* getgrgid(gid_t gid)
{
if (s_group_mmap == nullptr || s_group_mmap == MAP_FAILED)
if (!open_group_file())
return nullptr;
off_t start = 0;
off_t end = 0;
while (start < s_group_st.st_size)
{
while (end < s_group_st.st_size && s_group_mmap[end] != '\n')
end++;
BAN::StringView line(s_group_mmap + start, end - start);
start = ++end;
auto parts_or_error = line.split(':', true);
if (parts_or_error.is_error())
return nullptr;
auto parts = parts_or_error.release_value();
if (parts.size() == 4 && parse_id(parts[2]) == gid)
return fill_group(parts);
}
return nullptr;
}