765 lines
18 KiB
C
765 lines
18 KiB
C
/*
|
|
* montauk-compat.c -- POSIX calls git needs that the Montauk libc does not
|
|
* have. Compiled into libgitcompat.a and placed on the link line ahead of
|
|
* liblibc.a.
|
|
*
|
|
* The rule followed here: a shim either does the real thing, or it fails with
|
|
* an errno git already knows how to report. Nothing pretends to have done
|
|
* work it did not do -- with one deliberate exception, fsync(), noted at its
|
|
* definition.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <stddef.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <pwd.h>
|
|
#include <grp.h>
|
|
#include <netdb.h>
|
|
#include <poll.h>
|
|
#include <signal.h>
|
|
#include <termios.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/utsname.h>
|
|
|
|
/*
|
|
* <montauk.h> is the C mirror of the syscall ABI (the C++ SDK headers under montauk/
|
|
* are C++). Only two calls are used below: SYS_GETUSER for the session user
|
|
* and SYS_TERMSIZE for the terminal geometry.
|
|
*/
|
|
#include <montauk.h>
|
|
|
|
/* ==== Identity =======================================================
|
|
*
|
|
* MontaukOS has named users but no numeric uid space: a process runs as
|
|
* whoever is logged into the session. A single fixed non-root id is reported,
|
|
* which makes git's two questions answer correctly -- "am I root?" (no, so it
|
|
* does not relax its safety checks) and "does this repository belong to me?"
|
|
* (yes, since every path reports the same owner).
|
|
*/
|
|
|
|
#define MONTAUK_UID 1000
|
|
#define MONTAUK_GID 1000
|
|
|
|
uid_t getuid(void) { return MONTAUK_UID; }
|
|
uid_t geteuid(void) { return MONTAUK_UID; }
|
|
gid_t getgid(void) { return MONTAUK_GID; }
|
|
gid_t getegid(void) { return MONTAUK_GID; }
|
|
|
|
/* No process tree above us that userspace can see. */
|
|
pid_t getppid(void) { return 1; }
|
|
|
|
int setsid(void) { return getpid(); }
|
|
|
|
/*
|
|
* Process groups do not exist: every process is its own group, and whatever
|
|
* is reading the terminal is the foreground job. Reporting getpid() from all
|
|
* three keeps progress.c's foreground test (tcgetpgrp(fd) == getpgid(0))
|
|
* true, so the progress meter is drawn instead of suppressed.
|
|
*/
|
|
pid_t getpgid(pid_t pid) { return pid ? pid : getpid(); }
|
|
pid_t getpgrp(void) { return getpid(); }
|
|
pid_t tcgetpgrp(int fd) { (void) fd; return getpid(); }
|
|
|
|
int setpgid(pid_t pid, pid_t pgid)
|
|
{
|
|
(void) pid; (void) pgid;
|
|
return 0;
|
|
}
|
|
|
|
int gethostname(char *name, size_t len)
|
|
{
|
|
static const char host[] = "montauk";
|
|
|
|
if (!name || len == 0) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
if (len < sizeof(host)) {
|
|
errno = ENAMETOOLONG;
|
|
return -1;
|
|
}
|
|
memcpy(name, host, sizeof(host));
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* No interval timers exist and SIGALRM is never delivered, so nothing is
|
|
* armed and nothing was pending. Only upload-pack's idle timeout calls this,
|
|
* and upload-pack needs sockets to be reachable at all.
|
|
*/
|
|
unsigned int alarm(unsigned int seconds)
|
|
{
|
|
(void) seconds;
|
|
return 0;
|
|
}
|
|
|
|
/* ==== Passwd / group =================================================
|
|
*
|
|
* Answered from the session rather than from a database. git uses this for
|
|
* the fallback author identity and to expand "~"; a wrong-but-plausible entry
|
|
* beats a NULL return, which git reports as "You don't exist. Go away!".
|
|
*
|
|
* getpwnam() only recognises the current user: there is nobody else to look
|
|
* up, and inventing entries for arbitrary names would make "~someone" resolve
|
|
* to a directory that does not exist.
|
|
*/
|
|
|
|
static char pw_name_buf[64];
|
|
static char pw_dir_buf[128];
|
|
|
|
static struct passwd *fill_passwd(void)
|
|
{
|
|
static struct passwd pw;
|
|
int len = (int) _mtk_syscall2(MTK_SYS_GETUSER,
|
|
(long) pw_name_buf,
|
|
(long) sizeof(pw_name_buf));
|
|
|
|
if (len <= 0 || pw_name_buf[0] == '\0')
|
|
strcpy(pw_name_buf, "user");
|
|
pw_name_buf[sizeof(pw_name_buf) - 1] = '\0';
|
|
|
|
snprintf(pw_dir_buf, sizeof(pw_dir_buf), "0:/users/%s", pw_name_buf);
|
|
|
|
pw.pw_name = pw_name_buf;
|
|
pw.pw_passwd = (char *) "";
|
|
pw.pw_uid = MONTAUK_UID;
|
|
pw.pw_gid = MONTAUK_GID;
|
|
pw.pw_gecos = pw_name_buf;
|
|
pw.pw_dir = pw_dir_buf;
|
|
pw.pw_shell = (char *) "";
|
|
|
|
return &pw;
|
|
}
|
|
|
|
/*
|
|
* Called first thing from main() (patches/0001-montauk-startup.patch).
|
|
*
|
|
* MontaukOS starts every process with an EMPTY environment -- SYS_SPAWN
|
|
* transfers nothing, so environ is bare no matter who launched git. Without
|
|
* HOME, git silently skips the per-user config: ~/.gitconfig never resolves,
|
|
* so `git config --global user.email ...` has nowhere to write, and the
|
|
* repository config becomes the only place a setting can live. Pointing HOME
|
|
* at the session user's directory is what makes --global work.
|
|
*
|
|
* This is deliberately NOT an __attribute__((constructor)): programs linked
|
|
* with programs/link.ld get no .init_array section (the script does not name
|
|
* one, so the linker drops it), which means constructors silently never run.
|
|
* A call from main() is the only reliable hook.
|
|
*
|
|
* An inherited HOME, should the environment ever start carrying one, wins.
|
|
*/
|
|
void montauk_startup(void)
|
|
{
|
|
if (getenv("HOME"))
|
|
return;
|
|
setenv("HOME", fill_passwd()->pw_dir, 0);
|
|
}
|
|
|
|
struct passwd *getpwuid(uid_t uid)
|
|
{
|
|
if (uid != MONTAUK_UID) {
|
|
errno = 0; /* "no such user", not an error, per POSIX */
|
|
return NULL;
|
|
}
|
|
return fill_passwd();
|
|
}
|
|
|
|
struct passwd *getpwnam(const char *name)
|
|
{
|
|
struct passwd *pw = fill_passwd();
|
|
|
|
if (!name || strcmp(name, pw->pw_name) != 0) {
|
|
errno = 0;
|
|
return NULL;
|
|
}
|
|
return pw;
|
|
}
|
|
|
|
struct group *getgrnam(const char *name)
|
|
{
|
|
(void) name;
|
|
errno = 0;
|
|
return NULL;
|
|
}
|
|
|
|
struct group *getgrgid(gid_t gid)
|
|
{
|
|
(void) gid;
|
|
errno = 0;
|
|
return NULL;
|
|
}
|
|
|
|
/* ==== Filesystem =====================================================
|
|
*
|
|
* Symlinks have no representation in the MontaukOS VFS (the ramdisk drops
|
|
* them, ext2 support is read-side only for them), so these fail rather than
|
|
* silently creating something else. git's core.symlinks=false path handles
|
|
* the failure by writing a regular file whose contents are the link target.
|
|
*/
|
|
|
|
int symlink(const char *target, const char *linkpath)
|
|
{
|
|
(void) target; (void) linkpath;
|
|
errno = EPERM;
|
|
return -1;
|
|
}
|
|
|
|
ssize_t readlink(const char *path, char *buf, size_t bufsiz)
|
|
{
|
|
(void) path; (void) buf; (void) bufsiz;
|
|
errno = EINVAL; /* "not a symbolic link" -- and nothing here is */
|
|
return -1;
|
|
}
|
|
|
|
int link(const char *oldpath, const char *newpath)
|
|
{
|
|
(void) oldpath; (void) newpath;
|
|
errno = EPERM; /* no hard links; callers fall back to copying */
|
|
return -1;
|
|
}
|
|
|
|
int chown(const char *path, uid_t owner, gid_t group)
|
|
{
|
|
(void) path; (void) owner; (void) group;
|
|
errno = EPERM;
|
|
return -1;
|
|
}
|
|
|
|
int lchown(const char *path, uid_t owner, gid_t group)
|
|
{
|
|
(void) path; (void) owner; (void) group;
|
|
errno = EPERM;
|
|
return -1;
|
|
}
|
|
|
|
int fchown(int fd, uid_t owner, gid_t group)
|
|
{
|
|
(void) fd; (void) owner; (void) group;
|
|
errno = EPERM;
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* fsync()/fdatasync() report success without doing anything, which is the one
|
|
* shim here that claims more than it delivers. Failing instead is worse: git
|
|
* treats a failed fsync as a fatal error and aborts the write, so every
|
|
* commit would fail. Data does reach the disk -- the kernel writes through
|
|
* its block cache -- but there is no per-descriptor barrier, so ordering
|
|
* across a power loss is not guaranteed. SYS_FS_SYNC (whole-filesystem
|
|
* flush, used by shutdown) is the closest thing that exists.
|
|
*/
|
|
int fsync(int fd)
|
|
{
|
|
(void) fd;
|
|
return 0;
|
|
}
|
|
|
|
int fdatasync(int fd)
|
|
{
|
|
(void) fd;
|
|
return 0;
|
|
}
|
|
|
|
/* ==== Terminal input =================================================
|
|
*
|
|
* MontaukOS has no /dev/tty, so compat/terminal.c compiles its fallback
|
|
* branch, and every interactive prompt git makes -- passphrases included --
|
|
* arrives here.
|
|
*
|
|
* THE INPUT IS ECHOED. The libc reads stdin through SYS_GETCHAR and echoes
|
|
* each character itself; there is no line discipline to turn that off (see
|
|
* tcsetattr below, which is why it cannot help). Nothing in this port prompts
|
|
* for a secret today, since there are no network transports and no credential
|
|
* helper, but anything added later must not assume this hides what is typed.
|
|
*/
|
|
char *getpass(const char *prompt)
|
|
{
|
|
static char buf[256];
|
|
size_t len;
|
|
|
|
if (prompt && *prompt) {
|
|
fputs(prompt, stderr);
|
|
fflush(stderr);
|
|
}
|
|
|
|
if (!fgets(buf, sizeof(buf), stdin))
|
|
return NULL;
|
|
|
|
len = strlen(buf);
|
|
while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
|
|
buf[--len] = '\0';
|
|
|
|
return buf;
|
|
}
|
|
|
|
/* ==== exec ===========================================================
|
|
*
|
|
* execl()/execlp() collect their variadic arguments into an argv and defer to
|
|
* the libc's execv()/execvp(). Those fail with ENOSYS -- MontaukOS spawns new
|
|
* processes (SYS_SPAWN) rather than replacing the current image -- so these
|
|
* fail too, which is what the one caller (`git help`, launching a man viewer)
|
|
* is prepared for.
|
|
*
|
|
* MAX_EXEC_ARGV is generous for that caller; a longer list is rejected
|
|
* outright rather than silently truncated into a different command.
|
|
*/
|
|
|
|
#define MAX_EXEC_ARGV 64
|
|
|
|
static int collect_exec_argv(const char *arg, va_list ap,
|
|
const char *argv[], int max)
|
|
{
|
|
int argc = 0;
|
|
|
|
argv[argc++] = arg;
|
|
while (argc < max) {
|
|
const char *next = va_arg(ap, const char *);
|
|
|
|
argv[argc++] = next;
|
|
if (!next)
|
|
return argc;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int execl(const char *path, const char *arg, ...)
|
|
{
|
|
const char *argv[MAX_EXEC_ARGV];
|
|
va_list ap;
|
|
int argc;
|
|
|
|
va_start(ap, arg);
|
|
argc = collect_exec_argv(arg, ap, argv, MAX_EXEC_ARGV);
|
|
va_end(ap);
|
|
|
|
if (argc < 0) {
|
|
errno = E2BIG;
|
|
return -1;
|
|
}
|
|
return execv(path, (char *const *) argv);
|
|
}
|
|
|
|
int execlp(const char *file, const char *arg, ...)
|
|
{
|
|
const char *argv[MAX_EXEC_ARGV];
|
|
va_list ap;
|
|
int argc;
|
|
|
|
va_start(ap, arg);
|
|
argc = collect_exec_argv(arg, ap, argv, MAX_EXEC_ARGV);
|
|
va_end(ap);
|
|
|
|
if (argc < 0) {
|
|
errno = E2BIG;
|
|
return -1;
|
|
}
|
|
return execvp(file, (char *const *) argv);
|
|
}
|
|
|
|
/* ==== Signals ========================================================
|
|
*
|
|
* sigaction() over signal(). MontaukOS delivers SIGINT and nothing else, and
|
|
* has no per-process signal mask, so sa_mask and sa_flags (including
|
|
* SA_RESTART) are accepted and ignored -- there are no restartable syscalls
|
|
* to interrupt. The sigset_t operations maintain a bitmask that nothing
|
|
* reads; they exist so callers that build a mask before installing a handler
|
|
* compile and behave predictably.
|
|
*/
|
|
|
|
int sigemptyset(sigset_t *set)
|
|
{
|
|
if (set)
|
|
*set = 0;
|
|
return 0;
|
|
}
|
|
|
|
int sigfillset(sigset_t *set)
|
|
{
|
|
if (set)
|
|
*set = ~(sigset_t)0;
|
|
return 0;
|
|
}
|
|
|
|
int sigaddset(sigset_t *set, int signum)
|
|
{
|
|
if (!set || signum <= 0 || signum >= (int)(8 * sizeof(sigset_t))) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
*set |= (sigset_t)1 << signum;
|
|
return 0;
|
|
}
|
|
|
|
int sigdelset(sigset_t *set, int signum)
|
|
{
|
|
if (!set || signum <= 0 || signum >= (int)(8 * sizeof(sigset_t))) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
*set &= ~((sigset_t)1 << signum);
|
|
return 0;
|
|
}
|
|
|
|
int sigismember(const sigset_t *set, int signum)
|
|
{
|
|
if (!set || signum <= 0 || signum >= (int)(8 * sizeof(sigset_t))) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
return (*set & ((sigset_t)1 << signum)) != 0;
|
|
}
|
|
|
|
int sigaction(int signum, const struct sigaction *act, struct sigaction *old)
|
|
{
|
|
sighandler_t prev;
|
|
|
|
if (act) {
|
|
prev = signal(signum, act->sa_handler);
|
|
} else {
|
|
/* Query only: read the handler back by reinstalling it. */
|
|
prev = signal(signum, SIG_DFL);
|
|
if (prev != SIG_ERR)
|
|
signal(signum, prev);
|
|
}
|
|
|
|
if (prev == SIG_ERR)
|
|
return -1;
|
|
|
|
if (old) {
|
|
memset(old, 0, sizeof(*old));
|
|
old->sa_handler = prev;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* No signal mask exists to block anything with; report an empty one. */
|
|
int sigprocmask(int how, const sigset_t *set, sigset_t *old)
|
|
{
|
|
(void) how; (void) set;
|
|
if (old)
|
|
*old = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* ==== Time ===========================================================
|
|
*
|
|
* The libc's localtime()/gmtime() use a static buffer; copy it out. Safe
|
|
* here because the port is built NO_PTHREADS.
|
|
*/
|
|
|
|
struct tm *localtime_r(const time_t *timep, struct tm *result)
|
|
{
|
|
struct tm *tmp = localtime(timep);
|
|
|
|
if (!tmp || !result)
|
|
return NULL;
|
|
*result = *tmp;
|
|
return result;
|
|
}
|
|
|
|
struct tm *gmtime_r(const time_t *timep, struct tm *result)
|
|
{
|
|
struct tm *tmp = gmtime(timep);
|
|
|
|
if (!tmp || !result)
|
|
return NULL;
|
|
*result = *tmp;
|
|
return result;
|
|
}
|
|
|
|
char *ctime_r(const time_t *timep, char *buf)
|
|
{
|
|
char *s = ctime(timep);
|
|
|
|
if (!s || !buf)
|
|
return NULL;
|
|
strcpy(buf, s); /* caller supplies the POSIX-required 26 bytes */
|
|
return buf;
|
|
}
|
|
|
|
char *asctime_r(const struct tm *tm, char *buf)
|
|
{
|
|
char *s = asctime(tm);
|
|
|
|
if (!s || !buf)
|
|
return NULL;
|
|
strcpy(buf, s);
|
|
return buf;
|
|
}
|
|
|
|
/* ==== Terminal =======================================================
|
|
*
|
|
* There is no line discipline to query or configure: the libc reads stdin a
|
|
* character at a time through SYS_GETCHAR and echoes it itself. tcgetattr
|
|
* hands back a zeroed struct and tcsetattr accepts whatever it is given,
|
|
* because git treats a tcgetattr failure as "this is not a terminal" -- which
|
|
* would disable interactive prompting altogether -- and dies on some
|
|
* tcsetattr failures.
|
|
*
|
|
* The practical consequence: echo cannot be turned off, so a passphrase typed
|
|
* at a git prompt is visible. Nothing in this port prompts for one today
|
|
* (there are no network transports and no credential helper).
|
|
*/
|
|
|
|
int tcgetattr(int fd, struct termios *t)
|
|
{
|
|
if (!isatty(fd)) {
|
|
errno = ENOTTY;
|
|
return -1;
|
|
}
|
|
if (t)
|
|
memset(t, 0, sizeof(*t));
|
|
return 0;
|
|
}
|
|
|
|
int tcsetattr(int fd, int actions, const struct termios *t)
|
|
{
|
|
(void) actions; (void) t;
|
|
if (!isatty(fd)) {
|
|
errno = ENOTTY;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* The only ioctl git issues is TIOCGWINSZ, and MontaukOS answers that one
|
|
* directly through SYS_TERMSIZE, so the progress meter and `git column` get
|
|
* the real terminal width instead of the 80-column fallback. Every other
|
|
* request fails.
|
|
*/
|
|
int ioctl(int fd, unsigned long request, ...)
|
|
{
|
|
(void) fd;
|
|
|
|
if (request == TIOCGWINSZ) {
|
|
va_list ap;
|
|
struct winsize *ws;
|
|
int cols = 0, rows = 0;
|
|
|
|
va_start(ap, request);
|
|
ws = va_arg(ap, struct winsize *);
|
|
va_end(ap);
|
|
|
|
if (!ws) {
|
|
errno = EFAULT;
|
|
return -1;
|
|
}
|
|
|
|
mtk_termsize(&cols, &rows);
|
|
if (cols <= 0 || rows <= 0) {
|
|
errno = ENOTTY;
|
|
return -1;
|
|
}
|
|
|
|
ws->ws_col = (unsigned short) cols;
|
|
ws->ws_row = (unsigned short) rows;
|
|
ws->ws_xpixel = 0;
|
|
ws->ws_ypixel = 0;
|
|
return 0;
|
|
}
|
|
|
|
errno = ENOTTY;
|
|
return -1;
|
|
}
|
|
|
|
/* ==== poll ===========================================================
|
|
*
|
|
* Only ever called on the pipe ends of a spawned sub-process, and MontaukOS
|
|
* has neither pipe() nor fork(), so this is unreachable in practice. It
|
|
* reports every descriptor ready rather than failing, so that a caller which
|
|
* does get here proceeds to the read() that reports the real error instead of
|
|
* spinning.
|
|
*/
|
|
int poll(struct pollfd *fds, nfds_t nfds, int timeout)
|
|
{
|
|
nfds_t i;
|
|
|
|
(void) timeout;
|
|
|
|
if (!fds)
|
|
return 0;
|
|
|
|
for (i = 0; i < nfds; i++)
|
|
fds[i].revents = fds[i].events;
|
|
|
|
return (int) nfds;
|
|
}
|
|
|
|
/* ==== Sockets ========================================================
|
|
*
|
|
* MontaukOS TCP lives behind IPC handles (montauk::socket), not file
|
|
* descriptors, and git hands transport descriptors to sub-processes. Until
|
|
* something bridges the two, every call fails with ENOSYS; `git clone
|
|
* git://...` reports that it cannot connect. Local paths are unaffected.
|
|
*/
|
|
|
|
#define SOCKET_STUB_BODY do { errno = ENOSYS; return -1; } while (0)
|
|
|
|
int socket(int domain, int type, int protocol)
|
|
{
|
|
(void) domain; (void) type; (void) protocol;
|
|
SOCKET_STUB_BODY;
|
|
}
|
|
|
|
int connect(int fd, const struct sockaddr *addr, socklen_t len)
|
|
{
|
|
(void) fd; (void) addr; (void) len;
|
|
SOCKET_STUB_BODY;
|
|
}
|
|
|
|
int bind(int fd, const struct sockaddr *addr, socklen_t len)
|
|
{
|
|
(void) fd; (void) addr; (void) len;
|
|
SOCKET_STUB_BODY;
|
|
}
|
|
|
|
int listen(int fd, int backlog)
|
|
{
|
|
(void) fd; (void) backlog;
|
|
SOCKET_STUB_BODY;
|
|
}
|
|
|
|
int accept(int fd, struct sockaddr *addr, socklen_t *len)
|
|
{
|
|
(void) fd; (void) addr; (void) len;
|
|
SOCKET_STUB_BODY;
|
|
}
|
|
|
|
int shutdown(int fd, int how)
|
|
{
|
|
(void) fd; (void) how;
|
|
SOCKET_STUB_BODY;
|
|
}
|
|
|
|
int setsockopt(int fd, int level, int name, const void *val, socklen_t len)
|
|
{
|
|
(void) fd; (void) level; (void) name; (void) val; (void) len;
|
|
SOCKET_STUB_BODY;
|
|
}
|
|
|
|
int getsockopt(int fd, int level, int name, void *val, socklen_t *len)
|
|
{
|
|
(void) fd; (void) level; (void) name; (void) val; (void) len;
|
|
SOCKET_STUB_BODY;
|
|
}
|
|
|
|
int getsockname(int fd, struct sockaddr *addr, socklen_t *len)
|
|
{
|
|
(void) fd; (void) addr; (void) len;
|
|
SOCKET_STUB_BODY;
|
|
}
|
|
|
|
int getpeername(int fd, struct sockaddr *addr, socklen_t *len)
|
|
{
|
|
(void) fd; (void) addr; (void) len;
|
|
SOCKET_STUB_BODY;
|
|
}
|
|
|
|
ssize_t send(int fd, const void *buf, size_t len, int flags)
|
|
{
|
|
(void) fd; (void) buf; (void) len; (void) flags;
|
|
errno = ENOSYS;
|
|
return -1;
|
|
}
|
|
|
|
ssize_t recv(int fd, void *buf, size_t len, int flags)
|
|
{
|
|
(void) fd; (void) buf; (void) len; (void) flags;
|
|
errno = ENOSYS;
|
|
return -1;
|
|
}
|
|
|
|
/* ==== Name resolution ================================================
|
|
*
|
|
* DNS is resolved inside the kernel network stack; no resolver interface is
|
|
* exposed to userspace. Lookups therefore fail, which git reports as an
|
|
* unresolvable host.
|
|
*/
|
|
|
|
int h_errno;
|
|
|
|
struct hostent *gethostbyname(const char *name)
|
|
{
|
|
(void) name;
|
|
h_errno = HOST_NOT_FOUND;
|
|
return NULL;
|
|
}
|
|
|
|
struct servent *getservbyname(const char *name, const char *proto)
|
|
{
|
|
(void) name; (void) proto;
|
|
return NULL;
|
|
}
|
|
|
|
int getaddrinfo(const char *node, const char *service,
|
|
const struct addrinfo *hints, struct addrinfo **res)
|
|
{
|
|
(void) node; (void) service; (void) hints;
|
|
if (res)
|
|
*res = NULL;
|
|
return EAI_FAIL;
|
|
}
|
|
|
|
void freeaddrinfo(struct addrinfo *res)
|
|
{
|
|
(void) res;
|
|
}
|
|
|
|
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
|
char *host, socklen_t hostlen,
|
|
char *serv, socklen_t servlen, int flags)
|
|
{
|
|
(void) sa; (void) salen; (void) host; (void) hostlen;
|
|
(void) serv; (void) servlen; (void) flags;
|
|
return EAI_FAIL;
|
|
}
|
|
|
|
const char *gai_strerror(int errcode)
|
|
{
|
|
(void) errcode;
|
|
return "name resolution is not available on MontaukOS";
|
|
}
|
|
|
|
in_addr_t inet_addr(const char *cp)
|
|
{
|
|
(void) cp;
|
|
return INADDR_NONE;
|
|
}
|
|
|
|
char *inet_ntoa(struct in_addr in)
|
|
{
|
|
static char buf[16];
|
|
unsigned int a = (unsigned int) in.s_addr;
|
|
|
|
snprintf(buf, sizeof(buf), "%u.%u.%u.%u",
|
|
a & 0xff, (a >> 8) & 0xff, (a >> 16) & 0xff, (a >> 24) & 0xff);
|
|
return buf;
|
|
}
|
|
|
|
/* ==== uname ==========================================================
|
|
*
|
|
* Static answers: there is no kernel interface for the release/version
|
|
* strings. Feeds `git version --build-options` and `git bugreport`.
|
|
*/
|
|
int uname(struct utsname *buf)
|
|
{
|
|
if (!buf) {
|
|
errno = EFAULT;
|
|
return -1;
|
|
}
|
|
memset(buf, 0, sizeof(*buf));
|
|
strcpy(buf->sysname, "MontaukOS");
|
|
strcpy(buf->nodename, "montauk");
|
|
strcpy(buf->release, "");
|
|
strcpy(buf->version, "");
|
|
strcpy(buf->machine, "x86_64");
|
|
return 0;
|
|
}
|