feat(unistd): cwd/link/readlink/path ops
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* getlogin/getlogin_r: the login name associated with the calling
|
||||
* process — the user who owns its controlling terminal.
|
||||
*
|
||||
* POSIX.1-2008: getlogin() returns a pointer to the login name, or NULL
|
||||
* when the process is not associated with a terminal; getlogin_r may
|
||||
* fail with ENOTTY when the calling process has no controlling terminal.
|
||||
* The "controlling terminal" is the terminal of the session the process
|
||||
* belongs to; Linux reports it as field 7 (tty_nr) of /proc/self/stat
|
||||
* (0 when the process has none).
|
||||
*
|
||||
* Resolving the NAME of that terminal's user requires the session/utmp
|
||||
* database, which this libc does not yet carry (the passwd/group todo
|
||||
* owns /etc/passwd and the session records). This stage therefore never
|
||||
* fabricates a name: it distinguishes the no-terminal case (ENOTTY,
|
||||
* fully specified by POSIX) from the has-a-terminal-but-no-database
|
||||
* case (ENOENT), and getlogin() reports both as NULL with errno set.
|
||||
* The name resolution is completed by the session-database todo.
|
||||
*/
|
||||
|
||||
/* Static buffer for getlogin(); 256 bytes comfortably holds a login name. */
|
||||
#define VLIBC_UNISTD_LOGIN_BUF 256
|
||||
|
||||
static char getlogin_buf[VLIBC_UNISTD_LOGIN_BUF];
|
||||
|
||||
/*
|
||||
* Read field 7 (tty_nr) of /proc/self/stat. After the parenthesized
|
||||
* comm field — located by scanning back from the end for the last ')' —
|
||||
* the fields run state(3) ppid(4) pgrp(5) session(6) tty_nr(7), so
|
||||
* tty_nr is the token after four more whitespace-separated tokens.
|
||||
* Returns 1 and the value when the file could be read, 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
login_tty_nr(long *tty_out)
|
||||
{
|
||||
char buf[512];
|
||||
char *p;
|
||||
ssize_t n;
|
||||
int fd;
|
||||
int tok;
|
||||
long value = 0;
|
||||
int sign = 1;
|
||||
int have_digit = 0;
|
||||
|
||||
fd = open("/proc/self/stat", O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
n = read(fd, buf, sizeof(buf) - 1);
|
||||
close(fd);
|
||||
if (n <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
buf[n] = '\0';
|
||||
|
||||
p = buf + n;
|
||||
while (p > buf && *p != ')')
|
||||
{
|
||||
p--;
|
||||
}
|
||||
if (*p != ')')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
p++;
|
||||
|
||||
for (tok = 0; tok < 4; tok++)
|
||||
{
|
||||
while (*p == ' ' || *p == '\t')
|
||||
{
|
||||
p++;
|
||||
}
|
||||
while (*p != '\0' && *p != ' ' && *p != '\t' && *p != '\n')
|
||||
{
|
||||
p++;
|
||||
}
|
||||
if (*p == '\0')
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
while (*p == ' ' || *p == '\t')
|
||||
{
|
||||
p++;
|
||||
}
|
||||
if (*p == '-')
|
||||
{
|
||||
sign = -1;
|
||||
p++;
|
||||
}
|
||||
while (*p >= '0' && *p <= '9')
|
||||
{
|
||||
value = value * 10 + (*p - '0');
|
||||
p++;
|
||||
have_digit = 1;
|
||||
}
|
||||
if (!have_digit)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*tty_out = sign * value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
getlogin_r(char *name, size_t namesize)
|
||||
{
|
||||
long tty_nr;
|
||||
|
||||
if (name == NULL || namesize == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return EINVAL;
|
||||
}
|
||||
if (!login_tty_nr(&tty_nr) || tty_nr == 0)
|
||||
{
|
||||
/* No controlling terminal (or procfs cannot be read). */
|
||||
errno = ENOTTY;
|
||||
return ENOTTY;
|
||||
}
|
||||
/* A controlling terminal exists, but no session database to resolve
|
||||
* its owner's login name yet — never fabricate one. */
|
||||
errno = ENOENT;
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
char *
|
||||
getlogin(void)
|
||||
{
|
||||
int err = getlogin_r(getlogin_buf, sizeof(getlogin_buf));
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
errno = err;
|
||||
return NULL;
|
||||
}
|
||||
return getlogin_buf;
|
||||
}
|
||||
Reference in New Issue
Block a user