Re: "here strings" and tmpfiles
On Tue 2019-03-19 09:31:55 -0400, Greg Wooledge wrote: > There are scripts that *rely* on the seekability of the temporary files > created by here-documents and here-strings. "Improving" the "situation" > would break backward compatibility. i hope you noticed that of my suggested improvements, only one of them (a) breaks seekability. Do you have a preference among the other proposals? I'm partial to memfd_create(2) on platforms that support it, though i'm not sure how to turn that file descriptor into O_RDONLY before the exec. > There is simply NO valid reason to write <<<"$secret" in a script, and > thus there is no need to "improve" anything other than the scripts > that are doing that. Use a pipe instead. Not all tools take their secret inputs on stdin. indeed, some are explicitly designed to accept special values on other file descriptors. How do you replicate 3<<<"$secret" with a pipeline? Thanks for helping to think this through! Regards, --dkg signature.asc Description: PGP signature
Re: "here strings" and tmpfiles
On Wed, Mar 20, 2019 at 07:36:41AM -0400, Daniel Kahn Gillmor wrote: > How do you replicate 3<<<"$secret" with a pipeline? Not strictly a pipeline, but: 3< <(printf %s "$secret") This is actually preferred in many cases, because it doesn't add a newline. <<< always adds a newline to the result, because it's mimicking here documents, which always end in a newline due to their syntax.
Re: "here strings" and tmpfiles
On Wed, Mar 20, 2019 at 07:49:34AM +0700, Robert Elz wrote: > However, using files for here docs makes here docs unusable in a shell > running in single user mode with no writable filesystems (whatever is > mounted is read only, until after file system checks are finished). Meanwhile, proposals based around /dev/fd/* would also make here docs unusable in a shell running early in the boot process, before all file systems are mounted. Just like that one time L. Walsh tried to write a bash boot script that used <() to populate an array, and it failed because she was running it too early in the boot sequence, and /dev/fd/ wasn't available yet. So, my counterpoints are: 1) Leave it alone. It's fine. 2) Don't use bash for scripts that run early in the boot sequence. 3) Whatever features you *do* use in boot scripts, make sure they're available at the point in the boot sequence when the script runs. 4) Whatever features you use in scripts *in general*, make sure you understand how they work. Even if Chet changed how here docs work in bash 5.1, nobody would be safe to use those features in their "I'm feeding a password with a here string" scripts for at least 20 years, because there will still be people running older versions of bash for at least that long. Thus, leave it alone.
Bash-5.0 Official Patch 3
BASH PATCH REPORT = Bash-Release: 5.0 Patch-ID: bash50-003 Bug-Reported-by:Andrew Church Bug-Reference-ID: <5c534aa2.04...@msgid.achurch.org> Bug-Reference-URL: http://lists.gnu.org/archive/html/bug-bash/2019-01/msg00276.html Bug-Description: There are several incompatibilities in how bash-5.0 processes pathname expansion (globbing) of filename arguments that have backslashes in the directory portion. Patch (apply with `patch -p0'): *** ../bash-5.0-patched/lib/glob/glob_loop.c2019-01-16 16:13:21.0 -0500 --- lib/glob/glob_loop.c2019-02-01 09:45:11.0 -0500 *** *** 27,34 register const GCHAR *p; register GCHAR c; ! int bopen; p = pattern; ! bopen = 0; while ((c = *p++) != L('\0')) --- 27,34 register const GCHAR *p; register GCHAR c; ! int bopen, bsquote; p = pattern; ! bopen = bsquote = 0; while ((c = *p++) != L('\0')) *** *** 56,66 case L('\\'): /* Don't let the pattern end in a backslash (GMATCH returns no match ! if the pattern ends in a backslash anyway), but otherwise return 1, ! since the matching engine uses backslash as an escape character ! and it can be removed. */ ! return (*p != L('\0')); } ! return 0; } --- 56,75 case L('\\'): /* Don't let the pattern end in a backslash (GMATCH returns no match ! if the pattern ends in a backslash anyway), but otherwise note that ! we have seen this, since the matching engine uses backslash as an ! escape character and it can be removed. We return 2 later if we ! have seen only backslash-escaped characters, so interested callers ! know they can shortcut and just dequote the pathname. */ ! if (*p != L('\0')) ! { ! p++; ! bsquote = 1; ! continue; ! } ! else/* (*p == L('\0')) */ ! return 0; } ! return bsquote ? 2 : 0; } *** ../bash-5.0-patched/lib/glob/glob.h 2013-10-28 14:46:12.0 -0400 --- lib/glob/glob.h 2019-03-07 11:06:47.0 -0500 *** *** 31,34 --- 31,35 #define GX_ADDCURDIR 0x200 /* internal -- add passed directory name */ #define GX_GLOBSTAR 0x400 /* turn on special handling of ** */ + #define GX_RECURSE0x800 /* internal -- glob_filename called recursively */ extern int glob_pattern_p __P((const char *)); *** ../bash-5.0-patched/lib/glob/glob.c 2018-09-20 10:53:23.0 -0400 --- lib/glob/glob.c 2019-03-07 14:23:43.0 -0500 *** *** 1062,1066 unsigned int directory_len; int free_dirname; /* flag */ ! int dflags; result = (char **) malloc (sizeof (char *)); --- 1078,1082 unsigned int directory_len; int free_dirname; /* flag */ ! int dflags, hasglob; result = (char **) malloc (sizeof (char *)); *** *** ,1117 } /* If directory_name contains globbing characters, then we ! have to expand the previous levels. Just recurse. */ ! if (directory_len > 0 && glob_pattern_p (directory_name)) { char **directories, *d, *p; --- 1127,1136 } + hasglob = 0; /* If directory_name contains globbing characters, then we ! have to expand the previous levels. Just recurse. ! If glob_pattern_p returns != [0,1] we have a pattern that has backslash ! quotes but no unquoted glob pattern characters. We dequote it below. */ ! if (directory_len > 0 && (hasglob = glob_pattern_p (directory_name)) == 1) { char **directories, *d, *p; *** *** 1176,1180 d[directory_len - 1] = '\0'; ! directories = glob_filename (d, dflags); if (free_dirname) --- 1195,1199 d[directory_len - 1] = '\0'; ! directories = glob_filename (d, dflags|GX_RECURSE); if (free_dirname) *** *** 1333,1336 --- 1352,1369 return (NULL); } + /* If we have a directory name with quoted characters, and we are +being called recursively to glob the directory portion of a pathname, +we need to dequote the directory name before returning it so the +caller can read the directory */ + if (directory_len > 0 && hasglob == 2 && (flags & GX_RECURSE) != 0) + { + dequote_pathname (directory_name); + directory_len = strlen (directory_name); + } + + /* We could check whether or not the dequoted directory_name is a +directory and return it here, returning the original directory_name +if not, but we don't do that yet. I'm not sure it matters. */ + /* Handle GX_MARKDIRS here. */ result[0] = (char *) malloc (directory_len +
Re: bash-5.0: problem with variable scoping in posix-mode
> > Description: > > > > There is a problem with variable scoping when variable is created from > > assignment statement preceding function call in posix-mode. See an > > example below. > > > > > > Repeat-By: > > > > $ cat test.sh > > #!/bin/sh > > > > myecho() { > > echo $var > > } > > > > foo() { > > local var="foo: FAIL" > > var="foo: bar" myecho > > } > > > > foo > > > > $ bash test.sh > > foo: bar > > $ bash --posix test.sh > > foo: FAIL > > This is a consequence of a combination of two POSIX features. First, POSIX > requires assignment statements preceding special builtins to create global > variables (POSIX has no local variables) that persist in the shell context > after the special builtin completes. Second, POSIX requires* that > assignment statements preceding function calls have the same variable- > assignment behavior as special builtins. > > So the variable assignment preceding the function call creates a global > variable, and the local variable is found before that global when `myecho' > is executed according to the standard bash dynamic scoping rules. If you > add an `echo $var' after the call to foo, you'll see this behavior. > > (*) The most recent version of the standard has removed this requirement > for shell functions, and I will change that behavior for the next release > of bash. Until then, the old behavior persists. This behavior is not quite backwards-compatible with bash-4.4. Here is a patch that implements a portion of the proposed bash-5.1 behavior. It changes the variable assignment semantics so that variable assignments preceding builtins and shell functions act more like standalone assignment statements and modify the "current execution environment" (in POSIX terms) instead of unconditionally modifying the global variable scope. This means that assignments preceding shell functions and special builtins will modify existing local variables and modifications to local variables will not propagate to the calling environment, and will create global variables if there is not an existing local variable with that name. This is compatible with other POSIX shells that implement local variables. It is not completely compatible with bash-4.4, since the bash-4.4 behavior wasn't fully POSIX-conformant and had variable scoping bugs as well. The original discussion concerning this is at http://lists.gnu.org/archive/html/bug-bash/2018-05/msg2.html Chet *** ../bash-5.0-patched/variables.c 2018-12-18 11:07:21.0 -0500 --- variables.c 2019-03-20 10:30:56.0 -0400 *** *** 4473,4476 --- 4473,4489 var = (SHELL_VAR *)data; + #if 1 /* TAG:bash-5.1 */ + /* Just like do_assignment_internal(). This makes assignments preceding + special builtins act like standalone assignment statements when in + posix mode, satisfying the posix requirement that this affect the + "current execution environment." */ + v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP); + + /* If this modifies an existing local variable, v->context will be non-zero. + If it comes back with v->context == 0, we bound at the global context. + Set binding_table appropriately. It doesn't matter whether it's correct + if the variable is local, only that it's not global_variables->table */ + binding_table = v->context ? shell_variables->table : global_variables->table; + #else binding_table = global_variables->table; if (binding_table == 0) *** *** 4478,4486 v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP); /* global variables are no longer temporary and don't need propagating. */ ! var->attributes &= ~(att_tempvar|att_propagate); if (v) ! v->attributes |= var->attributes; if (find_special_var (var->name) >= 0) --- 4491,4508 v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP); + #endif /* global variables are no longer temporary and don't need propagating. */ ! if (binding_table == global_variables->table) ! var->attributes &= ~(att_tempvar|att_propagate); ! if (v) ! { ! v->attributes |= var->attributes; ! v->attributes &= ~att_tempvar; /* not a temp var now */ ! #if 0 /* TAG:bash-5.1 code doesn't need this, disable for bash-5.1 */ ! v->context = (binding_table == global_variables->table) ? 0 : shell_variables->scope; ! #endif ! } if (find_special_var (var->name) >= 0) *** *** 4576,4587 { int i; tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1); tempvar_list[tvlist_ind = 0] = 0; ! ! hash_flush (temporary_env, pushf); ! hash_dispose (temporary_env); temporary_env = (HASH_TABLE *)NULL; tempvar_list[tvlist_ind] = 0; --- 4598,4612 { int i; + HASH_TABLE *disposer; tempvar_list = strvec_create (HASH
[PATCH] bash: add support for TIPC network redirection
From: Erik Hugne Enables bash scripts to read and write data to TIPC RDM/DGRAM sockets. Signed-off-by: Erik Hugne --- Only available/enabled on Linux. config.h.in | 2 ++ configure.ac | 2 ++ doc/bash.1 | 5 +++ doc/bashref.texi | 10 -- externs.h| 2 +- lib/sh/netopen.c | 99 redir.c | 17 ++ 7 files changed, 134 insertions(+), 3 deletions(-) diff --git a/config.h.in b/config.h.in index 8554aecc..73db32cf 100644 --- a/config.h.in +++ b/config.h.in @@ -950,6 +950,8 @@ /* Define if you have the header file. */ #undef HAVE_ARPA_INET_H +/* Define if you have the header file */ +#undef HAVE_TIPC /* Define if you have the header file. */ #undef HAVE_DIRENT_H diff --git a/configure.ac b/configure.ac index 52b4cdbd..9e80d10d 100644 --- a/configure.ac +++ b/configure.ac @@ -717,6 +717,8 @@ AC_CHECK_HEADERS(sys/pte.h sys/stream.h sys/select.h sys/file.h sys/ioctl.h \ sys/time.h sys/times.h sys/types.h sys/wait.h) AC_CHECK_HEADERS(netinet/in.h arpa/inet.h) +AC_CHECK_HEADER(linux/tipc.h, AC_DEFINE(HAVE_TIPC)) + dnl sys/ptem.h requires definitions from sys/stream.h on systems where it dnl exists AC_CHECK_HEADER(sys/ptem.h, , ,[[ diff --git a/doc/bash.1 b/doc/bash.1 index e6cd08db..91179788 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -3889,6 +3889,11 @@ the corresponding TCP socket. If \fIhost\fP is a valid hostname or Internet address, and \fIport\fP is an integer port number or service name, \fBbash\fP attempts to open the corresponding UDP socket. +.TP +.B /dev/tipc/\fItype\fP/\fIinstance\fP|\fIlow\fP/\fIhigh\fP +if \fItype\fP is a valid TIPC instance integer value, and \fIinstance\fP or +\fIlow\fP/\fIhigh\fP are integer type numbers, Bash attempts to open the corresponding +TIPC RDM socket. Using \fIlow\fP/\fIhigh\fP notation will make the socket multicast. .PD .RE .PP diff --git a/doc/bashref.texi b/doc/bashref.texi index d33cd571..4342b4aa 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -2736,6 +2736,11 @@ the corresponding TCP socket. If @var{host} is a valid hostname or Internet address, and @var{port} is an integer port number or service name, Bash attempts to open the corresponding UDP socket. + +@item /dev/tipc/@var{type}/@var{instance}|@var{low}/@var{high} +If @var{type} is a valid TIPC instance integer value, and @var{instance} or @var{low}/ +@var{high} are integer type numbers, Bash attempts to open the corresponding +TIPC RDM socket. Using @var{low}/@var{high} notation will make the socket multicast. @end table A failure to open or create a file causes the redirection to fail. @@ -8632,8 +8637,9 @@ system provides the necessary support. @item --enable-net-redirections This enables the special handling of filenames of the form -@code{/dev/tcp/@var{host}/@var{port}} and -@code{/dev/udp/@var{host}/@var{port}} +@code{/dev/tcp/@var{host}/@var{port}}, +@code{/dev/udp/@var{host}/@var{port}} and +@code{/dev/tipc/@var{type}/@var{instance}|@var{low}/@var{high}} when used in redirections (@pxref{Redirections}). @item --enable-process-substitution diff --git a/externs.h b/externs.h index 72df33d1..0bd7958c 100644 --- a/externs.h +++ b/externs.h @@ -276,7 +276,7 @@ extern int isnetconn __P((int)); /* declarations for functions defined in lib/sh/netopen.c */ extern int netopen __P((char *)); - +extern int netopen_tipc __P((char *, enum r_instruction)); /* Declarations for functions defined in lib/sh/oslib.c */ #if !defined (HAVE_DUP2) || defined (DUP2_BROKEN) diff --git a/lib/sh/netopen.c b/lib/sh/netopen.c index bc3d8f8a..090756c8 100644 --- a/lib/sh/netopen.c +++ b/lib/sh/netopen.c @@ -31,6 +31,11 @@ # include #endif +#if defined (HAVE_TIPC) +# include +# include "command.h" +#endif + #include #include @@ -314,6 +319,91 @@ netopen (path) return fd; } +#if defined (HAVE_TIPC) +static int +_netopen_tipc(uint8_t addrtype, uint32_t addr1, uint32_t addr2, + uint32_t addr3, uint8_t do_bind, uint8_t do_connect) +{ + int fd, e; + + struct sockaddr_tipc sa = { + .family = AF_TIPC, + .addrtype = addrtype + }; + + switch (addrtype) { + case TIPC_ADDR_ID: + sa.addr.id.node = addr1; + sa.addr.id.ref = addr2; + break; + case TIPC_ADDR_NAME: + sa.addrtype = TIPC_ADDR_NAME; + sa.addr.name.name.type = addr1; + sa.addr.name.name.instance = addr2; + break; + case TIPC_ADDR_NAMESEQ: + sa.addrtype = TIPC_ADDR_NAMESEQ; + sa.addr.nameseq.type = addr1; + sa.addr.nameseq.lower = addr2; + sa.addr.nameseq.upper = addr3; + break; + default: + goto err; + } + if ((fd = socket(AF_TIPC, SOCK_RDM, 0)) < 0) { + e = errno; + sys_error("socket")