LibC: Implement getgrnam and getgrgid
This commit is contained in:
parent
d2bc399770
commit
668c4c8976
|
@ -7,6 +7,7 @@ set(LIBC_SOURCES
|
|||
ctype.cpp
|
||||
dirent.cpp
|
||||
fcntl.cpp
|
||||
grp.cpp
|
||||
malloc.cpp
|
||||
printf_impl.cpp
|
||||
pwd.cpp
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue