summaryrefslogtreecommitdiffhomepage
path: root/src/cmds/ntux_cmd_bridge.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmds/ntux_cmd_bridge.c')
-rw-r--r--src/cmds/ntux_cmd_bridge.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/src/cmds/ntux_cmd_bridge.c b/src/cmds/ntux_cmd_bridge.c
new file mode 100644
index 0000000..e187f11
--- /dev/null
+++ b/src/cmds/ntux_cmd_bridge.c
@@ -0,0 +1,202 @@
+/***********************************************************/
+/* ntux: native translation und extension */
+/* Copyright (C) 2016--2022 SysDeer Technologies, LLC */
+/* Released under GPLv2 and GPLv3; see COPYING.NTUX. */
+/***********************************************************/
+
+#include <ntapi/nt_termios.h>
+
+#include <psxabi/sys_sysapi.h>
+#include <psxabi/sys_fcntl.h>
+#include <psxabi/sys_errno.h>
+#include <psxabi/sys_process.h>
+#include <psxxfi/xfi_framework.h>
+
+#include <ntux/ntux.h>
+#include "ntux_driver_impl.h"
+#include "ntux_nolibc_impl.h"
+#include "ntux_errinfo_impl.h"
+
+int ntux_cmd_bridge(const struct ntux_driver_ctx * dctx)
+{
+ int ret;
+ int val;
+ pid_t pid;
+ int argc;
+ const char ** argv;
+ const char ** envp;
+ unsigned char * program;
+ unsigned char * logfile;
+ ssize_t rbytes;
+ ssize_t wbytes;
+ char * ch;
+ char * script;
+ char * interp;
+ const char * usrscript;
+ char ** sargv;
+ const char ** pargv;
+ const char ** aargv;
+ char buf[2048];
+ int fdlog[2];
+ int32_t status;
+
+ struct ntux_fd_ctx fdctx;
+
+ /* init */
+ ntux_driver_set_ectx(
+ dctx,0,
+ dctx->cctx->sargv[0]);
+
+ if (ntux_get_driver_fdctx(dctx,&fdctx) < 0)
+ if (ntux_errno_set(dctx,fdlog[1]))
+ return NTUX_SYSTEM_ERROR(dctx);
+
+ if (dctx->cctx->interp) {
+ ret = __xfi_framework_get_int32_slot_value(
+ PSX_RTDATA_UDAT32_ARGV1_IS_OPTARG,
+ &val);
+
+ if (ret < 0)
+ if (ntux_errno_set(dctx,fdlog[1]))
+ return NTUX_CUSTOM_ERROR(
+ dctx,
+ NTUX_ERR_FLOW_ERROR);
+
+ for (sargv=dctx->cctx->sargv; *sargv; sargv++)
+ (void)0;
+
+ argc = sargv - dctx->cctx->sargv;
+
+ if (!(aargv = ntux_calloc(argc + 3,sizeof(char *))))
+ if (ntux_errno_set(dctx,fdlog[1]))
+ return NTUX_SYSTEM_ERROR(dctx);
+
+ if (!(script = ntux_calloc(1,NTUX_MAX_PATH)))
+ if (ntux_errno_set(dctx,fdlog[1]))
+ return NTUX_SYSTEM_ERROR(dctx);
+
+ if (!(interp = ntux_calloc(1,NTUX_MAX_PATH)))
+ if (ntux_errno_set(dctx,fdlog[1]))
+ return NTUX_SYSTEM_ERROR(dctx);
+
+ usrscript = val ? dctx->cctx->sargv[2] : dctx->cctx->sargv[1];
+
+ if (__sys_fs_npath(fdctx.fdcwd,usrscript,0,script,NTUX_MAX_PATH) < 0)
+ if (ntux_errno_set(dctx,fdlog[1]))
+ return NTUX_SYSTEM_ERROR(dctx);
+
+ if (__sys_fs_npath(fdctx.fdcwd,dctx->cctx->interp,0,interp,NTUX_MAX_PATH) < 0)
+ if (ntux_errno_set(dctx,fdlog[1]))
+ return NTUX_SYSTEM_ERROR(dctx);
+
+ if (val) {
+ aargv[0] = interp;
+ aargv[1] = dctx->cctx->sargv[1];
+ aargv[2] = script;
+
+ sargv = &dctx->cctx->sargv[3];
+ pargv = &aargv[3];
+ } else {
+ aargv[0] = interp;
+ aargv[1] = script;
+
+ sargv = &dctx->cctx->sargv[2];
+ pargv = &aargv[2];
+ }
+
+ for (; *sargv; )
+ *pargv++ = *sargv++;
+
+ argv = aargv;
+ program = (unsigned char *)interp;
+ } else {
+ argv = (const char **)dctx->cctx->sargv;
+ program = (unsigned char *)dctx->cctx->sargv[0];
+ }
+
+ envp = (const char **)dctx->cctx->senvp;
+ logfile = (unsigned char *)dctx->cctx->logfile;
+
+ /* fdlog */
+ if (logfile) {
+ if ((fdlog[1] = __sys_openat(
+ ntux_driver_fdcwd(dctx),
+ logfile,O_CREAT|O_TRUNC|O_WRONLY,0)) < 0)
+ if (ntux_errno_set(dctx,fdlog[1]))
+ return NTUX_SYSTEM_ERROR(dctx);
+ } else {
+ if ((ret = __sys_pipe(fdlog)) < 0)
+ if (ntux_errno_set(dctx,ret))
+ return NTUX_SYSTEM_ERROR(dctx);
+ }
+
+ /* spawn */
+ pid = __sys_vfork();
+
+ /* failed? */
+ if (pid < 0)
+ if (ntux_errno_set(dctx,pid))
+ return NTUX_SYSTEM_ERROR(dctx);
+
+ /* child */
+ if (pid == 0)
+ if ((status = __sys_execve(program,argv,envp)))
+ if (ntux_errno_set(dctx,status))
+ if (NTUX_SYSTEM_ERROR(dctx))
+ __sys_exit(0);
+
+ /* parent */
+ __sys_close(fdlog[1]);
+
+ if (dctx->cctx->logfile) {
+ __sys_wait4(
+ pid,&status,
+ 0,0);
+
+ return 0;
+ }
+
+ /* piped bridge output */
+ rbytes = __sys_read(fdlog[0],buf,sizeof(buf));
+
+ while (rbytes == -EINTR)
+ rbytes = __sys_read(fdlog[0],buf,sizeof(buf));
+
+ while (rbytes > 0) {
+ for (ch=buf; rbytes; ch += wbytes) {
+ wbytes = __sys_write(2,ch,rbytes);
+
+ while (wbytes == -EINTR)
+ wbytes = __sys_write(2,buf,rbytes);
+
+ if (wbytes < 0) {
+ __sys_close(fdlog[0]);
+ ntux_errno_set(dctx,wbytes);
+ return NTUX_SYSTEM_ERROR(dctx);
+ }
+
+ rbytes -= wbytes;
+ }
+
+ rbytes = __sys_read(fdlog[0],buf,sizeof(buf));
+
+ while (rbytes == -EINTR)
+ rbytes = __sys_read(fdlog[0],buf,sizeof(buf));
+ }
+
+ __sys_close(fdlog[0]);
+
+ if (rbytes < 0)
+ if (ntux_errno_set(dctx,rbytes))
+ return NTUX_SYSTEM_ERROR(dctx);
+
+ /* wait */
+ struct ntux_driver_ctx_impl * ictx = ntux_get_driver_ictx(dctx);
+
+ __sys_wait4(
+ pid,
+ &ictx->cctx.status,
+ 0,0);
+
+ return 0;
+}