feat(unistd): cwd/link/readlink/path ops

This commit is contained in:
2026-09-05 23:32:29 -04:00
parent 523045b5ae
commit 9eb32c4010
22 changed files with 2001 additions and 1 deletions
+149
View File
@@ -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;
}