/***********************************************************/
/* 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;
}