Initial import

This commit is contained in:
Justine Tunney
2020-06-15 07:18:57 -07:00
commit c91b3c5006
14915 changed files with 590219 additions and 0 deletions

41
libc/calls/hefty/access.c Normal file
View File

@@ -0,0 +1,41 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/dce.h"
#include "libc/calls/internal.h"
#include "libc/calls/calls.h"
#include "libc/sysv/consts/at.h"
/**
* Checks if effective user can access path in particular ways.
*
* @param path is a filename or directory
* @param mode can be R_OK, W_OK, X_OK, F_OK
* @return 0 if ok, or -1 and sets errno
* @asyncsignalsafe
*/
int access(const char *path, int mode) {
if (!IsWindows()) {
return faccessat$sysv(AT_FDCWD, path, mode, 0);
} else {
char16_t path16[PATH_MAX];
if (mkntpath(path, path16) == -1) return -1;
return ntaccesscheck(path16, mode);
}
}

170
libc/calls/hefty/commandv.c Normal file
View File

@@ -0,0 +1,170 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/alg/alg.h"
#include "libc/bits/progn.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/conv/conv.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/mem/mem.h"
#include "libc/nt/ntdll.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/errfuns.h"
static struct critbit0 g_commandv;
textstartup static void g_commandv_init(void) {
__cxa_atexit(critbit0_clear, &g_commandv, NULL);
}
const void *const g_commandv_ctor[] initarray = {g_commandv_init};
static int accessexe(char pathname[hasatleast PATH_MAX], size_t len,
const char *ext) {
len = stpcpy(&pathname[len], ext) - &pathname[0];
if (access(pathname, X_OK) != -1) {
return len;
} else {
return -1;
}
}
static int accesscmd(char pathname[hasatleast PATH_MAX], const char *path,
const char *name, size_t namelen) { /* cf. %PATHEXT% */
int rc;
char *p;
bool hasdot;
size_t pathlen, len;
pathlen = strlen(path);
if (pathlen + 1 + namelen + 1 + 4 + 1 > PATH_MAX) return -1;
p = mempcpy(pathname, path, pathlen);
if (pathlen) *p++ = '/';
p = mempcpy(p, name, namelen);
len = p - &pathname[0];
hasdot = !!memchr(basename(name), '.', namelen);
if ((hasdot && (rc = accessexe(pathname, len, "")) != -1) ||
(!hasdot &&
((rc = accessexe(pathname, len, ".com")) != -1 ||
(IsWindows() && (rc = accessexe(pathname, len, ".exe")) != -1) ||
(!IsWindows() && (rc = accessexe(pathname, len, "")) != -1)))) {
return rc;
} else {
return -1;
}
}
static int searchcmdpath(char pathname[hasatleast PATH_MAX], const char *name,
size_t namelen) {
int rc;
char *ep, *path, *pathtok;
struct critbit0 deduplicate;
rc = -1;
pathtok = ep =
strdup(firstnonnull(getenv("PATH"), "/bin:/usr/local/bin:/usr/bin"));
memset(&deduplicate, 0, sizeof(deduplicate));
while ((path = strsep(&pathtok, IsWindows() ? ";" : ":"))) {
if (strchr(path, '=')) continue;
if (!critbit0_insert(&deduplicate, path)) continue;
if ((rc = accesscmd(pathname, path, name, namelen)) != -1) {
break;
}
}
critbit0_clear(&deduplicate);
free(ep);
return rc;
}
static char *mkcmdquery(const char *name, size_t namelen,
char scratch[hasatleast PATH_MAX]) {
char *p;
if (namelen + 1 + 1 > PATH_MAX) return NULL;
p = mempcpy(scratch, name, namelen);
*p++ = '=';
*p++ = '\0';
if (IsWindows() || IsXnu()) strntolower(scratch, namelen);
return &scratch[0];
}
static const char *cachecmd(const char *name, size_t namelen,
const char *pathname, size_t pathnamelen) {
size_t entrylen;
char *res, *entry;
if ((entry = malloc((entrylen = namelen + 1 + pathnamelen) + 1))) {
mkcmdquery(name, namelen, entry);
res = memcpy(&entry[namelen + 1], pathname, pathnamelen + 1);
critbit0_emplace(&g_commandv, entry, entrylen);
} else {
res = NULL;
}
return res;
}
static const char *getcmdcache(const char *name, size_t namelen,
char scratch[hasatleast PATH_MAX]) {
const char *entry;
if ((entry = critbit0_get(&g_commandv, mkcmdquery(name, namelen, scratch)))) {
return &entry[namelen + 1];
}
return NULL;
}
noinline static const char *findcmdpath(const char *name,
char pathname[hasatleast PATH_MAX]) {
char *p;
int rc, olderr;
size_t len;
olderr = errno;
if (!(len = strlen(name))) return PROGN(enoent(), NULL);
if (memchr(name, '=', len)) return PROGN(einval(), NULL);
if ((p = getcmdcache(name, len, pathname)) ||
(((IsWindows() &&
((rc = accesscmd(pathname, kNtSystemDirectory, name, len)) != -1 ||
(rc = accesscmd(pathname, kNtWindowsDirectory, name, len)) != -1)) ||
(rc = accesscmd(pathname, "", name, len)) != -1 ||
(!strpbrk(name, "/\\") &&
(rc = searchcmdpath(pathname, name, len)) != -1)) &&
(p = cachecmd(name, len, pathname, rc)))) {
errno = olderr;
return p;
} else {
return NULL;
}
}
/**
* Resolves pathname of executable.
*
* This does the same thing as `command -v` in bourne shell. Path
* lookups are cached for the lifetime of the process. Paths with
* multiple components will skip the resolution process. Undotted
* basenames get automatic .com and .exe suffix resolution on all
* platforms. Windows' system directories will always trump PATH.
*
* @return execve()'able path, or NULL w/ errno
* @errno ENOENT, EACCES, ENOMEM
* @see free(), execvpe()
*/
const char *commandv(const char *name) {
char pathname[PATH_MAX];
return findcmdpath(name, pathname);
}

View File

@@ -0,0 +1,190 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/bits/bits.h"
#include "libc/bits/progn.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/dirent.h"
#include "libc/dce.h"
#include "libc/mem/mem.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/win32finddata.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/dt.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
struct dirstream {
int64_t tell;
int64_t fd;
union {
struct {
unsigned buf_pos;
unsigned buf_end;
char buf[BUFSIZ];
};
struct {
struct dirent winent;
char __d_name[PATH_MAX];
bool isdone;
struct NtWin32FindData windata;
};
};
};
static textwindows noinline DIR *opendir$nt(const char *name) {
int len;
DIR *res;
char16_t name16[PATH_MAX];
if ((len = mkntpath(name, name16)) == -1) return NULL;
if (len + 2 + 1 > PATH_MAX) return PROGN(enametoolong(), NULL);
if (name16[len - 1] == u'/' || name16[len - 1] == u'\\') {
name16[--len] = u'\0';
}
name16[len++] = u'/';
name16[len++] = u'*';
name16[len] = u'\0';
if (!(res = calloc(1, sizeof(DIR)))) return NULL;
if ((res->fd = FindFirstFile(name16, &res->windata)) != -1) {
return res;
} else {
winerr();
free(res);
return NULL;
}
}
/**
* Opens directory so readdir() and closedir() may be called.
*
* @returns newly allocated DIR object, or NULL w/ errno
* @errors ENOENT, ENOTDIR, EACCES, EMFILE, ENFILE, ENOMEM
*/
DIR *opendir(const char *name) {
if (!IsWindows() && !IsXnu()) {
int fd;
DIR *res = NULL;
if ((fd = open(name, O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0)) != -1) {
if (!(res = fdopendir(fd))) close(fd);
}
return res;
} else if (IsWindows()) {
return opendir$nt(name);
} else {
enosys(); /* TODO(jart): Implement me! */
return NULL;
}
}
/**
* Creates directory object for file descriptor.
*
* @param fd gets owned by this function, if it succeeds
* @return new directory object, which must be freed by closedir(),
* or NULL w/ errno
* @errors ENOMEM and fd is closed
*/
DIR *fdopendir(int fd) {
if (!IsWindows() && !IsXnu()) {
DIR *dir;
if ((dir = calloc(1, sizeof(*dir)))) {
dir->fd = fd;
return dir;
}
} else {
enosys(); /* TODO(jart): Implement me! */
}
return NULL;
}
/**
* Reads next entry from DIR.
*
* This API doesn't define any particular ordering.
*
* @param dir is the object opendir() or fdopendir() returned
* @return next entry or NULL on end or error, which can be
* differentiated by setting errno to 0 beforehand
*/
struct dirent *readdir(DIR *dir) {
if (!IsWindows()) {
if (dir->buf_pos >= dir->buf_end) {
int rc;
if (!(rc = getdents(dir->fd, dir->buf, BUFSIZ)) || rc == -1) {
return NULL;
}
dir->buf_pos = 0;
dir->buf_end = rc;
}
/* TODO(jart): Check FreeBSD and OpenBSD again regarding this */
char *record = dir->buf + dir->buf_pos;
char *name = record + 8 + 8 + 2;
size_t namelen = strlen(name);
unsigned char dtype = name[namelen + 1];
memmove(name + 1, name, namelen + 1); /* shove forward one byte */
*name = dtype; /* is dirent d_type field */
struct dirent *ent = (void *)record;
dir->buf_pos += ent->d_reclen;
dir->tell = ent->d_off;
return ent;
} else {
if (dir->isdone) return NULL;
struct dirent *ent = &dir->winent;
memset(ent, 0, sizeof(*ent));
ent->d_reclen =
sizeof(*ent) +
tprecode16to8(ent->d_name, PATH_MAX, dir->windata.cFileName) + 1;
dir->isdone = FindNextFile(dir->fd, &dir->windata);
return ent;
}
}
/**
* Closes directory object returned by opendir().
* @return 0 on success or -1 w/ errno
*/
int closedir(DIR *dir) {
int rc;
if (dir) {
if (!IsWindows()) {
rc = close(dir->fd);
} else {
rc = FindClose(dir->fd) ? 0 : winerr();
}
free(dir);
} else {
rc = 0;
}
return rc;
}
/**
* Returns current byte offset into directory data.
*/
long telldir(DIR *dir) {
return dir->tell;
}
/**
* Returns file descriptor associated with DIR object.
*/
int dirfd(DIR *dir) {
return dir->fd;
}

47
libc/calls/hefty/execl.c Normal file
View File

@@ -0,0 +1,47 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/calls/hefty/mkvarargv.h"
#include "libc/calls/calls.h"
/**
* Executes program, with current environment.
*
* The current process is replaced with the executed one.
*
* @param prog will not be PATH searched, see execlp()
* @param arg[0] is the name of the program to run
* @param arg[1,n-2] optionally specify program arguments
* @param arg[n-1] is NULL
* @return doesn't return on success, otherwise -1 w/ errno
* @notasyncsignalsafe (TODO)
*/
int execl(const char *exe, const char *arg, ... /*, NULL*/) {
va_list va;
void *argv;
va_start(va, arg);
if ((argv = mkvarargv(arg, va))) {
execve(exe, argv, environ);
free(argv);
}
va_end(va);
return -1;
}

48
libc/calls/hefty/execle.c Normal file
View File

@@ -0,0 +1,48 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/mem/mem.h"
#include "libc/calls/hefty/mkvarargv.h"
#include "libc/calls/calls.h"
/**
* Executes program, with custom environment.
*
* The current process is replaced with the executed one.
*
* @param prog will not be PATH searched, see commandv()
* @param arg[0] is the name of the program to run
* @param arg[1,n-3] optionally specify program arguments
* @param arg[n-2] is NULL
* @param arg[n-1] is a pointer to a ["key=val",...,NULL] array
* @return doesn't return on success, otherwise -1 w/ errno
* @notasyncsignalsafe (TODO)
*/
int execle(const char *exe, const char *arg,
... /*, NULL, char *const envp[] */) {
va_list va;
void *argv;
va_start(va, arg);
if ((argv = mkvarargv(arg, va))) {
execve(exe, argv, va_arg(va, char *const *));
free(argv);
}
va_end(va);
return -1;
}

50
libc/calls/hefty/execlp.c Normal file
View File

@@ -0,0 +1,50 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/calls/hefty/mkvarargv.h"
#include "libc/calls/calls.h"
/**
* Executes program, with PATH search and current environment.
*
* The current process is replaced with the executed one.
*
* @param prog is program to launch (may be PATH searched)
* @param arg[0] is the name of the program to run
* @param arg[1,n-2] optionally specify program arguments
* @param arg[n-1] is NULL
* @return doesn't return on success, otherwise -1 w/ errno
* @notasyncsignalsafe
*/
int execlp(const char *prog, const char *arg, ... /*, NULL*/) {
char *exe;
if ((exe = commandv(prog))) {
va_list va;
void *argv;
va_start(va, arg);
if ((argv = mkvarargv(arg, va))) {
execve(exe, argv, environ);
free(argv);
}
va_end(va);
}
return -1;
}

29
libc/calls/hefty/execv.c Normal file
View File

@@ -0,0 +1,29 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/runtime/runtime.h"
#include "libc/calls/calls.h"
/**
* Replaces process with specific program, using default environment.
* @asyncsignalsafe
*/
int execv(const char *exe, char *const argv[]) {
return execve(exe, argv, environ);
}

View File

@@ -0,0 +1,55 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/hefty/internal.h"
#include "libc/calls/hefty/ntspawn.h"
#include "libc/calls/internal.h"
#include "libc/nt/enum/startf.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/startupinfo.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sock.h"
static textwindows int64_t passstdhand$nt(int fd) {
if (g_fds.p[fd].kind != kFdEmpty &&
!(g_fds.p[fd].flags &
(g_fds.p[fd].kind == kFdSocket ? SOCK_CLOEXEC : O_CLOEXEC))) {
return g_fds.p[fd].handle;
} else {
return -1;
}
}
textwindows int execve$nt(const char *program, char *const argv[],
char *const envp[]) {
struct NtStartupInfo startinfo;
memset(&startinfo, 0, sizeof(startinfo));
startinfo.cb = sizeof(struct NtStartupInfo);
startinfo.dwFlags = kNtStartfUsestdhandles;
startinfo.hStdInput = passstdhand$nt(STDIN_FILENO);
startinfo.hStdOutput = passstdhand$nt(STDOUT_FILENO);
startinfo.hStdError = passstdhand$nt(STDERR_FILENO);
if (ntspawn(program, argv, envp, NULL, NULL, true, 0, NULL, &startinfo,
NULL) != -1) {
for (;;) TerminateProcess(GetCurrentProcess(), 0);
}
return -1;
}

43
libc/calls/hefty/execve.c Normal file
View File

@@ -0,0 +1,43 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/hefty/internal.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
/**
* Replaces current process with program.
*
* @param program will not be PATH searched, see commandv()
* @param argv[0] is the name of the program to run
* @param argv[1,n-2] optionally specify program arguments
* @param argv[n-1] is NULL
* @param envp[0,n-2] specifies "foo=bar" environment variables
* @param envp[n-1] is NULL
* @return doesn't return, or -1 w/ errno
* @asyncsignalsafe
*/
int execve(const char *program, char *const argv[], char *const envp[]) {
if (!IsWindows()) {
return execve$sysv(program, argv, envp);
} else {
return execve$nt(program, argv, envp);
}
}

29
libc/calls/hefty/execvp.c Normal file
View File

@@ -0,0 +1,29 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/runtime/runtime.h"
#include "libc/calls/calls.h"
/**
* Replaces process, with path search, using default environment.
* @notasyncsignalsafe
*/
int execvp(const char *file, char *const argv[]) {
return execvpe(file, argv, environ);
}

View File

@@ -0,0 +1,40 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/mem/mem.h"
#include "libc/calls/calls.h"
/**
* Executes program, with path environment search.
*
* The current process is replaced with the executed one.
*
* @param prog is the program to launch
* @param argv is [file,argv₁..argvₙ₋₁,NULL]
* @param envp is ["key=val",...,NULL]
* @return doesn't return on success, otherwise -1 w/ errno
* @notasyncsignalsafe
*/
int execvpe(const char *prog, char *const argv[], char *const *envp) {
char *exe;
if ((exe = commandv(prog))) {
execve(exe, argv, envp);
}
return -1;
}

View File

@@ -0,0 +1,44 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Checks if effective user can access path in particular ways.
*
* @param dirfd is usually AT_FDCWD
* @param path is a filename or directory
* @param flags can be R_OK, W_OK, X_OK, F_OK
* @return 0 if ok, or -1 and sets errno
* @asyncsignalsafe
*/
int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
if (!IsWindows()) {
return faccessat$sysv(dirfd, path, mode, flags);
} else {
char16_t path16[PATH_MAX];
if (dirfd != AT_FDCWD || flags) return einval();
if (mkntpath(path, path16) == -1) return -1;
return ntaccesscheck(path16, mode);
}
}

View File

@@ -0,0 +1,78 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/alg/alg.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
static void *filecmp$mmap(int fd, size_t size) {
return size ? mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0) : NULL;
}
/**
* Compares contents of files with memcmp().
*
* @return ≤0, 0, or ≥0 based on comparison; or ≠0 on error, in which
* case we make our best effort to sift failing filenames rightward,
* and errno can be set to 0 beforehand to differentiate errors
*/
int filecmp(const char *pathname1, const char *pathname2) {
int res, olderr;
int fd1 = -1;
int fd2 = -1;
char *addr1 = MAP_FAILED;
char *addr2 = MAP_FAILED;
size_t size1 = 0;
size_t size2 = 0;
if ((fd1 = open(pathname1, O_RDONLY)) != -1 &&
(fd2 = open(pathname2, O_RDONLY)) != -1 &&
(size1 = getfiledescriptorsize(fd1)) != -1 &&
(size2 = getfiledescriptorsize(fd2)) != -1 &&
(addr1 = filecmp$mmap(fd1, size1)) != MAP_FAILED &&
(addr2 = filecmp$mmap(fd2, size2)) != MAP_FAILED) {
olderr = errno;
madvise(addr1, size1, MADV_WILLNEED | MADV_SEQUENTIAL);
madvise(addr2, size2, MADV_WILLNEED | MADV_SEQUENTIAL);
errno = olderr;
res = memcmp(addr1, addr2, min(size1, size2));
if (!res && size1 != size2) {
char kNul = '\0';
if (size1 > size2) {
res = cmpub(addr1 + size2, &kNul);
} else {
res = cmpub(addr2 + size1, &kNul);
}
}
} else {
res = cmpuq(&fd1, &fd2) | 1;
}
olderr = errno;
munmap(addr1, size1);
munmap(addr2, size2);
close(fd1);
close(fd2);
errno = olderr;
return res;
}

View File

@@ -0,0 +1,40 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/bits/safemacros.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/calls/calls.h"
#include "libc/sysv/errfuns.h"
/**
* Returns current working directory.
*
* If the PWD environment variable is set, that'll be returned (since
* it's faster than issuing a system call).
*
* @return pointer that must be free()'d, or NULL w/ errno
*/
nodiscard char *get_current_dir_name(void) {
char *buf, *res;
if ((res = getenv("PWD"))) return strdup(res);
if (!(buf = malloc(PATH_MAX))) return NULL;
if (!(res = (getcwd)(buf, PATH_MAX))) free(buf);
return res;
}

73
libc/calls/hefty/hefty.mk Normal file
View File

@@ -0,0 +1,73 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
#
# SYNOPSIS
#
# Cosmopolitan System Call Compatibility Layer
#
# DESCRIPTION
#
# This subpackage exports functions traditionally understood as system
# calls that Cosmopolitan needs to wrap in a nontrivial way, requiring
# things like dynamic memory allocation.
PKGS += LIBC_CALLS_HEFTY
LIBC_CALLS_HEFTY_ARTIFACTS += LIBC_CALLS_HEFTY_A
LIBC_CALLS_HEFTY = $(LIBC_CALLS_HEFTY_A_DEPS) $(LIBC_CALLS_HEFTY_A)
LIBC_CALLS_HEFTY_A = o/$(MODE)/libc/calls/hefty/hefty.a
LIBC_CALLS_HEFTY_A_FILES := $(wildcard libc/calls/hefty/*)
LIBC_CALLS_HEFTY_A_HDRS = $(filter %.h,$(LIBC_CALLS_HEFTY_A_FILES))
LIBC_CALLS_HEFTY_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_HEFTY_A_FILES))
LIBC_CALLS_HEFTY_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_HEFTY_A_FILES))
LIBC_CALLS_HEFTY_A_SRCS = \
$(LIBC_CALLS_HEFTY_A_SRCS_S) \
$(LIBC_CALLS_HEFTY_A_SRCS_C)
LIBC_CALLS_HEFTY_A_OBJS = \
$(LIBC_CALLS_HEFTY_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(LIBC_CALLS_HEFTY_A_SRCS_S:%.S=o/$(MODE)/%.o) \
$(LIBC_CALLS_HEFTY_A_SRCS_C:%.c=o/$(MODE)/%.o)
LIBC_CALLS_HEFTY_A_CHECKS = \
$(LIBC_CALLS_HEFTY_A).pkg \
$(LIBC_CALLS_HEFTY_A_HDRS:%=o/$(MODE)/%.ok)
LIBC_CALLS_HEFTY_A_DIRECTDEPS = \
LIBC_ALG \
LIBC_CONV \
LIBC_FMT \
LIBC_MEM \
LIBC_STR \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_CALLS \
LIBC_STUBS \
LIBC_NT_KERNELBASE \
LIBC_SYSV_CALLS \
LIBC_SYSV
LIBC_CALLS_HEFTY_A_DEPS := \
$(call uniq,$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x))))
$(LIBC_CALLS_HEFTY_A): \
libc/calls/hefty/ \
$(LIBC_CALLS_HEFTY_A).pkg \
$(LIBC_CALLS_HEFTY_A_OBJS)
$(LIBC_CALLS_HEFTY_A).pkg: \
$(LIBC_CALLS_HEFTY_A_OBJS) \
$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x)_A).pkg)
LIBC_CALLS_HEFTY_LIBS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)))
LIBC_CALLS_HEFTY_SRCS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_SRCS))
LIBC_CALLS_HEFTY_HDRS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_HDRS))
LIBC_CALLS_HEFTY_BINS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_BINS))
LIBC_CALLS_HEFTY_CHECKS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_CHECKS))
LIBC_CALLS_HEFTY_OBJS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_OBJS))
LIBC_CALLS_HEFTY_TESTS = $(foreach x,$(LIBC_CALLS_HEFTY_ARTIFACTS),$($(x)_TESTS))
$(LIBC_CALLS_HEFTY_OBJS): $(BUILD_FILES) libc/calls/hefty/hefty.mk
.PHONY: o/$(MODE)/libc/calls/hefty
o/$(MODE)/libc/calls/hefty: $(LIBC_CALLS_HEFTY_CHECKS)

View File

@@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int execve$nt(const char *, char *const[], char *const[]) hidden;
int spawnve$nt(unsigned, int[3], const char *, char *const[],
char *const[]) hidden;
int spawnve$sysv(unsigned, int[3], const char *, char *const[],
char *const[]) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_INTERNAL_H_ */

View File

@@ -0,0 +1,98 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/alg/arraylist2.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/ntspawn.h"
#include "libc/conv/conv.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/hascharacter.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/errfuns.h"
#define APPENDCHAR(C) \
do { \
if (mkntcmdline_append(&cmdline_p, &cmdline_i, &cmdline_n, C) == -1) { \
goto error; \
} \
} while (0)
static int mkntcmdline_append(char16_t **p, size_t *i, size_t *n, char16_t c) {
return APPEND(p, i, n, &c);
}
/**
* Converts System V argv to Windows-style command line.
*
* Escaping is performed and it's designed to round-trip with
* getdosargv() or getdosargv(). This function does NOT escape
* command interpreter syntax, e.g. $VAR (sh), %VAR% (cmd).
*
* @param argv is an a NULL-terminated array of UTF-8 strings
* @return freshly allocated lpCommandLine or NULL w/ errno
* @kudos Daniel Colascione for teaching how to quote
* @see libc/runtime/dosargv.c
*/
hidden textwindows nodiscard char16_t *mkntcmdline(char *const argv[]) {
wint_t wc;
size_t i, j;
char16_t cbuf[2];
char16_t *cmdline_p = NULL;
size_t cmdline_i = 0;
size_t cmdline_n = 0;
if (argv[0]) {
for (i = 0; argv[i]; ++i) {
if (i) APPENDCHAR(u' ');
bool needsquote = !argv[i] || !!argv[i][strcspn(argv[i], " \t\n\v\"")];
if (needsquote) APPENDCHAR(u'"');
for (j = 0;;) {
if (needsquote) {
int slashes = 0;
while (argv[i][j] && argv[i][j] == u'\\') slashes++, j++;
slashes <<= 1;
if (argv[i][j] == u'"') slashes++;
while (slashes--) APPENDCHAR(u'\\');
}
if (!argv[i][j]) break;
j += abs(tpdecode(&argv[i][j], &wc));
if (CONCAT(&cmdline_p, &cmdline_i, &cmdline_n, cbuf,
abs(pututf16(cbuf, ARRAYLEN(cbuf), wc, false))) == -1) {
goto error;
}
}
if (needsquote) APPENDCHAR(u'"');
}
APPENDCHAR(u'\0');
if (cmdline_i > CMD_MAX) {
e2big();
goto error;
}
} else {
einval();
}
return cmdline_p;
error:
free(cmdline_p);
return NULL;
}
#undef APPENDCHAR

View File

@@ -0,0 +1,69 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/alg/arraylist2.h"
#include "libc/calls/hefty/ntspawn.h"
#include "libc/conv/conv.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
/**
* Copies sorted environment variable block for Windows.
*
* This is designed to meet the requirements of CreateProcess().
*
* @param envp is an a NULL-terminated array of UTF-8 strings
* @return freshly allocated lpEnvironment or NULL w/ errno
*/
textwindows char16_t *mkntenvblock(char *const envp[]) {
size_t block_i = 0;
size_t block_n = 0;
char16_t *block_p = NULL;
size_t i, j;
if (!(envp = sortenvp(envp))) goto error;
const char16_t kNul = u'\0';
for (i = 0; envp[i]; ++i) {
unsigned consumed;
for (j = 0;; j += consumed) {
wint_t wc;
char16_t cbuf[2];
consumed = abs(tpdecode(&envp[i][j], &wc));
if (CONCAT(&block_p, &block_i, &block_n, cbuf,
abs(pututf16(cbuf, ARRAYLEN(cbuf), wc, false))) == -1) {
goto error;
}
if (!wc) break;
}
}
if (APPEND(&block_p, &block_i, &block_n, &kNul) == -1) {
goto error;
}
if (block_i > ENV_MAX) {
e2big();
goto error;
}
free(envp);
return block_p;
error:
free(envp);
free(block_p);
return NULL;
}

View File

@@ -0,0 +1,32 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_MKVARARGV_H_
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_MKVARARGV_H_
#include "libc/alg/arraylist2.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/**
* Turns variadic program arguments into array.
*
* This is a support function for execl(), execlp(), spawnl(), etc.
*
* @note type signatures are fubar for these functions
*/
forceinline void *mkvarargv(const char *arg1, va_list va) {
size_t i, n;
const char **p, *arg;
i = 0;
n = 0;
p = NULL;
arg = arg1;
do {
if (APPEND(&p, &i, &n, &arg) == -1) {
free(p);
return NULL;
}
} while ((arg = va_arg(va, const char *)));
return p;
}
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_MKVARARGV_H_ */

View File

@@ -0,0 +1,87 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/mem/mem.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/securityinformation.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/genericmapping.h"
#include "libc/nt/struct/privilegeset.h"
#include "libc/nt/struct/securitydescriptor.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/calls/internal.h"
#include "libc/calls/calls.h"
#include "libc/sysv/consts/ok.h"
/**
* Checks if current process has access to folder or file.
*
* @param flags can have R_OK, W_OK, X_OK, etc.
* @return 0 if authorized, or -1 w/ errno
* @kudos Aaron Ballman for teaching how to do this
* @see libc/sysv/consts.sh
*/
textwindows int ntaccesscheck(const char16_t *pathname, uint32_t flags) {
int rc;
bool32 result;
int64_t hToken, hImpersonatedToken;
uint32_t secsize, granted, privsize;
struct NtPrivilegeSet privileges;
struct NtGenericMapping mapping;
struct NtSecurityDescriptor security;
struct NtSecurityDescriptor *psecurity;
const uint32_t request = kNtOwnerSecurityInformation |
kNtGroupSecurityInformation |
kNtDaclSecurityInformation;
granted = 0;
result = false;
psecurity = &security;
secsize = sizeof(security);
privsize = sizeof(privileges);
memset(&privileges, 0, sizeof(privileges));
mapping.GenericRead = kNtFileGenericRead;
mapping.GenericWrite = kNtFileGenericWrite;
mapping.GenericExecute = kNtFileGenericExecute;
mapping.GenericAll = kNtFileAllAccess;
MapGenericMask(&flags, &mapping);
hImpersonatedToken = hToken = -1;
if ((GetFileSecurity(pathname, request, psecurity, 0, &secsize) ||
(GetLastError() == kNtErrorInsufficientBuffer &&
(psecurity = malloc(secsize)) &&
GetFileSecurity(pathname, request, psecurity, secsize, &secsize))) &&
OpenProcessToken(GetCurrentProcess(),
kNtTokenImpersonate | kNtTokenQuery | kNtTokenDuplicate |
kNtStandardRightsRead,
&hToken) &&
DuplicateToken(hToken, kNtSecurityImpersonation, &hImpersonatedToken) &&
AccessCheck(psecurity, hImpersonatedToken, flags, &mapping, &privileges,
&privsize, &granted, &result) &&
(result || flags == F_OK)) {
rc = 0;
} else {
rc = winerr();
}
free_s(&psecurity);
close(hImpersonatedToken);
close(hToken);
return rc;
}

View File

@@ -0,0 +1,88 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/alg/alg.h"
#include "libc/alg/arraylist.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/ntspawn.h"
#include "libc/calls/internal.h"
#include "libc/conv/conv.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/errfuns.h"
/**
* Spawns process on Windows NT.
*
* This function delegates to CreateProcess() with UTF-8 → UTF-16
* translation and argv escaping. Please note this will NOT escape
* command interpreter syntax.
*
* @param program will not be PATH searched, see commandv()
* @param argv[0] is the name of the program to run
* @param argv[1,n-2] optionally specifies program arguments
* @param argv[n-1] is NULL
* @param envp[𝟶,m-2] specifies "foo=bar" environment variables, which
* don't need to be passed in sorted order; however, this function
* goes faster the closer they are to sorted
* @param envp[m-1] is NULL
* @param bInheritHandles means handles already marked inheritable will
* be inherited; which, assuming the System V wrapper functions are
* being used, should mean (1) all files and sockets that weren't
* opened with O_CLOEXEC; and (2) all memory mappings
* @param opt_out_lpProcessInformation can be used to return process and
* thread IDs to parent, as well as open handles that need close()
* @return 0 on success, or -1 w/ errno
* @see spawnve() which abstracts this function
*/
textwindows int ntspawn(
const char *program, char *const argv[], char *const envp[],
struct NtSecurityAttributes *opt_lpProcessAttributes,
struct NtSecurityAttributes *opt_lpThreadAttributes, bool32 bInheritHandles,
uint32_t dwCreationFlags, const char16_t *opt_lpCurrentDirectory,
/*nodiscard*/ const struct NtStartupInfo *lpStartupInfo,
struct NtProcessInformation *opt_out_lpProcessInformation) {
int rc;
char16_t program16[PATH_MAX], *lpCommandLine, *lpEnvironment;
lpCommandLine = NULL;
lpEnvironment = NULL;
if (mkntpath(program, program16) != -1 &&
(lpCommandLine = mkntcmdline(argv)) &&
(lpEnvironment = mkntenvblock(envp))) {
if (CreateProcess(program16, lpCommandLine, opt_lpProcessAttributes,
opt_lpThreadAttributes, bInheritHandles,
dwCreationFlags | kNtCreateUnicodeEnvironment,
lpEnvironment, opt_lpCurrentDirectory, lpStartupInfo,
opt_out_lpProcessInformation)) {
rc = 0;
} else {
rc = winerr();
}
} else {
rc = -1;
}
free(lpCommandLine);
free(lpEnvironment);
return rc;
}

View File

@@ -0,0 +1,20 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct NtProcessInformation;
struct NtSecurityAttributes;
struct NtStartupInfo;
char **sortenvp(char *const[]) hidden nodiscard paramsnonnull();
char16_t *mkntcmdline(char *const[]) hidden nodiscard paramsnonnull();
char16_t *mkntenvblock(char *const[]) hidden nodiscard paramsnonnull();
int ntspawn(const char *, char *const[], char *const[],
struct NtSecurityAttributes *, struct NtSecurityAttributes *,
bool32, uint32_t, const char16_t *, const struct NtStartupInfo *,
struct NtProcessInformation *) paramsnonnull((1, 2, 3, 9)) hidden;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_NTSPAWN_H_ */

View File

@@ -0,0 +1,49 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/bits/safemacros.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/calls/calls.h"
/**
* Replaces tilde in path w/ user home folder.
*
* @param path is NULL propagating
* @return must be free()'d
*/
char *replaceuser(const char *path) {
char *res, *p;
const char *home;
size_t pathlen, homelen;
res = NULL;
if (path && *path++ == '~' && !isempty((home = getenv("HOME")))) {
while (*path == '/') path++;
pathlen = strlen(path);
homelen = strlen(home);
while (homelen && home[homelen - 1] == '/') homelen--;
if ((p = res = malloc(pathlen + 1 + homelen + 1))) {
p = mempcpy(p, home, homelen);
*p++ = '/';
memcpy(p, path, pathlen + 1);
}
}
return res;
}

89
libc/calls/hefty/slurp.c Normal file
View File

@@ -0,0 +1,89 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/alg/arraylist2.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/errno.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/o.h"
static size_t getfilesize(int fd) {
struct stat st;
st.st_size = 0;
fstat(fd, &st);
return st.st_size;
}
static size_t smudgefilesize(size_t size) {
return roundup(size, PAGESIZE) + PAGESIZE;
}
/**
* Reads entire file into memory.
*
* This function is fantastic for being lazy. It may waste space if the
* file is large, but it's implemented in a conscientious way that won't
* bomb the systemwide page cache. It means performance too, naturally.
*
* @return contents which must be free()'d or NULL w/ errno
*/
char *slurp(const char *path, size_t *opt_out_readlength) {
int fd;
ssize_t rc;
char *res, *p;
size_t i, n, got, want;
res = NULL;
if ((fd = open(path, O_RDONLY)) == -1) goto Failure;
n = getfilesize(fd);
/* TODO(jart): Fix this, it's totally broken */
if (!(res = valloc(smudgefilesize(n)))) goto Failure;
if (n > FRAMESIZE) fadvise(fd, 0, n, MADV_SEQUENTIAL);
i = 0;
for (;;) {
want = smudgefilesize(n - i);
TryAgain:
if ((rc = read(fd, &res[i], want)) == -1) {
if (errno == EINTR) goto TryAgain;
goto Failure;
}
got = (size_t)rc;
if (i + 1 >= n) {
if ((p = realloc(res, smudgefilesize((n += n >> 1))))) {
res = p;
} else {
goto Failure;
}
}
i += got;
if (got == 0) break;
if (got > want) abort();
}
if (opt_out_readlength) *opt_out_readlength = i;
res[i] = '\0';
close(fd);
return res;
Failure:
free(res);
close(fd);
return NULL;
}

View File

@@ -0,0 +1,68 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/alg/alg.h"
#include "libc/alg/arraylist.h"
#include "libc/calls/hefty/ntspawn.h"
#include "libc/dce.h"
#include "libc/nexgen32e/tinystrcmp.h"
#include "libc/str/str.h"
static int sortenvpcb(const char **a, const char **b) { return strcmp(*a, *b); }
static void slowsort(char **a, int n) {
size_t i, j;
const char *t;
for (i = 1; i < n; ++i) {
j = i;
t = a[i];
while (j > 0 && tinystrcmp(t, a[j - 1]) < 0) {
a[j] = a[j - 1];
--j;
}
a[j] = t;
}
}
/**
* Copies environment variable pointers and sorts them.
*
* This is useful for (a) binary searching; and (b) keeping the NT
* Executive happy, which wants strings to be ordered by UNICODE
* codepoint identifiers. That's basically what uint8_t comparisons on
* UTF8-encoded data gives us.
*
* @param envp is a NULL-terminated string array
* @return newly allocated sorted copy of envp pointer array
*/
hidden textwindows nodiscard char **sortenvp(char *const envp[]) {
size_t count = 0;
while (envp[count]) count++;
size_t bytesize = (count + 1) * sizeof(char *);
char **copy = malloc(bytesize);
if (copy) {
memcpy(copy, envp, bytesize);
if (IsTiny()) {
slowsort(copy, count);
} else {
qsort(copy, count, sizeof(char *), (void *)sortenvpcb);
}
}
return copy;
}

26
libc/calls/hefty/spawn.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_SPAWN_H_
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_SPAWN_H_
#define SPAWN_DETACH 1
#define SPAWN_TABULARASA 2
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
int spawnve(unsigned, int[3], const char *, char *const[], char *const[])
paramsnonnull((3, 4, 5));
int spawnl(unsigned, int[3], const char *, const char *, ...) nullterminated()
paramsnonnull((3, 4));
int spawnlp(unsigned, int[3], const char *, const char *, ...) nullterminated()
paramsnonnull((3, 4));
int spawnle(unsigned, int[3], const char *, const char *, ...)
nullterminated((1)) paramsnonnull((3, 4));
int spawnv(unsigned, int[3], const char *, char *const[]) paramsnonnull((3, 4));
int spawnvp(unsigned, int[3], const char *, char *const[])
paramsnonnull((3, 4));
int spawnvpe(unsigned, int[3], const char *, char *const[], char *const[])
paramsnonnull((3, 4, 5));
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_SPAWN_H_ */

49
libc/calls/hefty/spawnl.c Normal file
View File

@@ -0,0 +1,49 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/hefty/mkvarargv.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
/**
* Launches program, with current environment.
*
* @param stdiofds may optionally be passed to customize standard i/o
* @param stdiofds[𝑖] may be -1 to receive a pipe() fd
* @param prog is program to launch (may be PATH searched)
* @param arg[0] is the name of the program to run
* @param arg[1,n-2] optionally specify program arguments
* @param arg[n-1] is NULL
* @return pid of child, or -1 w/ errno
*/
int spawnl(unsigned flags, int stdiofds[3], const char *exe, const char *arg,
... /*, NULL*/) {
int rc;
va_list va;
void *argv;
rc = -1;
va_start(va, arg);
if ((argv = mkvarargv(arg, va))) {
rc = spawnve(flags, stdiofds, exe, argv, environ);
free(argv);
}
va_end(va);
return rc;
}

View File

@@ -0,0 +1,53 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/hefty/mkvarargv.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
/**
* Launches program, with PATH search and current environment.
*
* @param stdiofds may optionally be passed to customize standard i/o
* @param stdiofds[𝑖] may be -1 to receive a pipe() fd
* @param prog is program to launch (may be PATH searched)
* @param arg[0] is the name of the program to run
* @param arg[1,n-2] optionally specify program arguments
* @param arg[n-1] is NULL
* @return pid of child, or -1 w/ errno
*/
nodiscard int spawnlp(unsigned flags, int stdiofds[3], const char *prog,
const char *arg, ... /*, NULL*/) {
int pid;
char *exe;
va_list va;
void *argv;
pid = -1;
if ((exe = commandv(prog))) {
va_start(va, arg);
if ((argv = mkvarargv(arg, va))) {
pid = spawnve(flags, stdiofds, exe, argv, environ);
free(argv);
}
va_end(va);
}
return pid;
}

View File

@@ -0,0 +1,98 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/bits/xchg.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/internal.h"
#include "libc/calls/hefty/ntspawn.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/calls/internal.h"
#include "libc/nt/enum/startf.h"
#include "libc/nt/files.h"
#include "libc/nt/ipc.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/startupinfo.h"
#include "libc/nt/struct/processinformation.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
textwindows int spawnve$nt(unsigned flags, int stdiofds[3], const char *program,
char *const argv[], char *const envp[]) {
int pid;
size_t i;
int tubes[3];
int64_t handle, h, *x, *y;
struct NtStartupInfo sti;
struct NtProcessInformation procinfo;
handle = 0;
memset(&sti, 0, sizeof(sti));
sti.cb = sizeof(sti);
sti.dwFlags = kNtStartfUsestdhandles;
if ((pid = createfd()) == -1) return -1;
for (i = 0; i < 3; ++i) {
if (stdiofds[i] == -1) {
x = &h;
y = &sti.stdiofds[i];
if (kIoMotion[i]) xchg(&x, &y);
if ((tubes[i] = createfd()) != -1 &&
CreatePipe(x, y, &kNtIsInheritable, 0)) {
g_fds.p[tubes[i]].handle = h;
} else {
handle = -1;
}
} else {
sti.stdiofds[i] = g_fds.p[stdiofds[i]].handle;
}
}
if (handle != -1 &&
ntspawn(program, argv, envp, NULL, NULL,
(flags & SPAWN_TABULARASA) ? false : true,
(flags & SPAWN_DETACH)
? (kNtCreateNewProcessGroup | kNtDetachedProcess |
kNtCreateBreakawayFromJob)
: 0,
NULL, &sti, &procinfo) != -1) {
CloseHandle(procinfo.hThread);
handle = procinfo.hProcess;
}
for (i = 0; i < 3; ++i) {
if (stdiofds[i] == -1) {
if (handle != -1) {
stdiofds[i] = tubes[i];
g_fds.p[tubes[i]].kind = kFdFile;
g_fds.p[tubes[i]].flags = O_CLOEXEC;
CloseHandle(sti.stdiofds[i]);
} else {
CloseHandle(tubes[i]);
}
}
}
g_fds.p[pid].kind = kFdProcess;
g_fds.p[pid].handle = handle;
g_fds.p[pid].flags = flags;
return pid;
}

View File

@@ -0,0 +1,121 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/hefty/internal.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/calls/internal.h"
#include "libc/conv/conv.h"
#include "libc/dce.h"
#include "libc/mem/mem.h"
#include "libc/paths.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
int spawnve$sysv(unsigned flags, int stdiofds[3], const char *program,
char *const argv[], char *const envp[]) {
int rc, pid, fd;
size_t i, j, len;
int32_t tubes[3][2];
char **argv2, MZqFpD[8];
void *argv3;
pid = 0;
argv2 = NULL;
argv3 = argv;
/*
* αcτµαlly pδrταblε εxεcµταblε w/ thompson shell script
* morphology needs to be launched via command interpreter.
*/
if (endswith(program, ".com") || endswith(program, ".exe")) {
memset(MZqFpD, 0, sizeof(MZqFpD));
fd = openat$sysv(AT_FDCWD, program, O_RDONLY, 0);
read$sysv(fd, MZqFpD, sizeof(MZqFpD));
close$sysv(fd);
if (memcmp(MZqFpD, "MZqFpD", 6) == 0) {
/*
* If we got this:
*
* spawn(/bin/echo, [echo, hi, there])
*
* It will become this:
*
* spawn(/bin/sh, [sh, /bin/echo, hi, there])
*/
len = 1;
while (argv[len]) len++;
if ((argv2 = malloc((2 + len + 1) * sizeof(char *)))) {
i = 0, j = 1;
argv2[i++] = "sh";
argv2[i++] = program;
while (j < len) argv2[i++] = argv[j++];
argv2[i] = NULL;
argv3 = argv2;
program = "/bin/sh";
}
}
}
for (i = 0; i < 3; ++i) {
if (stdiofds[i] == -1) {
pid |= pipe$sysv(tubes[i]);
}
}
if (pid != -1) {
if ((pid = fork$sysv()) == 0) {
if (flags & SPAWN_DETACH) {
if (setsid() == -1) abort();
if ((rc = fork$sysv()) == -1) abort();
if (rc > 0) _exit(0);
}
for (i = 0; i < 3; ++i) {
if (stdiofds[i] == -1) {
close$sysv(tubes[i][kIoMotion[i]]);
fd = tubes[i][!kIoMotion[i]];
} else {
fd = stdiofds[i];
}
dup2$sysv(fd, i);
}
execve$sysv(program, argv3, envp);
abort();
}
}
for (i = 0; i < 3; ++i) {
if (stdiofds[i] == -1) {
close$sysv(tubes[i][!kIoMotion[i]]);
fd = tubes[i][kIoMotion[i]];
if (pid != -1) {
stdiofds[i] = fd;
} else {
close$sysv(fd);
}
}
}
if (argv2) free(argv2);
return pid;
}

View File

@@ -0,0 +1,63 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/bits/pushpop.h"
#include "libc/calls/hefty/internal.h"
#include "libc/calls/hefty/spawn.h"
#include "libc/dce.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/errfuns.h"
/**
* Launches program, e.g.
*
* char buf[2];
* int ws, pid, fds[3] = {-1, -1, STDERR_FILENO};
* CHECK_NE(-1, (pid = spawnve(0, fds, commandv("ssh"),
* (char *const[]){"ssh", hostname, "cat", NULL},
* environ)));
* CHECK_EQ(+2, write(fds[0], "hi", 2));
* CHECK_NE(-1, close(fds[0]));
* CHECK_EQ(+2, read(fds[1], buf, 2)));
* CHECK_NE(-1, close(fds[1]));
* CHECK_EQ(+0, memcmp(buf, "hi", 2)));
* CHECK_NE(-1, waitpid(pid, &ws, 0));
* CHECK_EQ(+0, WEXITSTATUS(ws));
*
* @param stdiofds may optionally be passed to customize standard i/o
* @param stdiofds[𝑖] may be -1 to receive a pipe() fd
* @param program will not be PATH searched, see commandv()
* @param argv[0] is the name of the program to run
* @param argv[1,n-2] optionally specify program arguments
* @param argv[n-1] is NULL
* @param envp[0,n-2] specifies "foo=bar" environment variables
* @param envp[n-1] is NULL
* @return pid of child, or -1 w/ errno
*/
int spawnve(unsigned flags, int stdiofds[3], const char *program,
char *const argv[], char *const envp[]) {
if (!argv[0]) return einval();
int defaultfds[3] = {pushpop(STDIN_FILENO), pushpop(STDOUT_FILENO),
pushpop(STDERR_FILENO)};
if (!IsWindows()) {
return spawnve$sysv(flags, stdiofds ?: defaultfds, program, argv, envp);
} else {
return spawnve$nt(flags, stdiofds ?: defaultfds, program, argv, envp);
}
}

View File

@@ -0,0 +1,29 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/log/log.h"
static char ttyname_buf[PATH_MAX];
char *ttyname(int fd) {
int rc = ttyname_r(fd, ttyname_buf, sizeof(ttyname_buf));
if (rc != 0) return NULL;
return &ttyname_buf[0];
}

View File

@@ -0,0 +1,86 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/log/log.h"
#include "libc/nt/console.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
static textwindows noinline int ttyname$nt(int fd, char *buf, size_t size) {
uint32_t mode;
if (GetConsoleMode(g_fds.p[fd].handle, &mode)) {
if (mode & kNtEnableVirtualTerminalInput) {
strncpy(buf, "CONIN$", size);
return 0;
} else {
strncpy(buf, "CONOUT$", size);
return 0;
}
} else {
return enotty();
}
}
static int ttyname$freebsd(int fd, char *buf, size_t size) {
const unsigned FIODGNAME = 2148558456;
struct fiodgname_arg {
int len;
void *buf;
} fg;
fg.buf = buf;
fg.len = size;
if (ioctl$sysv(fd, FIODGNAME, &fg) != -1) return 0;
return enotty();
}
static int ttyname$linux(int fd, char *buf, size_t size) {
struct stat st1, st2;
if (!isatty(fd)) return errno;
char name[PATH_MAX];
snprintf(name, sizeof(name), "/proc/self/fd/%d", fd);
ssize_t got;
got = readlink(name, buf, size);
if (got == -1) return errno;
if ((size_t)got >= size) return erange();
buf[got] = 0;
if (stat(buf, &st1) || fstat(fd, &st2)) return errno;
if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) return enodev();
return 0;
}
int ttyname_r(int fd, char *buf, size_t size) {
if (IsLinux()) {
return ttyname$linux(fd, buf, size);
} else if (IsFreebsd()) {
return ttyname$freebsd(fd, buf, size);
} else if (IsWindows()) {
if (isfdkind(fd, kFdFile)) {
return ttyname$nt(fd, buf, size);
} else {
return ebadf();
}
} else {
return enosys();
}
}