Skip to content

Instantly share code, notes, and snippets.

@p120ph37
Last active May 27, 2016 02:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save p120ph37/628f2eeb409fa43437aa32dae856b729 to your computer and use it in GitHub Desktop.
Save p120ph37/628f2eeb409fa43437aa32dae856b729 to your computer and use it in GitHub Desktop.
Add support for dynamic file descriptors to the MirBSD Korn Shell.
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 */
@p120ph37
Copy link
Author

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.

@p120ph37
Copy link
Author

p120ph37 commented May 26, 2016

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