Blob Blame History Raw
/***********************************************************/
/*  ntux: native translation und extension                 */
/*  Copyright (C) 2016--2018  Z. Gilboa                    */
/*  Released under GPLv2 and GPLv3; see COPYING.NTUX.      */
/***********************************************************/

#include <ntapi/ntapi.h>
#include <ntapi/nt_termios.h>

#include <psxabi/sys_sysapi.h>
#include <psxabi/sys_strace.h>
#include <psxabi/sys_fcntl.h>
#include <psxabi/sys_errno.h>

#include <ntux/ntux.h>
#include "ntux_driver_impl.h"
#include "ntux_nolibc_impl.h"
#include "ntux_errinfo_impl.h"

int ntux_cmd_strace(const struct ntux_driver_ctx * dctx)
{
	int		ret;
	int32_t		status;
	pid_t		pid;
	const char **	argv;
	const char **	envp;
	unsigned char * program;
	unsigned char * logfile;
	struct __strace strace;
	ssize_t		rbytes;
	ssize_t		wbytes;
	char *		ch;
	char		buf[2048];
	int		fdlog[2];
	int		i;

	/* init */
	ntux_driver_set_ectx(
		dctx,0,
		dctx->cctx->sargv[0]);

	argv    = (const char **)dctx->cctx->sargv;
	envp    = (const char **)dctx->cctx->senvp;
	program = (unsigned char *)dctx->cctx->sargv[0];
	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);
	}

	/* strace */
	strace.size   = sizeof(strace);
	strace.loader = dctx->cctx->loader;
	strace.fdlog  = fdlog[1];
	strace.flags  = 0;

	for (i=0; i<16; i++)
		strace.sysmask[i] = 0xFFFFFFFF;

	for (i=0; i<16; i++)
		strace.dbgmask[i] = 0;

	for (i=0; i<32; i++)
		strace.osmask[i]  = 0;

	/* 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_strace(program,argv,envp,&strace)))
			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 strace 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 */
	__sys_wait4(
		pid,&status,
		0,0);

	return 0;
}