[PATCH v2 0/8] Add isolated mode to source builtin

2024-05-13 Thread Matheus Afonso Martins Moreira
Bash scripts can be tricky to get right so reusing proven solutions
as shell script libraries is of immense value. However, the existing
shell script sourcing mechanisms are suboptimal for this task.

The source builtin uses the PATH variable for resolving file names
which means they would have to be placed alongside normal executables
which could cause false positives: executables and commands might be
accidentally sourced instead, causing hard to debug problems.

This could be fixed by overriding PATH so that it contains
only library directories but this interferes with the normal
execution of the sourced scripts: they are no longer able to
run commands normally because the commands are not in the PATH.
This is an undesirable and ultimately unnecessary limitation.

This patch set adds a special operating mode to the existing source
builtin to make it behave in the desired way. When source is passed
the -i option which stands for "isolated", it will search for files
in the directories given by the BASH_SOURCE_PATH environment variable,
and only in those directories. The PATH will not be modified.

A build time configurable default value is defined which includes
the user's home directory in addition to system directories,
enabling users to easily develop their own scripting systems.

Additionally, manipulation of the BASH_SOURCE_PATH variable
is prevented whenever the shell is running in restricted mode.
This allows users the same control over its value as they have
over the value of PATH, thereby helping to prevent unintended
sourcing of files.

Changes compared to v1 patch set:

 - Rebased on top of devel branch
 - Dropped library terminology
 - Removed long options and all related code
 - Made helper functions static and local
 - Changed default source paths to avoid clashes
 - Restricted source path variable

Matheus Afonso Martins Moreira (8):
  findcmd: parameterize path variable in functions
  findcmd: define find_in_path_var function
  builtins/source: extract file executor function
  builtins/source: refactor file searching function
  builtins/source: parse the -i option
  builtins/source: use source path in isolated mode
  variables: define default BASH_SOURCE_PATH
  shell: restrict BASH_SOURCE_PATH when appropriate

 builtins/source.def | 174 +++-
 config-top.h|   7 ++
 findcmd.c   |  32 +---
 findcmd.h   |   1 +
 shell.c |   1 +
 variables.c |   1 +
 6 files changed, 153 insertions(+), 63 deletions(-)

--
2.44.0




[PATCH v2 1/8] findcmd: parameterize path variable in functions

2024-05-13 Thread Matheus Afonso Martins Moreira
The PATH variable is hard coded in the user command finder function.
Transforming it into an argument allows reusing the file finding logic
with variables other than PATH, making the code more flexible.

Signed-off-by: Matheus Afonso Martins Moreira 
---
 findcmd.c | 25 +
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/findcmd.c b/findcmd.c
index 73c07bd8..fbcc0451 100644
--- a/findcmd.c
+++ b/findcmd.c
@@ -52,8 +52,8 @@ extern int errno;
 #endif
 
 /* Static functions defined and used in this file. */
-static char *_find_user_command_internal (const char *, int);
-static char *find_user_command_internal (const char *, int);
+static char *_find_user_command_internal (const char *, const char *, int);
+static char *find_user_command_internal (const char *, const char *, int);
 static char *find_user_command_in_path (const char *, char *, int, int *);
 static char *find_in_path_element (const char *, char *, int, size_t, struct 
stat *, int *);
 static char *find_absolute_program (const char *, int);
@@ -246,7 +246,7 @@ executable_or_directory (const char *file)
 char *
 find_user_command (const char *name)
 {
-  return (find_user_command_internal (name, FS_EXEC_PREFERRED|FS_NODIRS));
+  return (find_user_command_internal (name, "PATH", 
FS_EXEC_PREFERRED|FS_NODIRS));
 }
 
 /* Locate the file referenced by NAME, searching along the contents
@@ -257,7 +257,7 @@ find_user_command (const char *name)
 char *
 find_path_file (const char *name)
 {
-  return (find_user_command_internal (name, FS_READABLE));
+  return (find_user_command_internal (name, "PATH", FS_READABLE));
 }
 
 /* Get $PATH and normalize it. USE_TEMPENV, if non-zero, says to look in the
@@ -278,14 +278,15 @@ path_value (const char *pathvar, int use_tempenv)
 }
 
 static char *
-_find_user_command_internal (const char *name, int flags)
+_find_user_command_internal (const char *name, const char *path_var, int flags)
 {
   char *path_list, *cmd;
   SHELL_VAR *var;
 
-  /* Search for the value of PATH in both the temporary environments and
- in the regular list of variables. */
-  path_list = path_value ("PATH", 1);
+  /* Search for the value of specified path variable
+ in both the temporary environments
+ and in the regular list of variables. */
+  path_list = path_value (path_var, 1);
 
   if (path_list == 0)
 return (savestring (name));
@@ -296,7 +297,7 @@ _find_user_command_internal (const char *name, int flags)
 }
 
 static char *
-find_user_command_internal (const char *name, int flags)
+find_user_command_internal (const char *name, const char *path_var, int flags)
 {
 #ifdef __WIN32__
   char *res, *dotexe;
@@ -304,13 +305,13 @@ find_user_command_internal (const char *name, int flags)
   dotexe = (char *)xmalloc (strlen (name) + 5);
   strcpy (dotexe, name);
   strcat (dotexe, ".exe");
-  res = _find_user_command_internal (dotexe, flags);
+  res = _find_user_command_internal (dotexe, path_var, flags);
   free (dotexe);
   if (res == 0)
-res = _find_user_command_internal (name, flags);
+res = _find_user_command_internal (name, path_var, flags);
   return res;
 #else
-  return (_find_user_command_internal (name, flags));
+  return (_find_user_command_internal (name, path_var, flags));
 #endif
 }
 
-- 
2.44.0




[PATCH v2 3/8] builtins/source: extract file executor function

2024-05-13 Thread Matheus Afonso Martins Moreira
Extract into a dedicated helper function the code which loads
the contents of a file and executes it in the current shell.
This separates this useful functionality from the path resolution
mechanism used by the source builtin.

Signed-off-by: Matheus Afonso Martins Moreira 
---
 builtins/source.def | 78 +
 1 file changed, 44 insertions(+), 34 deletions(-)

diff --git a/builtins/source.def b/builtins/source.def
index b68d16a5..334404bd 100644
--- a/builtins/source.def
+++ b/builtins/source.def
@@ -81,6 +81,7 @@ extern int errno;
 #endif /* !errno */
 
 static void uw_maybe_pop_dollar_vars (void *);
+static int execute_file_contents (WORD_LIST *, char *, char *);
 
 /* If non-zero, `.' uses $PATH to look up the script to be sourced. */
 int source_uses_path = 1;
@@ -112,11 +113,51 @@ uw_maybe_pop_dollar_vars (void *ignore)
This cannot be done in a subshell, since things like variable assignments
take place in there.  So, I open the file, place it into a large string,
close the file, and then execute the string. */
+static int
+execute_file_contents (WORD_LIST *list, char *filename, char *framename)
+{
+  int result;
+  char *debug_trap;
+
+  begin_unwind_frame (framename);
+  add_unwind_protect (xfree, filename);
+
+  if (list->next)
+{
+  push_dollar_vars ();
+  add_unwind_protect (uw_maybe_pop_dollar_vars, NULL);
+  if (debugging_mode || shell_compatibility_level <= 44)
+   init_bash_argv ();  /* Initialize BASH_ARGV and BASH_ARGC */
+  remember_args (list->next, 1);
+  if (debugging_mode)
+   push_args (list->next); /* Update BASH_ARGV and BASH_ARGC */
+}
+  set_dollar_vars_unchanged ();
+
+  /* Don't inherit the DEBUG trap unless function_trace_mode (overloaded)
+ is set.  XXX - should sourced files inherit the RETURN trap?  Functions
+ don't. */
+  debug_trap = TRAP_STRING (DEBUG_TRAP);
+  if (debug_trap && function_trace_mode == 0)
+{
+  debug_trap = savestring (debug_trap);
+  add_unwind_protect (xfree, debug_trap);
+  add_unwind_protect (uw_maybe_set_debug_trap, debug_trap);
+  restore_default_signal (DEBUG_TRAP);
+}
+
+  result = source_file (filename, (list && list->next));
+
+  run_unwind_frame (framename);
+
+  return (result);
+}
+
+/* Read and execute commands from the file passed as argument. */
 int
 source_builtin (WORD_LIST *list)
 {
-  int result;
-  char *filename, *debug_trap, *x;
+  char *filename, *x;
 
   if (no_options (list))
 return (EX_USAGE);
@@ -164,36 +205,5 @@ source_builtin (WORD_LIST *list)
filename = savestring (list->word->word);
 }
 
-  begin_unwind_frame ("source");
-  add_unwind_protect (xfree, filename);
-
-  if (list->next)
-{
-  push_dollar_vars ();
-  add_unwind_protect (uw_maybe_pop_dollar_vars, NULL);
-  if (debugging_mode || shell_compatibility_level <= 44)
-   init_bash_argv ();  /* Initialize BASH_ARGV and BASH_ARGC */
-  remember_args (list->next, 1);
-  if (debugging_mode)
-   push_args (list->next); /* Update BASH_ARGV and BASH_ARGC */
-}
-  set_dollar_vars_unchanged ();
-
-  /* Don't inherit the DEBUG trap unless function_trace_mode (overloaded)
- is set.  XXX - should sourced files inherit the RETURN trap?  Functions
- don't. */
-  debug_trap = TRAP_STRING (DEBUG_TRAP);
-  if (debug_trap && function_trace_mode == 0)
-{
-  debug_trap = savestring (debug_trap);
-  add_unwind_protect (xfree, debug_trap);
-  add_unwind_protect (uw_maybe_set_debug_trap, debug_trap);
-  restore_default_signal (DEBUG_TRAP);
-}
-
-  result = source_file (filename, (list && list->next));
-
-  run_unwind_frame ("source");
-
-  return (result);
+  return execute_file_contents (list, filename, "source");
 }
-- 
2.44.0




[PATCH v2 2/8] findcmd: define find_in_path_var function

2024-05-13 Thread Matheus Afonso Martins Moreira
It works just like the find_in_path function
but takes a PATH-like variable name instead.
This allows defining and using more PATH-like
variables much more easily.

Signed-off-by: Matheus Afonso Martins Moreira 
---
 findcmd.c | 7 +++
 findcmd.h | 1 +
 2 files changed, 8 insertions(+)

diff --git a/findcmd.c b/findcmd.c
index fbcc0451..9d64317a 100644
--- a/findcmd.c
+++ b/findcmd.c
@@ -703,3 +703,10 @@ find_in_path (const char *name, char *path_list, int flags)
 {
   return (find_user_command_in_path (name, path_list, flags, (int *)0));
 }
+
+/* Like find_in_path but takes a PATH-like variable instead. */
+char *
+find_in_path_var (const char *name, char *path_var, int flags)
+{
+  return (_find_user_command_internal (name, path_var, flags));
+}
diff --git a/findcmd.h b/findcmd.h
index 6dbded4c..4976e422 100644
--- a/findcmd.h
+++ b/findcmd.h
@@ -34,6 +34,7 @@ extern int is_directory (const char *);
 extern int executable_or_directory (const char *);
 extern char *find_user_command (const char *);
 extern char *find_in_path (const char *, char *, int);
+extern char *find_in_path_var (const char *, char *, int);
 extern char *find_path_file (const char *);
 extern char *path_value (const char *, int);
 extern char *search_for_command (const char *, int);
-- 
2.44.0




[PATCH v2 5/8] builtins/source: parse the -i option

2024-05-13 Thread Matheus Afonso Martins Moreira
Passing the -i option to the source builtin
enables isolated sourcing mode which restricts
its search path to the directories defined by
the BASH_SOURCE_PATH variable. This also has
the added benefit of not touching PATH at all.

To maximize compatibility, the option will only
be recognized outside POSIXly correct mode.

Signed-off-by: Matheus Afonso Martins Moreira 
---
 builtins/source.def | 30 +++---
 1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/builtins/source.def b/builtins/source.def
index ba5e1596..26040e70 100644
--- a/builtins/source.def
+++ b/builtins/source.def
@@ -182,10 +182,34 @@ int
 source_builtin (WORD_LIST *list)
 {
   char *filename, *x;
+  int opt, isolated_mode = 0;
 
-  if (no_options (list))
-return (EX_USAGE);
-  list = loptend;
+  if (posixly_correct)
+{
+  /* Don't parse options in POSIX mode */
+  if (no_options (list))
+return (EX_USAGE);
+}
+  else
+{
+  reset_internal_getopt ();
+
+  while ((opt = internal_getopt (list, "i")) != -1)
+{
+  switch (opt)
+{
+case 'i':
+  isolated_mode = 1;
+  break;
+CASE_HELPOPT;
+default:
+  builtin_usage ();
+  return (EX_USAGE);
+}
+}
+
+  list = loptend;
+}
 
   if (list == 0)
 {
-- 
2.44.0




[PATCH v2 4/8] builtins/source: refactor file searching function

2024-05-13 Thread Matheus Afonso Martins Moreira
Extract the file searching algorithm of the source builtin into
a static helper function. Makes the code easier to understand
and separates the searching from the error handling logic.

Signed-off-by: Matheus Afonso Martins Moreira 
---
 builtins/source.def | 59 +++--
 1 file changed, 36 insertions(+), 23 deletions(-)

diff --git a/builtins/source.def b/builtins/source.def
index 334404bd..ba5e1596 100644
--- a/builtins/source.def
+++ b/builtins/source.def
@@ -82,6 +82,7 @@ extern int errno;
 
 static void uw_maybe_pop_dollar_vars (void *);
 static int execute_file_contents (WORD_LIST *, char *, char *);
+static char *search_for_file (WORD_LIST *);
 
 /* If non-zero, `.' uses $PATH to look up the script to be sourced. */
 int source_uses_path = 1;
@@ -153,6 +154,29 @@ execute_file_contents (WORD_LIST *list, char *filename, 
char *framename)
   return (result);
 }
 
+static char *
+search_for_file (WORD_LIST *list)
+{
+  char *filename = NULL, *x;
+
+  /* XXX -- should this be absolute_pathname? */
+  if (posixly_correct && strchr (list->word->word, '/'))
+filename = savestring (list->word->word);
+  else if (absolute_pathname (list->word->word))
+filename = savestring (list->word->word);
+  else if (source_uses_path)
+filename = find_path_file (list->word->word);
+  if (filename == 0)
+{
+  if (source_searches_cwd == 0)
+return (NULL);
+  else
+filename = savestring (list->word->word);
+}
+
+  return (filename);
+}
+
 /* Read and execute commands from the file passed as argument. */
 int
 source_builtin (WORD_LIST *list)
@@ -178,31 +202,20 @@ source_builtin (WORD_LIST *list)
 }
 #endif
 
-  filename = (char *)NULL;
-  /* XXX -- should this be absolute_pathname? */
-  if (posixly_correct && strchr (list->word->word, '/'))
-filename = savestring (list->word->word);
-  else if (absolute_pathname (list->word->word))
-filename = savestring (list->word->word);
-  else if (source_uses_path)
-filename = find_path_file (list->word->word);
+  filename = search_for_file (list);
+
   if (filename == 0)
 {
-  if (source_searches_cwd == 0)
-   {
- x = printable_filename (list->word->word, 0);
- builtin_error (_("%s: file not found"), x);
- if (x != list->word->word)
-   free (x);
- if (posixly_correct && interactive_shell == 0 && 
executing_command_builtin == 0)
-   {
- last_command_exit_value = EXECUTION_FAILURE;
- jump_to_top_level (EXITPROG);
-   }
- return (EXECUTION_FAILURE);
-   }
-  else
-   filename = savestring (list->word->word);
+  x = printable_filename (list->word->word, 0);
+  builtin_error (_("%s: file not found"), x);
+  if (x != list->word->word)
+free (x);
+  if (posixly_correct && interactive_shell == 0 && 
executing_command_builtin == 0)
+{
+  last_command_exit_value = EXECUTION_FAILURE;
+  jump_to_top_level (EXITPROG);
+}
+  return (EXECUTION_FAILURE);
 }
 
   return execute_file_contents (list, filename, "source");
-- 
2.44.0




[PATCH v2 8/8] shell: restrict BASH_SOURCE_PATH when appropriate

2024-05-13 Thread Matheus Afonso Martins Moreira
Make the BASH_SOURCE_PATH variable read-only and unsettable
when the shell is operating in restricted mode. This variable
should be restricted for the same reasons why PATH is restricted.

Signed-off-by: Matheus Afonso Martins Moreira 
---
 shell.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/shell.c b/shell.c
index 15e005d6..940de31b 100644
--- a/shell.c
+++ b/shell.c
@@ -1294,6 +1294,7 @@ maybe_make_restricted (char *name)
   set_var_read_only ("ENV");
   set_var_read_only ("BASH_ENV");
   set_var_read_only ("HISTFILE");
+  set_var_read_only ("BASH_SOURCE_PATH");
   restricted = 1;
 }
   return (restricted);
-- 
2.44.0




[PATCH v2 6/8] builtins/source: use source path in isolated mode

2024-05-13 Thread Matheus Afonso Martins Moreira
Behave normally when executed without any options.
Search only BASH_SOURCE_PATH for scripts to source
when isolated mode is enabled via the -i option.

Signed-off-by: Matheus Afonso Martins Moreira 
---
 builtins/source.def | 27 ++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/builtins/source.def b/builtins/source.def
index 26040e70..7f870bfe 100644
--- a/builtins/source.def
+++ b/builtins/source.def
@@ -83,6 +83,7 @@ extern int errno;
 static void uw_maybe_pop_dollar_vars (void *);
 static int execute_file_contents (WORD_LIST *, char *, char *);
 static char *search_for_file (WORD_LIST *);
+static char *isolated_search_for_file (WORD_LIST *);
 
 /* If non-zero, `.' uses $PATH to look up the script to be sourced. */
 int source_uses_path = 1;
@@ -177,6 +178,27 @@ search_for_file (WORD_LIST *list)
   return (filename);
 }
 
+static char *
+isolated_search_for_file (WORD_LIST *list)
+{
+  char *filename = NULL;
+
+  if (absolute_pathname (list->word->word))
+filename = savestring (list->word->word);
+  else
+filename = find_in_path_var (list->word->word, "BASH_SOURCE_PATH", 
FS_READABLE);
+
+  if (filename == 0)
+{
+  if (source_searches_cwd == 0)
+return (NULL);
+  else
+filename = savestring (list->word->word);
+}
+
+  return (filename);
+}
+
 /* Read and execute commands from the file passed as argument. */
 int
 source_builtin (WORD_LIST *list)
@@ -226,7 +248,10 @@ source_builtin (WORD_LIST *list)
 }
 #endif
 
-  filename = search_for_file (list);
+  if (!isolated_mode)
+filename = search_for_file (list);
+  else
+filename = isolated_search_for_file (list);
 
   if (filename == 0)
 {
-- 
2.44.0




[PATCH v2 7/8] variables: define default BASH_SOURCE_PATH

2024-05-13 Thread Matheus Afonso Martins Moreira
Define a build time configurable default value
for the new BASH_SOURCE_PATH variable.
Look for libraries in the user's home directory
as well as the system wide directories.

Signed-off-by: Matheus Afonso Martins Moreira 
---
 config-top.h | 7 +++
 variables.c  | 1 +
 2 files changed, 8 insertions(+)

diff --git a/config-top.h b/config-top.h
index b6e73c4b..65d52cb2 100644
--- a/config-top.h
+++ b/config-top.h
@@ -78,6 +78,13 @@
   
"/usr/local/lib/bash:/usr/lib/bash:/opt/local/lib/bash:/usr/pkg/lib/bash:/opt/pkg/lib/bash:."
 #endif
 
+/* The default value of the BASH_SOURCE_PATH variable
+   which is used by source -l instead of PATH. */
+#ifndef DEFAULT_SOURCE_PATH
+#define DEFAULT_SOURCE_PATH \
+  
"~/.local/share/bash/source:/usr/local/share/bash/source:/usr/share/bash/source"
+#endif
+
 /* Default primary and secondary prompt strings. */
 #define PPROMPT "\\s-\\v\\$ "
 #define SPROMPT "> "
diff --git a/variables.c b/variables.c
index 84b30d93..eb363332 100644
--- a/variables.c
+++ b/variables.c
@@ -694,6 +694,7 @@ initialize_shell_variables (char **env, int privmode)
   uidset ();
 
   temp_var = set_if_not ("BASH_LOADABLES_PATH", 
DEFAULT_LOADABLE_BUILTINS_PATH);
+  temp_var = set_if_not ("BASH_SOURCE_PATH", DEFAULT_SOURCE_PATH);
 
   temp_var = find_variable ("BASH_XTRACEFD");
   if (temp_var && imported_p (temp_var))
-- 
2.44.0




Changed behaviour of ${PARAMETER/#PATTERN/STRING} and ${PARAMETER/%PATTERN/STRING}

2024-05-13 Thread Andreas Schwab
In 5.3-alpha, it is no longer possible to quote the special % and #
characters in a pattern replacement expansion.

$ a=1/%2/%3
$ echo "${a/\%/##}"
1/%2/%3##
$ echo "${a/\/%/##}"
1##2/%3

The second example shows that quoting still works as expected for
${PARAMETER//PATTERN/STRING}.

-- 
Andreas Schwab, SUSE Labs, sch...@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."



Re: bug in bash

2024-05-13 Thread Chet Ramey

On 5/12/24 10:00 AM, Oğuz wrote:

On Sun, May 12, 2024 at 4:33 PM Andreas Schwab  wrote:

Since the redirection fails and the cat command is never started, bash
doesn't switch the terminal process group


It does on my computer:

554   ioctl(255, TIOCSPGRP, [554])  = 0
553   execve("/usr/bin/wc", ["wc", "-l"], 0x55706d7bac10 /* 30 vars */

554   +++ exited with 1 +++

But it doesn't change the process group ID of `wc' to its PID, so it
ends up in the foreground process group with bash.


Command substitutions and process substitutions run in the same process
group as the shell performing the word expansions. This is how ksh93 does
it as well (zsh, by contrast, performs the setpgid in the process forked
to run the process substitution).

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



OpenPGP_signature.asc
Description: OpenPGP digital signature


Re: bug in bash

2024-05-13 Thread Oğuz
On Monday, May 13, 2024, Chet Ramey  wrote:

> performs the setpgid in the process forked
> to run the process substitution).
>

Yes, this sounds like the easy way. I don't know how else to prevent the
race in OP. Close stdin/stdout? Direct it from /dev/null?


-- 
Oğuz


Re: [PATCH v2 6/8] builtins/source: use source path in isolated mode

2024-05-13 Thread Koichi Murase
2024年5月13日(月) 19:40 Matheus Afonso Martins Moreira
:
> diff --git a/builtins/source.def b/builtins/source.def
> index 26040e70..7f870bfe 100644
> --- a/builtins/source.def
> +++ b/builtins/source.def
> @@ -177,6 +178,27 @@ search_for_file (WORD_LIST *list)
> [...]
> +static char *
> +isolated_search_for_file (WORD_LIST *list)
> [...]
> +  if (filename == 0)
> +{
> +  if (source_searches_cwd == 0)
> +return (NULL);
> +  else
> +filename = savestring (list->word->word);
> +}

* With this, `isolated_search_for_file()' falls back to local files in
the current working directory. I'm unsure about whether this is
intentional, but I think we should restrict the search in
BASH_SOURCE_PATH and shouldn't fall back to local files. In that case,
we need to make sure that `find_in_path_var()' returns NULL in the
case of empty BASH_SOURCE_PATH. In the current implementation,
`find_in_path_var()' seems to return `save_string (name)' for empty
BASH_SOURCE_PATH, which would induce the search in the current working
directory.

* Even if we intensionally fall back to local files, this part seems
just a repetition of `search_for_file()'. I think this common part
should be moved to `builtin_source()'.



Re: [PATCH v2 3/8] builtins/source: extract file executor function

2024-05-13 Thread Koichi Murase
2024年5月13日(月) 19:39 Matheus Afonso Martins Moreira
:
> Extract into a dedicated helper function the code which loads
> the contents of a file and executes it in the current shell.
> This separates this useful functionality from the path resolution
> mechanism used by the source builtin.

To other reviewers: I checked that this commit is still independent of
the other parts, so you can skip this commit if you focus on the
suggested feature.



Re: [PATCH v2 1/8] findcmd: parameterize path variable in functions

2024-05-13 Thread Koichi Murase
2024年5月13日(月) 19:38 Matheus Afonso Martins Moreira
:
> The PATH variable is hard coded in the user command finder function.
> Transforming it into an argument allows reusing the file finding logic
> with variables other than PATH, making the code more flexible.

I think what was suggested by Chet is to confine the changes in
builtins/source.def. The patches touch the interface of many
functions, but it seems essentially equivalent to just calling

  find_in_path (list->word->word, path_value ("BASH_SOURCE_PATH", 1),
FS_READABLE);

The cases where path_value() returns NULL or an empty string would be
anyway handled by find_in_path() [more specifically by
_find_user_command_internal() and find_user_command_in_path() called
by find_in_path()]. I doubt it's worth adding those changes in
`findcmd.c'. So are the changes in [PATCH v2 2/8].



Re: Re: [PATCH v2 6/8] builtins/source: use source path in isolated mode

2024-05-13 Thread Matheus Afonso Martins Moreira
> I think we should restrict the search in
> BASH_SOURCE_PATH and shouldn't fall back to local files.

I concur but thought it'd be wise to discuss it first so I left it in.
Users might expect it to respect the configuration option.
I also saw that many of the PATH-like variable defaults
had the current directory in them. Finally, there is precedent
for this in other programming languages.

> Even if we intensionally fall back to local files, this part seems
> just a repetition of `search_for_file()'. I think this common part
> should be moved to `builtin_source()'.

I made it that way because it was explicitly requested
that the POSIX mode behavior not be affected in any way.
This way it's clear that there are two algorithms that the
function branches into and that they are completely
independent of each other. Should the current directory
searching logic be eliminated, the function will be simpler.

  -- Matheus



Re: Re: [PATCH v2 1/8] findcmd: parameterize path variable in functions

2024-05-13 Thread Matheus Afonso Martins Moreira
> The patches touch the interface of many functions

I added one external function: find_in_path_var.
The other changes are all static and local.

> It seems essentially equivalent to just calling
> find_in_path (list->word->word, path_value ("BASH_SOURCE_PATH", 1), 
> FS_READABLE);

It is. I'm just very averse to chaining functions like that in C
since you can't write f(g(x)) without worrying about freeing
the value returned by g. For that reason I think this is better:

find_in_path_var (list->word->word, "BASH_SOURCE_PATH", FS_READABLE);

Also, find_in_path is itself just a wrapper for a static function,
just like find_in_path_var. I followed the same approach.

> The cases where path_value() returns NULL or an empty string would be
> anyway handled by find_in_path()

With find_in_path_var there's no need to even consider that.
The knowledge of those cases has been captured by the function.
There's no need to explicitly use path_value either.

> I doubt it's worth adding those changes in
> `findcmd.c'. So are the changes in [PATCH v2 2/8].

You don't think they improve the code?

  -- Matheus



proposed BASH_SOURCE_PATH

2024-05-13 Thread Martin D Kealey
I wholeheartedly support the introduction of BASH_SOURCE_PATH, but I would
like to suggest three tweaks to its semantics.

A common pattern is to unpack a script with its associated library & config
files into a new directory, which then leaves a problem locating the
library files whose paths are only known relative to $0 (or
${BASH_SOURCE[0]}).

1. I therefore propose that where a relative path appears in
BASH_SOURCE_PATH, it should be taken as relative to the directory
containing $0 (after resolving symlinks), rather than relative to $PWD.

As an interim step until that's implemented, please ignore any relative
entries in BASH_SOURCE_PATH, so that users who really want the cwd in
BASH_SOURCE_PATH get used to writing $PWD or /proc/self/cwd instead.

2. Search BASH_SOURCE_PATH when any relative path is given, not just a path
that lacks a '/', so that libraries can be organized into subdirectories.

3. To avoid accidentally loading a script rather than a library, while
searching BASH_SOURCE_PATH, ignore any files that have exec permission,
inverting the check normally made for executables in PATH. This would keep
executables and libraries functionally separate, even if they're commingled
in the same directories.

Yes I know that some folk think it's occasionally useful to have a single
file that operates as both, but (a) new features should default to the
"safest" mode of operation, (b) this isn't python and so that's pretty rare
in practice, and (c) there was at least two work-arounds should that
behaviour actually be desired: (i) use an absolute path, or (ii) use PATH
instead of BASH_SOURCE_PATH.

4. When using "source -i", if BASH_SOURCE_PATH is unset or empty, it's
taken as equivalent to '.', so that it's useful to write "source -i
../lib/foo.bash" in a script at "$X/bin/bar" to load "$X/lib/foo.bash".

-Martin

PS: in the longer term, perhaps PATH could have similar behaviour, but
gated by a shopt or compat check.


Re: proposed BASH_SOURCE_PATH

2024-05-13 Thread Matheus Afonso Martins Moreira
Completely agree with your suggestions.
I've proposed suggestion 3 as well in previous
emails but consensus was not reached.

  -- Matheus