1c84f3f3cSopenharmony_ci/*-
2c84f3f3cSopenharmony_ci * Copyright (c) 2015, 2017, 2020
3c84f3f3cSopenharmony_ci *	KO Myung-Hun <komh@chollian.net>
4c84f3f3cSopenharmony_ci * Copyright (c) 2017, 2020
5c84f3f3cSopenharmony_ci *	mirabilos <m@mirbsd.org>
6c84f3f3cSopenharmony_ci *
7c84f3f3cSopenharmony_ci * Provided that these terms and disclaimer and all copyright notices
8c84f3f3cSopenharmony_ci * are retained or reproduced in an accompanying document, permission
9c84f3f3cSopenharmony_ci * is granted to deal in this work without restriction, including un-
10c84f3f3cSopenharmony_ci * limited rights to use, publicly perform, distribute, sell, modify,
11c84f3f3cSopenharmony_ci * merge, give away, or sublicence.
12c84f3f3cSopenharmony_ci *
13c84f3f3cSopenharmony_ci * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
14c84f3f3cSopenharmony_ci * the utmost extent permitted by applicable law, neither express nor
15c84f3f3cSopenharmony_ci * implied; without malicious intent or gross negligence. In no event
16c84f3f3cSopenharmony_ci * may a licensor, author or contributor be held liable for indirect,
17c84f3f3cSopenharmony_ci * direct, other damage, loss, or other issues arising in any way out
18c84f3f3cSopenharmony_ci * of dealing in the work, even if advised of the possibility of such
19c84f3f3cSopenharmony_ci * damage or existence of a defect, except proven that it results out
20c84f3f3cSopenharmony_ci * of said person's immediate fault when using the work as intended.
21c84f3f3cSopenharmony_ci */
22c84f3f3cSopenharmony_ci
23c84f3f3cSopenharmony_ci#define INCL_KBD
24c84f3f3cSopenharmony_ci#define INCL_DOS
25c84f3f3cSopenharmony_ci#include <os2.h>
26c84f3f3cSopenharmony_ci
27c84f3f3cSopenharmony_ci#include "sh.h"
28c84f3f3cSopenharmony_ci
29c84f3f3cSopenharmony_ci#include <klibc/startup.h>
30c84f3f3cSopenharmony_ci#include <errno.h>
31c84f3f3cSopenharmony_ci#include <io.h>
32c84f3f3cSopenharmony_ci#include <unistd.h>
33c84f3f3cSopenharmony_ci#include <process.h>
34c84f3f3cSopenharmony_ci
35c84f3f3cSopenharmony_ci__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.11 2020/10/01 21:13:45 tg Exp $");
36c84f3f3cSopenharmony_ci
37c84f3f3cSopenharmony_cistruct a_s_arg {
38c84f3f3cSopenharmony_ci	union {
39c84f3f3cSopenharmony_ci		int (*i)(const char *, int);
40c84f3f3cSopenharmony_ci		int (*p)(const char *, void *);
41c84f3f3cSopenharmony_ci	} fn;
42c84f3f3cSopenharmony_ci	union {
43c84f3f3cSopenharmony_ci		int i;
44c84f3f3cSopenharmony_ci		void *p;
45c84f3f3cSopenharmony_ci	} arg;
46c84f3f3cSopenharmony_ci	bool isint;
47c84f3f3cSopenharmony_ci};
48c84f3f3cSopenharmony_ci
49c84f3f3cSopenharmony_cistatic void remove_trailing_dots(char *, size_t);
50c84f3f3cSopenharmony_cistatic int access_stat_ex(const char *, struct a_s_arg *);
51c84f3f3cSopenharmony_cistatic int test_exec_exist(const char *, void *);
52c84f3f3cSopenharmony_cistatic void response(int *, const char ***);
53c84f3f3cSopenharmony_cistatic char *make_response_file(char * const *);
54c84f3f3cSopenharmony_cistatic void add_temp(const char *);
55c84f3f3cSopenharmony_cistatic void cleanup_temps(void);
56c84f3f3cSopenharmony_cistatic void cleanup(void);
57c84f3f3cSopenharmony_ci
58c84f3f3cSopenharmony_ci#define RPUT(x) do {					\
59c84f3f3cSopenharmony_ci	if (new_argc >= new_alloc) {			\
60c84f3f3cSopenharmony_ci		new_alloc += 20;			\
61c84f3f3cSopenharmony_ci		if (!(new_argv = realloc(new_argv,	\
62c84f3f3cSopenharmony_ci		    new_alloc * sizeof(char *))))	\
63c84f3f3cSopenharmony_ci			goto exit_out_of_memory;	\
64c84f3f3cSopenharmony_ci	}						\
65c84f3f3cSopenharmony_ci	new_argv[new_argc++] = (x);			\
66c84f3f3cSopenharmony_ci} while (/* CONSTCOND */ 0)
67c84f3f3cSopenharmony_ci
68c84f3f3cSopenharmony_ci#define KLIBC_ARG_RESPONSE_EXCLUDE	\
69c84f3f3cSopenharmony_ci	(__KLIBC_ARG_DQUOTE | __KLIBC_ARG_WILDCARD | __KLIBC_ARG_SHELL)
70c84f3f3cSopenharmony_ci
71c84f3f3cSopenharmony_cistatic void
72c84f3f3cSopenharmony_ciresponse(int *argcp, const char ***argvp)
73c84f3f3cSopenharmony_ci{
74c84f3f3cSopenharmony_ci	int i, old_argc, new_argc, new_alloc = 0;
75c84f3f3cSopenharmony_ci	const char **old_argv, **new_argv;
76c84f3f3cSopenharmony_ci	char *line, *l, *p;
77c84f3f3cSopenharmony_ci	FILE *f;
78c84f3f3cSopenharmony_ci
79c84f3f3cSopenharmony_ci	old_argc = *argcp;
80c84f3f3cSopenharmony_ci	old_argv = *argvp;
81c84f3f3cSopenharmony_ci	for (i = 1; i < old_argc; ++i)
82c84f3f3cSopenharmony_ci		if (old_argv[i] &&
83c84f3f3cSopenharmony_ci		    !(old_argv[i][-1] & KLIBC_ARG_RESPONSE_EXCLUDE) &&
84c84f3f3cSopenharmony_ci		    old_argv[i][0] == '@')
85c84f3f3cSopenharmony_ci			break;
86c84f3f3cSopenharmony_ci
87c84f3f3cSopenharmony_ci	if (i >= old_argc)
88c84f3f3cSopenharmony_ci		/* do nothing */
89c84f3f3cSopenharmony_ci		return;
90c84f3f3cSopenharmony_ci
91c84f3f3cSopenharmony_ci	new_argv = NULL;
92c84f3f3cSopenharmony_ci	new_argc = 0;
93c84f3f3cSopenharmony_ci	for (i = 0; i < old_argc; ++i) {
94c84f3f3cSopenharmony_ci		if (i == 0 || !old_argv[i] ||
95c84f3f3cSopenharmony_ci		    (old_argv[i][-1] & KLIBC_ARG_RESPONSE_EXCLUDE) ||
96c84f3f3cSopenharmony_ci		    old_argv[i][0] != '@' ||
97c84f3f3cSopenharmony_ci		    !(f = fopen(old_argv[i] + 1, "rt")))
98c84f3f3cSopenharmony_ci			RPUT(old_argv[i]);
99c84f3f3cSopenharmony_ci		else {
100c84f3f3cSopenharmony_ci			long filesize;
101c84f3f3cSopenharmony_ci
102c84f3f3cSopenharmony_ci			fseek(f, 0, SEEK_END);
103c84f3f3cSopenharmony_ci			filesize = ftell(f);
104c84f3f3cSopenharmony_ci			fseek(f, 0, SEEK_SET);
105c84f3f3cSopenharmony_ci
106c84f3f3cSopenharmony_ci			line = malloc(filesize + /* type */ 1 + /* NUL */ 1);
107c84f3f3cSopenharmony_ci			if (!line) {
108c84f3f3cSopenharmony_ci exit_out_of_memory:
109c84f3f3cSopenharmony_ci				fputs("Out of memory while reading response file\n", stderr);
110c84f3f3cSopenharmony_ci				exit(255);
111c84f3f3cSopenharmony_ci			}
112c84f3f3cSopenharmony_ci
113c84f3f3cSopenharmony_ci			line[0] = __KLIBC_ARG_NONZERO | __KLIBC_ARG_RESPONSE;
114c84f3f3cSopenharmony_ci			l = line + 1;
115c84f3f3cSopenharmony_ci			while (fgets(l, (filesize + 1) - (l - (line + 1)), f)) {
116c84f3f3cSopenharmony_ci				p = strchr(l, '\n');
117c84f3f3cSopenharmony_ci				if (p) {
118c84f3f3cSopenharmony_ci					/*
119c84f3f3cSopenharmony_ci					 * if a line ends with a backslash,
120c84f3f3cSopenharmony_ci					 * concatenate with the next line
121c84f3f3cSopenharmony_ci					 */
122c84f3f3cSopenharmony_ci					if (p > l && p[-1] == '\\') {
123c84f3f3cSopenharmony_ci						char *p1;
124c84f3f3cSopenharmony_ci						int count = 0;
125c84f3f3cSopenharmony_ci
126c84f3f3cSopenharmony_ci						for (p1 = p - 1; p1 >= l &&
127c84f3f3cSopenharmony_ci						    *p1 == '\\'; p1--)
128c84f3f3cSopenharmony_ci							count++;
129c84f3f3cSopenharmony_ci
130c84f3f3cSopenharmony_ci						if (count & 1) {
131c84f3f3cSopenharmony_ci							l = p + 1;
132c84f3f3cSopenharmony_ci
133c84f3f3cSopenharmony_ci							continue;
134c84f3f3cSopenharmony_ci						}
135c84f3f3cSopenharmony_ci					}
136c84f3f3cSopenharmony_ci
137c84f3f3cSopenharmony_ci					*p = 0;
138c84f3f3cSopenharmony_ci				}
139c84f3f3cSopenharmony_ci				p = strdup(line);
140c84f3f3cSopenharmony_ci				if (!p)
141c84f3f3cSopenharmony_ci					goto exit_out_of_memory;
142c84f3f3cSopenharmony_ci
143c84f3f3cSopenharmony_ci				RPUT(p + 1);
144c84f3f3cSopenharmony_ci
145c84f3f3cSopenharmony_ci				l = line + 1;
146c84f3f3cSopenharmony_ci			}
147c84f3f3cSopenharmony_ci
148c84f3f3cSopenharmony_ci			free(line);
149c84f3f3cSopenharmony_ci
150c84f3f3cSopenharmony_ci			if (ferror(f)) {
151c84f3f3cSopenharmony_ci				fputs("Cannot read response file\n", stderr);
152c84f3f3cSopenharmony_ci				exit(255);
153c84f3f3cSopenharmony_ci			}
154c84f3f3cSopenharmony_ci
155c84f3f3cSopenharmony_ci			fclose(f);
156c84f3f3cSopenharmony_ci		}
157c84f3f3cSopenharmony_ci	}
158c84f3f3cSopenharmony_ci
159c84f3f3cSopenharmony_ci	RPUT(NULL);
160c84f3f3cSopenharmony_ci	--new_argc;
161c84f3f3cSopenharmony_ci
162c84f3f3cSopenharmony_ci	*argcp = new_argc;
163c84f3f3cSopenharmony_ci	*argvp = new_argv;
164c84f3f3cSopenharmony_ci}
165c84f3f3cSopenharmony_ci
166c84f3f3cSopenharmony_cistatic void
167c84f3f3cSopenharmony_ciinit_extlibpath(void)
168c84f3f3cSopenharmony_ci{
169c84f3f3cSopenharmony_ci	const char *vars[] = {
170c84f3f3cSopenharmony_ci		"BEGINLIBPATH",
171c84f3f3cSopenharmony_ci		"ENDLIBPATH",
172c84f3f3cSopenharmony_ci		"LIBPATHSTRICT",
173c84f3f3cSopenharmony_ci		NULL
174c84f3f3cSopenharmony_ci	};
175c84f3f3cSopenharmony_ci	char val[512];
176c84f3f3cSopenharmony_ci	int flag;
177c84f3f3cSopenharmony_ci
178c84f3f3cSopenharmony_ci	for (flag = 0; vars[flag]; flag++) {
179c84f3f3cSopenharmony_ci		DosQueryExtLIBPATH(val, flag + 1);
180c84f3f3cSopenharmony_ci		if (val[0])
181c84f3f3cSopenharmony_ci			setenv(vars[flag], val, 1);
182c84f3f3cSopenharmony_ci	}
183c84f3f3cSopenharmony_ci}
184c84f3f3cSopenharmony_ci
185c84f3f3cSopenharmony_civoid
186c84f3f3cSopenharmony_cios2_init(int *argcp, const char ***argvp)
187c84f3f3cSopenharmony_ci{
188c84f3f3cSopenharmony_ci	KBDINFO ki;
189c84f3f3cSopenharmony_ci
190c84f3f3cSopenharmony_ci	response(argcp, argvp);
191c84f3f3cSopenharmony_ci
192c84f3f3cSopenharmony_ci	init_extlibpath();
193c84f3f3cSopenharmony_ci
194c84f3f3cSopenharmony_ci	if (!isatty(STDIN_FILENO))
195c84f3f3cSopenharmony_ci		setmode(STDIN_FILENO, O_BINARY);
196c84f3f3cSopenharmony_ci	if (!isatty(STDOUT_FILENO))
197c84f3f3cSopenharmony_ci		setmode(STDOUT_FILENO, O_BINARY);
198c84f3f3cSopenharmony_ci	if (!isatty(STDERR_FILENO))
199c84f3f3cSopenharmony_ci		setmode(STDERR_FILENO, O_BINARY);
200c84f3f3cSopenharmony_ci
201c84f3f3cSopenharmony_ci	/* ensure ECHO mode is ON so that read command echoes. */
202c84f3f3cSopenharmony_ci	memset(&ki, 0, sizeof(ki));
203c84f3f3cSopenharmony_ci	ki.cb = sizeof(ki);
204c84f3f3cSopenharmony_ci	ki.fsMask |= KEYBOARD_ECHO_ON;
205c84f3f3cSopenharmony_ci	KbdSetStatus(&ki, 0);
206c84f3f3cSopenharmony_ci
207c84f3f3cSopenharmony_ci	atexit(cleanup);
208c84f3f3cSopenharmony_ci}
209c84f3f3cSopenharmony_ci
210c84f3f3cSopenharmony_civoid
211c84f3f3cSopenharmony_cisetextlibpath(const char *name, const char *val)
212c84f3f3cSopenharmony_ci{
213c84f3f3cSopenharmony_ci	int flag;
214c84f3f3cSopenharmony_ci	char *p, *cp;
215c84f3f3cSopenharmony_ci
216c84f3f3cSopenharmony_ci	if (!strcmp(name, "BEGINLIBPATH"))
217c84f3f3cSopenharmony_ci		flag = BEGIN_LIBPATH;
218c84f3f3cSopenharmony_ci	else if (!strcmp(name, "ENDLIBPATH"))
219c84f3f3cSopenharmony_ci		flag = END_LIBPATH;
220c84f3f3cSopenharmony_ci	else if (!strcmp(name, "LIBPATHSTRICT"))
221c84f3f3cSopenharmony_ci		flag = LIBPATHSTRICT;
222c84f3f3cSopenharmony_ci	else
223c84f3f3cSopenharmony_ci		return;
224c84f3f3cSopenharmony_ci
225c84f3f3cSopenharmony_ci	/* convert slashes to backslashes */
226c84f3f3cSopenharmony_ci	strdupx(cp, val, ATEMP);
227c84f3f3cSopenharmony_ci	for (p = cp; *p; p++) {
228c84f3f3cSopenharmony_ci		if (*p == '/')
229c84f3f3cSopenharmony_ci			*p = '\\';
230c84f3f3cSopenharmony_ci	}
231c84f3f3cSopenharmony_ci
232c84f3f3cSopenharmony_ci	DosSetExtLIBPATH(cp, flag);
233c84f3f3cSopenharmony_ci
234c84f3f3cSopenharmony_ci	afree(cp, ATEMP);
235c84f3f3cSopenharmony_ci}
236c84f3f3cSopenharmony_ci
237c84f3f3cSopenharmony_ci/* remove trailing dots */
238c84f3f3cSopenharmony_cistatic void
239c84f3f3cSopenharmony_ciremove_trailing_dots(char *name, size_t namelen)
240c84f3f3cSopenharmony_ci{
241c84f3f3cSopenharmony_ci	char *p = name + namelen;
242c84f3f3cSopenharmony_ci
243c84f3f3cSopenharmony_ci	while (--p > name && *p == '.')
244c84f3f3cSopenharmony_ci		/* nothing */;
245c84f3f3cSopenharmony_ci
246c84f3f3cSopenharmony_ci	if (*p != '.' && *p != '/' && *p != '\\' && *p != ':')
247c84f3f3cSopenharmony_ci		p[1] = '\0';
248c84f3f3cSopenharmony_ci}
249c84f3f3cSopenharmony_ci
250c84f3f3cSopenharmony_ci/* alias of stat() */
251c84f3f3cSopenharmony_ciextern int _std_stat(const char *, struct stat *);
252c84f3f3cSopenharmony_ci
253c84f3f3cSopenharmony_ci/* replacement for stat() of kLIBC which fails if there are trailing dots */
254c84f3f3cSopenharmony_ciint
255c84f3f3cSopenharmony_cistat(const char *name, struct stat *buffer)
256c84f3f3cSopenharmony_ci{
257c84f3f3cSopenharmony_ci	size_t namelen = strlen(name) + 1;
258c84f3f3cSopenharmony_ci	char nodots[namelen];
259c84f3f3cSopenharmony_ci
260c84f3f3cSopenharmony_ci	memcpy(nodots, name, namelen);
261c84f3f3cSopenharmony_ci	remove_trailing_dots(nodots, namelen);
262c84f3f3cSopenharmony_ci	return (_std_stat(nodots, buffer));
263c84f3f3cSopenharmony_ci}
264c84f3f3cSopenharmony_ci
265c84f3f3cSopenharmony_ci/* alias of access() */
266c84f3f3cSopenharmony_ciextern int _std_access(const char *, int);
267c84f3f3cSopenharmony_ci
268c84f3f3cSopenharmony_ci/* replacement for access() of kLIBC which fails if there are trailing dots */
269c84f3f3cSopenharmony_ciint
270c84f3f3cSopenharmony_ciaccess(const char *name, int mode)
271c84f3f3cSopenharmony_ci{
272c84f3f3cSopenharmony_ci	size_t namelen = strlen(name) + 1;
273c84f3f3cSopenharmony_ci	char nodots[namelen];
274c84f3f3cSopenharmony_ci
275c84f3f3cSopenharmony_ci	/*
276c84f3f3cSopenharmony_ci	 * On OS/2 kLIBC, X_OK is set only for executable files.
277c84f3f3cSopenharmony_ci	 * This prevents scripts from being executed.
278c84f3f3cSopenharmony_ci	 */
279c84f3f3cSopenharmony_ci	if (mode & X_OK)
280c84f3f3cSopenharmony_ci		mode = (mode & ~X_OK) | R_OK;
281c84f3f3cSopenharmony_ci
282c84f3f3cSopenharmony_ci	memcpy(nodots, name, namelen);
283c84f3f3cSopenharmony_ci	remove_trailing_dots(nodots, namelen);
284c84f3f3cSopenharmony_ci	return (_std_access(nodots, mode));
285c84f3f3cSopenharmony_ci}
286c84f3f3cSopenharmony_ci
287c84f3f3cSopenharmony_ci#define MAX_X_SUFFIX_LEN	4
288c84f3f3cSopenharmony_ci
289c84f3f3cSopenharmony_cistatic const char *x_suffix_list[] =
290c84f3f3cSopenharmony_ci    { "", ".ksh", ".exe", ".sh", ".cmd", ".com", ".bat", NULL };
291c84f3f3cSopenharmony_ci
292c84f3f3cSopenharmony_ci/* call fn() by appending executable extensions */
293c84f3f3cSopenharmony_cistatic int
294c84f3f3cSopenharmony_ciaccess_stat_ex(const char *name, struct a_s_arg *action)
295c84f3f3cSopenharmony_ci{
296c84f3f3cSopenharmony_ci	char *x_name;
297c84f3f3cSopenharmony_ci	const char **x_suffix;
298c84f3f3cSopenharmony_ci	int rc = -1;
299c84f3f3cSopenharmony_ci	size_t x_namelen = strlen(name) + MAX_X_SUFFIX_LEN + 1;
300c84f3f3cSopenharmony_ci
301c84f3f3cSopenharmony_ci	/* otherwise, try to append executable suffixes */
302c84f3f3cSopenharmony_ci	x_name = alloc(x_namelen, ATEMP);
303c84f3f3cSopenharmony_ci
304c84f3f3cSopenharmony_ci	for (x_suffix = x_suffix_list; rc && *x_suffix; x_suffix++) {
305c84f3f3cSopenharmony_ci		strlcpy(x_name, name, x_namelen);
306c84f3f3cSopenharmony_ci		strlcat(x_name, *x_suffix, x_namelen);
307c84f3f3cSopenharmony_ci
308c84f3f3cSopenharmony_ci		rc = action->isint ? action->fn.i(x_name, action->arg.i) :
309c84f3f3cSopenharmony_ci		    action->fn.p(x_name, action->arg.p);
310c84f3f3cSopenharmony_ci	}
311c84f3f3cSopenharmony_ci
312c84f3f3cSopenharmony_ci	afree(x_name, ATEMP);
313c84f3f3cSopenharmony_ci
314c84f3f3cSopenharmony_ci	return (rc);
315c84f3f3cSopenharmony_ci}
316c84f3f3cSopenharmony_ci
317c84f3f3cSopenharmony_ci/* access()/search_access() version */
318c84f3f3cSopenharmony_ciint
319c84f3f3cSopenharmony_ciaccess_ex(int (*fn)(const char *, int), const char *name, int mode)
320c84f3f3cSopenharmony_ci{
321c84f3f3cSopenharmony_ci	struct a_s_arg arg;
322c84f3f3cSopenharmony_ci
323c84f3f3cSopenharmony_ci	arg.fn.i = fn;
324c84f3f3cSopenharmony_ci	arg.arg.i = mode;
325c84f3f3cSopenharmony_ci	arg.isint = true;
326c84f3f3cSopenharmony_ci	return (access_stat_ex(name, &arg));
327c84f3f3cSopenharmony_ci}
328c84f3f3cSopenharmony_ci
329c84f3f3cSopenharmony_ci/* stat()/lstat() version */
330c84f3f3cSopenharmony_ciint
331c84f3f3cSopenharmony_cistat_ex(int (*fn)(const char *, struct stat *),
332c84f3f3cSopenharmony_ci    const char *name, struct stat *buffer)
333c84f3f3cSopenharmony_ci{
334c84f3f3cSopenharmony_ci	struct a_s_arg arg;
335c84f3f3cSopenharmony_ci
336c84f3f3cSopenharmony_ci	arg.fn.p = fn;
337c84f3f3cSopenharmony_ci	arg.arg.p = buffer;
338c84f3f3cSopenharmony_ci	arg.isint = false;
339c84f3f3cSopenharmony_ci	return (access_stat_ex(name, &arg));
340c84f3f3cSopenharmony_ci}
341c84f3f3cSopenharmony_ci
342c84f3f3cSopenharmony_cistatic int
343c84f3f3cSopenharmony_citest_exec_exist(const char *name, void *arg)
344c84f3f3cSopenharmony_ci{
345c84f3f3cSopenharmony_ci	struct stat sb;
346c84f3f3cSopenharmony_ci	char *real_name;
347c84f3f3cSopenharmony_ci
348c84f3f3cSopenharmony_ci	if (stat(name, &sb) < 0 || !S_ISREG(sb.st_mode))
349c84f3f3cSopenharmony_ci		return (-1);
350c84f3f3cSopenharmony_ci
351c84f3f3cSopenharmony_ci	/*XXX memory leak */
352c84f3f3cSopenharmony_ci	strdupx(real_name, name, ATEMP);
353c84f3f3cSopenharmony_ci	*((char **)arg) = real_name;
354c84f3f3cSopenharmony_ci	return (0);
355c84f3f3cSopenharmony_ci}
356c84f3f3cSopenharmony_ci
357c84f3f3cSopenharmony_ciconst char *
358c84f3f3cSopenharmony_cireal_exec_name(const char *name)
359c84f3f3cSopenharmony_ci{
360c84f3f3cSopenharmony_ci	struct a_s_arg arg;
361c84f3f3cSopenharmony_ci	char *real_name;
362c84f3f3cSopenharmony_ci
363c84f3f3cSopenharmony_ci	arg.fn.p = &test_exec_exist;
364c84f3f3cSopenharmony_ci	arg.arg.p = (void *)(&real_name);
365c84f3f3cSopenharmony_ci	arg.isint = false;
366c84f3f3cSopenharmony_ci	return (access_stat_ex(name, &arg) ? name : real_name);
367c84f3f3cSopenharmony_ci}
368c84f3f3cSopenharmony_ci
369c84f3f3cSopenharmony_ci/* make a response file to pass a very long command line */
370c84f3f3cSopenharmony_cistatic char *
371c84f3f3cSopenharmony_cimake_response_file(char * const *argv)
372c84f3f3cSopenharmony_ci{
373c84f3f3cSopenharmony_ci	char rsp_name_arg[] = "@mksh-rsp-XXXXXX";
374c84f3f3cSopenharmony_ci	char *rsp_name = &rsp_name_arg[1];
375c84f3f3cSopenharmony_ci	int i;
376c84f3f3cSopenharmony_ci	int fd;
377c84f3f3cSopenharmony_ci	char *result;
378c84f3f3cSopenharmony_ci
379c84f3f3cSopenharmony_ci	if ((fd = mkstemp(rsp_name)) == -1)
380c84f3f3cSopenharmony_ci		return (NULL);
381c84f3f3cSopenharmony_ci
382c84f3f3cSopenharmony_ci	/* write all the arguments except a 0th program name */
383c84f3f3cSopenharmony_ci	for (i = 1; argv[i]; i++) {
384c84f3f3cSopenharmony_ci		write(fd, argv[i], strlen(argv[i]));
385c84f3f3cSopenharmony_ci		write(fd, "\n", 1);
386c84f3f3cSopenharmony_ci	}
387c84f3f3cSopenharmony_ci
388c84f3f3cSopenharmony_ci	close(fd);
389c84f3f3cSopenharmony_ci	add_temp(rsp_name);
390c84f3f3cSopenharmony_ci	strdupx(result, rsp_name_arg, ATEMP);
391c84f3f3cSopenharmony_ci
392c84f3f3cSopenharmony_ci	return (result);
393c84f3f3cSopenharmony_ci}
394c84f3f3cSopenharmony_ci
395c84f3f3cSopenharmony_ci/* alias of execve() */
396c84f3f3cSopenharmony_ciextern int _std_execve(const char *, char * const *, char * const *);
397c84f3f3cSopenharmony_ci
398c84f3f3cSopenharmony_ci/* replacement for execve() of kLIBC */
399c84f3f3cSopenharmony_ciint
400c84f3f3cSopenharmony_ciexecve(const char *name, char * const *argv, char * const *envp)
401c84f3f3cSopenharmony_ci{
402c84f3f3cSopenharmony_ci	const char *exec_name;
403c84f3f3cSopenharmony_ci	FILE *fp;
404c84f3f3cSopenharmony_ci	char sign[2];
405c84f3f3cSopenharmony_ci	int pid;
406c84f3f3cSopenharmony_ci	int status;
407c84f3f3cSopenharmony_ci	int fd;
408c84f3f3cSopenharmony_ci	int rc;
409c84f3f3cSopenharmony_ci	int saved_mode;
410c84f3f3cSopenharmony_ci	int saved_errno;
411c84f3f3cSopenharmony_ci
412c84f3f3cSopenharmony_ci	/*
413c84f3f3cSopenharmony_ci	 * #! /bin/sh : append .exe
414c84f3f3cSopenharmony_ci	 * extproc sh : search sh.exe in PATH
415c84f3f3cSopenharmony_ci	 */
416c84f3f3cSopenharmony_ci	exec_name = search_path(name, path, X_OK, NULL);
417c84f3f3cSopenharmony_ci	if (!exec_name) {
418c84f3f3cSopenharmony_ci		errno = ENOENT;
419c84f3f3cSopenharmony_ci		return (-1);
420c84f3f3cSopenharmony_ci	}
421c84f3f3cSopenharmony_ci
422c84f3f3cSopenharmony_ci	/*-
423c84f3f3cSopenharmony_ci	 * kLIBC execve() has problems when executing scripts.
424c84f3f3cSopenharmony_ci	 * 1. it fails to execute a script if a directory whose name
425c84f3f3cSopenharmony_ci	 *    is same as an interpreter exists in a current directory.
426c84f3f3cSopenharmony_ci	 * 2. it fails to execute a script not starting with sharpbang.
427c84f3f3cSopenharmony_ci	 * 3. it fails to execute a batch file if COMSPEC is set to a shell
428c84f3f3cSopenharmony_ci	 *    incompatible with cmd.exe, such as /bin/sh.
429c84f3f3cSopenharmony_ci	 * And ksh process scripts more well, so let ksh process scripts.
430c84f3f3cSopenharmony_ci	 */
431c84f3f3cSopenharmony_ci	errno = 0;
432c84f3f3cSopenharmony_ci	if (!(fp = fopen(exec_name, "rb")))
433c84f3f3cSopenharmony_ci		errno = ENOEXEC;
434c84f3f3cSopenharmony_ci
435c84f3f3cSopenharmony_ci	if (!errno && fread(sign, 1, sizeof(sign), fp) != sizeof(sign))
436c84f3f3cSopenharmony_ci		errno = ENOEXEC;
437c84f3f3cSopenharmony_ci
438c84f3f3cSopenharmony_ci	if (fp && fclose(fp))
439c84f3f3cSopenharmony_ci		errno = ENOEXEC;
440c84f3f3cSopenharmony_ci
441c84f3f3cSopenharmony_ci	if (!errno &&
442c84f3f3cSopenharmony_ci	    !((sign[0] == 'M' && sign[1] == 'Z') ||
443c84f3f3cSopenharmony_ci	      (sign[0] == 'N' && sign[1] == 'E') ||
444c84f3f3cSopenharmony_ci	      (sign[0] == 'L' && sign[1] == 'X')))
445c84f3f3cSopenharmony_ci		errno = ENOEXEC;
446c84f3f3cSopenharmony_ci
447c84f3f3cSopenharmony_ci	if (errno == ENOEXEC)
448c84f3f3cSopenharmony_ci		return (-1);
449c84f3f3cSopenharmony_ci
450c84f3f3cSopenharmony_ci	/*
451c84f3f3cSopenharmony_ci	 * Normal OS/2 programs expect that standard IOs, especially stdin,
452c84f3f3cSopenharmony_ci	 * are opened in text mode at the startup. By the way, on OS/2 kLIBC
453c84f3f3cSopenharmony_ci	 * child processes inherit a translation mode of a parent process.
454c84f3f3cSopenharmony_ci	 * As a result, if stdin is set to binary mode in a parent process,
455c84f3f3cSopenharmony_ci	 * stdin of child processes is opened in binary mode as well at the
456c84f3f3cSopenharmony_ci	 * startup. In this case, some programs such as sed suffer from CR.
457c84f3f3cSopenharmony_ci	 */
458c84f3f3cSopenharmony_ci	saved_mode = setmode(STDIN_FILENO, O_TEXT);
459c84f3f3cSopenharmony_ci
460c84f3f3cSopenharmony_ci	pid = spawnve(P_NOWAIT, exec_name, argv, envp);
461c84f3f3cSopenharmony_ci	saved_errno = errno;
462c84f3f3cSopenharmony_ci
463c84f3f3cSopenharmony_ci	/* arguments too long? */
464c84f3f3cSopenharmony_ci	if (pid == -1 && saved_errno == EINVAL) {
465c84f3f3cSopenharmony_ci		/* retry with a response file */
466c84f3f3cSopenharmony_ci		char *rsp_name_arg = make_response_file(argv);
467c84f3f3cSopenharmony_ci
468c84f3f3cSopenharmony_ci		if (rsp_name_arg) {
469c84f3f3cSopenharmony_ci			char *rsp_argv[3] = { argv[0], rsp_name_arg, NULL };
470c84f3f3cSopenharmony_ci
471c84f3f3cSopenharmony_ci			pid = spawnve(P_NOWAIT, exec_name, rsp_argv, envp);
472c84f3f3cSopenharmony_ci			saved_errno = errno;
473c84f3f3cSopenharmony_ci
474c84f3f3cSopenharmony_ci			afree(rsp_name_arg, ATEMP);
475c84f3f3cSopenharmony_ci		}
476c84f3f3cSopenharmony_ci	}
477c84f3f3cSopenharmony_ci
478c84f3f3cSopenharmony_ci	/* restore translation mode of stdin */
479c84f3f3cSopenharmony_ci	setmode(STDIN_FILENO, saved_mode);
480c84f3f3cSopenharmony_ci
481c84f3f3cSopenharmony_ci	if (pid == -1) {
482c84f3f3cSopenharmony_ci		cleanup_temps();
483c84f3f3cSopenharmony_ci
484c84f3f3cSopenharmony_ci		errno = saved_errno;
485c84f3f3cSopenharmony_ci		return (-1);
486c84f3f3cSopenharmony_ci	}
487c84f3f3cSopenharmony_ci
488c84f3f3cSopenharmony_ci	/* close all opened handles */
489c84f3f3cSopenharmony_ci	for (fd = 0; fd < NUFILE; fd++) {
490c84f3f3cSopenharmony_ci		if (fcntl(fd, F_GETFD) == -1)
491c84f3f3cSopenharmony_ci			continue;
492c84f3f3cSopenharmony_ci
493c84f3f3cSopenharmony_ci		close(fd);
494c84f3f3cSopenharmony_ci	}
495c84f3f3cSopenharmony_ci
496c84f3f3cSopenharmony_ci	while ((rc = waitpid(pid, &status, 0)) < 0 && errno == EINTR)
497c84f3f3cSopenharmony_ci		/* nothing */;
498c84f3f3cSopenharmony_ci
499c84f3f3cSopenharmony_ci	cleanup_temps();
500c84f3f3cSopenharmony_ci
501c84f3f3cSopenharmony_ci	/* Is this possible? And is this right? */
502c84f3f3cSopenharmony_ci	if (rc == -1)
503c84f3f3cSopenharmony_ci		return (-1);
504c84f3f3cSopenharmony_ci
505c84f3f3cSopenharmony_ci	if (WIFSIGNALED(status))
506c84f3f3cSopenharmony_ci		_exit(ksh_sigmask(WTERMSIG(status)));
507c84f3f3cSopenharmony_ci
508c84f3f3cSopenharmony_ci	_exit(WEXITSTATUS(status));
509c84f3f3cSopenharmony_ci}
510c84f3f3cSopenharmony_ci
511c84f3f3cSopenharmony_cistatic struct temp *templist = NULL;
512c84f3f3cSopenharmony_ci
513c84f3f3cSopenharmony_cistatic void
514c84f3f3cSopenharmony_ciadd_temp(const char *name)
515c84f3f3cSopenharmony_ci{
516c84f3f3cSopenharmony_ci	struct temp *tp;
517c84f3f3cSopenharmony_ci
518c84f3f3cSopenharmony_ci	tp = alloc(offsetof(struct temp, tffn[0]) + strlen(name) + 1, APERM);
519c84f3f3cSopenharmony_ci	memcpy(tp->tffn, name, strlen(name) + 1);
520c84f3f3cSopenharmony_ci	tp->next = templist;
521c84f3f3cSopenharmony_ci	templist = tp;
522c84f3f3cSopenharmony_ci}
523c84f3f3cSopenharmony_ci
524c84f3f3cSopenharmony_ci/* alias of unlink() */
525c84f3f3cSopenharmony_ciextern int _std_unlink(const char *);
526c84f3f3cSopenharmony_ci
527c84f3f3cSopenharmony_ci/*
528c84f3f3cSopenharmony_ci * Replacement for unlink() of kLIBC not supporting to remove files used by
529c84f3f3cSopenharmony_ci * another processes.
530c84f3f3cSopenharmony_ci */
531c84f3f3cSopenharmony_ciint
532c84f3f3cSopenharmony_ciunlink(const char *name)
533c84f3f3cSopenharmony_ci{
534c84f3f3cSopenharmony_ci	int rc;
535c84f3f3cSopenharmony_ci
536c84f3f3cSopenharmony_ci	rc = _std_unlink(name);
537c84f3f3cSopenharmony_ci	if (rc == -1 && errno != ENOENT)
538c84f3f3cSopenharmony_ci		add_temp(name);
539c84f3f3cSopenharmony_ci
540c84f3f3cSopenharmony_ci	return (rc);
541c84f3f3cSopenharmony_ci}
542c84f3f3cSopenharmony_ci
543c84f3f3cSopenharmony_cistatic void
544c84f3f3cSopenharmony_cicleanup_temps(void)
545c84f3f3cSopenharmony_ci{
546c84f3f3cSopenharmony_ci	struct temp *tp;
547c84f3f3cSopenharmony_ci	struct temp **tpnext;
548c84f3f3cSopenharmony_ci
549c84f3f3cSopenharmony_ci	for (tpnext = &templist, tp = templist; tp; tp = *tpnext) {
550c84f3f3cSopenharmony_ci		if (_std_unlink(tp->tffn) == 0 || errno == ENOENT) {
551c84f3f3cSopenharmony_ci			*tpnext = tp->next;
552c84f3f3cSopenharmony_ci			afree(tp, APERM);
553c84f3f3cSopenharmony_ci		} else {
554c84f3f3cSopenharmony_ci			tpnext = &tp->next;
555c84f3f3cSopenharmony_ci		}
556c84f3f3cSopenharmony_ci	}
557c84f3f3cSopenharmony_ci}
558c84f3f3cSopenharmony_ci
559c84f3f3cSopenharmony_cistatic void
560c84f3f3cSopenharmony_cicleanup(void)
561c84f3f3cSopenharmony_ci{
562c84f3f3cSopenharmony_ci	cleanup_temps();
563c84f3f3cSopenharmony_ci}
564c84f3f3cSopenharmony_ci
565c84f3f3cSopenharmony_ciint
566c84f3f3cSopenharmony_cigetdrvwd(char **cpp, unsigned int drvltr)
567c84f3f3cSopenharmony_ci{
568c84f3f3cSopenharmony_ci	PBYTE cp;
569c84f3f3cSopenharmony_ci	ULONG sz;
570c84f3f3cSopenharmony_ci	APIRET rc;
571c84f3f3cSopenharmony_ci	ULONG drvno;
572c84f3f3cSopenharmony_ci
573c84f3f3cSopenharmony_ci	if (DosQuerySysInfo(QSV_MAX_PATH_LENGTH, QSV_MAX_PATH_LENGTH,
574c84f3f3cSopenharmony_ci	    &sz, sizeof(sz)) != 0) {
575c84f3f3cSopenharmony_ci		errno = EDOOFUS;
576c84f3f3cSopenharmony_ci		return (-1);
577c84f3f3cSopenharmony_ci	}
578c84f3f3cSopenharmony_ci
579c84f3f3cSopenharmony_ci	/* allocate 'X:/' plus sz plus NUL */
580c84f3f3cSopenharmony_ci	checkoktoadd((size_t)sz, (size_t)4);
581c84f3f3cSopenharmony_ci	cp = aresize(*cpp, (size_t)sz + (size_t)4, ATEMP);
582c84f3f3cSopenharmony_ci	cp[0] = ksh_toupper(drvltr);
583c84f3f3cSopenharmony_ci	cp[1] = ':';
584c84f3f3cSopenharmony_ci	cp[2] = '/';
585c84f3f3cSopenharmony_ci	drvno = ksh_numuc(cp[0]) + 1;
586c84f3f3cSopenharmony_ci	/* NUL is part of space within buffer passed */
587c84f3f3cSopenharmony_ci	++sz;
588c84f3f3cSopenharmony_ci	if ((rc = DosQueryCurrentDir(drvno, cp + 3, &sz)) == 0) {
589c84f3f3cSopenharmony_ci		/* success! */
590c84f3f3cSopenharmony_ci		*cpp = cp;
591c84f3f3cSopenharmony_ci		return (0);
592c84f3f3cSopenharmony_ci	}
593c84f3f3cSopenharmony_ci	afree(cp, ATEMP);
594c84f3f3cSopenharmony_ci	*cpp = NULL;
595c84f3f3cSopenharmony_ci	switch (rc) {
596c84f3f3cSopenharmony_ci	case 15: /* invalid drive */
597c84f3f3cSopenharmony_ci		errno = ENOTBLK;
598c84f3f3cSopenharmony_ci		break;
599c84f3f3cSopenharmony_ci	case 26: /* not dos disk */
600c84f3f3cSopenharmony_ci		errno = ENODEV;
601c84f3f3cSopenharmony_ci		break;
602c84f3f3cSopenharmony_ci	case 108: /* drive locked */
603c84f3f3cSopenharmony_ci		errno = EDEADLK;
604c84f3f3cSopenharmony_ci		break;
605c84f3f3cSopenharmony_ci	case 111: /* buffer overflow */
606c84f3f3cSopenharmony_ci		errno = ENAMETOOLONG;
607c84f3f3cSopenharmony_ci		break;
608c84f3f3cSopenharmony_ci	default:
609c84f3f3cSopenharmony_ci		errno = EINVAL;
610c84f3f3cSopenharmony_ci	}
611c84f3f3cSopenharmony_ci	return (-1);
612c84f3f3cSopenharmony_ci}
613