merge mksh-os2 by KO Myung-Hun <komh@chollian.net> from https://github.com/komh/mksh-os2
This commit is contained in:
commit
718d397fff
6
Build.sh
6
Build.sh
@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.711 2017/04/02 14:14:03 tg Exp $'
|
||||
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.712 2017/04/02 15:00:39 tg Exp $'
|
||||
#-
|
||||
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
# 2011, 2012, 2013, 2014, 2015, 2016, 2017
|
||||
@ -862,11 +862,11 @@ OpenBSD)
|
||||
OS/2)
|
||||
HAVE_TERMIOS_H=0
|
||||
HAVE_MKNOD=0 # setmode() incompatible
|
||||
oswarn="; it is currently being ported, get it from"
|
||||
oswarn="$oswarn${nl}https://github.com/komh/mksh-os2 in the meanwhile"
|
||||
oswarn="; it is being ported"
|
||||
check_categories="$check_categories nosymlink"
|
||||
: "${CC=gcc}"
|
||||
: "${SIZE=: size}"
|
||||
SRCS="$SRCS os2.c"
|
||||
add_cppflags -DMKSH_UNEMPLOYED
|
||||
add_cppflags -DMKSH_NOPROSPECTOFWORK
|
||||
add_cppflags -DMKSH_NO_LIMITS
|
||||
|
6
edit.c
6
edit.c
@ -28,7 +28,7 @@
|
||||
|
||||
#ifndef MKSH_NO_CMDLINE_EDITING
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.313 2017/03/11 22:49:54 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.314 2017/04/02 15:00:40 tg Exp $");
|
||||
|
||||
/*
|
||||
* in later versions we might use libtermcap for this, but since external
|
||||
@ -145,6 +145,9 @@ x_read(char *buf)
|
||||
static int
|
||||
x_getc(void)
|
||||
{
|
||||
#ifdef __OS2__
|
||||
return (_read_kbd(0, 1, 0));
|
||||
#else
|
||||
char c;
|
||||
ssize_t n;
|
||||
|
||||
@ -166,6 +169,7 @@ x_getc(void)
|
||||
x_mode(true);
|
||||
}
|
||||
return ((n == 1) ? (int)(unsigned char)c : -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
24
eval.c
24
eval.c
@ -23,7 +23,7 @@
|
||||
|
||||
#include "sh.h"
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.199 2017/03/26 00:10:23 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.200 2017/04/02 15:00:41 tg Exp $");
|
||||
|
||||
/*
|
||||
* string expansion
|
||||
@ -879,10 +879,30 @@ expand(
|
||||
c = '\n';
|
||||
--newlines;
|
||||
} else {
|
||||
while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
|
||||
while ((c = shf_getc(x.u.shf)) == 0 ||
|
||||
#ifdef MKSH_WITH_TEXTMODE
|
||||
c == '\r' ||
|
||||
#endif
|
||||
c == '\n') {
|
||||
#ifdef MKSH_WITH_TEXTMODE
|
||||
if (c == '\r') {
|
||||
c = shf_getc(x.u.shf);
|
||||
switch (c) {
|
||||
case '\n':
|
||||
break;
|
||||
default:
|
||||
shf_ungetc(c, x.u.shf);
|
||||
/* FALLTHROUGH */
|
||||
case -1:
|
||||
c = '\r';
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (c == '\n')
|
||||
/* save newlines */
|
||||
newlines++;
|
||||
}
|
||||
if (newlines && c != -1) {
|
||||
shf_ungetc(c, x.u.shf);
|
||||
c = '\n';
|
||||
|
44
exec.c
44
exec.c
@ -23,7 +23,7 @@
|
||||
|
||||
#include "sh.h"
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.192 2017/04/02 13:08:06 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.193 2017/04/02 15:00:42 tg Exp $");
|
||||
|
||||
#ifndef MKSH_DEFAULT_EXECSHELL
|
||||
#define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh"
|
||||
@ -889,6 +889,9 @@ scriptexec(struct op *tp, const char **ap)
|
||||
unsigned short m;
|
||||
ssize_t n;
|
||||
|
||||
#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
|
||||
setmode(fd, O_TEXT);
|
||||
#endif
|
||||
/* read first couple of octets from file */
|
||||
n = read(fd, buf, sizeof(buf) - 1);
|
||||
close(fd);
|
||||
@ -944,6 +947,17 @@ scriptexec(struct op *tp, const char **ap)
|
||||
if (*cp)
|
||||
*tp->args-- = (char *)cp;
|
||||
}
|
||||
#ifdef __OS2__
|
||||
/*
|
||||
* Search shell/interpreter name without directory in PATH
|
||||
* if specified path does not exist
|
||||
*/
|
||||
if (mksh_vdirsep(sh) && !search_path(sh, path, X_OK, NULL)) {
|
||||
cp = search_path(_getname(sh), path, X_OK, NULL);
|
||||
if (cp)
|
||||
sh = cp;
|
||||
}
|
||||
#endif
|
||||
goto nomagic;
|
||||
noshebang:
|
||||
m = buf[0] << 8 | buf[1];
|
||||
@ -964,6 +978,19 @@ scriptexec(struct op *tp, const char **ap)
|
||||
buf[4] == 'Z') || (m == /* 7zip */ 0x377A) ||
|
||||
(m == /* gzip */ 0x1F8B) || (m == /* .Z */ 0x1F9D))
|
||||
errorf("%s: not executable: magic %04X", tp->str, m);
|
||||
#ifdef __OS2__
|
||||
cp = _getext(tp->str);
|
||||
if (cp && (!stricmp(cp, ".cmd") || !stricmp(cp, ".bat"))) {
|
||||
/* execute .cmd and .bat with OS2_SHELL, usually CMD.EXE */
|
||||
sh = getenv("OS2_SHELL");
|
||||
*tp->args-- = "/c";
|
||||
/* convert slahes to backslashes */
|
||||
for (cp = tp->str; *cp; cp++) {
|
||||
if (*cp == '/')
|
||||
*cp = '\\';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
nomagic:
|
||||
;
|
||||
}
|
||||
@ -1267,6 +1294,13 @@ search_access(const char *fn, int mode)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef __OS2__
|
||||
/* check if path is something we want to find, adding executable extensions */
|
||||
#define search_access(fn, mode) access_ex((search_access), (fn), (mode))
|
||||
#else
|
||||
#define search_access(fn, mode) (search_access)((fn), (mode))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* search for command with PATH
|
||||
*/
|
||||
@ -1288,7 +1322,11 @@ search_path(const char *name, const char *lpath,
|
||||
search_path_ok:
|
||||
if (errnop)
|
||||
*errnop = 0;
|
||||
#ifndef __OS2__
|
||||
return (name);
|
||||
#else
|
||||
return (real_exec_name(name));
|
||||
#endif
|
||||
}
|
||||
goto search_path_err;
|
||||
}
|
||||
@ -1305,6 +1343,10 @@ search_path(const char *name, const char *lpath,
|
||||
XcheckN(xs, xp, p - sp);
|
||||
memcpy(xp, sp, p - sp);
|
||||
xp += p - sp;
|
||||
#ifdef __OS2__
|
||||
if (xp > Xstring(xs, xp) && mksh_cdirsep(xp[-1]))
|
||||
xp--;
|
||||
#endif
|
||||
*xp++ = '/';
|
||||
}
|
||||
sp = p;
|
||||
|
6
expr.c
6
expr.c
@ -23,7 +23,7 @@
|
||||
|
||||
#include "sh.h"
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.91 2017/03/26 00:10:23 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.92 2017/04/02 15:00:42 tg Exp $");
|
||||
|
||||
#define EXPRTOK_DEFNS
|
||||
#include "exprtok.h"
|
||||
@ -857,6 +857,9 @@ utf_wctomb(char *dst, unsigned int wc)
|
||||
int
|
||||
ksh_access(const char *fn, int mode)
|
||||
{
|
||||
#ifdef __OS2__
|
||||
return (access_ex(access, fn, mode));
|
||||
#else
|
||||
int rv;
|
||||
struct stat sb;
|
||||
|
||||
@ -866,6 +869,7 @@ ksh_access(const char *fn, int mode)
|
||||
rv = -1;
|
||||
|
||||
return (rv);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef MIRBSD_BOOTFLOPPY
|
||||
|
35
funcs.c
35
funcs.c
@ -38,7 +38,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.331 2017/03/22 00:20:41 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.332 2017/04/02 15:00:42 tg Exp $");
|
||||
|
||||
#if HAVE_KILLPG
|
||||
/*
|
||||
@ -1968,6 +1968,10 @@ c_read(const char **wp)
|
||||
#define c_read_opts "Aad:N:n:prst:u,"
|
||||
#else
|
||||
#define c_read_opts "Aad:N:n:prsu,"
|
||||
#endif
|
||||
#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
|
||||
int saved_mode;
|
||||
int saved_errno;
|
||||
#endif
|
||||
|
||||
while ((c = ksh_getopt(wp, &builtin_opt, c_read_opts)) != -1)
|
||||
@ -2097,7 +2101,15 @@ c_read(const char **wp)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
|
||||
saved_mode = setmode(fd, O_TEXT);
|
||||
#endif
|
||||
if ((bytesread = blocking_read(fd, xp, bytesleft)) == (size_t)-1) {
|
||||
#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
|
||||
saved_errno = errno;
|
||||
setmode(fd, saved_mode);
|
||||
errno = saved_errno;
|
||||
#endif
|
||||
if (errno == EINTR) {
|
||||
/* check whether the signal would normally kill */
|
||||
if (!fatal_trap_check()) {
|
||||
@ -2112,6 +2124,9 @@ c_read(const char **wp)
|
||||
rv = 2;
|
||||
goto c_read_out;
|
||||
}
|
||||
#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
|
||||
setmode(fd, saved_mode);
|
||||
#endif
|
||||
|
||||
switch (readmode) {
|
||||
case READALL:
|
||||
@ -2828,7 +2843,7 @@ c_exec(const char **wp MKSH_A_UNUSED)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if HAVE_MKNOD
|
||||
#if HAVE_MKNOD && !defined(__OS2__)
|
||||
int
|
||||
c_mknod(const char **wp)
|
||||
{
|
||||
@ -3085,6 +3100,14 @@ test_isop(Test_meta meta, const char *s)
|
||||
return (TO_NONOP);
|
||||
}
|
||||
|
||||
#ifdef __OS2__
|
||||
#define test_access(name, mode) access_ex(access, (name), (mode))
|
||||
#define test_stat(name, buffer) stat_ex((name), (buffer))
|
||||
#else
|
||||
#define test_access(name, mode) access((name), (mode))
|
||||
#define test_stat(name, buffer) stat((name), (buffer))
|
||||
#endif
|
||||
|
||||
int
|
||||
test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
|
||||
bool do_eval)
|
||||
@ -3150,12 +3173,12 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
|
||||
/* -r */
|
||||
case TO_FILRD:
|
||||
/* LINTED use of access */
|
||||
return (access(opnd1, R_OK) == 0);
|
||||
return (test_access(opnd1, R_OK) == 0);
|
||||
|
||||
/* -w */
|
||||
case TO_FILWR:
|
||||
/* LINTED use of access */
|
||||
return (access(opnd1, W_OK) == 0);
|
||||
return (test_access(opnd1, W_OK) == 0);
|
||||
|
||||
/* -x */
|
||||
case TO_FILEX:
|
||||
@ -3165,11 +3188,11 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
|
||||
case TO_FILAXST:
|
||||
/* -e */
|
||||
case TO_FILEXST:
|
||||
return (stat(opnd1, &b1) == 0);
|
||||
return (test_stat(opnd1, &b1) == 0);
|
||||
|
||||
/* -r */
|
||||
case TO_FILREG:
|
||||
return (stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode));
|
||||
return (test_stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode));
|
||||
|
||||
/* -d */
|
||||
case TO_FILID:
|
||||
|
12
main.c
12
main.c
@ -34,7 +34,7 @@
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.328 2017/03/19 22:31:27 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.329 2017/04/02 15:00:43 tg Exp $");
|
||||
|
||||
extern char **environ;
|
||||
|
||||
@ -195,6 +195,8 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
|
||||
for (i = 0; i < 3; ++i)
|
||||
if (!isatty(i))
|
||||
setmode(i, O_BINARY);
|
||||
|
||||
os2_init(&argc, &argv);
|
||||
#endif
|
||||
|
||||
/* do things like getpgrp() et al. */
|
||||
@ -467,7 +469,9 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
|
||||
* to search for it. This changes the behaviour of a
|
||||
* simple "mksh foo", but can't be helped.
|
||||
*/
|
||||
s->file = search_path(argv[argi++], path, X_OK, NULL);
|
||||
s->file = argv[argi++];
|
||||
if (search_access(s->file, X_OK) != 0)
|
||||
s->file = search_path(s->file, path, X_OK, NULL);
|
||||
if (!s->file || !*s->file)
|
||||
s->file = argv[argi - 1];
|
||||
#else
|
||||
@ -1461,6 +1465,10 @@ openpipe(int *pv)
|
||||
pv[1] = savefd(lpv[1]);
|
||||
if (pv[1] != lpv[1])
|
||||
close(lpv[1]);
|
||||
#ifdef __OS2__
|
||||
setmode(pv[0], O_BINARY);
|
||||
setmode(pv[1], O_BINARY);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
557
os2.c
Normal file
557
os2.c
Normal file
@ -0,0 +1,557 @@
|
||||
/*-
|
||||
* Copyright (c) 2015
|
||||
* KO Myung-Hun <komh@chollian.net>
|
||||
*
|
||||
* Provided that these terms and disclaimer and all copyright notices
|
||||
* are retained or reproduced in an accompanying document, permission
|
||||
* is granted to deal in this work without restriction, including un-
|
||||
* limited rights to use, publicly perform, distribute, sell, modify,
|
||||
* merge, give away, or sublicence.
|
||||
*
|
||||
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
|
||||
* the utmost extent permitted by applicable law, neither express nor
|
||||
* implied; without malicious intent or gross negligence. In no event
|
||||
* may a licensor, author or contributor be held liable for indirect,
|
||||
* direct, other damage, loss, or other issues arising in any way out
|
||||
* of dealing in the work, even if advised of the possibility of such
|
||||
* damage or existence of a defect, except proven that it results out
|
||||
* of said person's immediate fault when using the work as intended.
|
||||
*/
|
||||
|
||||
#define INCL_DOS
|
||||
#include <os2.h>
|
||||
|
||||
#include "sh.h"
|
||||
|
||||
#include <klibc/startup.h>
|
||||
#include <io.h>
|
||||
#include <unistd.h>
|
||||
#include <process.h>
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.1 2017/04/02 15:00:44 tg Exp $");
|
||||
|
||||
static char *remove_trailing_dots(char *);
|
||||
static int access_stat_ex(int (*)(), const char *, void *);
|
||||
static int test_exec_exist(const char *, char *);
|
||||
static void response(int *, const char ***);
|
||||
static char *make_response_file(char * const *);
|
||||
static void env_slashify(void);
|
||||
static void add_temp(const char *);
|
||||
static void cleanup_temps(void);
|
||||
static void cleanup(void);
|
||||
|
||||
#define RPUT(x) do { \
|
||||
if (new_argc >= new_alloc) { \
|
||||
new_alloc += 20; \
|
||||
if (!(new_argv = realloc(new_argv, \
|
||||
new_alloc * sizeof(char *)))) \
|
||||
goto exit_out_of_memory; \
|
||||
} \
|
||||
new_argv[new_argc++] = (x); \
|
||||
} while (/* CONSTCOND */ 0)
|
||||
|
||||
#define KLIBC_ARG_RESPONSE_EXCLUDE \
|
||||
(__KLIBC_ARG_DQUOTE | __KLIBC_ARG_WILDCARD | __KLIBC_ARG_SHELL)
|
||||
|
||||
static void
|
||||
response(int *argcp, const char ***argvp)
|
||||
{
|
||||
int i, old_argc, new_argc, new_alloc = 0;
|
||||
const char **old_argv, **new_argv;
|
||||
char *line, *l, *p;
|
||||
FILE *f;
|
||||
|
||||
old_argc = *argcp;
|
||||
old_argv = *argvp;
|
||||
for (i = 1; i < old_argc; ++i)
|
||||
if (old_argv[i] &&
|
||||
!(old_argv[i][-1] & KLIBC_ARG_RESPONSE_EXCLUDE) &&
|
||||
old_argv[i][0] == '@')
|
||||
break;
|
||||
|
||||
if (i >= old_argc)
|
||||
/* do nothing */
|
||||
return;
|
||||
|
||||
new_argv = NULL;
|
||||
new_argc = 0;
|
||||
for (i = 0; i < old_argc; ++i) {
|
||||
if (i == 0 || !old_argv[i] ||
|
||||
(old_argv[i][-1] & KLIBC_ARG_RESPONSE_EXCLUDE) ||
|
||||
old_argv[i][0] != '@' ||
|
||||
!(f = fopen(old_argv[i] + 1, "rt")))
|
||||
RPUT(old_argv[i]);
|
||||
else {
|
||||
long filesize;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
filesize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
line = malloc(filesize + /* type */ 1 + /* NUL */ 1);
|
||||
if (!line) {
|
||||
exit_out_of_memory:
|
||||
fputs("Out of memory while reading response file\n", stderr);
|
||||
exit(255);
|
||||
}
|
||||
|
||||
line[0] = __KLIBC_ARG_NONZERO | __KLIBC_ARG_RESPONSE;
|
||||
l = line + 1;
|
||||
while (fgets(l, (filesize + 1) - (l - (line + 1)), f)) {
|
||||
p = strchr(l, '\n');
|
||||
if (p) {
|
||||
/*
|
||||
* if a line ends with a backslash,
|
||||
* concatenate with the next line
|
||||
*/
|
||||
if (p > l && p[-1] == '\\') {
|
||||
char *p1;
|
||||
int count = 0;
|
||||
|
||||
for (p1 = p - 1; p1 >= l &&
|
||||
*p1 == '\\'; p1--)
|
||||
count++;
|
||||
|
||||
if (count & 1) {
|
||||
l = p + 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
}
|
||||
p = strdup(line);
|
||||
if (!p)
|
||||
goto exit_out_of_memory;
|
||||
|
||||
RPUT(p + 1);
|
||||
|
||||
l = line + 1;
|
||||
}
|
||||
|
||||
free(line);
|
||||
|
||||
if (ferror(f)) {
|
||||
fputs("Cannot read response file\n", stderr);
|
||||
exit(255);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
RPUT(NULL);
|
||||
--new_argc;
|
||||
|
||||
*argcp = new_argc;
|
||||
*argvp = new_argv;
|
||||
}
|
||||
|
||||
static void
|
||||
init_extlibpath(void)
|
||||
{
|
||||
const char *vars[] = {
|
||||
"BEGINLIBPATH",
|
||||
"ENDLIBPATH",
|
||||
"LIBPATHSTRICT",
|
||||
NULL
|
||||
};
|
||||
char val[512];
|
||||
int flag;
|
||||
|
||||
for (flag = 0; vars[flag]; flag++) {
|
||||
DosQueryExtLIBPATH(val, flag + 1);
|
||||
if (val[0])
|
||||
setenv(vars[flag], val, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert backslashes of environmental variables to forward slahes.
|
||||
* A backslash may be used as an escaped character when doing 'echo'.
|
||||
* This leads to an unexpected behavior.
|
||||
*/
|
||||
static void
|
||||
env_slashify(void)
|
||||
{
|
||||
/*
|
||||
* PATH and TMPDIR are used by OS/2 as well. That is, they may
|
||||
* have backslashes as a directory separator.
|
||||
* BEGINLIBPATH and ENDLIBPATH are special variables on OS/2.
|
||||
*/
|
||||
const char *var_list[] = {
|
||||
"PATH",
|
||||
"TMPDIR",
|
||||
"BEGINLIBPATH",
|
||||
"ENDLIBPATH",
|
||||
NULL
|
||||
};
|
||||
const char **var;
|
||||
char *value;
|
||||
|
||||
for (var = var_list; *var; var++) {
|
||||
value = getenv(*var);
|
||||
|
||||
if (value)
|
||||
_fnslashify(value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
os2_init(int *argcp, const char ***argvp)
|
||||
{
|
||||
response(argcp, argvp);
|
||||
|
||||
init_extlibpath();
|
||||
env_slashify();
|
||||
|
||||
if (!isatty(STDIN_FILENO))
|
||||
setmode(STDIN_FILENO, O_BINARY);
|
||||
if (!isatty(STDOUT_FILENO))
|
||||
setmode(STDOUT_FILENO, O_BINARY);
|
||||
if (!isatty(STDERR_FILENO))
|
||||
setmode(STDERR_FILENO, O_BINARY);
|
||||
|
||||
atexit(cleanup);
|
||||
}
|
||||
|
||||
void
|
||||
setextlibpath(const char *name, const char *val)
|
||||
{
|
||||
int flag;
|
||||
char *p, *cp;
|
||||
|
||||
if (!strcmp(name, "BEGINLIBPATH"))
|
||||
flag = BEGIN_LIBPATH;
|
||||
else if (!strcmp(name, "ENDLIBPATH"))
|
||||
flag = END_LIBPATH;
|
||||
else if (!strcmp(name, "LIBPATHSTRICT"))
|
||||
flag = LIBPATHSTRICT;
|
||||
else
|
||||
return;
|
||||
|
||||
/* convert slashes to backslashes */
|
||||
strdupx(cp, val, ATEMP);
|
||||
for (p = cp; *p; p++) {
|
||||
if (*p == '/')
|
||||
*p = '\\';
|
||||
}
|
||||
|
||||
DosSetExtLIBPATH(cp, flag);
|
||||
|
||||
afree(cp, ATEMP);
|
||||
}
|
||||
|
||||
/* remove trailing dots */
|
||||
static char *
|
||||
remove_trailing_dots(char *name)
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p = name + strlen(name); --p > name && *p == '.'; )
|
||||
/* nothing */;
|
||||
|
||||
if (*p != '.' && *p != '/' && *p != '\\' && *p != ':')
|
||||
p[1] = '\0';
|
||||
|
||||
return (name);
|
||||
}
|
||||
|
||||
#define REMOVE_TRAILING_DOTS(name) \
|
||||
remove_trailing_dots(memcpy(alloca(strlen(name) + 1), name, strlen(name) + 1))
|
||||
|
||||
/* alias of stat() */
|
||||
extern int _std_stat(const char *, struct stat *);
|
||||
|
||||
/* replacement for stat() of kLIBC which fails if there are trailing dots */
|
||||
int
|
||||
stat(const char *name, struct stat *buffer)
|
||||
{
|
||||
return (_std_stat(REMOVE_TRAILING_DOTS(name), buffer));
|
||||
}
|
||||
|
||||
/* alias of access() */
|
||||
extern int _std_access(const char *, int);
|
||||
|
||||
/* replacement for access() of kLIBC which fails if there are trailing dots */
|
||||
int
|
||||
access(const char *name, int mode)
|
||||
{
|
||||
/*
|
||||
* On OS/2 kLIBC, X_OK is set only for executable files.
|
||||
* This prevents scripts from being executed.
|
||||
*/
|
||||
if (mode & X_OK)
|
||||
mode = (mode & ~X_OK) | R_OK;
|
||||
|
||||
return (_std_access(REMOVE_TRAILING_DOTS(name), mode));
|
||||
}
|
||||
|
||||
#define MAX_X_SUFFIX_LEN 4
|
||||
|
||||
static const char *x_suffix_list[] =
|
||||
{ "", ".ksh", ".exe", ".sh", ".cmd", ".com", ".bat", NULL };
|
||||
|
||||
/* call fn() by appending executable extensions */
|
||||
static int
|
||||
access_stat_ex(int (*fn)(), const char *name, void *arg)
|
||||
{
|
||||
char *x_name;
|
||||
const char **x_suffix;
|
||||
int rc = -1;
|
||||
size_t x_namelen = strlen(name) + MAX_X_SUFFIX_LEN + 1;
|
||||
|
||||
/* otherwise, try to append executable suffixes */
|
||||
x_name = alloc(x_namelen, ATEMP);
|
||||
|
||||
for (x_suffix = x_suffix_list; rc && *x_suffix; x_suffix++) {
|
||||
strlcpy(x_name, name, x_namelen);
|
||||
strlcat(x_name, *x_suffix, x_namelen);
|
||||
|
||||
rc = fn(x_name, arg);
|
||||
}
|
||||
|
||||
afree(x_name, ATEMP);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/* access()/search_access() version */
|
||||
int
|
||||
access_ex(int (*fn)(const char *, int), const char *name, int mode)
|
||||
{
|
||||
/*XXX this smells fishy --mirabilos */
|
||||
return (access_stat_ex(fn, name, (void *)mode));
|
||||
}
|
||||
|
||||
/* stat() version */
|
||||
int
|
||||
stat_ex(const char *name, struct stat *buffer)
|
||||
{
|
||||
return (access_stat_ex(stat, name, buffer));
|
||||
}
|
||||
|
||||
static int
|
||||
test_exec_exist(const char *name, char *real_name)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (stat(name, &sb) < 0 || !S_ISREG(sb.st_mode))
|
||||
return (-1);
|
||||
|
||||
/* safe due to calculations in real_exec_name() */
|
||||
memcpy(real_name, name, strlen(name) + 1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
const char *
|
||||
real_exec_name(const char *name)
|
||||
{
|
||||
char x_name[strlen(name) + MAX_X_SUFFIX_LEN + 1];
|
||||
const char *real_name = name;
|
||||
|
||||
if (access_stat_ex(test_exec_exist, real_name, x_name) != -1)
|
||||
/*XXX memory leak */
|
||||
strdupx(real_name, x_name, ATEMP);
|
||||
|
||||
return (real_name);
|
||||
}
|
||||
|
||||
/* OS/2 can process a command line up to 32 KiB */
|
||||
#define MAX_CMD_LINE_LEN 32768
|
||||
|
||||
/* make a response file to pass a very long command line */
|
||||
static char *
|
||||
make_response_file(char * const *argv)
|
||||
{
|
||||
char rsp_name_arg[] = "@mksh-rsp-XXXXXX";
|
||||
char *rsp_name = &rsp_name_arg[1];
|
||||
int arg_len = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; argv[i]; i++)
|
||||
arg_len += strlen(argv[i]) + 1;
|
||||
|
||||
/*
|
||||
* If a length of command line is longer than MAX_CMD_LINE_LEN, then
|
||||
* use a response file. OS/2 cannot process a command line longer
|
||||
* than 32K. Of course, a response file cannot be recognised by a
|
||||
* normal OS/2 program, that is, neither non-EMX or non-kLIBC. But
|
||||
* it cannot accept a command line longer than 32K in itself. So
|
||||
* using a response file in this case, is an acceptable solution.
|
||||
*/
|
||||
if (arg_len > MAX_CMD_LINE_LEN) {
|
||||
int fd;
|
||||
char *result;
|
||||
|
||||
if ((fd = mkstemp(rsp_name)) == -1)
|
||||
return (NULL);
|
||||
|
||||
/* write all the arguments except a 0th program name */
|
||||
for (i = 1; argv[i]; i++) {
|
||||
write(fd, argv[i], strlen(argv[i]));
|
||||
write(fd, "\n", 1);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
add_temp(rsp_name);
|
||||
strdupx(result, rsp_name_arg, ATEMP);
|
||||
return (result);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* alias of execve() */
|
||||
extern int _std_execve(const char *, char * const *, char * const *);
|
||||
|
||||
/* replacement for execve() of kLIBC */
|
||||
int
|
||||
execve(const char *name, char * const *argv, char * const *envp)
|
||||
{
|
||||
const char *exec_name;
|
||||
FILE *fp;
|
||||
char sign[2];
|
||||
char *rsp_argv[3];
|
||||
char *rsp_name_arg;
|
||||
int pid;
|
||||
int status;
|
||||
int fd;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* #! /bin/sh : append .exe
|
||||
* extproc sh : search sh.exe in PATH
|
||||
*/
|
||||
exec_name = search_path(name, path, X_OK, NULL);
|
||||
if (!exec_name) {
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*-
|
||||
* kLIBC execve() has problems when executing scripts.
|
||||
* 1. it fails to execute a script if a directory whose name
|
||||
* is same as an interpreter exists in a current directory.
|
||||
* 2. it fails to execute a script not starting with sharpbang.
|
||||
* 3. it fails to execute a batch file if COMSPEC is set to a shell
|
||||
* incompatible with cmd.exe, such as /bin/sh.
|
||||
* And ksh process scripts more well, so let ksh process scripts.
|
||||
*/
|
||||
errno = 0;
|
||||
if (!(fp = fopen(exec_name, "rb")))
|
||||
errno = ENOEXEC;
|
||||
|
||||
if (!errno && fread(sign, 1, sizeof(sign), fp) != sizeof(sign))
|
||||
errno = ENOEXEC;
|
||||
|
||||
if (fp && fclose(fp))
|
||||
errno = ENOEXEC;
|
||||
|
||||
if (!errno &&
|
||||
!((sign[0] == 'M' && sign[1] == 'Z') ||
|
||||
(sign[0] == 'N' && sign[1] == 'E') ||
|
||||
(sign[0] == 'L' && sign[1] == 'X')))
|
||||
errno = ENOEXEC;
|
||||
|
||||
if (errno == ENOEXEC)
|
||||
return (-1);
|
||||
|
||||
rsp_name_arg = make_response_file(argv);
|
||||
|
||||
if (rsp_name_arg) {
|
||||
rsp_argv[0] = argv[0];
|
||||
rsp_argv[1] = rsp_name_arg;
|
||||
rsp_argv[2] = NULL;
|
||||
|
||||
argv = rsp_argv;
|
||||
}
|
||||
|
||||
pid = spawnve(P_NOWAIT, exec_name, argv, envp);
|
||||
|
||||
afree(rsp_name_arg, ATEMP);
|
||||
|
||||
if (pid == -1) {
|
||||
cleanup_temps();
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* close all opened handles */
|
||||
for (fd = 0; fd < NUFILE; fd++) {
|
||||
if (fcntl(fd, F_GETFD) == -1)
|
||||
continue;
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
while ((rc = waitpid(pid, &status, 0)) < 0 && errno == EINTR)
|
||||
/* nothing */;
|
||||
|
||||
cleanup_temps();
|
||||
|
||||
/* Is this possible? And is this right? */
|
||||
if (rc == -1)
|
||||
return (-1);
|
||||
|
||||
if (WIFSIGNALED(status))
|
||||
_exit(ksh_sigmask(WTERMSIG(status)));
|
||||
|
||||
_exit(WEXITSTATUS(status));
|
||||
}
|
||||
|
||||
static struct temp *templist = NULL;
|
||||
|
||||
static void
|
||||
add_temp(const char *name)
|
||||
{
|
||||
struct temp *tp;
|
||||
|
||||
tp = alloc(offsetof(struct temp, tffn[0]) + strlen(name) + 1, APERM);
|
||||
memcpy(tp->tffn, name, strlen(name) + 1);
|
||||
tp->next = templist;
|
||||
templist = tp;
|
||||
}
|
||||
|
||||
/* alias of unlink() */
|
||||
extern int _std_unlink(const char *);
|
||||
|
||||
/*
|
||||
* Replacement for unlink() of kLIBC not supporting to remove files used by
|
||||
* another processes.
|
||||
*/
|
||||
int
|
||||
unlink(const char *name)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = _std_unlink(name);
|
||||
if (rc == -1 && errno != ENOENT)
|
||||
add_temp(name);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_temps(void)
|
||||
{
|
||||
struct temp *tp;
|
||||
struct temp **tpnext;
|
||||
|
||||
for (tpnext = &templist, tp = templist; tp; tp = *tpnext) {
|
||||
if (_std_unlink(tp->tffn) == 0 || errno == ENOENT) {
|
||||
*tpnext = tp->next;
|
||||
afree(tp, APERM);
|
||||
} else {
|
||||
tpnext = &tp->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup(void)
|
||||
{
|
||||
cleanup_temps();
|
||||
}
|
23
sh.h
23
sh.h
@ -175,7 +175,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef EXTERN
|
||||
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.800 2017/04/02 14:14:08 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.801 2017/04/02 15:00:44 tg Exp $");
|
||||
#endif
|
||||
#define MKSH_VERSION "R54 2017/03/25"
|
||||
|
||||
@ -2273,6 +2273,14 @@ char *strdup_i(const char *, Area *);
|
||||
char *strndup_i(const char *, size_t, Area *);
|
||||
#endif
|
||||
int unbksl(bool, int (*)(void), void (*)(int));
|
||||
#ifdef __OS2__
|
||||
/* os2.c */
|
||||
void os2_init(int *, const char ***);
|
||||
void setextlibpath(const char *, const char *);
|
||||
int access_ex(int (*)(const char *, int), const char *, int);
|
||||
int stat_ex(const char *, struct stat *);
|
||||
const char *real_exec_name(const char *);
|
||||
#endif
|
||||
/* shf.c */
|
||||
struct shf *shf_open(const char *, int, int, int);
|
||||
struct shf *shf_fdopen(int, int, struct shf *);
|
||||
@ -2448,11 +2456,14 @@ extern int tty_init_fd(void); /* initialise tty_fd, tty_devtty */
|
||||
char mksh_cdirsep_c = (c); \
|
||||
(mksh_cdirsep_c == '/' || mksh_cdirsep_c == '\\'); \
|
||||
})
|
||||
/*
|
||||
* I've seen mksh_sdirsep(s) and mksh_vdirsep(s) but need to think
|
||||
* more about the OS/2 port (and, possibly, toy with it) before I
|
||||
* can merge this upstream, but good job so far @komh, thanks!
|
||||
*/
|
||||
#define mksh_sdirsep(s) __extension__({ \
|
||||
const char *mksh_sdirsep_s = (s); \
|
||||
((char *)((ksh_isalphx(mksh_sdirsep_s[0]) && \
|
||||
mksh_sdirsep_s[1] == ':' && \
|
||||
!mksh_cdirsep(mksh_sdirsep_s[2])) ? \
|
||||
(mksh_sdirsep_s + 1) : strpbrk(mksh_sdirsep_s, "/\\"))); \
|
||||
})
|
||||
#define mksh_vdirsep(s) (mksh_sdirsep((s)) != NULL)
|
||||
#else
|
||||
#define mksh_abspath(s) ((s)[0] == '/')
|
||||
#define mksh_cdirsep(c) ((c) == '/')
|
||||
|
18
shf.c
18
shf.c
@ -25,7 +25,7 @@
|
||||
|
||||
#include "sh.h"
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.76 2016/07/25 00:04:47 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.77 2017/04/02 15:00:45 tg Exp $");
|
||||
|
||||
/* flags to shf_emptybuf() */
|
||||
#define EB_READSW 0x01 /* about to switch to reading */
|
||||
@ -518,7 +518,23 @@ shf_getse(char *buf, ssize_t bsize, struct shf *shf)
|
||||
shf->rnleft -= ncopy;
|
||||
buf += ncopy;
|
||||
bsize -= ncopy;
|
||||
#ifdef MKSH_WITH_TEXTMODE
|
||||
if (end && buf > orig_buf + 1 && buf[-2] == '\r') {
|
||||
buf--;
|
||||
bsize++;
|
||||
buf[-1] = '\n';
|
||||
}
|
||||
#endif
|
||||
} while (!end && bsize);
|
||||
#ifdef MKSH_WITH_TEXTMODE
|
||||
if (!bsize && buf[-1] == '\r') {
|
||||
int c = shf_getc(shf);
|
||||
if (c == '\n')
|
||||
buf[-1] = '\n';
|
||||
else if (c != -1)
|
||||
shf_ungetc(c, shf);
|
||||
}
|
||||
#endif
|
||||
*buf = '\0';
|
||||
return (buf);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user