From 17109a3a3167fb1b39a6878b23519331020ac1f8 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Tue, 25 Aug 2020 17:21:45 +0300 Subject: LibC: Use AK::String-backed buffers instead of static buffers Also, refactor the hell out of pwd.cpp & grp.cpp --- Libraries/LibC/grp.cpp | 150 +++++++++++++++++++++++++++---------------------- 1 file changed, 82 insertions(+), 68 deletions(-) (limited to 'Libraries/LibC/grp.cpp') diff --git a/Libraries/LibC/grp.cpp b/Libraries/LibC/grp.cpp index 23eaef4cb0..9750389281 100644 --- a/Libraries/LibC/grp.cpp +++ b/Libraries/LibC/grp.cpp @@ -26,54 +26,51 @@ #include #include +#include #include #include #include #include -#include #include extern "C" { -#define GRDB_STR_MAX_LEN 256 +static FILE* s_stream = nullptr; +static unsigned s_line_number = 0; +static struct group s_group; -struct group_with_strings : public group { - char name_buffer[GRDB_STR_MAX_LEN]; - char passwd_buffer[GRDB_STR_MAX_LEN]; - char* members[32]; - char members_buffer[32][32]; -}; - -static FILE* __grdb_stream = nullptr; -static unsigned __grdb_line_number = 0; -static struct group_with_strings* __grdb_entry = nullptr; +static String s_name; +static String s_passwd; +static Vector s_members; +static Vector s_members_ptrs; void setgrent() { - __grdb_line_number = 0; - if (__grdb_stream) { - rewind(__grdb_stream); + s_line_number = 0; + if (s_stream) { + rewind(s_stream); } else { - __grdb_stream = fopen("/etc/group", "r"); - if (!__grdb_stream) { + s_stream = fopen("/etc/group", "r"); + if (!s_stream) { perror("open /etc/group"); } - assert(__grdb_stream); - __grdb_entry = (struct group_with_strings*)mmap_with_name(nullptr, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, "setgrent"); } } void endgrent() { - __grdb_line_number = 0; - if (__grdb_stream) { - fclose(__grdb_stream); - __grdb_stream = nullptr; - } - if (__grdb_entry) { - munmap(__grdb_entry, getpagesize()); - __grdb_entry = nullptr; + s_line_number = 0; + if (s_stream) { + fclose(s_stream); + s_stream = nullptr; } + + memset(&s_group, 0, sizeof(s_group)); + + s_name = {}; + s_passwd = {}; + s_members = {}; + s_members_ptrs = {}; } struct group* getgrgid(gid_t gid) @@ -96,52 +93,69 @@ struct group* getgrnam(const char* name) return nullptr; } -struct group* getgrent() +static bool parse_grpdb_entry(const String& line) { - if (!__grdb_stream) - setgrent(); - - assert(__grdb_stream); - if (feof(__grdb_stream)) - return nullptr; - -next_entry: - char buffer[1024]; - ++__grdb_line_number; - char* s = fgets(buffer, sizeof(buffer), __grdb_stream); - if (!s) - return nullptr; - assert(__grdb_stream); - if (feof(__grdb_stream)) - return nullptr; - String line(s, Chomp); - auto parts = line.split(':', true); + auto parts = line.split_view(':', true); if (parts.size() != 4) { - fprintf(stderr, "getgrent(): Malformed entry on line %u: '%s' has %zu parts\n", __grdb_line_number, line.characters(), parts.size()); - goto next_entry; + fprintf(stderr, "getgrent(): Malformed entry on line %u: '%s' has %zu parts\n", s_line_number, line.characters(), parts.size()); + return false; } - auto& e_name = parts[0]; - auto& e_passwd = parts[1]; - auto& e_gid_string = parts[2]; - auto& e_members_string = parts[3]; - auto e_gid = e_gid_string.to_uint(); - if (!e_gid.has_value()) { - fprintf(stderr, "getgrent(): Malformed GID on line %u\n", __grdb_line_number); - goto next_entry; + + s_name = parts[0]; + s_passwd = parts[1]; + + auto& gid_string = parts[2]; + String members_string = parts[3]; + + auto gid = gid_string.to_uint(); + if (!gid.has_value()) { + fprintf(stderr, "getgrent(): Malformed GID on line %u\n", s_line_number); + return false; } - auto members = e_members_string.split(','); - __grdb_entry->gr_gid = e_gid.value(); - __grdb_entry->gr_name = __grdb_entry->name_buffer; - __grdb_entry->gr_passwd = __grdb_entry->passwd_buffer; - for (size_t i = 0; i < members.size(); ++i) { - __grdb_entry->members[i] = __grdb_entry->members_buffer[i]; - strlcpy(__grdb_entry->members_buffer[i], members[i].characters(), sizeof(__grdb_entry->members_buffer[i])); + + s_members = members_string.split(','); + s_members_ptrs.clear_with_capacity(); + s_members_ptrs.ensure_capacity(s_members.size() + 1); + for (auto& member : s_members) { + s_members_ptrs.append(member.characters()); + } + s_members_ptrs.append(nullptr); + + s_group.gr_gid = gid.value(); + s_group.gr_name = const_cast(s_name.characters()); + s_group.gr_passwd = const_cast(s_passwd.characters()); + s_group.gr_mem = const_cast(s_members_ptrs.data()); + + return true; +} + +struct group* getgrent() +{ + if (!s_stream) + setgrent(); + + while (true) { + if (!s_stream || feof(s_stream)) + return nullptr; + + if (ferror(s_stream)) { + fprintf(stderr, "getgrent(): Read error: %s\n", strerror(ferror(s_stream))); + return nullptr; + } + + char buffer[1024]; + ++s_line_number; + char* s = fgets(buffer, sizeof(buffer), s_stream); + + // Silently tolerate an empty line at the end. + if ((!s || !s[0]) && feof(s_stream)) + return nullptr; + + String line(s, Chomp); + if (parse_grpdb_entry(line)) + return &s_group; + // Otherwise, proceed to the next line. } - __grdb_entry->members[members.size()] = nullptr; - __grdb_entry->gr_mem = __grdb_entry->members; - strlcpy(__grdb_entry->name_buffer, e_name.characters(), GRDB_STR_MAX_LEN); - strlcpy(__grdb_entry->passwd_buffer, e_passwd.characters(), GRDB_STR_MAX_LEN); - return __grdb_entry; } int initgroups(const char* user, gid_t extra_gid) -- cgit v1.2.3