Blame os2.c

Packit Service 95ac19
/*-
Packit Service 95ac19
 * Copyright (c) 2015, 2017
Packit Service 95ac19
 *	KO Myung-Hun <komh@chollian.net>
Packit Service 95ac19
 * Copyright (c) 2017
Packit Service 95ac19
 *	mirabilos <m@mirbsd.org>
Packit Service 95ac19
 *
Packit Service 95ac19
 * Provided that these terms and disclaimer and all copyright notices
Packit Service 95ac19
 * are retained or reproduced in an accompanying document, permission
Packit Service 95ac19
 * is granted to deal in this work without restriction, including un-
Packit Service 95ac19
 * limited rights to use, publicly perform, distribute, sell, modify,
Packit Service 95ac19
 * merge, give away, or sublicence.
Packit Service 95ac19
 *
Packit Service 95ac19
 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
Packit Service 95ac19
 * the utmost extent permitted by applicable law, neither express nor
Packit Service 95ac19
 * implied; without malicious intent or gross negligence. In no event
Packit Service 95ac19
 * may a licensor, author or contributor be held liable for indirect,
Packit Service 95ac19
 * direct, other damage, loss, or other issues arising in any way out
Packit Service 95ac19
 * of dealing in the work, even if advised of the possibility of such
Packit Service 95ac19
 * damage or existence of a defect, except proven that it results out
Packit Service 95ac19
 * of said person's immediate fault when using the work as intended.
Packit Service 95ac19
 */
Packit Service 95ac19
Packit Service 95ac19
#define INCL_DOS
Packit Service 95ac19
#include <os2.h>
Packit Service 95ac19
Packit Service 95ac19
#include "sh.h"
Packit Service 95ac19
Packit Service 95ac19
#include <klibc/startup.h>
Packit Service 95ac19
#include <errno.h>
Packit Service 95ac19
#include <io.h>
Packit Service 95ac19
#include <unistd.h>
Packit Service 95ac19
#include <process.h>
Packit Service 95ac19
Packit Service 95ac19
__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.8 2017/12/22 16:41:42 tg Exp $");
Packit Service 95ac19
Packit Service 95ac19
static char *remove_trailing_dots(char *);
Packit Service 95ac19
static int access_stat_ex(int (*)(), const char *, void *);
Packit Service 95ac19
static int test_exec_exist(const char *, char *);
Packit Service 95ac19
static void response(int *, const char ***);
Packit Service 95ac19
static char *make_response_file(char * const *);
Packit Service 95ac19
static void add_temp(const char *);
Packit Service 95ac19
static void cleanup_temps(void);
Packit Service 95ac19
static void cleanup(void);
Packit Service 95ac19
Packit Service 95ac19
#define RPUT(x) do {					\
Packit Service 95ac19
	if (new_argc >= new_alloc) {			\
Packit Service 95ac19
		new_alloc += 20;			\
Packit Service 95ac19
		if (!(new_argv = realloc(new_argv,	\
Packit Service 95ac19
		    new_alloc * sizeof(char *))))	\
Packit Service 95ac19
			goto exit_out_of_memory;	\
Packit Service 95ac19
	}						\
Packit Service 95ac19
	new_argv[new_argc++] = (x);			\
Packit Service 95ac19
} while (/* CONSTCOND */ 0)
Packit Service 95ac19
Packit Service 95ac19
#define KLIBC_ARG_RESPONSE_EXCLUDE	\
Packit Service 95ac19
	(__KLIBC_ARG_DQUOTE | __KLIBC_ARG_WILDCARD | __KLIBC_ARG_SHELL)
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
response(int *argcp, const char ***argvp)
Packit Service 95ac19
{
Packit Service 95ac19
	int i, old_argc, new_argc, new_alloc = 0;
Packit Service 95ac19
	const char **old_argv, **new_argv;
Packit Service 95ac19
	char *line, *l, *p;
Packit Service 95ac19
	FILE *f;
Packit Service 95ac19
Packit Service 95ac19
	old_argc = *argcp;
Packit Service 95ac19
	old_argv = *argvp;
Packit Service 95ac19
	for (i = 1; i < old_argc; ++i)
Packit Service 95ac19
		if (old_argv[i] &&
Packit Service 95ac19
		    !(old_argv[i][-1] & KLIBC_ARG_RESPONSE_EXCLUDE) &&
Packit Service 95ac19
		    old_argv[i][0] == '@')
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
	if (i >= old_argc)
Packit Service 95ac19
		/* do nothing */
Packit Service 95ac19
		return;
Packit Service 95ac19
Packit Service 95ac19
	new_argv = NULL;
Packit Service 95ac19
	new_argc = 0;
Packit Service 95ac19
	for (i = 0; i < old_argc; ++i) {
Packit Service 95ac19
		if (i == 0 || !old_argv[i] ||
Packit Service 95ac19
		    (old_argv[i][-1] & KLIBC_ARG_RESPONSE_EXCLUDE) ||
Packit Service 95ac19
		    old_argv[i][0] != '@' ||
Packit Service 95ac19
		    !(f = fopen(old_argv[i] + 1, "rt")))
Packit Service 95ac19
			RPUT(old_argv[i]);
Packit Service 95ac19
		else {
Packit Service 95ac19
			long filesize;
Packit Service 95ac19
Packit Service 95ac19
			fseek(f, 0, SEEK_END);
Packit Service 95ac19
			filesize = ftell(f);
Packit Service 95ac19
			fseek(f, 0, SEEK_SET);
Packit Service 95ac19
Packit Service 95ac19
			line = malloc(filesize + /* type */ 1 + /* NUL */ 1);
Packit Service 95ac19
			if (!line) {
Packit Service 95ac19
 exit_out_of_memory:
Packit Service 95ac19
				fputs("Out of memory while reading response file\n", stderr);
Packit Service 95ac19
				exit(255);
Packit Service 95ac19
			}
Packit Service 95ac19
Packit Service 95ac19
			line[0] = __KLIBC_ARG_NONZERO | __KLIBC_ARG_RESPONSE;
Packit Service 95ac19
			l = line + 1;
Packit Service 95ac19
			while (fgets(l, (filesize + 1) - (l - (line + 1)), f)) {
Packit Service 95ac19
				p = strchr(l, '\n');
Packit Service 95ac19
				if (p) {
Packit Service 95ac19
					/*
Packit Service 95ac19
					 * if a line ends with a backslash,
Packit Service 95ac19
					 * concatenate with the next line
Packit Service 95ac19
					 */
Packit Service 95ac19
					if (p > l && p[-1] == '\\') {
Packit Service 95ac19
						char *p1;
Packit Service 95ac19
						int count = 0;
Packit Service 95ac19
Packit Service 95ac19
						for (p1 = p - 1; p1 >= l &&
Packit Service 95ac19
						    *p1 == '\\'; p1--)
Packit Service 95ac19
							count++;
Packit Service 95ac19
Packit Service 95ac19
						if (count & 1) {
Packit Service 95ac19
							l = p + 1;
Packit Service 95ac19
Packit Service 95ac19
							continue;
Packit Service 95ac19
						}
Packit Service 95ac19
					}
Packit Service 95ac19
Packit Service 95ac19
					*p = 0;
Packit Service 95ac19
				}
Packit Service 95ac19
				p = strdup(line);
Packit Service 95ac19
				if (!p)
Packit Service 95ac19
					goto exit_out_of_memory;
Packit Service 95ac19
Packit Service 95ac19
				RPUT(p + 1);
Packit Service 95ac19
Packit Service 95ac19
				l = line + 1;
Packit Service 95ac19
			}
Packit Service 95ac19
Packit Service 95ac19
			free(line);
Packit Service 95ac19
Packit Service 95ac19
			if (ferror(f)) {
Packit Service 95ac19
				fputs("Cannot read response file\n", stderr);
Packit Service 95ac19
				exit(255);
Packit Service 95ac19
			}
Packit Service 95ac19
Packit Service 95ac19
			fclose(f);
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	RPUT(NULL);
Packit Service 95ac19
	--new_argc;
Packit Service 95ac19
Packit Service 95ac19
	*argcp = new_argc;
Packit Service 95ac19
	*argvp = new_argv;
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
init_extlibpath(void)
Packit Service 95ac19
{
Packit Service 95ac19
	const char *vars[] = {
Packit Service 95ac19
		"BEGINLIBPATH",
Packit Service 95ac19
		"ENDLIBPATH",
Packit Service 95ac19
		"LIBPATHSTRICT",
Packit Service 95ac19
		NULL
Packit Service 95ac19
	};
Packit Service 95ac19
	char val[512];
Packit Service 95ac19
	int flag;
Packit Service 95ac19
Packit Service 95ac19
	for (flag = 0; vars[flag]; flag++) {
Packit Service 95ac19
		DosQueryExtLIBPATH(val, flag + 1);
Packit Service 95ac19
		if (val[0])
Packit Service 95ac19
			setenv(vars[flag], val, 1);
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
os2_init(int *argcp, const char ***argvp)
Packit Service 95ac19
{
Packit Service 95ac19
	response(argcp, argvp);
Packit Service 95ac19
Packit Service 95ac19
	init_extlibpath();
Packit Service 95ac19
Packit Service 95ac19
	if (!isatty(STDIN_FILENO))
Packit Service 95ac19
		setmode(STDIN_FILENO, O_BINARY);
Packit Service 95ac19
	if (!isatty(STDOUT_FILENO))
Packit Service 95ac19
		setmode(STDOUT_FILENO, O_BINARY);
Packit Service 95ac19
	if (!isatty(STDERR_FILENO))
Packit Service 95ac19
		setmode(STDERR_FILENO, O_BINARY);
Packit Service 95ac19
Packit Service 95ac19
	atexit(cleanup);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
setextlibpath(const char *name, const char *val)
Packit Service 95ac19
{
Packit Service 95ac19
	int flag;
Packit Service 95ac19
	char *p, *cp;
Packit Service 95ac19
Packit Service 95ac19
	if (!strcmp(name, "BEGINLIBPATH"))
Packit Service 95ac19
		flag = BEGIN_LIBPATH;
Packit Service 95ac19
	else if (!strcmp(name, "ENDLIBPATH"))
Packit Service 95ac19
		flag = END_LIBPATH;
Packit Service 95ac19
	else if (!strcmp(name, "LIBPATHSTRICT"))
Packit Service 95ac19
		flag = LIBPATHSTRICT;
Packit Service 95ac19
	else
Packit Service 95ac19
		return;
Packit Service 95ac19
Packit Service 95ac19
	/* convert slashes to backslashes */
Packit Service 95ac19
	strdupx(cp, val, ATEMP);
Packit Service 95ac19
	for (p = cp; *p; p++) {
Packit Service 95ac19
		if (*p == '/')
Packit Service 95ac19
			*p = '\\';
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	DosSetExtLIBPATH(cp, flag);
Packit Service 95ac19
Packit Service 95ac19
	afree(cp, ATEMP);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* remove trailing dots */
Packit Service 95ac19
static char *
Packit Service 95ac19
remove_trailing_dots(char *name)
Packit Service 95ac19
{
Packit Service 95ac19
	char *p = strnul(name);
Packit Service 95ac19
Packit Service 95ac19
	while (--p > name && *p == '.')
Packit Service 95ac19
		/* nothing */;
Packit Service 95ac19
Packit Service 95ac19
	if (*p != '.' && *p != '/' && *p != '\\' && *p != ':')
Packit Service 95ac19
		p[1] = '\0';
Packit Service 95ac19
Packit Service 95ac19
	return (name);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
#define REMOVE_TRAILING_DOTS(name)	\
Packit Service 95ac19
	remove_trailing_dots(memcpy(alloca(strlen(name) + 1), name, strlen(name) + 1))
Packit Service 95ac19
Packit Service 95ac19
/* alias of stat() */
Packit Service 95ac19
extern int _std_stat(const char *, struct stat *);
Packit Service 95ac19
Packit Service 95ac19
/* replacement for stat() of kLIBC which fails if there are trailing dots */
Packit Service 95ac19
int
Packit Service 95ac19
stat(const char *name, struct stat *buffer)
Packit Service 95ac19
{
Packit Service 95ac19
	return (_std_stat(REMOVE_TRAILING_DOTS(name), buffer));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* alias of access() */
Packit Service 95ac19
extern int _std_access(const char *, int);
Packit Service 95ac19
Packit Service 95ac19
/* replacement for access() of kLIBC which fails if there are trailing dots */
Packit Service 95ac19
int
Packit Service 95ac19
access(const char *name, int mode)
Packit Service 95ac19
{
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * On OS/2 kLIBC, X_OK is set only for executable files.
Packit Service 95ac19
	 * This prevents scripts from being executed.
Packit Service 95ac19
	 */
Packit Service 95ac19
	if (mode & X_OK)
Packit Service 95ac19
		mode = (mode & ~X_OK) | R_OK;
Packit Service 95ac19
Packit Service 95ac19
	return (_std_access(REMOVE_TRAILING_DOTS(name), mode));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
#define MAX_X_SUFFIX_LEN	4
Packit Service 95ac19
Packit Service 95ac19
static const char *x_suffix_list[] =
Packit Service 95ac19
    { "", ".ksh", ".exe", ".sh", ".cmd", ".com", ".bat", NULL };
Packit Service 95ac19
Packit Service 95ac19
/* call fn() by appending executable extensions */
Packit Service 95ac19
static int
Packit Service 95ac19
access_stat_ex(int (*fn)(), const char *name, void *arg)
Packit Service 95ac19
{
Packit Service 95ac19
	char *x_name;
Packit Service 95ac19
	const char **x_suffix;
Packit Service 95ac19
	int rc = -1;
Packit Service 95ac19
	size_t x_namelen = strlen(name) + MAX_X_SUFFIX_LEN + 1;
Packit Service 95ac19
Packit Service 95ac19
	/* otherwise, try to append executable suffixes */
Packit Service 95ac19
	x_name = alloc(x_namelen, ATEMP);
Packit Service 95ac19
Packit Service 95ac19
	for (x_suffix = x_suffix_list; rc && *x_suffix; x_suffix++) {
Packit Service 95ac19
		strlcpy(x_name, name, x_namelen);
Packit Service 95ac19
		strlcat(x_name, *x_suffix, x_namelen);
Packit Service 95ac19
Packit Service 95ac19
		rc = fn(x_name, arg);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	afree(x_name, ATEMP);
Packit Service 95ac19
Packit Service 95ac19
	return (rc);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* access()/search_access() version */
Packit Service 95ac19
int
Packit Service 95ac19
access_ex(int (*fn)(const char *, int), const char *name, int mode)
Packit Service 95ac19
{
Packit Service 95ac19
	/*XXX this smells fishy --mirabilos */
Packit Service 95ac19
	return (access_stat_ex(fn, name, (void *)mode));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* stat() version */
Packit Service 95ac19
int
Packit Service 95ac19
stat_ex(const char *name, struct stat *buffer)
Packit Service 95ac19
{
Packit Service 95ac19
	return (access_stat_ex(stat, name, buffer));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static int
Packit Service 95ac19
test_exec_exist(const char *name, char *real_name)
Packit Service 95ac19
{
Packit Service 95ac19
	struct stat sb;
Packit Service 95ac19
Packit Service 95ac19
	if (stat(name, &sb) < 0 || !S_ISREG(sb.st_mode))
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
Packit Service 95ac19
	/* safe due to calculations in real_exec_name() */
Packit Service 95ac19
	memcpy(real_name, name, strlen(name) + 1);
Packit Service 95ac19
Packit Service 95ac19
	return (0);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
const char *
Packit Service 95ac19
real_exec_name(const char *name)
Packit Service 95ac19
{
Packit Service 95ac19
	char x_name[strlen(name) + MAX_X_SUFFIX_LEN + 1];
Packit Service 95ac19
	const char *real_name = name;
Packit Service 95ac19
Packit Service 95ac19
	if (access_stat_ex(test_exec_exist, real_name, x_name) != -1)
Packit Service 95ac19
		/*XXX memory leak */
Packit Service 95ac19
		strdupx(real_name, x_name, ATEMP);
Packit Service 95ac19
Packit Service 95ac19
	return (real_name);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* make a response file to pass a very long command line */
Packit Service 95ac19
static char *
Packit Service 95ac19
make_response_file(char * const *argv)
Packit Service 95ac19
{
Packit Service 95ac19
	char rsp_name_arg[] = "@mksh-rsp-XXXXXX";
Packit Service 95ac19
	char *rsp_name = &rsp_name_arg[1];
Packit Service 95ac19
	int i;
Packit Service 95ac19
	int fd;
Packit Service 95ac19
	char *result;
Packit Service 95ac19
Packit Service 95ac19
	if ((fd = mkstemp(rsp_name)) == -1)
Packit Service 95ac19
		return (NULL);
Packit Service 95ac19
Packit Service 95ac19
	/* write all the arguments except a 0th program name */
Packit Service 95ac19
	for (i = 1; argv[i]; i++) {
Packit Service 95ac19
		write(fd, argv[i], strlen(argv[i]));
Packit Service 95ac19
		write(fd, "\n", 1);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	close(fd);
Packit Service 95ac19
	add_temp(rsp_name);
Packit Service 95ac19
	strdupx(result, rsp_name_arg, ATEMP);
Packit Service 95ac19
Packit Service 95ac19
	return (result);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* alias of execve() */
Packit Service 95ac19
extern int _std_execve(const char *, char * const *, char * const *);
Packit Service 95ac19
Packit Service 95ac19
/* replacement for execve() of kLIBC */
Packit Service 95ac19
int
Packit Service 95ac19
execve(const char *name, char * const *argv, char * const *envp)
Packit Service 95ac19
{
Packit Service 95ac19
	const char *exec_name;
Packit Service 95ac19
	FILE *fp;
Packit Service 95ac19
	char sign[2];
Packit Service 95ac19
	int pid;
Packit Service 95ac19
	int status;
Packit Service 95ac19
	int fd;
Packit Service 95ac19
	int rc;
Packit Service 95ac19
	int saved_mode;
Packit Service 95ac19
	int saved_errno;
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * #! /bin/sh : append .exe
Packit Service 95ac19
	 * extproc sh : search sh.exe in PATH
Packit Service 95ac19
	 */
Packit Service 95ac19
	exec_name = search_path(name, path, X_OK, NULL);
Packit Service 95ac19
	if (!exec_name) {
Packit Service 95ac19
		errno = ENOENT;
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	/*-
Packit Service 95ac19
	 * kLIBC execve() has problems when executing scripts.
Packit Service 95ac19
	 * 1. it fails to execute a script if a directory whose name
Packit Service 95ac19
	 *    is same as an interpreter exists in a current directory.
Packit Service 95ac19
	 * 2. it fails to execute a script not starting with sharpbang.
Packit Service 95ac19
	 * 3. it fails to execute a batch file if COMSPEC is set to a shell
Packit Service 95ac19
	 *    incompatible with cmd.exe, such as /bin/sh.
Packit Service 95ac19
	 * And ksh process scripts more well, so let ksh process scripts.
Packit Service 95ac19
	 */
Packit Service 95ac19
	errno = 0;
Packit Service 95ac19
	if (!(fp = fopen(exec_name, "rb")))
Packit Service 95ac19
		errno = ENOEXEC;
Packit Service 95ac19
Packit Service 95ac19
	if (!errno && fread(sign, 1, sizeof(sign), fp) != sizeof(sign))
Packit Service 95ac19
		errno = ENOEXEC;
Packit Service 95ac19
Packit Service 95ac19
	if (fp && fclose(fp))
Packit Service 95ac19
		errno = ENOEXEC;
Packit Service 95ac19
Packit Service 95ac19
	if (!errno &&
Packit Service 95ac19
	    !((sign[0] == 'M' && sign[1] == 'Z') ||
Packit Service 95ac19
	      (sign[0] == 'N' && sign[1] == 'E') ||
Packit Service 95ac19
	      (sign[0] == 'L' && sign[1] == 'X')))
Packit Service 95ac19
		errno = ENOEXEC;
Packit Service 95ac19
Packit Service 95ac19
	if (errno == ENOEXEC)
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * Normal OS/2 programs expect that standard IOs, especially stdin,
Packit Service 95ac19
	 * are opened in text mode at the startup. By the way, on OS/2 kLIBC
Packit Service 95ac19
	 * child processes inherit a translation mode of a parent process.
Packit Service 95ac19
	 * As a result, if stdin is set to binary mode in a parent process,
Packit Service 95ac19
	 * stdin of child processes is opened in binary mode as well at the
Packit Service 95ac19
	 * startup. In this case, some programs such as sed suffer from CR.
Packit Service 95ac19
	 */
Packit Service 95ac19
	saved_mode = setmode(STDIN_FILENO, O_TEXT);
Packit Service 95ac19
Packit Service 95ac19
	pid = spawnve(P_NOWAIT, exec_name, argv, envp);
Packit Service 95ac19
	saved_errno = errno;
Packit Service 95ac19
Packit Service 95ac19
	/* arguments too long? */
Packit Service 95ac19
	if (pid == -1 && saved_errno == EINVAL) {
Packit Service 95ac19
		/* retry with a response file */
Packit Service 95ac19
		char *rsp_name_arg = make_response_file(argv);
Packit Service 95ac19
Packit Service 95ac19
		if (rsp_name_arg) {
Packit Service 95ac19
			char *rsp_argv[3] = { argv[0], rsp_name_arg, NULL };
Packit Service 95ac19
Packit Service 95ac19
			pid = spawnve(P_NOWAIT, exec_name, rsp_argv, envp);
Packit Service 95ac19
			saved_errno = errno;
Packit Service 95ac19
Packit Service 95ac19
			afree(rsp_name_arg, ATEMP);
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	/* restore translation mode of stdin */
Packit Service 95ac19
	setmode(STDIN_FILENO, saved_mode);
Packit Service 95ac19
Packit Service 95ac19
	if (pid == -1) {
Packit Service 95ac19
		cleanup_temps();
Packit Service 95ac19
Packit Service 95ac19
		errno = saved_errno;
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	/* close all opened handles */
Packit Service 95ac19
	for (fd = 0; fd < NUFILE; fd++) {
Packit Service 95ac19
		if (fcntl(fd, F_GETFD) == -1)
Packit Service 95ac19
			continue;
Packit Service 95ac19
Packit Service 95ac19
		close(fd);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	while ((rc = waitpid(pid, &status, 0)) < 0 && errno == EINTR)
Packit Service 95ac19
		/* nothing */;
Packit Service 95ac19
Packit Service 95ac19
	cleanup_temps();
Packit Service 95ac19
Packit Service 95ac19
	/* Is this possible? And is this right? */
Packit Service 95ac19
	if (rc == -1)
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
Packit Service 95ac19
	if (WIFSIGNALED(status))
Packit Service 95ac19
		_exit(ksh_sigmask(WTERMSIG(status)));
Packit Service 95ac19
Packit Service 95ac19
	_exit(WEXITSTATUS(status));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static struct temp *templist = NULL;
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
add_temp(const char *name)
Packit Service 95ac19
{
Packit Service 95ac19
	struct temp *tp;
Packit Service 95ac19
Packit Service 95ac19
	tp = alloc(offsetof(struct temp, tffn[0]) + strlen(name) + 1, APERM);
Packit Service 95ac19
	memcpy(tp->tffn, name, strlen(name) + 1);
Packit Service 95ac19
	tp->next = templist;
Packit Service 95ac19
	templist = tp;
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* alias of unlink() */
Packit Service 95ac19
extern int _std_unlink(const char *);
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Replacement for unlink() of kLIBC not supporting to remove files used by
Packit Service 95ac19
 * another processes.
Packit Service 95ac19
 */
Packit Service 95ac19
int
Packit Service 95ac19
unlink(const char *name)
Packit Service 95ac19
{
Packit Service 95ac19
	int rc;
Packit Service 95ac19
Packit Service 95ac19
	rc = _std_unlink(name);
Packit Service 95ac19
	if (rc == -1 && errno != ENOENT)
Packit Service 95ac19
		add_temp(name);
Packit Service 95ac19
Packit Service 95ac19
	return (rc);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
cleanup_temps(void)
Packit Service 95ac19
{
Packit Service 95ac19
	struct temp *tp;
Packit Service 95ac19
	struct temp **tpnext;
Packit Service 95ac19
Packit Service 95ac19
	for (tpnext = &templist, tp = templist; tp; tp = *tpnext) {
Packit Service 95ac19
		if (_std_unlink(tp->tffn) == 0 || errno == ENOENT) {
Packit Service 95ac19
			*tpnext = tp->next;
Packit Service 95ac19
			afree(tp, APERM);
Packit Service 95ac19
		} else {
Packit Service 95ac19
			tpnext = &tp->next;
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
cleanup(void)
Packit Service 95ac19
{
Packit Service 95ac19
	cleanup_temps();
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
int
Packit Service 95ac19
getdrvwd(char **cpp, unsigned int drvltr)
Packit Service 95ac19
{
Packit Service 95ac19
	PBYTE cp;
Packit Service 95ac19
	ULONG sz;
Packit Service 95ac19
	APIRET rc;
Packit Service 95ac19
	ULONG drvno;
Packit Service 95ac19
Packit Service 95ac19
	if (DosQuerySysInfo(QSV_MAX_PATH_LENGTH, QSV_MAX_PATH_LENGTH,
Packit Service 95ac19
	    &sz, sizeof(sz)) != 0) {
Packit Service 95ac19
		errno = EDOOFUS;
Packit Service 95ac19
		return (-1);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	/* allocate 'X:/' plus sz plus NUL */
Packit Service 95ac19
	checkoktoadd((size_t)sz, (size_t)4);
Packit Service 95ac19
	cp = aresize(*cpp, (size_t)sz + (size_t)4, ATEMP);
Packit Service 95ac19
	cp[0] = ksh_toupper(drvltr);
Packit Service 95ac19
	cp[1] = ':';
Packit Service 95ac19
	cp[2] = '/';
Packit Service 95ac19
	drvno = ksh_numuc(cp[0]) + 1;
Packit Service 95ac19
	/* NUL is part of space within buffer passed */
Packit Service 95ac19
	++sz;
Packit Service 95ac19
	if ((rc = DosQueryCurrentDir(drvno, cp + 3, &sz)) == 0) {
Packit Service 95ac19
		/* success! */
Packit Service 95ac19
		*cpp = cp;
Packit Service 95ac19
		return (0);
Packit Service 95ac19
	}
Packit Service 95ac19
	afree(cp, ATEMP);
Packit Service 95ac19
	*cpp = NULL;
Packit Service 95ac19
	switch (rc) {
Packit Service 95ac19
	case 15: /* invalid drive */
Packit Service 95ac19
		errno = ENOTBLK;
Packit Service 95ac19
		break;
Packit Service 95ac19
	case 26: /* not dos disk */
Packit Service 95ac19
		errno = ENODEV;
Packit Service 95ac19
		break;
Packit Service 95ac19
	case 108: /* drive locked */
Packit Service 95ac19
		errno = EDEADLK;
Packit Service 95ac19
		break;
Packit Service 95ac19
	case 111: /* buffer overflow */
Packit Service 95ac19
		errno = ENAMETOOLONG;
Packit Service 95ac19
		break;
Packit Service 95ac19
	default:
Packit Service 95ac19
		errno = EINVAL;
Packit Service 95ac19
	}
Packit Service 95ac19
	return (-1);
Packit Service 95ac19
}