2020-06-15 14:18:57 +00:00
|
|
|
/*-*- 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 │
|
|
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
2020-08-25 11:23:25 +00:00
|
|
|
#include "libc/bits/weaken.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/calls/calls.h"
|
|
|
|
#include "libc/calls/internal.h"
|
|
|
|
#include "libc/mem/mem.h"
|
|
|
|
#include "libc/nt/accounting.h"
|
|
|
|
#include "libc/nt/enum/startf.h"
|
|
|
|
#include "libc/nt/enum/status.h"
|
|
|
|
#include "libc/nt/process.h"
|
|
|
|
#include "libc/nt/runtime.h"
|
|
|
|
#include "libc/nt/struct/processinformation.h"
|
|
|
|
#include "libc/nt/synchronization.h"
|
|
|
|
#include "libc/stdio/stdio.h"
|
|
|
|
#include "libc/str/str.h"
|
|
|
|
#include "libc/sysv/consts/fileno.h"
|
|
|
|
#include "libc/sysv/errfuns.h"
|
|
|
|
|
|
|
|
#define SHELL_BIN "/bin/sh"
|
|
|
|
#define SHELL_ARG "-c"
|
|
|
|
#define CMD_C "CMD /C "
|
|
|
|
|
|
|
|
static int system$sysv(const char *cmdline) {
|
2020-10-29 11:53:20 +00:00
|
|
|
int rc, n, wstatus;
|
|
|
|
struct mem {
|
|
|
|
char shell[sizeof(SHELL_BIN)];
|
|
|
|
char arg[sizeof(SHELL_ARG)];
|
|
|
|
char *args[4];
|
|
|
|
char cmdline[];
|
|
|
|
} * mem;
|
2020-06-15 14:18:57 +00:00
|
|
|
if (cmdline != NULL) {
|
2020-10-29 11:53:20 +00:00
|
|
|
mem = malloc(sizeof(struct mem) + (strlen(cmdline) + 1));
|
|
|
|
if (!mem) return enomem();
|
|
|
|
strcpy(mem->shell, SHELL_BIN);
|
|
|
|
strcpy(mem->arg, SHELL_ARG);
|
|
|
|
mem->args[0] = mem->shell;
|
|
|
|
mem->args[1] = mem->arg;
|
|
|
|
mem->args[2] = mem->cmdline;
|
|
|
|
mem->args[3] = NULL;
|
|
|
|
strcpy(mem->cmdline, cmdline);
|
|
|
|
if ((rc = vfork()) != -1) {
|
|
|
|
if (rc == 0) {
|
|
|
|
execve$sysv(mem->shell, mem->args, environ);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
if ((rc = wait4$sysv(rc, &wstatus, 0, NULL)) != -1) {
|
|
|
|
rc = wstatus;
|
|
|
|
}
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
2020-10-29 11:53:20 +00:00
|
|
|
free(mem);
|
2020-06-15 14:18:57 +00:00
|
|
|
return rc;
|
|
|
|
} else {
|
|
|
|
return fileexists(SHELL_BIN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static textwindows noinline int system$nt(const char *cmdline) {
|
2020-10-29 11:53:20 +00:00
|
|
|
char *mem;
|
|
|
|
int rc, status;
|
|
|
|
uint32_t dwExitCode;
|
|
|
|
struct NtStartupInfo startinfo;
|
|
|
|
struct NtProcessInformation *info;
|
|
|
|
uint16_t *cmdline16, *quotedcmdline16;
|
|
|
|
unsigned len, dosquotemultiplier, cmdline16bytes, quotedcmdline16bytes;
|
2020-06-15 14:18:57 +00:00
|
|
|
if (cmdline != NULL) {
|
2020-10-29 11:53:20 +00:00
|
|
|
rc = -1;
|
|
|
|
dosquotemultiplier = 2;
|
|
|
|
len = strlen(cmdline);
|
|
|
|
cmdline16bytes = (len + 1) * sizeof(uint16_t);
|
|
|
|
quotedcmdline16bytes =
|
2020-06-15 14:18:57 +00:00
|
|
|
strlen(CMD_C) * sizeof(uint16_t) + cmdline16bytes * dosquotemultiplier;
|
2020-10-29 11:53:20 +00:00
|
|
|
if (!(mem = malloc(sizeof(struct NtProcessInformation) + cmdline16bytes +
|
|
|
|
quotedcmdline16bytes))) {
|
|
|
|
return enomem();
|
|
|
|
}
|
|
|
|
info = (struct NtProcessInformation *)mem;
|
|
|
|
cmdline16 = (uint16_t *)(mem + sizeof(struct NtProcessInformation));
|
|
|
|
quotedcmdline16 = (uint16_t *)(mem + sizeof(struct NtProcessInformation) +
|
|
|
|
cmdline16bytes);
|
2020-06-15 14:18:57 +00:00
|
|
|
strcpyzbw(cmdline16, cmdline);
|
|
|
|
strcpyzbw(quotedcmdline16, CMD_C);
|
|
|
|
if (escapedos(quotedcmdline16 + strlen(CMD_C), len * dosquotemultiplier,
|
|
|
|
cmdline16, len)) {
|
|
|
|
memset(&startinfo, 0, sizeof(startinfo));
|
|
|
|
startinfo.cb = sizeof(struct NtStartupInfo);
|
|
|
|
startinfo.dwFlags = kNtStartfUsestdhandles;
|
|
|
|
startinfo.hStdInput = STDIN_FILENO;
|
|
|
|
startinfo.hStdOutput = STDOUT_FILENO;
|
|
|
|
startinfo.hStdError = STDERR_FILENO;
|
|
|
|
if (CreateProcess(
|
|
|
|
/* lpApplicationName */ NULL,
|
|
|
|
/* lpCommandLine */ quotedcmdline16,
|
|
|
|
/* lpProcessAttributes */ NULL,
|
|
|
|
/* lpThreadAttributes */ NULL,
|
|
|
|
/* bInheritHandles */ true,
|
|
|
|
/* dwCreationFlags */ kNtCreateNoWindow,
|
|
|
|
/* lpEnvironment */ NULL,
|
|
|
|
/* lpCurrentDirectory */ NULL,
|
|
|
|
/* lpStartupInfo */ &startinfo,
|
|
|
|
/* lpProcessInformation */ info)) {
|
2020-10-29 11:53:20 +00:00
|
|
|
dwExitCode = kNtStillActive;
|
2020-06-15 14:18:57 +00:00
|
|
|
do {
|
|
|
|
WaitForSingleObject(info->hProcess, 0xffffffff);
|
|
|
|
} while ((status = GetExitCodeProcess(info->hProcess, &dwExitCode)) &&
|
|
|
|
dwExitCode == kNtStillActive);
|
|
|
|
if (weaken(fflush)) {
|
|
|
|
weaken(fflush)(*weaken(stderr));
|
|
|
|
}
|
|
|
|
rc = (dwExitCode & 0xff) << 8; /* @see WEXITSTATUS() */
|
|
|
|
CloseHandle(info->hProcess);
|
|
|
|
CloseHandle(info->hThread);
|
|
|
|
} else {
|
|
|
|
rc = winerr();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = einval();
|
|
|
|
}
|
2020-10-29 11:53:20 +00:00
|
|
|
free(mem);
|
2020-06-15 14:18:57 +00:00
|
|
|
return rc;
|
|
|
|
} else {
|
|
|
|
/* how could cmd.exe not exist? */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Launches program with system command interpreter.
|
|
|
|
*
|
|
|
|
* @param cmdline is an interpreted Turing-complete command
|
|
|
|
* @return -1 if child process couldn't be created, otherwise a wait
|
|
|
|
* status that can be accessed using macros like WEXITSTATUS(s)
|
|
|
|
*/
|
|
|
|
int system(const char *cmdline) {
|
|
|
|
int rc;
|
|
|
|
if (weaken(fflush)) weaken(fflush)(NULL);
|
|
|
|
if (!IsWindows()) {
|
|
|
|
rc = system$sysv(cmdline);
|
|
|
|
} else {
|
|
|
|
rc = system$nt(cmdline);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|