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