feat: ports - git port
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
compat/ -- what MontaukOS does not have, and what git gets instead.
|
||||
|
||||
Two kinds of file live here.
|
||||
|
||||
HEADER OVERLAYS use #include_next to pull in the Montauk libc's own header
|
||||
and then add what git needs on top. They are found first because -I compat
|
||||
precedes the libc include path.
|
||||
|
||||
unistd.h identity (getuid/geteuid/...), symlink/readlink/link,
|
||||
chown, fsync, process groups, execl/execlp, getpass, alarm
|
||||
signal.h the sigaction() family and NSIG
|
||||
time.h localtime_r/gmtime_r/ctime_r/asctime_r
|
||||
sys/stat.h S_ISUID/S_ISGID/S_ISVTX and the S_IF* type constants
|
||||
sys/time.h ITIMER_* selectors
|
||||
sys/types.h the BSD aliases (u_char, u_int, ...) the ISC-derived
|
||||
inet_ntop/inet_pton want
|
||||
|
||||
STANDALONE HEADERS are for things the libc has no header for at all:
|
||||
|
||||
poll.h struct pollfd; the implementation reports everything ready
|
||||
pwd.h struct passwd, answered from the session user
|
||||
grp.h struct group; every lookup fails (no group database)
|
||||
termios.h accepted and ignored; there is no line discipline
|
||||
netdb.h resolver types; every lookup fails
|
||||
syslog.h discards (only `git daemon` logs, and it is not built)
|
||||
sys/socket.h BSD socket API; every call fails with ENOSYS
|
||||
sys/un.h struct sockaddr_un, for the type only
|
||||
sys/ioctl.h TIOCGWINSZ, which IS implemented (SYS_TERMSIZE)
|
||||
sys/utsname.h uname(), static MontaukOS strings
|
||||
sys/resource.h getrlimit says "unlimited"; getrusage fails
|
||||
sys/statvfs.h fails; no filesystem statistics syscall
|
||||
netinet/in.h, netinet/tcp.h, arpa/inet.h address types and byte order
|
||||
|
||||
THESE FILES ARE NOT SHIMS. They are the port's own code:
|
||||
|
||||
montauk-paths.h force-included into every translation unit, ahead of
|
||||
git-compat-util.h, so git recognises "0:/path" as an
|
||||
absolute path. Without it git treats every MontaukOS
|
||||
absolute path as relative and prepends the cwd to it.
|
||||
montauk-ownership.h also force-included: answers git's safe.directory
|
||||
"is this repository mine?" check with yes. MontaukOS
|
||||
stores no per-file owner, so the default lstat-vs-geteuid
|
||||
comparison is false for every directory on the system.
|
||||
Read the header before changing it -- it says what this
|
||||
gives up once the OS grows real ownership.
|
||||
montauk-init.h declares montauk_startup(), called from main() by the
|
||||
patch series.
|
||||
|
||||
montauk-compat.c the implementations, each commented with what it
|
||||
really does. Built into libgitcompat.a, which sits on
|
||||
the link line ahead of liblibc.a.
|
||||
|
||||
THE RULE followed throughout: a shim either does the real thing, or fails
|
||||
with an errno git already knows how to report. Nothing silently pretends to
|
||||
have done work it did not do -- with one deliberate exception, fsync(),
|
||||
which reports success because git treats a failed fsync as fatal and would
|
||||
abort every commit. That one is called out at its definition.
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* <arpa/inet.h> for the MontaukOS git port.
|
||||
*
|
||||
* inet_ntop/inet_pton are not declared here: the port builds with
|
||||
* NO_INET_NTOP=1 / NO_INET_PTON=1, so git compiles its own portable versions
|
||||
* (compat/inet_ntop.c, compat/inet_pton.c) and declares them itself in
|
||||
* git-compat-util.h. Everything else an address needs comes from
|
||||
* <netinet/in.h>.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_ARPA_INET_H_
|
||||
#define _MONTAUK_GIT_ARPA_INET_H_
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
in_addr_t inet_addr(const char *cp);
|
||||
char *inet_ntoa(struct in_addr in);
|
||||
|
||||
#endif /* _MONTAUK_GIT_ARPA_INET_H_ */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* <grp.h> stub for the MontaukOS git port.
|
||||
*
|
||||
* Included by git-compat-util.h for the group lookups in daemon.c and
|
||||
* setup.c's shared-repository handling. MontaukOS has no group database, so
|
||||
* every lookup fails and git falls back to its "no group" paths.
|
||||
*
|
||||
* Implementation in montauk-compat.c.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_GRP_H_
|
||||
#define _MONTAUK_GIT_GRP_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct group {
|
||||
char *gr_name;
|
||||
char *gr_passwd;
|
||||
gid_t gr_gid;
|
||||
char **gr_mem;
|
||||
};
|
||||
|
||||
struct group *getgrnam(const char *name);
|
||||
struct group *getgrgid(gid_t gid);
|
||||
|
||||
#endif /* _MONTAUK_GIT_GRP_H_ */
|
||||
@@ -0,0 +1,764 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* montauk-init.h -- one-time startup fixups, called from main().
|
||||
*
|
||||
* See montauk_startup() in montauk-compat.c for what it does and why it
|
||||
* cannot be an __attribute__((constructor)): programs linked with
|
||||
* programs/link.ld have no .init_array section, so constructors never run.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_INIT_H_
|
||||
#define _MONTAUK_GIT_INIT_H_
|
||||
|
||||
void montauk_startup(void);
|
||||
|
||||
#endif /* _MONTAUK_GIT_INIT_H_ */
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* montauk-ownership.h -- answer git's "is this repository mine?" question.
|
||||
*
|
||||
* FORCE-INCLUDED into every translation unit (-include, see the port
|
||||
* Makefile), because it has to win the #ifndef guard in git-compat-util.h.
|
||||
*
|
||||
* git's safe.directory check exists because on a multi-user system a
|
||||
* repository owned by somebody else can attack you the moment you run git in
|
||||
* it -- its config names hooks, pagers and external diff commands that would
|
||||
* run as you. The default implementation answers by comparing the owner
|
||||
* reported by lstat() against geteuid().
|
||||
*
|
||||
* Neither side of that comparison means anything on MontaukOS. The VFS stores
|
||||
* no owner at all -- stat() zero-fills st_uid, on the ramdisk, on ext2 and on
|
||||
* FAT32 alike -- and there is one session user, so the compat layer reports a
|
||||
* single fixed uid for everybody (see montauk-compat.c). The comparison is
|
||||
* therefore 0 == 1000, false for EVERY repository: unpatched, git refuses to
|
||||
* work in any directory on the system, which is what
|
||||
*
|
||||
* fatal: detected dubious ownership in repository at '0:/users/...'
|
||||
*
|
||||
* was. Picking the uid to match the zero from stat() would only paper over it,
|
||||
* and would mean claiming to be root.
|
||||
*
|
||||
* So answer honestly: every file belongs to the one user, and the check has
|
||||
* nothing to distinguish. This is the same seam Windows uses for the same
|
||||
* reason (compat/mingw.h defines is_path_owned_by_current_sid here).
|
||||
*
|
||||
* WHAT THIS GIVES UP: nothing today, and something real later. When MontaukOS
|
||||
* grows per-file ownership, this must go back to comparing owners -- otherwise
|
||||
* git in another user's repository will run that repository's hooks as you.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_OWNERSHIP_H_
|
||||
#define _MONTAUK_GIT_OWNERSHIP_H_
|
||||
|
||||
/*
|
||||
* A macro, not a function: this header is force-included before anything
|
||||
* declares struct strbuf, so the report parameter cannot be named in a
|
||||
* prototype here. Both arguments are still evaluated-as-void so an unused
|
||||
* variable at a call site does not start warning.
|
||||
*/
|
||||
#define is_path_owned_by_current_user(path, report) \
|
||||
((void)(path), (void)(report), 1)
|
||||
|
||||
#endif /* _MONTAUK_GIT_OWNERSHIP_H_ */
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* montauk-paths.h -- teach git what an absolute path looks like on MontaukOS.
|
||||
*
|
||||
* FORCE-INCLUDED into every translation unit (-include, see the port
|
||||
* Makefile), because it has to win the #ifndef guards in git-compat-util.h.
|
||||
*
|
||||
* MontaukOS paths are drive-prefixed: "0:/users/dan/repo". getcwd() returns
|
||||
* one of those, and the kernel's path resolver (kernel/src/Api/Path.hpp)
|
||||
* accepts three forms -- "N:/abs", "/abs" (the current drive's root) and
|
||||
* "rel/ative" against the process cwd.
|
||||
*
|
||||
* Without this header git's is_absolute_path() is just is_dir_sep(path[0]),
|
||||
* so every MontaukOS absolute path reads as RELATIVE and git helpfully
|
||||
* prepends the cwd to it: "0:/users/dan/repo/0:/users/dan/repo". That breaks
|
||||
* setup_git_directory(), real_path() and every worktree path it stores.
|
||||
*
|
||||
* The fix reuses git's existing Windows abstraction rather than inventing
|
||||
* one: has_dos_drive_prefix / skip_dos_drive_prefix / offset_1st_component
|
||||
* are exactly the hooks the DOS "C:/" case goes through, and a MontaukOS
|
||||
* drive differs only in being a digit run rather than a letter. The bodies
|
||||
* below mirror compat/win32/path-utils.c, minus the UNC handling, which has
|
||||
* no MontaukOS equivalent.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_PATHS_H_
|
||||
#define _MONTAUK_GIT_PATHS_H_
|
||||
|
||||
/*
|
||||
* "12:" as well as "0:" -- ParseDrivePrefix() accepts a multi-digit drive
|
||||
* number, so this must too, or a two-digit drive would silently be treated
|
||||
* as a relative path.
|
||||
*/
|
||||
static inline int montauk_has_drive_prefix(const char *path)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (!path)
|
||||
return 0;
|
||||
while (path[i] >= '0' && path[i] <= '9')
|
||||
i++;
|
||||
return i > 0 && path[i] == ':';
|
||||
}
|
||||
#define has_dos_drive_prefix montauk_has_drive_prefix
|
||||
|
||||
static inline int montauk_skip_drive_prefix(char **path)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (!montauk_has_drive_prefix(*path))
|
||||
return 0;
|
||||
|
||||
while ((*path)[i] >= '0' && (*path)[i] <= '9')
|
||||
i++;
|
||||
*path += i + 1; /* the digits and the ':' */
|
||||
return 1;
|
||||
}
|
||||
#define skip_dos_drive_prefix montauk_skip_drive_prefix
|
||||
|
||||
/*
|
||||
* Length of the leading "root" of the path: the drive prefix plus one
|
||||
* separator if present. Mirrors win32_offset_1st_component().
|
||||
*/
|
||||
static inline int montauk_offset_1st_component(const char *path)
|
||||
{
|
||||
char *pos = (char *)path;
|
||||
|
||||
montauk_skip_drive_prefix(&pos);
|
||||
return (int)(pos - path) + (*pos == '/');
|
||||
}
|
||||
#define offset_1st_component montauk_offset_1st_component
|
||||
|
||||
#endif /* _MONTAUK_GIT_PATHS_H_ */
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* <netdb.h> for the MontaukOS git port.
|
||||
*
|
||||
* The port builds NO_IPV6=1, so git resolves names through gethostbyname()
|
||||
* and getservbyname() rather than getaddrinfo(). Both fail here: MontaukOS
|
||||
* resolves DNS inside the kernel network stack, and no userspace resolver
|
||||
* interface is exposed. `git clone git://host/repo` therefore reports that it
|
||||
* cannot look up the host. getaddrinfo() is still declared because
|
||||
* git-compat-util.h references the types unconditionally.
|
||||
*
|
||||
* Implementations in montauk-compat.c.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_NETDB_H_
|
||||
#define _MONTAUK_GIT_NETDB_H_
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
struct hostent {
|
||||
char *h_name;
|
||||
char **h_aliases;
|
||||
int h_addrtype;
|
||||
int h_length;
|
||||
char **h_addr_list;
|
||||
};
|
||||
|
||||
#define h_addr h_addr_list[0]
|
||||
|
||||
struct servent {
|
||||
char *s_name;
|
||||
char **s_aliases;
|
||||
int s_port;
|
||||
char *s_proto;
|
||||
};
|
||||
|
||||
struct addrinfo {
|
||||
int ai_flags;
|
||||
int ai_family;
|
||||
int ai_socktype;
|
||||
int ai_protocol;
|
||||
socklen_t ai_addrlen;
|
||||
struct sockaddr *ai_addr;
|
||||
char *ai_canonname;
|
||||
struct addrinfo *ai_next;
|
||||
};
|
||||
|
||||
#define AI_PASSIVE 0x0001
|
||||
#define AI_CANONNAME 0x0002
|
||||
#define AI_NUMERICHOST 0x0004
|
||||
#define AI_NUMERICSERV 0x0400
|
||||
|
||||
#define NI_MAXHOST 1025
|
||||
#define NI_MAXSERV 32
|
||||
#define NI_NUMERICHOST 1
|
||||
#define NI_NUMERICSERV 2
|
||||
#define NI_NAMEREQD 8
|
||||
|
||||
#define EAI_NONAME -2
|
||||
#define EAI_AGAIN -3
|
||||
#define EAI_FAIL -4
|
||||
#define EAI_FAMILY -6
|
||||
#define EAI_SYSTEM -11
|
||||
|
||||
#define HOST_NOT_FOUND 1
|
||||
#define TRY_AGAIN 2
|
||||
#define NO_RECOVERY 3
|
||||
#define NO_DATA 4
|
||||
|
||||
extern int h_errno;
|
||||
|
||||
struct hostent *gethostbyname(const char *name);
|
||||
struct servent *getservbyname(const char *name, const char *proto);
|
||||
|
||||
int getaddrinfo(const char *node, const char *service,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
void freeaddrinfo(struct addrinfo *res);
|
||||
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
||||
char *host, socklen_t hostlen,
|
||||
char *serv, socklen_t servlen, int flags);
|
||||
const char *gai_strerror(int errcode);
|
||||
|
||||
#endif /* _MONTAUK_GIT_NETDB_H_ */
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* <netinet/in.h> for the MontaukOS git port.
|
||||
*
|
||||
* Address types only. See compat/sys/socket.h for why nothing here connects
|
||||
* to anything yet. The byte-order helpers are real (x86-64 is little-endian,
|
||||
* so they are byte swaps).
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_NETINET_IN_H_
|
||||
#define _MONTAUK_GIT_NETINET_IN_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
typedef uint16_t in_port_t;
|
||||
typedef uint32_t in_addr_t;
|
||||
|
||||
struct in_addr {
|
||||
in_addr_t s_addr;
|
||||
};
|
||||
|
||||
struct in6_addr {
|
||||
union {
|
||||
uint8_t __u6_addr8[16];
|
||||
uint16_t __u6_addr16[8];
|
||||
uint32_t __u6_addr32[4];
|
||||
} __in6_u;
|
||||
};
|
||||
|
||||
#define s6_addr __in6_u.__u6_addr8
|
||||
#define s6_addr16 __in6_u.__u6_addr16
|
||||
#define s6_addr32 __in6_u.__u6_addr32
|
||||
|
||||
struct sockaddr_in {
|
||||
sa_family_t sin_family;
|
||||
in_port_t sin_port;
|
||||
struct in_addr sin_addr;
|
||||
unsigned char sin_zero[8];
|
||||
};
|
||||
|
||||
struct sockaddr_in6 {
|
||||
sa_family_t sin6_family;
|
||||
in_port_t sin6_port;
|
||||
uint32_t sin6_flowinfo;
|
||||
struct in6_addr sin6_addr;
|
||||
uint32_t sin6_scope_id;
|
||||
};
|
||||
|
||||
#define INADDR_ANY ((in_addr_t)0x00000000)
|
||||
#define INADDR_LOOPBACK ((in_addr_t)0x7f000001)
|
||||
#define INADDR_NONE ((in_addr_t)0xffffffff)
|
||||
|
||||
#define INET_ADDRSTRLEN 16
|
||||
#define INET6_ADDRSTRLEN 46
|
||||
|
||||
#define IPPROTO_IP 0
|
||||
#define IPPROTO_TCP 6
|
||||
#define IPPROTO_UDP 17
|
||||
|
||||
static inline uint16_t htons(uint16_t x) { return __builtin_bswap16(x); }
|
||||
static inline uint16_t ntohs(uint16_t x) { return __builtin_bswap16(x); }
|
||||
static inline uint32_t htonl(uint32_t x) { return __builtin_bswap32(x); }
|
||||
static inline uint32_t ntohl(uint32_t x) { return __builtin_bswap32(x); }
|
||||
|
||||
#endif /* _MONTAUK_GIT_NETINET_IN_H_ */
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* <netinet/tcp.h> for the MontaukOS git port.
|
||||
*
|
||||
* Socket option names only; setsockopt() itself fails here. See
|
||||
* compat/sys/socket.h.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_NETINET_TCP_H_
|
||||
#define _MONTAUK_GIT_NETINET_TCP_H_
|
||||
|
||||
#define TCP_NODELAY 1
|
||||
#define TCP_KEEPIDLE 4
|
||||
#define TCP_KEEPINTVL 5
|
||||
#define TCP_KEEPCNT 6
|
||||
|
||||
#endif /* _MONTAUK_GIT_NETINET_TCP_H_ */
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* <poll.h> for the MontaukOS git port.
|
||||
*
|
||||
* git polls only descriptors it created itself with pipe() -- the stdout and
|
||||
* stderr of a spawned sub-process (run-command.c's pump loop, sideband
|
||||
* demultiplexing). MontaukOS has neither pipe() nor fork(), so those code
|
||||
* paths are unreachable at runtime; this header exists so they compile, and
|
||||
* the implementation reports every descriptor ready so that a caller which
|
||||
* somehow gets here makes progress into the read() that reports the real
|
||||
* error, instead of spinning in the poll loop forever.
|
||||
*
|
||||
* git's own compat/poll (NO_POLL=1) is not used: it is written against
|
||||
* select() and <sys/select.h>, neither of which exists here.
|
||||
*
|
||||
* Implementation in montauk-compat.c.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_POLL_H_
|
||||
#define _MONTAUK_GIT_POLL_H_
|
||||
|
||||
typedef unsigned long nfds_t;
|
||||
|
||||
struct pollfd {
|
||||
int fd;
|
||||
short events;
|
||||
short revents;
|
||||
};
|
||||
|
||||
#define POLLIN 0x001
|
||||
#define POLLPRI 0x002
|
||||
#define POLLOUT 0x004
|
||||
#define POLLERR 0x008
|
||||
#define POLLHUP 0x010
|
||||
#define POLLNVAL 0x020
|
||||
|
||||
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
|
||||
#endif /* _MONTAUK_GIT_POLL_H_ */
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* <pwd.h> for the MontaukOS git port.
|
||||
*
|
||||
* MontaukOS has users (0:/users/<name>, see montauk/user.h) but no
|
||||
* /etc/passwd database and no numeric uid model -- everything runs as the
|
||||
* session user. getpwuid()/getpwnam() therefore answer from the current
|
||||
* session rather than from a database, which is exactly what git wants them
|
||||
* for: the fallback identity in ident.c ("You gotta tell me who you are") and
|
||||
* the home directory behind "~".
|
||||
*
|
||||
* Implementation in montauk-compat.c.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_PWD_H_
|
||||
#define _MONTAUK_GIT_PWD_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct passwd {
|
||||
char *pw_name;
|
||||
char *pw_passwd;
|
||||
uid_t pw_uid;
|
||||
gid_t pw_gid;
|
||||
char *pw_gecos;
|
||||
char *pw_dir;
|
||||
char *pw_shell;
|
||||
};
|
||||
|
||||
struct passwd *getpwuid(uid_t uid);
|
||||
struct passwd *getpwnam(const char *name);
|
||||
|
||||
#endif /* _MONTAUK_GIT_PWD_H_ */
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* <signal.h> overlay for the MontaukOS git port.
|
||||
*
|
||||
* The libc supplies signal()/raise()/kill() and the signal numbers; this adds
|
||||
* the sigaction() family that git uses in a handful of places (fast-import's
|
||||
* SIGUSR1 checkpoint handler, sigchain's SIGPIPE and SIGINT handling).
|
||||
*
|
||||
* MontaukOS delivers only SIGINT, and has no signal masks: a handler is
|
||||
* either installed or it is not. sigaction() below is therefore a wrapper
|
||||
* around signal() that honours sa_handler and ignores sa_mask and sa_flags,
|
||||
* and the sigset_t operations manipulate a plain bitmask that nothing
|
||||
* consults. See montauk-compat.c.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_SIGNAL_H_
|
||||
#define _MONTAUK_GIT_SIGNAL_H_
|
||||
|
||||
#include_next <signal.h>
|
||||
|
||||
/* One past the highest signal number the libc names (SIGSTOP, 19). */
|
||||
#define NSIG 32
|
||||
|
||||
typedef unsigned long sigset_t;
|
||||
|
||||
struct sigaction {
|
||||
sighandler_t sa_handler;
|
||||
sigset_t sa_mask;
|
||||
int sa_flags;
|
||||
void (*sa_restorer)(void);
|
||||
};
|
||||
|
||||
#define SA_RESTART 0x10000000
|
||||
#define SA_NOCLDSTOP 0x00000001
|
||||
#define SA_SIGINFO 0x00000004
|
||||
#define SA_NODEFER 0x40000000
|
||||
#define SA_RESETHAND 0x80000000
|
||||
|
||||
#define SIG_BLOCK 0
|
||||
#define SIG_UNBLOCK 1
|
||||
#define SIG_SETMASK 2
|
||||
|
||||
int sigemptyset(sigset_t *set);
|
||||
int sigfillset(sigset_t *set);
|
||||
int sigaddset(sigset_t *set, int signum);
|
||||
int sigdelset(sigset_t *set, int signum);
|
||||
int sigismember(const sigset_t *set, int signum);
|
||||
int sigaction(int signum, const struct sigaction *act, struct sigaction *old);
|
||||
int sigprocmask(int how, const sigset_t *set, sigset_t *old);
|
||||
|
||||
#endif /* _MONTAUK_GIT_SIGNAL_H_ */
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* <sys/ioctl.h> for the MontaukOS git port.
|
||||
*
|
||||
* git uses exactly one ioctl: TIOCGWINSZ, to find the terminal width for
|
||||
* `git column`, the progress meter and `git help -a`. MontaukOS has no ioctl
|
||||
* syscall, so the request fails and git falls back to its default 80 columns.
|
||||
*
|
||||
* Implementation in montauk-compat.c.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_SYS_IOCTL_H_
|
||||
#define _MONTAUK_GIT_SYS_IOCTL_H_
|
||||
|
||||
#define TIOCGWINSZ 0x5413
|
||||
|
||||
struct winsize {
|
||||
unsigned short ws_row;
|
||||
unsigned short ws_col;
|
||||
unsigned short ws_xpixel;
|
||||
unsigned short ws_ypixel;
|
||||
};
|
||||
|
||||
int ioctl(int fd, unsigned long request, ...);
|
||||
|
||||
#endif /* _MONTAUK_GIT_SYS_IOCTL_H_ */
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* <sys/resource.h> stub for the MontaukOS git port.
|
||||
*
|
||||
* Reached only through git-compat-util.h's unconditional include and
|
||||
* trace2's resource accounting, which is compiled out without getrusage.
|
||||
* MontaukOS keeps no per-process resource accounting, so getrlimit reports
|
||||
* "unlimited" and everything else fails.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_SYS_RESOURCE_H_
|
||||
#define _MONTAUK_GIT_SYS_RESOURCE_H_
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define RLIMIT_NOFILE 7
|
||||
|
||||
typedef unsigned long rlim_t;
|
||||
|
||||
#define RLIM_INFINITY (~(rlim_t)0)
|
||||
|
||||
struct rlimit {
|
||||
rlim_t rlim_cur;
|
||||
rlim_t rlim_max;
|
||||
};
|
||||
|
||||
struct rusage {
|
||||
struct timeval ru_utime;
|
||||
struct timeval ru_stime;
|
||||
long ru_maxrss;
|
||||
long ru_minflt;
|
||||
long ru_majflt;
|
||||
long ru_inblock;
|
||||
long ru_oublock;
|
||||
long ru_nvcsw;
|
||||
long ru_nivcsw;
|
||||
};
|
||||
|
||||
#define RUSAGE_SELF 0
|
||||
|
||||
static inline int getrlimit(int resource, struct rlimit *rlim)
|
||||
{
|
||||
(void) resource;
|
||||
if (rlim) {
|
||||
rlim->rlim_cur = RLIM_INFINITY;
|
||||
rlim->rlim_max = RLIM_INFINITY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int setrlimit(int resource, const struct rlimit *rlim)
|
||||
{
|
||||
(void) resource; (void) rlim;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int getrusage(int who, struct rusage *usage)
|
||||
{
|
||||
(void) who; (void) usage;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* _MONTAUK_GIT_SYS_RESOURCE_H_ */
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* <sys/socket.h> for the MontaukOS git port.
|
||||
*
|
||||
* MontaukOS does have TCP -- the kernel exposes it as IPC handles through
|
||||
* montauk::socket(), not as BSD descriptors -- but nothing bridges the two
|
||||
* into the fd space that read()/write() use, and git's transports assume a
|
||||
* descriptor it can hand to a sub-process. Until that bridge exists, every
|
||||
* call here fails with ENOSYS, which surfaces as "unable to connect" from
|
||||
* `git clone git://...` rather than as a crash.
|
||||
*
|
||||
* That leaves the local transports -- init, add, commit, log, diff, and
|
||||
* clone/fetch/push against a path on disk -- which are what this port is for.
|
||||
*
|
||||
* Implementations in montauk-compat.c.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_SYS_SOCKET_H_
|
||||
#define _MONTAUK_GIT_SYS_SOCKET_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef unsigned int socklen_t;
|
||||
typedef unsigned short sa_family_t;
|
||||
|
||||
#define AF_UNSPEC 0
|
||||
#define AF_UNIX 1
|
||||
#define AF_LOCAL 1
|
||||
#define AF_INET 2
|
||||
#define AF_INET6 10
|
||||
|
||||
#define PF_UNSPEC AF_UNSPEC
|
||||
#define PF_UNIX AF_UNIX
|
||||
#define PF_INET AF_INET
|
||||
#define PF_INET6 AF_INET6
|
||||
|
||||
#define SOCK_STREAM 1
|
||||
#define SOCK_DGRAM 2
|
||||
|
||||
#define SOL_SOCKET 1
|
||||
|
||||
#define SO_REUSEADDR 2
|
||||
#define SO_ERROR 4
|
||||
#define SO_KEEPALIVE 9
|
||||
#define SO_LINGER 13
|
||||
|
||||
#define SHUT_RD 0
|
||||
#define SHUT_WR 1
|
||||
#define SHUT_RDWR 2
|
||||
|
||||
#define MSG_PEEK 2
|
||||
|
||||
struct sockaddr {
|
||||
sa_family_t sa_family;
|
||||
char sa_data[14];
|
||||
};
|
||||
|
||||
/* Large enough for sockaddr_in6, aligned like the real thing. */
|
||||
struct sockaddr_storage {
|
||||
sa_family_t ss_family;
|
||||
unsigned long __ss_align;
|
||||
char __ss_padding[112];
|
||||
};
|
||||
|
||||
struct linger {
|
||||
int l_onoff;
|
||||
int l_linger;
|
||||
};
|
||||
|
||||
int socket(int domain, int type, int protocol);
|
||||
int connect(int fd, const struct sockaddr *addr, socklen_t len);
|
||||
int bind(int fd, const struct sockaddr *addr, socklen_t len);
|
||||
int listen(int fd, int backlog);
|
||||
int accept(int fd, struct sockaddr *addr, socklen_t *len);
|
||||
int shutdown(int fd, int how);
|
||||
int setsockopt(int fd, int level, int name, const void *val, socklen_t len);
|
||||
int getsockopt(int fd, int level, int name, void *val, socklen_t *len);
|
||||
int getsockname(int fd, struct sockaddr *addr, socklen_t *len);
|
||||
int getpeername(int fd, struct sockaddr *addr, socklen_t *len);
|
||||
ssize_t send(int fd, const void *buf, size_t len, int flags);
|
||||
ssize_t recv(int fd, void *buf, size_t len, int flags);
|
||||
|
||||
#endif /* _MONTAUK_GIT_SYS_SOCKET_H_ */
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* <sys/stat.h> overlay for the MontaukOS git port.
|
||||
*
|
||||
* The libc header comes in through #include_next; this only adds the mode
|
||||
* bits it leaves out. They are not idle definitions:
|
||||
*
|
||||
* S_ISUID builtin/fast-import.c borrows it as a private in-memory flag
|
||||
* (NO_DELTA), so it must exist even though no file ever carries
|
||||
* it on MontaukOS.
|
||||
* S_ISGID setup.c uses it for shared-repository directory modes.
|
||||
* S_ISVTX referenced when normalising modes read from an index.
|
||||
*
|
||||
* The S_IF* type constants below round out the set for the same reason: git
|
||||
* masks against them. MontaukOS never reports a fifo, socket or block device
|
||||
* from stat(), and the libc's S_ISFIFO/S_ISSOCK/S_ISBLK are hard-coded false
|
||||
* to say exactly that -- they are deliberately left alone here.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_SYS_STAT_H_
|
||||
#define _MONTAUK_GIT_SYS_STAT_H_
|
||||
|
||||
#include_next <sys/stat.h>
|
||||
|
||||
#ifndef S_ISUID
|
||||
#define S_ISUID 04000
|
||||
#endif
|
||||
#ifndef S_ISGID
|
||||
#define S_ISGID 02000
|
||||
#endif
|
||||
#ifndef S_ISVTX
|
||||
#define S_ISVTX 01000
|
||||
#endif
|
||||
|
||||
#ifndef S_IFIFO
|
||||
#define S_IFIFO 0010000
|
||||
#endif
|
||||
#ifndef S_IFBLK
|
||||
#define S_IFBLK 0060000
|
||||
#endif
|
||||
#ifndef S_IFSOCK
|
||||
#define S_IFSOCK 0140000
|
||||
#endif
|
||||
|
||||
#endif /* _MONTAUK_GIT_SYS_STAT_H_ */
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* <sys/statvfs.h> stub for the MontaukOS git port.
|
||||
*
|
||||
* git calls statvfs() in one place: fsmonitor's "is this a network
|
||||
* filesystem" probe, which this port does not build. MontaukOS exposes no
|
||||
* filesystem statistics syscall, so the call fails and callers take their
|
||||
* "unknown filesystem" branch.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_SYS_STATVFS_H_
|
||||
#define _MONTAUK_GIT_SYS_STATVFS_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
typedef unsigned long fsblkcnt_t;
|
||||
typedef unsigned long fsfilcnt_t;
|
||||
|
||||
struct statvfs {
|
||||
unsigned long f_bsize;
|
||||
unsigned long f_frsize;
|
||||
fsblkcnt_t f_blocks;
|
||||
fsblkcnt_t f_bfree;
|
||||
fsblkcnt_t f_bavail;
|
||||
fsfilcnt_t f_files;
|
||||
fsfilcnt_t f_ffree;
|
||||
fsfilcnt_t f_favail;
|
||||
unsigned long f_fsid;
|
||||
unsigned long f_flag;
|
||||
unsigned long f_namemax;
|
||||
unsigned long f_type;
|
||||
};
|
||||
|
||||
static inline int statvfs(const char *path, struct statvfs *buf)
|
||||
{
|
||||
(void) path; (void) buf;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int fstatvfs(int fd, struct statvfs *buf)
|
||||
{
|
||||
(void) fd; (void) buf;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* _MONTAUK_GIT_SYS_STATVFS_H_ */
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* <sys/time.h> overlay for the MontaukOS git port.
|
||||
*
|
||||
* Adds the ITIMER_* selectors on top of the libc header. MontaukOS has no
|
||||
* interval timers, so the port is built NO_SETITIMER=1 and NO_STRUCT_ITIMERVAL=1
|
||||
* -- git supplies its own struct itimerval and a setitimer() that returns
|
||||
* success without arming anything. The selectors still have to exist, because
|
||||
* the call sites name them (builtin/log.c's early-output timer, progress.c).
|
||||
*
|
||||
* What that costs: `git log`'s half-second early-output nudge never fires, so
|
||||
* the first commits appear when the traversal produces them rather than on a
|
||||
* timer. Nothing depends on it for correctness.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_SYS_TIME_H_
|
||||
#define _MONTAUK_GIT_SYS_TIME_H_
|
||||
|
||||
#include_next <sys/time.h>
|
||||
|
||||
#define ITIMER_REAL 0
|
||||
#define ITIMER_VIRTUAL 1
|
||||
#define ITIMER_PROF 2
|
||||
|
||||
#endif /* _MONTAUK_GIT_SYS_TIME_H_ */
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* <sys/types.h> overlay for the MontaukOS git port.
|
||||
*
|
||||
* Adds the historical BSD type aliases on top of the libc header. git's
|
||||
* compat/inet_ntop.c and compat/inet_pton.c come from the ISC resolver and
|
||||
* are written in terms of u_char/u_int; both are compiled here because the
|
||||
* port sets NO_INET_NTOP=1 / NO_INET_PTON=1.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_SYS_TYPES_H_
|
||||
#define _MONTAUK_GIT_SYS_TYPES_H_
|
||||
|
||||
#include_next <sys/types.h>
|
||||
|
||||
typedef unsigned char u_char;
|
||||
typedef unsigned short u_short;
|
||||
typedef unsigned int u_int;
|
||||
typedef unsigned long u_long;
|
||||
|
||||
typedef char *caddr_t;
|
||||
|
||||
#endif /* _MONTAUK_GIT_SYS_TYPES_H_ */
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* <sys/un.h> for the MontaukOS git port.
|
||||
*
|
||||
* Included unconditionally by git-compat-util.h. The port builds with
|
||||
* NO_UNIX_SOCKETS=1, so nothing constructs one of these -- the type just has
|
||||
* to exist.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_SYS_UN_H_
|
||||
#define _MONTAUK_GIT_SYS_UN_H_
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
struct sockaddr_un {
|
||||
sa_family_t sun_family;
|
||||
char sun_path[108];
|
||||
};
|
||||
|
||||
#endif /* _MONTAUK_GIT_SYS_UN_H_ */
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* <sys/utsname.h> for the MontaukOS git port.
|
||||
*
|
||||
* Used by help.c for the "uname" lines of `git version --build-options` and
|
||||
* by the bugreport builtin. Answers static MontaukOS strings; there is no
|
||||
* kernel interface for the release/version fields yet.
|
||||
*
|
||||
* Implementation in montauk-compat.c.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_SYS_UTSNAME_H_
|
||||
#define _MONTAUK_GIT_SYS_UTSNAME_H_
|
||||
|
||||
struct utsname {
|
||||
char sysname[65];
|
||||
char nodename[65];
|
||||
char release[65];
|
||||
char version[65];
|
||||
char machine[65];
|
||||
};
|
||||
|
||||
int uname(struct utsname *buf);
|
||||
|
||||
#endif /* _MONTAUK_GIT_SYS_UTSNAME_H_ */
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* <syslog.h> stub for the MontaukOS git port.
|
||||
*
|
||||
* git-compat-util.h includes this unconditionally, but the only caller is
|
||||
* daemon.c (`git daemon`), which this port does not build -- there are no
|
||||
* sockets to serve on. The declarations exist so the include resolves; the
|
||||
* inline bodies discard everything, which is the honest behaviour on a system
|
||||
* with no system logger.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_SYSLOG_H_
|
||||
#define _MONTAUK_GIT_SYSLOG_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define LOG_EMERG 0
|
||||
#define LOG_ALERT 1
|
||||
#define LOG_CRIT 2
|
||||
#define LOG_ERR 3
|
||||
#define LOG_WARNING 4
|
||||
#define LOG_NOTICE 5
|
||||
#define LOG_INFO 6
|
||||
#define LOG_DEBUG 7
|
||||
|
||||
#define LOG_PID 0x01
|
||||
#define LOG_CONS 0x02
|
||||
#define LOG_NDELAY 0x08
|
||||
|
||||
#define LOG_DAEMON (3 << 3)
|
||||
#define LOG_USER (1 << 3)
|
||||
|
||||
static inline void openlog(const char *ident, int option, int facility)
|
||||
{
|
||||
(void) ident; (void) option; (void) facility;
|
||||
}
|
||||
|
||||
static inline void closelog(void) { }
|
||||
|
||||
static inline void syslog(int priority, const char *fmt, ...)
|
||||
{
|
||||
(void) priority; (void) fmt;
|
||||
}
|
||||
|
||||
#endif /* _MONTAUK_GIT_SYSLOG_H_ */
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* <termios.h> for the MontaukOS git port.
|
||||
*
|
||||
* compat/terminal.c uses tcgetattr/tcsetattr to turn off echo while reading a
|
||||
* passphrase, and to put the terminal in raw mode for single-keystroke reads
|
||||
* ("git add -p"). The MontaukOS terminal has no line discipline to configure:
|
||||
* the libc reads stdin through SYS_GETCHAR and does its own echoing.
|
||||
*
|
||||
* These calls therefore succeed and do nothing rather than failing, because
|
||||
* git treats a tcgetattr() failure as "not a terminal" and a tcsetattr()
|
||||
* failure as fatal in some paths. The visible consequence is that a typed
|
||||
* passphrase is echoed -- there is no credential helper in this port, so
|
||||
* nothing prompts for one yet.
|
||||
*
|
||||
* Implementation in montauk-compat.c.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_TERMIOS_H_
|
||||
#define _MONTAUK_GIT_TERMIOS_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef unsigned int tcflag_t;
|
||||
typedef unsigned char cc_t;
|
||||
typedef unsigned int speed_t;
|
||||
|
||||
#define NCCS 32
|
||||
|
||||
struct termios {
|
||||
tcflag_t c_iflag;
|
||||
tcflag_t c_oflag;
|
||||
tcflag_t c_cflag;
|
||||
tcflag_t c_lflag;
|
||||
cc_t c_line;
|
||||
cc_t c_cc[NCCS];
|
||||
speed_t c_ispeed;
|
||||
speed_t c_ospeed;
|
||||
};
|
||||
|
||||
/* Linux values, so code that masks bits it never applies still builds. */
|
||||
#define ECHO 0000010
|
||||
#define ECHONL 0000100
|
||||
#define ICANON 0000002
|
||||
#define ISIG 0000001
|
||||
#define IEXTEN 0100000
|
||||
#define IXON 0002000
|
||||
#define ICRNL 0000400
|
||||
#define OPOST 0000001
|
||||
|
||||
#define VMIN 6
|
||||
#define VTIME 5
|
||||
|
||||
#define TCSANOW 0
|
||||
#define TCSADRAIN 1
|
||||
#define TCSAFLUSH 2
|
||||
|
||||
int tcgetattr(int fd, struct termios *t);
|
||||
int tcsetattr(int fd, int actions, const struct termios *t);
|
||||
|
||||
#endif /* _MONTAUK_GIT_TERMIOS_H_ */
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* <time.h> overlay for the MontaukOS git port.
|
||||
*
|
||||
* Adds the reentrant conversions on top of the libc's own <time.h>. The libc
|
||||
* has localtime()/gmtime() with the usual static buffer; the _r forms below
|
||||
* are thin wrappers that copy that buffer out. Single-threaded programs see
|
||||
* no difference, and git is built NO_PTHREADS here, so there is no shared
|
||||
* buffer to race over.
|
||||
*
|
||||
* Implementations in montauk-compat.c.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_TIME_H_
|
||||
#define _MONTAUK_GIT_TIME_H_
|
||||
|
||||
#include_next <time.h>
|
||||
|
||||
struct tm *localtime_r(const time_t *timep, struct tm *result);
|
||||
struct tm *gmtime_r(const time_t *timep, struct tm *result);
|
||||
char *ctime_r(const time_t *timep, char *buf);
|
||||
char *asctime_r(const struct tm *tm, char *buf);
|
||||
|
||||
#endif /* _MONTAUK_GIT_TIME_H_ */
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* <unistd.h> overlay for the MontaukOS git port.
|
||||
*
|
||||
* The Montauk libc's own <unistd.h> is pulled in with #include_next -- this
|
||||
* file only ADDS the POSIX calls git expects and the libc does not declare.
|
||||
* Keeping them here rather than in the libc is deliberate: each one below is
|
||||
* either meaningless on MontaukOS today (there is one user, no groups, no
|
||||
* symlinks in the ramdisk) or needs kernel support that does not exist, and a
|
||||
* libc declaration would promise more than the system delivers.
|
||||
*
|
||||
* Implementations in montauk-compat.c, each documented there with what it
|
||||
* actually does.
|
||||
*/
|
||||
#ifndef _MONTAUK_GIT_UNISTD_H_
|
||||
#define _MONTAUK_GIT_UNISTD_H_
|
||||
|
||||
#include_next <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Identity. MontaukOS runs everything as the session user; these report a
|
||||
* single fixed non-root id so that git's "am I root?" and "does this repo
|
||||
* belong to me?" checks answer sensibly (yes, it is mine; no, I am not root). */
|
||||
uid_t getuid(void);
|
||||
uid_t geteuid(void);
|
||||
gid_t getgid(void);
|
||||
gid_t getegid(void);
|
||||
pid_t getppid(void);
|
||||
|
||||
int gethostname(char *name, size_t len);
|
||||
|
||||
/* No interval timers and no SIGALRM delivery, so this arms nothing.
|
||||
* upload-pack's idle timeout is its only caller here, and upload-pack cannot
|
||||
* run without sockets anyway. */
|
||||
unsigned int alarm(unsigned int seconds);
|
||||
|
||||
/* Symlinks. Neither the ramdisk nor the VFS represents them, so these fail;
|
||||
* git falls back to writing a regular file with the link text, which is what
|
||||
* core.symlinks=false already asks for. */
|
||||
int symlink(const char *target, const char *linkpath);
|
||||
ssize_t readlink(const char *path, char *buf, size_t bufsiz);
|
||||
int link(const char *oldpath, const char *newpath);
|
||||
|
||||
/* Ownership. No uid/gid model to change anything to. */
|
||||
int chown(const char *path, uid_t owner, gid_t group);
|
||||
int lchown(const char *path, uid_t owner, gid_t group);
|
||||
int fchown(int fd, uid_t owner, gid_t group);
|
||||
|
||||
/* Durability. The kernel writes through its block cache on close; there is no
|
||||
* per-descriptor flush syscall, so these report success rather than failing a
|
||||
* commit that is in fact on disk. See SYS_FS_SYNC for the whole-filesystem
|
||||
* flush that shutdown uses. */
|
||||
int fsync(int fd);
|
||||
int fdatasync(int fd);
|
||||
|
||||
int setsid(void);
|
||||
|
||||
/* Process groups. MontaukOS has none: a process is its own group, and a
|
||||
* program reading the terminal is by definition the foreground one. These
|
||||
* answer consistently so that progress.c's "am I in the foreground?" test
|
||||
* (tcgetpgrp(fd) == getpgid(0)) says yes and the progress meter is drawn. */
|
||||
pid_t getpgid(pid_t pid);
|
||||
pid_t getpgrp(void);
|
||||
pid_t tcgetpgrp(int fd);
|
||||
int setpgid(pid_t pid, pid_t pgid);
|
||||
|
||||
/* The variadic exec forms. The libc has execv/execvp (both of which fail:
|
||||
* MontaukOS spawns rather than execs), so these only repack their arguments
|
||||
* and hand them over -- they exist because `git help` calls execlp() to run
|
||||
* the man viewer. */
|
||||
int execl(const char *path, const char *arg, ...);
|
||||
int execlp(const char *file, const char *arg, ...);
|
||||
|
||||
/* Reads a line from the terminal. It CANNOT suppress echo -- see the
|
||||
* implementation. compat/terminal.c calls it for every interactive prompt on
|
||||
* a platform without /dev/tty, which is what MontaukOS is. */
|
||||
char *getpass(const char *prompt);
|
||||
|
||||
#endif /* _MONTAUK_GIT_UNISTD_H_ */
|
||||
Reference in New Issue
Block a user