Last active
May 9, 2024 02:12
-
-
Save ookiineko/863304fb9e943824969085ab6397c377 to your computer and use it in GitHub Desktop.
Invoke Cygwin programs for msys2-cygwin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* SPDX-License-Identifier: MIT */ | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#define WIN32_LEAN_AND_MEAN | |
#include <windows.h> | |
#define AUTOCLO __attribute__((cleanup(__drop_fd))) | |
#define AUTOFREE __attribute__((cleanup(__drop_mem))) | |
#define err(_fmt, ...) fprintf (stderr, "%s: " _fmt "\n", progname, ##__VA_ARGS__) | |
#define die(_fmt, ...) \ | |
{ \ | |
err(_fmt, ##__VA_ARGS__); \ | |
exit (1); \ | |
} | |
static const char *progname; | |
static void | |
__drop_fd (int *fd) | |
{ | |
if (*fd < 0) | |
return; | |
close (*fd); | |
} | |
static void | |
__drop_mem (void *ptr) | |
{ | |
#define _ptr (*(void **)ptr) | |
if (!_ptr) | |
return; | |
free (_ptr); | |
} | |
static inline const char * | |
_map2tgt (unsigned short nt_mach) | |
{ | |
switch (nt_mach) | |
{ | |
case IMAGE_FILE_MACHINE_AMD64: | |
return "x86_64-pc-cygwin"; | |
default: | |
return NULL; | |
} | |
} | |
__attribute__((noreturn)) static inline void | |
_cygexec (const char *prog, | |
const char *tgt, | |
const char *const *argv) | |
{ | |
AUTOFREE char *pfx = NULL; | |
AUTOFREE char *old_path = NULL; | |
AUTOFREE char *buff = NULL; | |
ssize_t len; | |
int ex; | |
#define _agetenv(name) strdup (getenv (name)) | |
// e.g. /mingw64 | |
pfx = _agetenv("MINGW_PREFIX"); | |
if (!pfx) | |
die("Not running in an MSYS2 MINGW terminal"); | |
old_path = _agetenv("PATH"); | |
if (!old_path) | |
die("PATH is not set"); | |
// make target DLLs available in PATH | |
#define _format_new_path(_buff, _len) \ | |
snprintf (_buff, _len, "PATH=%s/%s/bin;%s", pfx, tgt, old_path) | |
len = _format_new_path(NULL, 0); | |
if (len < 0) | |
print_err: | |
die("%s", strerror (errno)); | |
len += 1; // terminate byte | |
buff = malloc (len); | |
if (!buff) | |
goto print_err; | |
if (_format_new_path(buff, len) < 0) | |
goto print_err; | |
if (putenv (buff)) | |
goto print_err; | |
// avoid freeing its now a part of environ | |
buff = NULL; | |
ex = _spawnv (P_WAIT, prog, argv); | |
if (ex < 0) | |
goto print_err; | |
exit (ex); | |
} | |
int | |
main (int argc, char **argv) | |
{ | |
AUTOCLO int fd = -1; | |
union | |
{ | |
IMAGE_DOS_HEADER dos; | |
IMAGE_NT_HEADERS nt; | |
} hdr; | |
union | |
{ | |
ssize_t cnt; | |
off_t off; | |
} err; | |
const char *tgt; | |
progname = argv[0]; | |
if (argc < 2) | |
{ | |
fprintf (stderr, "Usage: %s PROGRAM [ARGUMENTS...]\t" | |
"Run the specified program\n", progname); | |
return 1; | |
} | |
// check dos header | |
#define _prog argv[1] | |
fd = open (_prog, O_RDONLY | O_BINARY); | |
if (fd < 0) | |
{ | |
print_err: | |
err("%s: %s", _prog, strerror (errno)); | |
return 1; | |
} | |
err.cnt = read (fd, &hdr.dos, sizeof(hdr.dos)); | |
if (err.cnt < 0) | |
goto print_err; | |
else if (err.cnt != sizeof(hdr.dos)) | |
{ | |
too_small: | |
err("%s: File too small to be an valid executable", _prog); | |
return 1; | |
} | |
if (hdr.dos.e_magic != IMAGE_DOS_SIGNATURE) | |
{ | |
bad_prog: | |
err("%s: Is not a Cygwin program", _prog); | |
return 1; | |
} | |
// check nt header | |
#define _nt_hdr_off (hdr.dos.e_lfanew) | |
err.off = lseek (fd, _nt_hdr_off, SEEK_SET); | |
if (err.off < 0) | |
goto print_err; | |
else if (err.off != _nt_hdr_off) | |
goto too_small; | |
err.cnt = read (fd, &hdr.nt, sizeof(hdr.nt)); | |
if (err.cnt < 0) | |
goto print_err; | |
else if (err.cnt != sizeof(hdr.nt)) | |
goto too_small; | |
if (hdr.nt.Signature != IMAGE_NT_SIGNATURE) | |
goto bad_prog; | |
tgt = _map2tgt (hdr.nt.FileHeader.Machine); | |
if (!tgt) | |
{ | |
err("%s: Unknown architecture", _prog); | |
return 1; | |
} | |
_cygexec (_prog, tgt, (const char *const *)&argv[1]); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment