132 lines
2.7 KiB
C++
132 lines
2.7 KiB
C++
#include <fcntl.h>
|
|
#include <pwd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static struct passwd pwd;
|
|
static FILE* f { nullptr };
|
|
static char buf[4096];
|
|
|
|
// Variant of strtok that returns empty tokens when there are several delimiters, instead of skipping all at once.
|
|
// Example:
|
|
// strtok("hello:world::!:", ":") -> "hello", "world", "!"
|
|
// _strtok_once("hello:world::!:", ":") -> "hello", "world", "", "!"
|
|
char* _strtok_once(char* str, const char* delim)
|
|
{
|
|
static char* s = nullptr;
|
|
if (str) s = str;
|
|
if (!s) return nullptr;
|
|
|
|
if (*s)
|
|
{
|
|
if (*s == 0) return nullptr;
|
|
|
|
size_t use = strcspn(s, delim);
|
|
char* result = s;
|
|
|
|
if (s[use] != 0)
|
|
{
|
|
s[use] = 0;
|
|
s += (use + 1);
|
|
}
|
|
else { s = nullptr; }
|
|
|
|
return result;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
extern "C"
|
|
{
|
|
struct passwd* getpwent()
|
|
{
|
|
if (!f)
|
|
{
|
|
f = fopen("/etc/passwd", "r");
|
|
if (!f) return nullptr;
|
|
fcntl(fileno(f), F_SETFD, FD_CLOEXEC);
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
char* rc = fgets(buf, sizeof(buf), f);
|
|
if (!rc) return nullptr;
|
|
|
|
char* name = _strtok_once(rc, ":\n");
|
|
if (!name) continue;
|
|
|
|
char* passwd = _strtok_once(nullptr, ":\n");
|
|
if (!passwd) continue;
|
|
|
|
char* uid = _strtok_once(nullptr, ":\n");
|
|
if (!uid) continue;
|
|
|
|
char* gid = _strtok_once(nullptr, ":\n");
|
|
if (!gid) continue;
|
|
|
|
char* gecos = _strtok_once(nullptr, ":\n");
|
|
if (!gecos) continue;
|
|
|
|
char* dir = _strtok_once(nullptr, ":\n");
|
|
if (!dir) continue;
|
|
|
|
char* shell = _strtok_once(nullptr, ":\n");
|
|
if (!shell) continue;
|
|
|
|
pwd.pw_name = name;
|
|
pwd.pw_passwd = passwd;
|
|
pwd.pw_uid = (uid_t)strtoul(uid, NULL, 10);
|
|
pwd.pw_gid = (gid_t)strtoul(gid, NULL, 10);
|
|
pwd.pw_gecos = gecos;
|
|
pwd.pw_dir = dir;
|
|
pwd.pw_shell = shell;
|
|
|
|
return &pwd;
|
|
}
|
|
}
|
|
|
|
struct passwd* getpwnam(const char* name)
|
|
{
|
|
setpwent();
|
|
|
|
struct passwd* entry;
|
|
|
|
while ((entry = getpwent()))
|
|
{
|
|
if (!strcmp(entry->pw_name, name)) { return entry; }
|
|
}
|
|
|
|
return entry;
|
|
}
|
|
|
|
struct passwd* getpwuid(uid_t uid)
|
|
{
|
|
setpwent();
|
|
|
|
struct passwd* entry;
|
|
|
|
while ((entry = getpwent()))
|
|
{
|
|
if (entry->pw_uid == uid) { return entry; }
|
|
}
|
|
|
|
return entry;
|
|
}
|
|
|
|
void setpwent()
|
|
{
|
|
if (f) rewind(f);
|
|
}
|
|
|
|
void endpwent()
|
|
{
|
|
if (f)
|
|
{
|
|
fclose(f);
|
|
f = nullptr;
|
|
}
|
|
}
|
|
}
|