mirror of
https://github.com/skeeto/w64devkit.git
synced 2025-07-05 00:02:27 +03:00
Tidy alias.c, separate busybox-w32 aliases (#61)
The busybox-w32 alias binaries need not be unique. The command line string contains all the necessary information, and busybox-w32 already interprets that information properly. So just forward the command line string to busybox.exe. I also gave alias.c another tidying pass following my personal Windows systems programming style. I'm sufficiently confident in this approach that I feel it no longer requires apologetics. It speaks for itself. It also now releases its "heap" before waiting on the target process. While I'm at it, I also added a c89 command which is as "standard" as the already-existing c99 command.
This commit is contained in:
15
Dockerfile
15
Dockerfile
@ -294,6 +294,9 @@ RUN $ARCH-gcc -DEXE=gcc.exe -DCMD=cc \
|
|||||||
&& $ARCH-gcc -DEXE=gcc.exe -DCMD="cc -std=c99" \
|
&& $ARCH-gcc -DEXE=gcc.exe -DCMD="cc -std=c99" \
|
||||||
-Os -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \
|
-Os -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \
|
||||||
-o $PREFIX/bin/c99.exe $PREFIX/src/alias.c -lkernel32 \
|
-o $PREFIX/bin/c99.exe $PREFIX/src/alias.c -lkernel32 \
|
||||||
|
&& $ARCH-gcc -DEXE=gcc.exe -DCMD="cc -ansi" \
|
||||||
|
-Os -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \
|
||||||
|
-o $PREFIX/bin/c89.exe $PREFIX/src/alias.c -lkernel32 \
|
||||||
&& printf '%s\n' addr2line ar as c++filt cpp dlltool dllwrap elfedit g++ \
|
&& printf '%s\n' addr2line ar as c++filt cpp dlltool dllwrap elfedit g++ \
|
||||||
gcc gcc-ar gcc-nm gcc-ranlib gcov gcov-dump gcov-tool ld nm objcopy \
|
gcc gcc-ar gcc-nm gcc-ranlib gcov gcov-dump gcov-tool ld nm objcopy \
|
||||||
objdump ranlib readelf size strings strip windmc windres \
|
objdump ranlib readelf size strings strip windmc windres \
|
||||||
@ -375,7 +378,7 @@ RUN /make-$MAKE_VERSION/configure \
|
|||||||
-o $PREFIX/bin/mingw32-make.exe $PREFIX/src/alias.c -lkernel32
|
-o $PREFIX/bin/mingw32-make.exe $PREFIX/src/alias.c -lkernel32
|
||||||
|
|
||||||
WORKDIR /busybox-w32
|
WORKDIR /busybox-w32
|
||||||
COPY src/busybox-*.patch $PREFIX/src/
|
COPY src/busybox-* $PREFIX/src/
|
||||||
RUN cat $PREFIX/src/busybox-*.patch | patch -p1 \
|
RUN cat $PREFIX/src/busybox-*.patch | patch -p1 \
|
||||||
&& make mingw64_defconfig \
|
&& make mingw64_defconfig \
|
||||||
&& sed -ri 's/^(CONFIG_AR)=y/\1=n/' .config \
|
&& sed -ri 's/^(CONFIG_AR)=y/\1=n/' .config \
|
||||||
@ -398,7 +401,9 @@ RUN cat $PREFIX/src/busybox-*.patch | patch -p1 \
|
|||||||
&& cp busybox.exe $PREFIX/bin/
|
&& cp busybox.exe $PREFIX/bin/
|
||||||
|
|
||||||
# Create BusyBox command aliases (like "busybox --install")
|
# Create BusyBox command aliases (like "busybox --install")
|
||||||
RUN printf '%s\n' arch ash awk base32 base64 basename bash bc bunzip2 bzcat \
|
RUN $ARCH-gcc -Os -fno-asynchronous-unwind-tables -Wl,--gc-sections -s \
|
||||||
|
-nostdlib -o alias.exe $PREFIX/src/busybox-alias.c -lkernel32 \
|
||||||
|
&& printf '%s\n' arch ash awk base32 base64 basename bash bc bunzip2 bzcat \
|
||||||
bzip2 cal cat chattr chmod cksum clear cmp comm cp cpio crc32 cut date \
|
bzip2 cal cat chattr chmod cksum clear cmp comm cp cpio crc32 cut date \
|
||||||
dc dd df diff dirname dos2unix du echo ed egrep env expand expr factor \
|
dc dd df diff dirname dos2unix du echo ed egrep env expand expr factor \
|
||||||
false fgrep find fold free fsync getopt grep groups gunzip gzip hd \
|
false fgrep find fold free fsync getopt grep groups gunzip gzip hd \
|
||||||
@ -411,11 +416,7 @@ RUN printf '%s\n' arch ash awk base32 base64 basename bash bc bunzip2 bzcat \
|
|||||||
tr true truncate ts ttysize uname uncompress unexpand uniq unix2dos \
|
tr true truncate ts ttysize uname uncompress unexpand uniq unix2dos \
|
||||||
unlzma unlzop unxz unzip uptime usleep uudecode uuencode watch \
|
unlzma unlzop unxz unzip uptime usleep uudecode uuencode watch \
|
||||||
wc wget which whoami whois xargs xz xzcat yes zcat \
|
wc wget which whoami whois xargs xz xzcat yes zcat \
|
||||||
| xargs -I{} -P$(nproc) \
|
| xargs -I{} cp alias.exe $PREFIX/bin/{}.exe
|
||||||
$ARCH-gcc -DEXE=busybox.exe -DCMD={} \
|
|
||||||
-Os -fno-asynchronous-unwind-tables \
|
|
||||||
-Wl,--gc-sections -s -nostdlib \
|
|
||||||
-o $PREFIX/bin/{}.exe $PREFIX/src/alias.c -lkernel32
|
|
||||||
|
|
||||||
# TODO: Either somehow use $VIM_VERSION or normalize the workdir
|
# TODO: Either somehow use $VIM_VERSION or normalize the workdir
|
||||||
WORKDIR /vim90/src
|
WORKDIR /vim90/src
|
||||||
|
282
src/alias.c
282
src/alias.c
@ -3,94 +3,105 @@
|
|||||||
// Unlike batch script aliases, this program will not produce an annoying
|
// Unlike batch script aliases, this program will not produce an annoying
|
||||||
// and useless "Terminate batch job (Y/N)" prompt. When compiling, define
|
// and useless "Terminate batch job (Y/N)" prompt. When compiling, define
|
||||||
// EXE as the target executable (relative or absolute path), and define CMD
|
// EXE as the target executable (relative or absolute path), and define CMD
|
||||||
// as the argv[0] replacement, including additional arguments. Example:
|
// as the argv[0] replacement, including additional arguments.
|
||||||
//
|
//
|
||||||
// $ gcc -DEXE="target.exe" -DCMD="argv0 argv1"
|
// $ gcc -DEXE="target.exe" -DCMD="argv0 argv1"
|
||||||
// -Os -fno-asynchronous-unwind-tables
|
// -nostartfiles -fno-builtin -o alias.exe alias.c
|
||||||
// -s -nostartfiles -Wl,--gc-sections -o alias.exe alias.c
|
|
||||||
//
|
//
|
||||||
// This is free and unencumbered software released into the public domain.
|
// This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
// Win32 declarations
|
#define sizeof(x) (i32)sizeof(x)
|
||||||
// NOTE: Parsing windows.h was by far the slowest part of the build, and
|
#define alignof(x) (i32)_Alignof(x)
|
||||||
// this program is compiled hundreds times for w64devkit. So instead,
|
#define countof(a) (sizeof(a) / sizeof(*(a)))
|
||||||
// define just what's needed.
|
#define lengthof(s) (countof(s) - 1)
|
||||||
|
|
||||||
#define MAX_PATH 260
|
|
||||||
|
|
||||||
typedef __SIZE_TYPE__ size_t;
|
|
||||||
typedef unsigned short char16_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int cb;
|
|
||||||
void *a, *b, *c;
|
|
||||||
int d, e, f, g, h, i, j, k;
|
|
||||||
short l, m;
|
|
||||||
void *n, *o, *p, *q;
|
|
||||||
} StartupInfo;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void *process;
|
|
||||||
void *thread;
|
|
||||||
int pid;
|
|
||||||
int tid;
|
|
||||||
} ProcessInformation;
|
|
||||||
|
|
||||||
int CreateProcessW(
|
|
||||||
void *, void *, void *, void *, int, int, void *, void *, void *, void *
|
|
||||||
) __attribute((dllimport,stdcall));
|
|
||||||
void ExitProcess(int)
|
|
||||||
__attribute((dllimport,stdcall));
|
|
||||||
char16_t *GetCommandLineW(void)
|
|
||||||
__attribute((dllimport,stdcall));
|
|
||||||
int GetExitCodeProcess(void *, int *)
|
|
||||||
__attribute((dllimport,stdcall));
|
|
||||||
int GetModuleFileNameW(void *, char16_t *, int)
|
|
||||||
__attribute((dllimport,stdcall));
|
|
||||||
void *GetStdHandle(int)
|
|
||||||
__attribute((dllimport,stdcall));
|
|
||||||
int lstrlenW(void *)
|
|
||||||
__attribute((dllimport,stdcall));
|
|
||||||
void *VirtualAlloc(void *, size_t, int, int)
|
|
||||||
__attribute__((dllimport,stdcall,malloc));
|
|
||||||
int WriteFile(void *, void *, int, int *, void *)
|
|
||||||
__attribute((dllimport,stdcall));
|
|
||||||
int WaitForSingleObject(void *, int)
|
|
||||||
__attribute((dllimport,stdcall));
|
|
||||||
|
|
||||||
// Application
|
|
||||||
|
|
||||||
#define FATAL "fatal: w64devkit alias failed: "
|
|
||||||
#define TOOLONG "command too long\n"
|
|
||||||
#define OOM "out of memory\n"
|
|
||||||
#define CREATEPROC "cannot create process\n"
|
|
||||||
#define COUNTOF(a) (int)(sizeof(a) / sizeof(0[a]))
|
|
||||||
#define LSTR(s) XSTR(s)
|
#define LSTR(s) XSTR(s)
|
||||||
#define XSTR(s) L ## # s
|
#define XSTR(s) u ## # s
|
||||||
#define LEXE LSTR(EXE)
|
#define LEXE LSTR(EXE)
|
||||||
#define LCMD LSTR(CMD)
|
#define LCMD LSTR(CMD)
|
||||||
|
|
||||||
#define STRBUF(buf, cap) {buf, cap, 0, 0}
|
typedef __UINT8_TYPE__ u8;
|
||||||
typedef struct {
|
typedef signed short i16;
|
||||||
char16_t *buf;
|
typedef signed int b32;
|
||||||
int cap;
|
typedef signed int i32;
|
||||||
int len;
|
typedef unsigned int u32;
|
||||||
int error;
|
typedef unsigned char byte;
|
||||||
} StrBuf;
|
typedef __UINTPTR_TYPE__ uptr;
|
||||||
|
typedef __SIZE_TYPE__ usize;
|
||||||
|
typedef unsigned short char16_t; // for GDB
|
||||||
|
typedef char16_t c16;
|
||||||
|
|
||||||
static void append(StrBuf *b, char16_t *s, int len)
|
// Win32
|
||||||
|
|
||||||
|
#define MAX_PATH 260
|
||||||
|
#define MAX_CMDLINE (1<<15)
|
||||||
|
|
||||||
|
typedef struct {} *handle;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u32 cb;
|
||||||
|
uptr a, b, c;
|
||||||
|
i32 d, e, f, g, h, i, j, k;
|
||||||
|
i16 l, m;
|
||||||
|
uptr n, o, p, q;
|
||||||
|
} si;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
handle process;
|
||||||
|
handle thread;
|
||||||
|
u32 pid;
|
||||||
|
u32 tid;
|
||||||
|
} pi;
|
||||||
|
|
||||||
|
#define W32 __attribute((dllimport, stdcall))
|
||||||
|
W32 b32 CreateProcessW(c16*,c16*,void*,void*,b32,u32,c16*,c16*,si*,pi*);
|
||||||
|
W32 void ExitProcess(u32) __attribute((noreturn));
|
||||||
|
W32 c16 *GetCommandLineW(void);
|
||||||
|
W32 i32 GetExitCodeProcess(handle, u32 *);
|
||||||
|
W32 u32 GetFullPathNameW(c16 *, u32, c16 *, c16 *);
|
||||||
|
W32 u32 GetModuleFileNameW(handle, c16 *, u32);
|
||||||
|
W32 handle GetStdHandle(u32);
|
||||||
|
W32 byte *VirtualAlloc(byte *, usize, u32, u32);
|
||||||
|
W32 b32 VirtualFree(byte *, usize, u32);
|
||||||
|
W32 u32 WaitForSingleObject(handle, u32);
|
||||||
|
W32 b32 WriteFile(handle, u8 *, u32, u32 *, void *);
|
||||||
|
|
||||||
|
// Application
|
||||||
|
|
||||||
|
#define ERR(s) "w64devkit (alias): " s "\n"
|
||||||
|
|
||||||
|
#define new(h, t, n) (t *)alloc(h, sizeof(t), alignof(t), n)
|
||||||
|
__attribute((malloc))
|
||||||
|
__attribute((alloc_align(3)))
|
||||||
|
__attribute((alloc_size(2, 4)))
|
||||||
|
static byte *alloc(byte **heap, i32 size, i32 align, i32 count)
|
||||||
{
|
{
|
||||||
int avail = b->cap - b->len;
|
*heap += -(uptr)*heap & (align - 1);
|
||||||
int count = len<avail ? len : avail;
|
byte *p = *heap;
|
||||||
for (int i = 0; i < count; i++) {
|
*heap += size * count;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
c16 *buf;
|
||||||
|
i32 len;
|
||||||
|
i32 cap;
|
||||||
|
b32 err;
|
||||||
|
} c16buf;
|
||||||
|
|
||||||
|
static void append(c16buf *b, c16 *s, i32 len)
|
||||||
|
{
|
||||||
|
i32 avail = b->cap - b->len;
|
||||||
|
i32 count = avail<len ? avail : len;
|
||||||
|
for (i32 i = 0; i < count; i++) {
|
||||||
b->buf[b->len+i] = s[i];
|
b->buf[b->len+i] = s[i];
|
||||||
}
|
}
|
||||||
b->len += count;
|
b->len += count;
|
||||||
b->error |= len > avail;
|
b->err |= avail < len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the end of argv[0].
|
// Find the end of argv[0].
|
||||||
static char16_t *findargs(char16_t *s)
|
static c16 *findargs(c16 *s)
|
||||||
{
|
{
|
||||||
if (s[0] == '"') {
|
if (s[0] == '"') {
|
||||||
for (s++;; s++) { // quoted argv[0]
|
for (s++;; s++) { // quoted argv[0]
|
||||||
@ -110,80 +121,105 @@ static char16_t *findargs(char16_t *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the directory component length including the last slash.
|
static i32 c16len(c16 *s)
|
||||||
static int dirname(char16_t *s)
|
|
||||||
{
|
{
|
||||||
int len = 0;
|
i32 len = 0;
|
||||||
for (int i = 0; s[i]; i++) {
|
for (; s[len]; len++) {}
|
||||||
if (s[i]=='/' || s[i]=='\\') {
|
|
||||||
len = i + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fail(char *reason, int len)
|
static u32 fatal(u8 *msg, i32 len)
|
||||||
{
|
{
|
||||||
int dummy;
|
handle stderr = GetStdHandle(-12);
|
||||||
void *out = GetStdHandle(-12);
|
u32 dummy;
|
||||||
WriteFile(out, FATAL, COUNTOF(FATAL), &dummy, 0);
|
WriteFile(stderr, msg, len, &dummy, 0);
|
||||||
WriteFile(out, reason, len, &dummy, 0);
|
return 0x17e;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int aliasmain(void)
|
static void getmoduledir(c16buf *b)
|
||||||
{
|
{
|
||||||
// Replace alias module with adjacent target
|
c16 path[MAX_PATH];
|
||||||
char16_t exebuf[MAX_PATH];
|
u32 len = GetModuleFileNameW(0, path, countof(path));
|
||||||
StrBuf exe = STRBUF(exebuf, COUNTOF(exebuf));
|
for (; len; len--) {
|
||||||
if (LEXE[1] == ':') {
|
switch (path[len-1]) {
|
||||||
// EXE looks like an absolute path
|
case '/': case '\\':
|
||||||
append(&exe, LEXE, COUNTOF(LEXE));
|
append(b, path, len);
|
||||||
} else {
|
return;
|
||||||
// EXE looks like a relative path
|
}
|
||||||
char16_t module[MAX_PATH];
|
}
|
||||||
GetModuleFileNameW(0, module, COUNTOF(module));
|
}
|
||||||
int len = dirname(module);
|
|
||||||
append(&exe, module, len);
|
static si *newstartupinfo(byte **heap)
|
||||||
append(&exe, LEXE, COUNTOF(LEXE));
|
{
|
||||||
|
si *s = new(heap, si, 1);
|
||||||
|
s->cb = sizeof(si);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static i32 aliasmain(void)
|
||||||
|
{
|
||||||
|
byte *heap_start = VirtualAlloc(0, 1<<18, 0x3000, 4);
|
||||||
|
byte *heap = heap_start;
|
||||||
|
if (!heap) {
|
||||||
|
static const u8 msg[] = ERR("out of memory");
|
||||||
|
return fatal((u8 *)msg, lengthof(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct a path to the .exe
|
||||||
|
c16buf *exe = new(&heap, c16buf, 1);
|
||||||
|
exe->cap = 2*MAX_PATH; // concatenating two paths
|
||||||
|
exe->buf = new(&heap, c16, exe->cap);
|
||||||
|
if (LEXE[1] != ':') { // relative path?
|
||||||
|
getmoduledir(exe);
|
||||||
|
}
|
||||||
|
append(exe, LEXE, countof(LEXE));
|
||||||
|
if (exe->err) {
|
||||||
|
static const u8 msg[] = ERR(".exe path too long");
|
||||||
|
return fatal((u8 *)msg, lengthof(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to collapse relative components
|
||||||
|
if (LEXE[0] == '.') { // relative components?
|
||||||
|
c16buf *tmp = new(&heap, c16buf, 1);
|
||||||
|
tmp->buf = new(&heap, c16, MAX_PATH);
|
||||||
|
tmp->cap = MAX_PATH;
|
||||||
|
tmp->len = GetFullPathNameW(exe->buf, tmp->cap, tmp->buf, 0);
|
||||||
|
if (tmp->len>0 && tmp->len<tmp->cap) {
|
||||||
|
tmp->len++; // include null terminator
|
||||||
|
*exe = *tmp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct a new command line string
|
// Construct a new command line string
|
||||||
int cmdcap = 1<<15;
|
c16buf *cmd = new(&heap, c16buf, 1);
|
||||||
char16_t *cmdbuf = VirtualAlloc(0, 2*cmdcap, 0x3000, 4);
|
cmd->cap = MAX_CMDLINE;
|
||||||
if (!cmdbuf) {
|
cmd->buf = new(&heap, c16, cmd->cap);
|
||||||
fail(OOM, COUNTOF(OOM)-1);
|
append(cmd, LCMD, lengthof(LCMD));
|
||||||
return -2;
|
c16 *args = findargs(GetCommandLineW());
|
||||||
}
|
append(cmd, args, c16len(args)+1);
|
||||||
StrBuf cmd = STRBUF(cmdbuf, cmdcap);
|
if (cmd->err) {
|
||||||
append(&cmd, LCMD, COUNTOF(LCMD)-1);
|
static const u8 msg[] = ERR("command line too long");
|
||||||
char16_t *args = findargs(GetCommandLineW());
|
return fatal((u8 *)msg, lengthof(msg));
|
||||||
append(&cmd, args, lstrlenW(args)+1);
|
|
||||||
|
|
||||||
if (exe.error || cmd.error) {
|
|
||||||
fail(TOOLONG, COUNTOF(TOOLONG)-1);
|
|
||||||
return -3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StartupInfo si = {0};
|
si *si = newstartupinfo(&heap);
|
||||||
si.cb = sizeof(si);
|
pi pi;
|
||||||
ProcessInformation pi;
|
if (!CreateProcessW(exe->buf, cmd->buf, 0, 0, 1, 0, 0, 0, si, &pi)) {
|
||||||
if (!CreateProcessW(exebuf, cmdbuf, 0, 0, 1, 0, 0, 0, &si, &pi)) {
|
static const u8 msg[] = ERR("could not start process\n");
|
||||||
fail(CREATEPROC, COUNTOF(CREATEPROC)-1);
|
return fatal((u8 *)msg, lengthof(msg));
|
||||||
return -4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret;
|
// Wait for child to exit
|
||||||
|
VirtualFree(heap_start, 0, 0x8000);
|
||||||
|
u32 ret;
|
||||||
WaitForSingleObject(pi.process, -1);
|
WaitForSingleObject(pi.process, -1);
|
||||||
GetExitCodeProcess(pi.process, &ret);
|
GetExitCodeProcess(pi.process, &ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __i386
|
|
||||||
__attribute((force_align_arg_pointer))
|
__attribute((force_align_arg_pointer))
|
||||||
#endif
|
void mainCRTStartup(void)
|
||||||
__attribute((externally_visible))
|
|
||||||
int mainCRTStartup(void)
|
|
||||||
{
|
{
|
||||||
int r = aliasmain();
|
u32 r = aliasmain();
|
||||||
ExitProcess(r);
|
ExitProcess(r);
|
||||||
}
|
}
|
||||||
|
122
src/busybox-alias.c
Normal file
122
src/busybox-alias.c
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
// busybox-w32 command alias
|
||||||
|
// Starts the adjacent busybox.exe with an unmodified command line.
|
||||||
|
// $ cc -nostartfiles -fno-builtin -o COMMAND busybox-alias.c
|
||||||
|
// This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
#define sizeof(x) (i32)sizeof(x)
|
||||||
|
#define countof(a) (sizeof(a) / sizeof(*(a)))
|
||||||
|
#define lengthof(s) (countof(s) - 1)
|
||||||
|
|
||||||
|
typedef __UINT8_TYPE__ u8;
|
||||||
|
typedef signed short i16;
|
||||||
|
typedef signed int b32;
|
||||||
|
typedef signed int i32;
|
||||||
|
typedef unsigned int u32;
|
||||||
|
typedef unsigned short char16_t; // for GDB
|
||||||
|
typedef char16_t c16;
|
||||||
|
|
||||||
|
#define MAX_PATH 260
|
||||||
|
|
||||||
|
typedef struct {} *handle;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u32 cb;
|
||||||
|
void *a, *b, *c;
|
||||||
|
i32 d, e, f, g, h, i, j, k;
|
||||||
|
i16 l, m;
|
||||||
|
void *n, *o, *p, *q;
|
||||||
|
} si;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
handle process;
|
||||||
|
handle thread;
|
||||||
|
u32 pid;
|
||||||
|
u32 tid;
|
||||||
|
} pi;
|
||||||
|
|
||||||
|
#define W32 __attribute((dllimport, stdcall))
|
||||||
|
W32 b32 CreateProcessW(c16*,c16*,void*,void*,b32,u32,c16*,c16*,si*,pi*);
|
||||||
|
W32 void ExitProcess(u32) __attribute((noreturn));
|
||||||
|
W32 c16 *GetCommandLineW(void);
|
||||||
|
W32 i32 GetExitCodeProcess(handle, u32 *);
|
||||||
|
W32 u32 GetModuleFileNameW(handle, c16 *, u32);
|
||||||
|
W32 handle GetStdHandle(u32);
|
||||||
|
W32 u32 WaitForSingleObject(handle, u32);
|
||||||
|
W32 b32 WriteFile(handle, u8 *, u32, u32 *, void *);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
c16 *buf;
|
||||||
|
i32 len;
|
||||||
|
i32 cap;
|
||||||
|
b32 err;
|
||||||
|
} c16buf;
|
||||||
|
|
||||||
|
static void append(c16buf *b, c16 *buf, i32 len)
|
||||||
|
{
|
||||||
|
i32 avail = b->cap - b->len;
|
||||||
|
i32 count = avail<len ? avail : len;
|
||||||
|
c16 *dst = b->buf + b->len;
|
||||||
|
for (i32 i = 0; i < count; i++) {
|
||||||
|
dst[i] = buf[i];
|
||||||
|
}
|
||||||
|
b->len += count;
|
||||||
|
b->err |= count < len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void getmoduledir(c16buf *b)
|
||||||
|
{
|
||||||
|
c16 path[MAX_PATH];
|
||||||
|
u32 len = GetModuleFileNameW(0, path, countof(path));
|
||||||
|
for (; len; len--) {
|
||||||
|
switch (path[len-1]) {
|
||||||
|
case '/': case '\\':
|
||||||
|
append(b, path, len-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 fatal(u8 *msg, i32 len)
|
||||||
|
{
|
||||||
|
handle stderr = GetStdHandle(-12);
|
||||||
|
u32 dummy;
|
||||||
|
WriteFile(stderr, msg, len, &dummy, 0);
|
||||||
|
return 0x17e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 run(void)
|
||||||
|
{
|
||||||
|
c16 buf[MAX_PATH];
|
||||||
|
c16buf exe = {};
|
||||||
|
exe.buf = buf;
|
||||||
|
exe.cap = countof(buf);
|
||||||
|
|
||||||
|
getmoduledir(&exe);
|
||||||
|
c16 busybox[] = u"\\busybox.exe";
|
||||||
|
append(&exe, busybox, countof(busybox));
|
||||||
|
if (exe.err) {
|
||||||
|
static u8 msg[] = "w64devkit: busybox.exe path too long\n";
|
||||||
|
return fatal(msg, lengthof(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
si si = {};
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
pi pi;
|
||||||
|
c16 *cmdline = GetCommandLineW();
|
||||||
|
if (!CreateProcessW(exe.buf, cmdline, 0, 0, 1, 0, 0, 0, &si, &pi)) {
|
||||||
|
static u8 msg[] = "w64devkit: could not start busybox.exe\n";
|
||||||
|
return fatal(msg, lengthof(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ret;
|
||||||
|
WaitForSingleObject(pi.process, -1);
|
||||||
|
GetExitCodeProcess(pi.process, &ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute((force_align_arg_pointer))
|
||||||
|
void mainCRTStartup(void)
|
||||||
|
{
|
||||||
|
u32 r = run();
|
||||||
|
ExitProcess(r);
|
||||||
|
}
|
Reference in New Issue
Block a user