Last active
May 27, 2016 02:00
-
-
Save p120ph37/628f2eeb409fa43437aa32dae856b729 to your computer and use it in GitHub Desktop.
Add support for dynamic file descriptors to the MirBSD Korn Shell.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: check.t | |
=================================================================== | |
RCS file: /cvs/src/bin/mksh/check.t,v | |
retrieving revision 1.732 | |
diff -u -r1.732 check.t | |
--- check.t 17 May 2016 15:36:56 -0000 1.732 | |
+++ check.t 27 May 2016 01:47:35 -0000 | |
@@ -10032,6 +10032,28 @@ | |
bar | |
baz | |
--- | |
+name: mkshiop-3 | |
+description: | |
+ Check support of dynamic file descriptors | |
+category: !convfds | |
+stdin: | |
+ exec 9<&- 10<&- 11<&- 12<&- | |
+ exec {FDA}<<< foo | |
+ read -u$FDA bar | |
+ echo x$bar$FDA | |
+ exec {FDB}<<< baz | |
+ read -u$FDB bar | |
+ echo x$bar$FDB | |
+ exec {FDA}<&- | |
+ exec {FDB}<&- | |
+ exec {FDC}<<< frob | |
+ read -u$FDC bar | |
+ echo x$bar$FDC | |
+expected-stdout: | |
+ xfoo10 | |
+ xbaz11 | |
+ xfrob10 | |
+--- | |
name: oksh-eval | |
description: | |
Check expansions. | |
Index: exec.c | |
=================================================================== | |
RCS file: /cvs/src/bin/mksh/exec.c,v | |
retrieving revision 1.173 | |
diff -u -r1.173 exec.c | |
--- exec.c 9 Apr 2016 16:41:32 -0000 1.173 | |
+++ exec.c 27 May 2016 01:47:35 -0000 | |
@@ -1363,6 +1363,7 @@ | |
int u = -1; | |
char *cp = iop->ioname; | |
int iotype = iop->ioflag & IOTYPE; | |
+ struct tbl *vp = NULL; | |
bool do_open = true, do_close = false, do_fstat = false; | |
int flags = 0; | |
struct ioword iotmp; | |
@@ -1371,6 +1372,9 @@ | |
if (iotype != IOHERE) | |
cp = evalonestr(cp, DOTILDE|(Flag(FTALKING_I) ? DOGLOB : 0)); | |
+ if (iop->ioflag & IODYNAMIC) | |
+ vp = global(evalstr(iop->varname, 0)); | |
+ | |
/* Used for tracing and error messages to print expanded cp */ | |
iotmp = *iop; | |
iotmp.ioname = (iotype == IOHERE) ? NULL : cp; | |
@@ -1434,6 +1438,12 @@ | |
/* prevent error return below */ | |
u = 1009; | |
do_close = true; | |
+ /* read variable for {FD}>&- syntax */ | |
+ if (iop->ioflag & IODYNAMIC) { | |
+ int i = 0; | |
+ getn(str_val(vp), &i); | |
+ iop->unit = i; | |
+ } | |
} else if ((u = check_fd(cp, | |
X_OK | ((iop->ioflag & IORDUP) ? R_OK : W_OK), | |
&emsg)) < 0) { | |
@@ -1444,7 +1454,7 @@ | |
afree(sp, ATEMP); | |
return (-1); | |
} | |
- if (u == (int)iop->unit) | |
+ if (u == (int)iop->unit && !(iop->ioflag & IODYNAMIC)) | |
/* "dup from" == "dup to" */ | |
return (0); | |
break; | |
@@ -1478,6 +1488,21 @@ | |
} | |
return (-1); | |
} | |
+ /* If unit was dynamic, pick an unused unit (fd) and store in variable */ | |
+ if (iop->ioflag & IODYNAMIC && !do_close) { | |
+ /* Dynamic file descriptors should always be >=10 */ | |
+ if (u < 10) { | |
+ int nu; | |
+ nu = fcntl(u, F_DUPFD, 10); | |
+ if (nu >= 0) { | |
+ if (iotype != IODUP) | |
+ close(u); | |
+ u = nu; | |
+ } | |
+ } | |
+ iop->unit = u; | |
+ setint(vp, iop->unit); | |
+ } | |
/* Do not save if it has already been redirected (i.e. "cat >x >y"). */ | |
if (e->savefd[iop->unit] == 0) { | |
/* If these are the same, it means unit was previously closed */ | |
Index: lex.c | |
=================================================================== | |
RCS file: /cvs/src/bin/mksh/lex.c,v | |
retrieving revision 1.224 | |
diff -u -r1.224 lex.c | |
--- lex.c 5 May 2016 22:46:23 -0000 1.224 | |
+++ lex.c 27 May 2016 01:47:35 -0000 | |
@@ -890,8 +890,18 @@ | |
c == '<' || c == '>')) { | |
struct ioword *iop = alloc(sizeof(struct ioword), ATEMP); | |
+ iop->ioflag = 0; | |
+ | |
if (Xlength(ws, wp) == 0) | |
iop->unit = c == '<' ? 0 : 1; | |
+ else if (dp[0] == CHAR && dp[1] == '{' && | |
+ dp[Xlength(ws, wp) - 2] == CHAR && dp[Xlength(ws, wp) - 1] == '}' && | |
+ Xlength(ws, wp) > 4) { | |
+ iop->ioflag |= IODYNAMIC; | |
+ iop->varname = alloc(Xlength(ws, wp) - 4 + 1, ATEMP); | |
+ memcpy(iop->varname, dp + 2, Xlength(ws, wp) - 4); | |
+ iop->varname[Xlength(ws, wp) - 4] = '\0'; | |
+ } | |
else for (iop->unit = 0, c2 = 0; c2 < Xlength(ws, wp); c2 += 2) { | |
if (dp[c2] != CHAR) | |
goto no_iop; | |
@@ -908,16 +918,15 @@ | |
goto no_iop; | |
} | |
c = c2; | |
- iop->ioflag = IOBASH; | |
- } else | |
- iop->ioflag = 0; | |
+ iop->ioflag |= IOBASH; | |
+ } | |
c2 = getsc(); | |
/* <<, >>, <> are ok, >< is not */ | |
if (c == c2 || (c == '<' && c2 == '>')) { | |
iop->ioflag |= c == c2 ? | |
(c == '>' ? IOCAT : IOHERE) : IORDWR; | |
- if (iop->ioflag == IOHERE) { | |
+ if (iop->ioflag & IOHERE) { | |
if ((c2 = getsc()) == '-') | |
iop->ioflag |= IOSKIP; | |
else if (c2 == '<') | |
Index: sh.h | |
=================================================================== | |
RCS file: /cvs/src/bin/mksh/sh.h,v | |
retrieving revision 1.772 | |
diff -u -r1.772 sh.h | |
--- sh.h 17 May 2016 15:36:59 -0000 1.772 | |
+++ sh.h 27 May 2016 01:47:35 -0000 | |
@@ -1429,6 +1429,7 @@ | |
char *heredoc; /* content of heredoc */ | |
unsigned short ioflag; /* action (below) */ | |
short unit; /* unit (fd) affected */ | |
+ char *varname; /* variable in which to store unit */ | |
}; | |
/* ioword.flag - type of redirection */ | |
@@ -1447,6 +1448,7 @@ | |
#define IOBASH BIT(9) /* &> etc. */ | |
#define IOHERESTR BIT(10) /* <<< (here string) */ | |
#define IONDELIM BIT(11) /* null delimiter (<<) */ | |
+#define IODYNAMIC BIT(12) /* dynamic fd allocation ({}<) */ | |
/* execute/exchild flags */ | |
#define XEXEC BIT(0) /* execute without forking */ |
One of the more interesting uses for this is in conjunction with the automatic creation of unlinked temp-files when you use a here-doc/string:
exec {FD}<<<''
echo "Hello, temp!" >/dev/fd/$FD
cat </dev/fd/$FD
exec {FD}<&-
Or, even access the tempfile via /proc/$$/fd/$FD
like this:
exec {KEY_FD}<<'END_KEY'
-----BEGIN RSA PRIVATE KEY-----
... key embedded in script here ...
-----END RSA PRIVATE KEY-----
END_KEY
ssh -T user@remotehost -i /proc/$$/fd/${KEY_FD} <<'END_SCRIPT'
echo "Hello from `hostname`"
END_SCRIPT
Of course both of these examples could be written without dynamic file descriptors entirely, but making the descriptors dynamic allows interoperability with other script-libraries and functions that might use conflicting file descriptors.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This adds the functionality described here: http://www.unix.com/302586545-post4.html
This was already available in recent versions of the Bash, KSH, and ZSH shells.