Re: PWD not made canonical on shell start

2017-05-29 Thread dualbus
On Wed, May 24, 2017 at 11:53:45AM -0400, Chet Ramey wrote:
[...]
> It was changed back in 2015 as the result of
> 
> http://lists.gnu.org/archive/html/bug-bash/2015-09/msg00053.html

After reading POSIX's [1] (section 2.5.3 "Shell Variables"), I noticed
that bash may not be following the specification. This is what the description
of `PWD' says:

| PWD
| Set by the shell and by the cd utility. In the shell the value shall be
| initialized from the environment as follows. If a value for PWD is passed to
| the shell in the environment when it is executed, the value is an absolute
| pathname of the current working directory that is no longer than {PATH_MAX}
| bytes including the terminating null byte, and the value does not contain any
| components that are dot or dot-dot, then the shell shall set PWD to the value
| from the environment. Otherwise, if a value for PWD is passed to the shell in
| the environment when it is executed, the value is an absolute pathname of the
| current working directory, and the value does not contain any components that
| are dot or dot-dot, then it is unspecified whether the shell sets PWD to the
| value from the environment or sets PWD to the pathname that would be output by
| pwd -P. Otherwise, the sh utility sets PWD to the pathname that would be 
output
| by pwd -P. In cases where PWD is set to the value from the environment, the
| value can contain components that refer to files of type symbolic link. In
| cases where PWD is set to the pathname that would be output by pwd -P, if 
there
| is insufficient permission on the current working directory, or on any parent
| of that directory, to determine what that pathname would be, the value of PWD
| is unspecified. Assignments to this variable may be ignored. If an application
| sets or unsets the value of PWD, the behaviors of the cd and pwd utilities are
| unspecified.

My interpretation is the following:

  case 1)
  
  If PWD is passed through the environment,
  and the value is an absolute pathname of the CWD
  and the value is no longer than PATH_MAX
  and the value does not contain any components that are dot or dot-dot,
  then set PWD to the value from the environment.
  
  case 2)
  
  The same as case 1, except for the restriction on PATH_MAX. The result
  is unspecified.
  
  case 3)
  
  If case 1 and 2 do not apply, then set PWD=$(pwd -P)


Bash doesn't really do that. What bash does is:

  case 1)
  
  If PWD is passed through the environment,
  and the value is an absolute pathname of the CWD,
  then set PWD to the current value from the environment

  case 2)

  If case 1 does not apply,
  and the shell is an interactive shell,
  and the shell is a login shell,
  and $HOME is the same as the CWD,
  then set PWD=$HOME

  case 3)

  If case 2 does not apply,
  then call getcwd() and sets PWD to the return value.


The patch below makes bash behave as described by POSIX.


diff --git a/variables.c b/variables.c
index 944de86e..dbf21339 100644
--- a/variables.c
+++ b/variables.c
@@ -827,49 +827,39 @@ initialize_shell_level ()
 /* If we got PWD from the environment, update our idea of the current
working directory.  In any case, make sure that PWD exists before
checking it.  It is possible for getcwd () to fail on shell startup,
-   and in that case, PWD would be undefined.  If this is an interactive
-   login shell, see if $HOME is the current working directory, and if
-   that's not the same string as $PWD, set PWD=$HOME. */
-
+   and in that case, PWD would be undefined. */
 void
 set_pwd ()
 {
   SHELL_VAR *temp_var, *home_var;
-  char *temp_string, *home_string, *current_dir;
-
-  home_var = find_variable ("HOME");
-  home_string = home_var ? value_cell (home_var) : (char *)NULL;
+  char *temp_string, *current_dir, *last_component;
 
   temp_var = find_variable ("PWD");
   /* Follow posix rules for importing PWD */
   if (temp_var && imported_p (temp_var) &&
   (temp_string = value_cell (temp_var)) &&
   temp_string[0] == '/' &&
+  !strstr(temp_string, "/./") &&
+  !strstr(temp_string, "/../") &&
+  (last_component=strrchr(temp_string, '/')) &&
+  strcmp(last_component, ".") &&
+  strcmp(last_component, "..") &&
   same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL))
 {
-  current_dir = sh_canonpath (temp_string, 
PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
-  if (current_dir == 0)
-   current_dir = get_working_directory ("shell_init");
-  else 
-   set_working_directory (current_dir);
-  free (current_dir);
-}
-  else if (home_string && interactive_shell && login_shell &&
-  same_file (home_string, ".", (struct stat *)NULL, (struct stat 
*)NULL))
-{
-  set_working_directory (home_string);
-  temp_var = bind_variable ("PWD", home_string, 0);
-  set_auto_export (temp_var);
+  set_working_directory (temp_string);
 }
   else
 {
-  temp_string = get_working_directory ("shell-init");
-  if (t

Re: read -e allows execution of commands (edit-and-execute-command) as the shell's process user

2017-05-29 Thread dualbus
On Mon, May 29, 2017 at 12:29:16AM -0400, George Caswell wrote:
[...]
> Bash's builtin function "read" has one simple job: read data, return
> it to the caller. There shouldn't be anything in there about executing
> commands.
> 
> Why does read even need a function like this? Is it something that was
> useful in the days before job control? ##SELECTION_END##

The -e flag causes read to use GNU Readline if the input comes from a
terminal. This is *very* useful, since Readline allows you to perform
text manipulation functions, completion, advanced cursor movement, etc.

Also, the likelyhood of this being a real security issue is very small.

--
Eduardo Bustamante
https://dualbus.me/



Re: {varname} redirection for a command or group leaves the file open

2017-05-29 Thread Chet Ramey
On 5/19/17 4:32 PM, tetsu...@scope-eye.net wrote:

>  > Well, that's disappointing. So there is no technical reason for
> this behavior 
>  > other than copying the behavior of ksh. BTW zsh does the right
> thing and in the 
>  > following scenario: 
>  > 
>  > ls -lh /proc/self/fd {fd}>/dev/null 
>  > 
>  > and it closes the file descriptor after the command has completed.

Face it: there's no real reason to implement this construct, period, and
especially little reason for the way the Korn shell does it.  A script
can trivially emulate the ksh usage by picking the file descriptor and
performing the variable assignment itself; this construct is minimal
syntactic sugar.

I think Korn introduced it to overcome the traditional sh restriction of
the user-modifiable file descriptors to the range 0-9. Bash doesn't have
that limitation, so that's not enough of a reason to do it.

The way bash implements it offers features that are not available in any
other use. While the not-closing aspects can be emulated using `exec', a
file descriptor manipulated with `exec' is close-on-exec. Bash offers a
direct analogue to the open system call.

Now, bash does implement some other constructs that are nothing but
syntactic sugar (|&), but only after user requests. There aren't any
user requests for this, so a purely syntactic sugar feature isn't any
direct user benefit. There needs to be something that isn't otherwise
available.

It's kind of flip to recommend not using it if you don't like it, but
that's pretty much the case here. Or accept the rationale and work
around it.

Chet
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/



Re: Builtin history -r does not work with named pipes (i.e. GNU readline's histfile.c read_history_range)

2017-05-29 Thread Chet Ramey
On 5/23/17 11:32 AM, Eduardo Bustamante wrote:
> (I think this is a good problem for Pranav to tackle if you consider
> this to be a bug, Chet).
> 
> The problem is that fstat(2) will return an st_size of 0 if the file
> is non-regular. I think that the easiest path here is to goto
> `error_and_exit' if `file' is not a regular file (and perhaps print a
> useful error message?).

So the bug is that readline doesn't print an error message if the history
file isn't a regular file?

-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/



Re: Builtin history -r does not work with named pipes (i.e. GNU readline's histfile.c read_history_range)

2017-05-29 Thread dualbus
On Mon, May 29, 2017 at 04:17:16PM -0400, Chet Ramey wrote:
[...]
> So the bug is that readline doesn't print an error message if the history
> file isn't a regular file?

Correct. Another problem is that the history builtin doesn't propagate
back a meaningful return code indicating that there was a problem.

A simple example is that you're trying to seed your history by appending
the output of a command using `history -r'. So you might try:

| $ history -cr <(echo a complex command); echo $?; history
| 0

But for some reason that doesn't work and there is no apparent problem
with it. 

Whereas the following does work:

| $ history -cr /dev/stdin <<<'a complex command'; echo $?; history
| 0
| 1  a complex command

Or, which indicates that something went wrong:

| $ history -cr /tmp; echo $?; history
| 1

In my opinion it should at least return an error code. And if possible
an error message.

The other option is to implement support for reading from non-regular
files, but I'm not sure if it's worth it.

-- 
Eduardo Bustamante
https://dualbus.me/



Re: Builtin history -r does not work with named pipes (i.e. GNU readline's histfile.c read_history_range)

2017-05-29 Thread Chet Ramey
On 5/29/17 4:40 PM, dualbus wrote:
> On Mon, May 29, 2017 at 04:17:16PM -0400, Chet Ramey wrote:
> [...]
>> So the bug is that readline doesn't print an error message if the history
>> file isn't a regular file?
> 
> Correct. Another problem is that the history builtin doesn't propagate
> back a meaningful return code indicating that there was a problem.

OK, that's an easy fix. It wasn't clear whether this was the problem, or
whether the original poster was complaining that the lack of support for
non-regular files was the bug. Thanks.

Chet

-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/



Re: PWD not made canonical on shell start

2017-05-29 Thread Chet Ramey
On 5/29/17 12:22 PM, dualbus wrote:

> Bash doesn't really do that. What bash does is:

This isn't quite an accurate representation of the bash behavior.

> 
>   case 1)
>   
>   If PWD is passed through the environment,
>   and the value is an absolute pathname of the CWD,
>   then set PWD to the current value from the environment

If PWD appears in the environment, and it is an absolute pathname of the
CWD, set PWD to the canonicalized version of the environment value. The
canonicalized version removes . and .., makes sure that the length is
less than PATH_MAX, and validates that at each step, removing . and ..
results in a valid pathname. If canonicalization fails, PWD gets the value
that would be printed by pwd -P if PWD were not set.

> 
>   case 2)
> 
>   If case 1 does not apply,
>   and the shell is an interactive shell,
>   and the shell is a login shell,
>   and $HOME is the same as the CWD,
>   then set PWD=$HOME

This is to avoid long NFS pathnames from the equivalent of pwd -P when the
current directory is obviously the home directory.

> 
>   case 3)
> 
>   If case 2 does not apply,
>   then call getcwd() and sets PWD to the return value.

That's the behavior of pwd -P when PWD is not set (which it obviously
is not).

> The patch below makes bash behave as described by POSIX.

I'm comfortable with the bash behavior.

-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/



Re: PWD not made canonical on shell start

2017-05-29 Thread dualbus
On Mon, May 29, 2017 at 06:25:06PM -0400, Chet Ramey wrote:
[...]
> If PWD appears in the environment, and it is an absolute pathname of the
> CWD, set PWD to the canonicalized version of the environment value. The
> canonicalized version removes . and .., makes sure that the length is
> less than PATH_MAX, and validates that at each step, removing . and ..
> results in a valid pathname. If canonicalization fails, PWD gets the value
> that would be printed by pwd -P if PWD were not set.

That's not quite true. In variables.c `set_pwd', there's the following:

 843   temp_var = find_variable ("PWD");
 844   /* Follow posix rules for importing PWD */
 845   if (temp_var && imported_p (temp_var) &&
 846   (temp_string = value_cell (temp_var)) &&
 847   temp_string[0] == '/' &&
 848   same_file (temp_string, ".", (struct stat *)NULL, (struct stat 
*)NULL))
 849 {
 850   current_dir = sh_canonpath (temp_string, 
PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
 851   if (current_dir == 0)
 852 current_dir = get_working_directory ("shell_init");
 853   else
 854 set_working_directory (current_dir);
 855   free (current_dir);
 856 }

`current_dir' is a copy of `temp_string' which holds the canonicalized version
of the environment value. That's true. *But* PWD is not re-set to the value of
`current_dir'. Instead, it has the same value as passed through the
environment (i.e. `temp_string').

For completeness, in builtins/common.c `set_working_directory' just updates a
global variable, but doesn't touch the value of the PWD variable.

 589 /* Make NAME our internal idea of the current working directory. */
 590 void
 591 set_working_directory (name)
 592  char *name;
 593 {  
 594   FREE (the_current_working_directory);
 595   the_current_working_directory = savestring (name);
 596 } 

Hence, my initial patch:

diff --git a/variables.c b/variables.c
index 944de86e..62f9f229 100644
--- a/variables.c
+++ b/variables.c
@@ -852,6 +852,8 @@ set_pwd ()
current_dir = get_working_directory ("shell_init");
   else 
set_working_directory (current_dir);
+  temp_var = bind_variable ("PWD", current_dir);
+  set_auto_export (temp_var);
   free (current_dir);
 }
   else if (home_string && interactive_shell && login_shell &&



Re: {varname} redirection for a command or group leaves the file open

2017-05-29 Thread George
On Mon, 2017-05-29 at 15:36 -0400, Chet Ramey wrote:
> 
> > 
> >  > Well, that's disappointing. So there is no technical reason for
> > this behavior 
> >  > other than copying the behavior of ksh. BTW zsh does the right
> > thing and in the 
> >  > following scenario: 
> >  > 
> >  > ls -lh /proc/self/fd {fd}>/dev/null 
> >  > 
> >  > and it closes the file descriptor after the command has completed.
> Face it: there's no real reason to implement this construct, period, and
> especially little reason for the way the Korn shell does it.  A script
> can trivially emulate the ksh usage by picking the file descriptor and
> performing the variable assignment itself; this construct is minimal
> syntactic sugar.
The way Korn shell does it makes sense, it is consistent with the way other 
file redirections work. Normally redirecting any command applies just to
that command, and not to surrounding code. "exec" is the exception to the rule, 
a redirection that stays open. (If there was no reason to implement
the construct, why was it implemented?)
And it is not "trivial" for a shell script to even find an unused file 
descriptor EXCEPT by using the dynamic FD assignment syntax, which does it for
you. And even if your shell code could find a vacant file descriptor to use, 
you can't do this:
$ fd=$(find_vacant_fd)
$ exec $fd The way bash implements it offers features that are not available in any 
> other use.
> 
It really doesn't. And Bash's behavior seems very inconsistent, even 
nonsensically so:
"cmd --fd=$fd {fd} While the not-closing aspects can be emulated using `exec', a file descriptor 
> manipulated with `exec' is close-on-exec. Bash offers a direct analogue
> to the open system call.
> 
Even if that were true, it makes no sense. File redirections should not outlive 
the command they're attached to - unless the command is "exec". And
files opened with "exec" are not close-on-exec:
$ exec {fd} 
/home/tetsujin/src/bash-4.3/README
The file was opened with "exec" and didn't close-on-exec when "ls" was run. 
(CLOEXEC files are almost useless in Bash, because you have no way in the
shell to hand that file to another process. Even if you duplicate it with a 
redirection, the duplicate is set CLOEXEC as well.)



Re: read -e allows execution of commands (edit-and-execute-command) as the shell's process user

2017-05-29 Thread George
On Mon, 2017-05-29 at 11:37 -0500, dualbus wrote:
> On Mon, May 29, 2017 at 12:29:16AM -0400, George Caswell wrote:
> [...]
> > 
> > Bash's builtin function "read" has one simple job: read data, return
> > it to the caller. There shouldn't be anything in there about executing
> > commands.
> > 
> > Why does read even need a function like this? Is it something that was
> > useful in the days before job control? ##SELECTION_END##
> The -e flag causes read to use GNU Readline if the input comes from a
> terminal. This is *very* useful
You misunderstand. Being able to use Readline in "read" is great! And 
"edit-and-execute-command" may have its uses when invoked from an interactive
shell session. But why is "edit-and-execute-command" useful or in any way 
desirable in "read"?
If you were using "read -e" in a script, and someone wanted to run some 
commands, they could suspend the script with job control, or open another
terminal window to run some commands. The feature is unnecessary, and has no 
business being a part of "read".


Re: Builtin history -r does not work with named pipes (i.e. GNU readline's histfile.c read_history_range)

2017-05-29 Thread Pranav Deshpande
So I can't take up this one?

Regards,
Pranav

On May 30, 2017 2:35 AM, "Chet Ramey"  wrote:

> On 5/29/17 4:40 PM, dualbus wrote:
> > On Mon, May 29, 2017 at 04:17:16PM -0400, Chet Ramey wrote:
> > [...]
> >> So the bug is that readline doesn't print an error message if the
> history
> >> file isn't a regular file?
> >
> > Correct. Another problem is that the history builtin doesn't propagate
> > back a meaningful return code indicating that there was a problem.
>
> OK, that's an easy fix. It wasn't clear whether this was the problem, or
> whether the original poster was complaining that the lack of support for
> non-regular files was the bug. Thanks.
>
> Chet
>
> --
> ``The lyf so short, the craft so long to lerne.'' - Chaucer
>  ``Ars longa, vita brevis'' - Hippocrates
> Chet Ramey, UTech, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~
> chet/
>