189 lines
6.3 KiB
C
189 lines
6.3 KiB
C
/*-*- mode:c;indent-tabs-mode:t;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
│vi: set et ft=c ts=2 tw=8 fenc=utf-8 :vi│
|
|
╚──────────────────────────────────────────────────────────────────────────────╝
|
|
│ │
|
|
│ Musl Libc │
|
|
│ Copyright © 2005-2014 Rich Felker, et al. │
|
|
│ │
|
|
│ Permission is hereby granted, free of charge, to any person obtaining │
|
|
│ a copy of this software and associated documentation files (the │
|
|
│ "Software"), to deal in the Software without restriction, including │
|
|
│ without limitation the rights to use, copy, modify, merge, publish, │
|
|
│ distribute, sublicense, and/or sell copies of the Software, and to │
|
|
│ permit persons to whom the Software is furnished to do so, subject to │
|
|
│ the following conditions: │
|
|
│ │
|
|
│ The above copyright notice and this permission notice shall be │
|
|
│ included in all copies or substantial portions of the Software. │
|
|
│ │
|
|
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │
|
|
│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │
|
|
│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │
|
|
│ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY │
|
|
│ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, │
|
|
│ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE │
|
|
│ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
|
|
│ │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/calls/weirdtypes.h"
|
|
#include "libc/errno.h"
|
|
#include "libc/mem/mem.h"
|
|
#include "libc/stdio/stdio.h"
|
|
#include "libc/str/str.h"
|
|
#include "third_party/musl/passwd.h"
|
|
|
|
asm(".ident\t\"\\n\\n\
|
|
Musl libc (MIT License)\\n\
|
|
Copyright 2005-2014 Rich Felker, et. al.\"");
|
|
asm(".include \"libc/disclaimer.inc\"");
|
|
|
|
#define PTHREAD_CANCEL_DISABLE 0
|
|
#define pthread_setcancelstate(x, y) (void)y
|
|
|
|
static unsigned atou(char **s) {
|
|
unsigned x;
|
|
for (x = 0; **s - '0' < 10U; ++*s) x = 10 * x + (**s - '0');
|
|
return x;
|
|
}
|
|
|
|
static int __getpwent_a(FILE *f, struct passwd *pw, char **line, size_t *size,
|
|
struct passwd **res) {
|
|
ssize_t l;
|
|
char *s;
|
|
int rv = 0;
|
|
int cs;
|
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
|
for (;;) {
|
|
if ((l = getline(line, size, f)) < 0) {
|
|
rv = ferror(f) ? errno : 0;
|
|
free(*line);
|
|
*line = 0;
|
|
pw = 0;
|
|
break;
|
|
}
|
|
line[0][l - 1] = 0;
|
|
s = line[0];
|
|
pw->pw_name = s++;
|
|
if (!(s = strchr(s, ':'))) continue;
|
|
*s++ = 0;
|
|
pw->pw_passwd = s;
|
|
if (!(s = strchr(s, ':'))) continue;
|
|
*s++ = 0;
|
|
pw->pw_uid = atou(&s);
|
|
if (*s != ':') continue;
|
|
*s++ = 0;
|
|
pw->pw_gid = atou(&s);
|
|
if (*s != ':') continue;
|
|
*s++ = 0;
|
|
pw->pw_gecos = s;
|
|
if (!(s = strchr(s, ':'))) continue;
|
|
*s++ = 0;
|
|
pw->pw_dir = s;
|
|
if (!(s = strchr(s, ':'))) continue;
|
|
*s++ = 0;
|
|
pw->pw_shell = s;
|
|
break;
|
|
}
|
|
pthread_setcancelstate(cs, 0);
|
|
*res = pw;
|
|
if (rv) errno = rv;
|
|
return rv;
|
|
}
|
|
|
|
static int __getpw_a(const char *name, uid_t uid, struct passwd *pw, char **buf,
|
|
size_t *size, struct passwd **res) {
|
|
FILE *f;
|
|
int cs;
|
|
int rv = 0;
|
|
*res = 0;
|
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
|
if ((f = fopen("/etc/passwd", "rbe"))) {
|
|
while (!(rv = __getpwent_a(f, pw, buf, size, res)) && *res) {
|
|
if ((name && !strcmp(name, (*res)->pw_name)) ||
|
|
(!name && (*res)->pw_uid == uid)) {
|
|
break;
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
pthread_setcancelstate(cs, 0);
|
|
if (rv) errno = rv;
|
|
return rv;
|
|
}
|
|
|
|
static int getpw_r(const char *name, uid_t uid, struct passwd *pw, char *buf,
|
|
size_t size, struct passwd **res) {
|
|
#define FIX(x) (pw->pw_##x = pw->pw_##x - line + buf)
|
|
char *line = 0;
|
|
size_t len = 0;
|
|
int rv = 0;
|
|
int cs;
|
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
|
|
rv = __getpw_a(name, uid, pw, &line, &len, res);
|
|
if (*res && size < len) {
|
|
*res = 0;
|
|
rv = ERANGE;
|
|
}
|
|
if (*res) {
|
|
memcpy(buf, line, len);
|
|
FIX(name);
|
|
FIX(passwd);
|
|
FIX(gecos);
|
|
FIX(dir);
|
|
FIX(shell);
|
|
}
|
|
free(line);
|
|
pthread_setcancelstate(cs, 0);
|
|
if (rv) errno = rv;
|
|
return rv;
|
|
#undef FIX
|
|
}
|
|
|
|
int getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t size,
|
|
struct passwd **res) {
|
|
return getpw_r(name, 0, pw, buf, size, res);
|
|
}
|
|
|
|
int getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t size,
|
|
struct passwd **res) {
|
|
return getpw_r(0, uid, pw, buf, size, res);
|
|
}
|
|
|
|
static struct GetpwentState {
|
|
FILE *f;
|
|
char *line;
|
|
struct passwd pw;
|
|
size_t size;
|
|
} g_getpwent[1];
|
|
|
|
void endpwent() {
|
|
setpwent();
|
|
}
|
|
void setpwent() {
|
|
if (g_getpwent->f) fclose(g_getpwent->f);
|
|
g_getpwent->f = 0;
|
|
}
|
|
|
|
struct passwd *getpwent() {
|
|
struct passwd *res;
|
|
if (!g_getpwent->f) g_getpwent->f = fopen("/etc/passwd", "rbe");
|
|
if (!g_getpwent->f) return 0;
|
|
__getpwent_a(g_getpwent->f, &g_getpwent->pw, &g_getpwent->line,
|
|
&g_getpwent->size, &res);
|
|
return res;
|
|
}
|
|
|
|
struct passwd *getpwuid(uid_t uid) {
|
|
struct passwd *res;
|
|
__getpw_a(0, uid, &g_getpwent->pw, &g_getpwent->line, &g_getpwent->size,
|
|
&res);
|
|
return res;
|
|
}
|
|
|
|
struct passwd *getpwnam(const char *name) {
|
|
struct passwd *res;
|
|
__getpw_a(name, 0, &g_getpwent->pw, &g_getpwent->line, &g_getpwent->size,
|
|
&res);
|
|
return res;
|
|
}
|