Blob Blame History Raw
/***********************************************************/
/*  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;
}