LCOV - code coverage report
Current view: top level - builtins - setattr.def (source / functions) Hit Total Coverage
Test: cov-sh.info Lines: 124 252 49.2 %
Date: 2020-10-29 14:49:55 Functions: 6 9 66.7 %

          Line data    Source code
       1             : This file is setattr.def, from which is created setattr.c.
       2             : It implements the builtins "export" and "readonly", in Bash.
       3             : 
       4             : Copyright (C) 1987-2015 Free Software Foundation, Inc.
       5             : 
       6             : This file is part of GNU Bash, the Bourne Again SHell.
       7             : 
       8             : Bash is free software: you can redistribute it and/or modify
       9             : it under the terms of the GNU General Public License as published by
      10             : the Free Software Foundation, either version 3 of the License, or
      11             : (at your option) any later version.
      12             : 
      13             : Bash is distributed in the hope that it will be useful,
      14             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             : GNU General Public License for more details.
      17             : 
      18             : You should have received a copy of the GNU General Public License
      19             : along with Bash.  If not, see <http://www.gnu.org/licenses/>.
      20             : 
      21             : $PRODUCES setattr.c
      22             : 
      23             : #include <config.h>
      24             : 
      25             : #if defined (HAVE_UNISTD_H)
      26             : #  ifdef _MINIX
      27             : #    include <sys/types.h>
      28             : #  endif
      29             : #  include <unistd.h>
      30             : #endif
      31             : 
      32             : #include <stdio.h>
      33             : #include "../bashansi.h"
      34             : #include "../bashintl.h"
      35             : 
      36             : #include "../shell.h"
      37             : #include "../flags.h"
      38             : #include "common.h"
      39             : #include "bashgetopt.h"
      40             : 
      41             : extern int posixly_correct;
      42             : extern int array_needs_making;
      43             : extern char *this_command_name;
      44             : extern sh_builtin_func_t *this_shell_builtin;
      45             : 
      46             : #ifdef ARRAY_VARS
      47             : extern int declare_builtin __P((WORD_LIST *));
      48             : #endif
      49             : 
      50             : #define READONLY_OR_EXPORT \
      51             :   (this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin)
      52             : 
      53             : $BUILTIN export
      54             : $FUNCTION export_builtin
      55             : $SHORT_DOC export [-fn] [name[=value] ...] or export -p
      56             : Set export attribute for shell variables.
      57             : 
      58             : Marks each NAME for automatic export to the environment of subsequently
      59             : executed commands.  If VALUE is supplied, assign VALUE before exporting.
      60             : 
      61             : Options:
      62             :   -f    refer to shell functions
      63             :   -n    remove the export property from each NAME
      64             :   -p    display a list of all exported variables and functions
      65             : 
      66             : An argument of `--' disables further option processing.
      67             : 
      68             : Exit Status:
      69             : Returns success unless an invalid option is given or NAME is invalid.
      70             : $END
      71             : 
      72             : /* For each variable name in LIST, make that variable appear in the
      73             :    environment passed to simple commands.  If there is no LIST, then
      74             :    print all such variables.  An argument of `-n' says to remove the
      75             :    exported attribute from variables named in LIST.  An argument of
      76             :   -f indicates that the names present in LIST refer to functions. */
      77             : int
      78         127 : export_builtin (list)
      79             :      register WORD_LIST *list;
      80             : {
      81         127 :   return (set_or_show_attributes (list, att_exported, 0));
      82             : }
      83             : 
      84             : $BUILTIN readonly
      85             : $FUNCTION readonly_builtin
      86             : $SHORT_DOC readonly [-aAf] [name[=value] ...] or readonly -p
      87             : Mark shell variables as unchangeable.
      88             : 
      89             : Mark each NAME as read-only; the values of these NAMEs may not be
      90             : changed by subsequent assignment.  If VALUE is supplied, assign VALUE
      91             : before marking as read-only.
      92             : 
      93             : Options:
      94             :   -a    refer to indexed array variables
      95             :   -A    refer to associative array variables
      96             :   -f    refer to shell functions
      97             :   -p    display a list of all readonly variables or functions,
      98             :                 depending on whether or not the -f option is given
      99             : 
     100             : An argument of `--' disables further option processing.
     101             : 
     102             : Exit Status:
     103             : Returns success unless an invalid option is given or NAME is invalid.
     104             : $END
     105             : 
     106             : /* For each variable name in LIST, make that variable readonly.  Given an
     107             :    empty LIST, print out all existing readonly variables. */
     108             : int
     109         109 : readonly_builtin (list)
     110             :      register WORD_LIST *list;
     111             : {
     112         109 :   return (set_or_show_attributes (list, att_readonly, 0));
     113             : }
     114             : 
     115             : #if defined (ARRAY_VARS)
     116             : #  define ATTROPTS      "aAfnp"
     117             : #else
     118             : #  define ATTROPTS      "fnp"
     119             : #endif
     120             : 
     121             : /* For each variable name in LIST, make that variable have the specified
     122             :    ATTRIBUTE.  An arg of `-n' says to remove the attribute from the the
     123             :    remaining names in LIST (doesn't work for readonly). */
     124             : int
     125         236 : set_or_show_attributes (list, attribute, nodefs)
     126             :      register WORD_LIST *list;
     127             :      int attribute, nodefs;
     128             : {
     129         236 :   register SHELL_VAR *var;
     130         236 :   int assign, undo, any_failed, assign_error, opt;
     131         236 :   int functions_only, arrays_only, assoc_only;
     132         236 :   int aflags;
     133         236 :   char *name;
     134             : #if defined (ARRAY_VARS)
     135         236 :   WORD_LIST *nlist, *tlist;
     136         236 :   WORD_DESC *w;
     137         236 :   char optw[8];
     138         236 :   int opti;
     139             : #endif
     140             : 
     141         236 :   functions_only = arrays_only = assoc_only = 0;
     142         236 :   undo = any_failed = assign_error = 0;
     143             :   /* Read arguments from the front of the list. */
     144         236 :   reset_internal_getopt ();
     145         236 :   while ((opt = internal_getopt (list, ATTROPTS)) != -1)
     146             :     {
     147           0 :       switch (opt)
     148             :         {
     149           0 :           case 'n':
     150           0 :             undo = 1;
     151           0 :             break;
     152           0 :           case 'f':
     153           0 :             functions_only = 1;
     154           0 :             break;
     155             : #if defined (ARRAY_VARS)
     156           0 :           case 'a':
     157           0 :             arrays_only = 1;
     158           0 :             break;
     159           0 :           case 'A':
     160           0 :             assoc_only = 1;
     161           0 :             break;
     162             : #endif
     163             :           case 'p':
     164             :             break;
     165           0 :           CASE_HELPOPT;
     166           0 :           default:
     167           0 :             builtin_usage ();
     168           0 :             return (EX_USAGE);
     169             :         }
     170             :     }
     171         236 :   list = loptend;
     172             : 
     173         236 :   if (list)
     174             :     {
     175          52 :       if (attribute & att_exported)
     176          35 :         array_needs_making = 1;
     177             : 
     178             :       /* Cannot undo readonly status, silently disallowed. */
     179          52 :       if (undo && (attribute & att_readonly))
     180           0 :         attribute &= ~att_readonly;
     181             : 
     182         157 :       while (list)
     183             :         {
     184         105 :           name = list->word->word;
     185             : 
     186         105 :           if (functions_only)           /* xxx -f name */
     187             :             {
     188           0 :               var = find_function (name);
     189           0 :               if (var == 0)
     190             :                 {
     191           0 :                   builtin_error (_("%s: not a function"), name);
     192           0 :                   any_failed++;
     193             :                 }
     194           0 :               else if ((attribute & att_exported) && undo == 0 && exportable_function_name (name) == 0)
     195             :                 {
     196           0 :                   builtin_error (_("%s: cannot export"), name);
     197           0 :                   any_failed++;
     198             :                 }
     199             :               else
     200           0 :                 SETVARATTR (var, attribute, undo);
     201             : 
     202           0 :               list = list->next;
     203           0 :               continue;
     204             :             }
     205             : 
     206             :           /* xxx [-np] name[=value] */
     207         105 :           assign = assignment (name, 0);
     208             : 
     209         105 :           aflags = 0;
     210         105 :           if (assign)
     211             :             {
     212          16 :               name[assign] = '\0';
     213          16 :               if (name[assign - 1] == '+')
     214             :                 {
     215           0 :                   aflags |= ASS_APPEND;
     216           0 :                   name[assign - 1] = '\0';
     217             :                 }
     218             :             }
     219             : 
     220         105 :           if (legal_identifier (name) == 0)
     221             :             {
     222          35 :               sh_invalidid (name);
     223          35 :               if (assign)
     224           0 :                 assign_error++;
     225             :               else
     226          35 :                 any_failed++;
     227          35 :               list = list->next;
     228          35 :               continue;
     229             :             }
     230             : 
     231          70 :           if (assign)   /* xxx [-np] name=value */
     232             :             {
     233          16 :               name[assign] = '=';
     234          16 :               if (aflags & ASS_APPEND)
     235           0 :                 name[assign - 1] = '+';
     236             : #if defined (ARRAY_VARS)
     237             :               /* Let's try something here.  Turn readonly -a xxx=yyy into
     238             :                  declare -ra xxx=yyy and see what that gets us. */
     239          16 :               if (arrays_only || assoc_only)
     240             :                 {
     241           0 :                   tlist = list->next;
     242           0 :                   list->next = (WORD_LIST *)NULL;
     243             :                   /* Add -g to avoid readonly/export creating local variables:
     244             :                      only local/declare/typeset create local variables */
     245           0 :                   opti = 0;
     246           0 :                   optw[opti++] = '-';
     247           0 :                   optw[opti++] = 'g';
     248           0 :                   if (attribute & att_readonly)
     249           0 :                     optw[opti++] = 'r';
     250           0 :                   if (attribute & att_exported)
     251           0 :                     optw[opti++] = 'x';
     252           0 :                   if (arrays_only)
     253           0 :                     optw[opti++] = 'a';
     254             :                   else
     255           0 :                     optw[opti++] = 'A';
     256           0 :                   optw[opti] = '\0';
     257             : 
     258           0 :                   w = make_word (optw);
     259           0 :                   nlist = make_word_list (w, list);
     260             : 
     261           0 :                   opt = declare_builtin (nlist);
     262           0 :                   if (opt != EXECUTION_SUCCESS)
     263           0 :                     assign_error++;
     264           0 :                   list->next = tlist;
     265           0 :                   dispose_word (w);
     266           0 :                   free (nlist);
     267             :                 }
     268             :               else
     269             : #endif
     270             :               /* This word has already been expanded once with command
     271             :                  and parameter expansion.  Call do_assignment_no_expand (),
     272             :                  which does not do command or parameter substitution.  If
     273             :                  the assignment is not performed correctly, flag an error. */
     274          16 :               if (do_assignment_no_expand (name) == 0)
     275           0 :                 assign_error++;
     276          16 :               name[assign] = '\0';
     277          16 :               if (aflags & ASS_APPEND)
     278           0 :                 name[assign - 1] = '\0';
     279             :             }
     280             : 
     281          70 :           set_var_attribute (name, attribute, undo);
     282          70 :           list = list->next;
     283             :         }
     284             :     }
     285             :   else
     286             :     {
     287         184 :       SHELL_VAR **variable_list;
     288         184 :       register int i;
     289             : 
     290         184 :       if ((attribute & att_function) || functions_only)
     291             :         {
     292           0 :           variable_list = all_shell_functions ();
     293           0 :           if (attribute != att_function)
     294           0 :             attribute &= ~att_function;     /* so declare -xf works, for example */
     295             :         }
     296             :       else
     297         184 :         variable_list = all_shell_variables ();
     298             : 
     299             : #if defined (ARRAY_VARS)
     300         184 :       if (attribute & att_array)
     301             :         {
     302           0 :           arrays_only++;
     303           0 :           if (attribute != att_array)
     304           0 :             attribute &= ~att_array;
     305             :         }
     306         184 :       else if (attribute & att_assoc)
     307             :         {
     308           0 :           assoc_only++;
     309           0 :           if (attribute != att_assoc)
     310           0 :             attribute &= ~att_assoc;
     311             :         }
     312             : #endif
     313             : 
     314         184 :       if (variable_list)
     315             :         {
     316        9742 :           for (i = 0; var = variable_list[i]; i++)
     317             :             {
     318             : #if defined (ARRAY_VARS)
     319        9605 :               if (arrays_only && array_p (var) == 0)
     320             :                 continue;
     321        9605 :               else if (assoc_only && assoc_p (var) == 0)
     322             :                 continue;
     323             : #endif
     324             : 
     325             :               /* If we imported a variable that's not a valid identifier, don't
     326             :                  show it in any lists. */
     327        9605 :               if ((var->attributes & (att_invisible|att_imported)) == (att_invisible|att_imported))
     328             :                 continue;
     329             : 
     330        9605 :               if ((var->attributes & attribute))
     331             :                 {
     332        2891 :                   show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
     333        2891 :                   if (any_failed = sh_chkwrite (any_failed))
     334             :                     break;
     335             :                 }
     336             :             }
     337         184 :           free (variable_list);
     338             :         }
     339             :     }
     340             : 
     341         184 :   return (assign_error ? EX_BADASSIGN
     342          52 :                        : ((any_failed == 0) ? EXECUTION_SUCCESS
     343         236 :                                             : EXECUTION_FAILURE));
     344             : }
     345             : 
     346             : /* Show all variable variables (v == 1) or functions (v == 0) with
     347             :    attributes. */
     348             : int
     349           0 : show_all_var_attributes (v, nodefs)
     350             :      int v, nodefs;
     351             : {
     352           0 :   SHELL_VAR **variable_list, *var;
     353           0 :   int any_failed;
     354           0 :   register int i;
     355             : 
     356           0 :   variable_list = v ? all_shell_variables () : all_shell_functions ();
     357           0 :   if (variable_list == 0)  
     358             :     return (EXECUTION_SUCCESS);
     359             : 
     360           0 :   for (i = any_failed = 0; var = variable_list[i]; i++)
     361             :     {
     362           0 :       show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
     363           0 :       if (any_failed = sh_chkwrite (any_failed))
     364             :         break;
     365             :     }
     366           0 :   free (variable_list);
     367           0 :   return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
     368             : }
     369             : 
     370             : int
     371        2891 : var_attribute_string (var, pattr, flags)
     372             :      SHELL_VAR *var;
     373             :      int pattr;
     374             :      char *flags;       /* filled in with attributes */
     375             : {
     376        2891 :   int i;
     377             : 
     378        2891 :   i = 0;
     379             : 
     380             :   /* pattr == 0 means we are called from `declare'. */
     381        2891 :   if (pattr == 0 || posixly_correct == 0)
     382             :     {
     383             : #if defined (ARRAY_VARS)
     384        2891 :       if (array_p (var))
     385          72 :         flags[i++] = 'a';
     386             : 
     387        2891 :       if (assoc_p (var))
     388           0 :         flags[i++] = 'A';
     389             : #endif
     390             : 
     391        2891 :       if (function_p (var))
     392           0 :         flags[i++] = 'f';
     393             : 
     394        2891 :       if (integer_p (var))
     395         288 :         flags[i++] = 'i';
     396             : 
     397        2891 :       if (nameref_p (var))
     398           0 :         flags[i++] = 'n';
     399             : 
     400        2891 :       if (readonly_p (var))
     401         524 :         flags[i++] = 'r';
     402             : 
     403        2891 :       if (trace_p (var))
     404           0 :         flags[i++] = 't';
     405             : 
     406        2891 :       if (exported_p (var))
     407        2367 :         flags[i++] = 'x';
     408             : 
     409        2891 :       if (capcase_p (var))
     410           0 :         flags[i++] = 'c';
     411             : 
     412        2891 :       if (lowercase_p (var))
     413           0 :         flags[i++] = 'l';
     414             : 
     415        2891 :       if (uppercase_p (var))
     416           0 :         flags[i++] = 'u';
     417             :     }
     418             :   else
     419             :     {
     420             : #if defined (ARRAY_VARS)
     421           0 :       if (array_p (var))
     422           0 :         flags[i++] = 'a';
     423             : 
     424           0 :       if (assoc_p (var))
     425           0 :         flags[i++] = 'A';
     426             : #endif
     427             : 
     428           0 :       if (function_p (var))
     429           0 :         flags[i++] = 'f';
     430             :     }
     431             : 
     432        2891 :   flags[i] = '\0';
     433        2891 :   return i;
     434             : }
     435             : 
     436             : /* Show the attributes for shell variable VAR.  If NODEFS is non-zero,
     437             :    don't show function definitions along with the name.  If PATTR is
     438             :    non-zero, it indicates we're being called from `export' or `readonly'.
     439             :    In POSIX mode, this prints the name of the calling builtin (`export'
     440             :    or `readonly') instead of `declare', and doesn't print function defs
     441             :    when called by `export' or `readonly'. */
     442             : int
     443        2891 : show_var_attributes (var, pattr, nodefs)
     444             :      SHELL_VAR *var;
     445             :      int pattr, nodefs;
     446             : {
     447        2891 :   char flags[MAX_ATTRIBUTES], *x;
     448        2891 :   int i;
     449             : 
     450        2891 :   i = var_attribute_string (var, pattr, flags);
     451             : 
     452             :   /* If we're printing functions with definitions, print the function def
     453             :      first, then the attributes, instead of printing output that can't be
     454             :      reused as input to recreate the current state. */
     455        2891 :   if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0))
     456             :     {
     457           0 :       printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
     458           0 :       nodefs++;
     459           0 :       if (pattr == 0 && i == 1 && flags[0] == 'f')
     460             :         return 0;               /* don't print `declare -f name' */
     461             :     }
     462             : 
     463        2891 :   if (pattr == 0 || posixly_correct == 0)
     464        2891 :     printf ("declare -%s ", i ? flags : "-");
     465           0 :   else if (i)
     466           0 :     printf ("%s -%s ", this_command_name, flags);
     467             :   else
     468           0 :     printf ("%s ", this_command_name);
     469             : 
     470             : #if defined (ARRAY_VARS)
     471        2891 :   if (invisible_p (var) && (array_p (var) || assoc_p (var)))
     472           0 :     printf ("%s\n", var->name);
     473        2891 :   else if (array_p (var))
     474          72 :     print_array_assignment (var, 0);
     475        2819 :   else if (assoc_p (var))
     476           0 :     print_assoc_assignment (var, 0);
     477             :   else
     478             : #endif
     479             :   /* force `readonly' and `export' to not print out function definitions
     480             :      when in POSIX mode. */
     481        2819 :   if (nodefs || (function_p (var) && pattr != 0 && posixly_correct))
     482           0 :     printf ("%s\n", var->name);
     483        2819 :   else if (function_p (var))
     484           0 :     printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
     485        2819 :   else if (invisible_p (var) || var_isset (var) == 0)
     486          72 :     printf ("%s\n", var->name);
     487             :   else
     488             :     {
     489        2747 :       x = sh_double_quote (value_cell (var));
     490        2747 :       printf ("%s=%s\n", var->name, x);
     491        2747 :       free (x);
     492             :     }
     493             :   return (0);
     494             : }
     495             : 
     496             : int
     497           0 : show_name_attributes (name, nodefs)
     498             :      char *name;
     499             :      int nodefs;
     500             : {
     501           0 :   SHELL_VAR *var;
     502             : 
     503             : #if 0
     504             :   var = find_variable_tempenv (name);
     505             : #else
     506           0 :   var = find_variable_noref (name);
     507             : #endif
     508             : 
     509           0 :   if (var /* && invisible_p (var) == 0 */)      /* XXX bash-4.4/bash-5.0 */
     510             :     {
     511           0 :       show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
     512           0 :       return (0);
     513             :     }
     514             :   else
     515             :     return (1);
     516             : }
     517             : 
     518             : int
     519           0 : show_func_attributes (name, nodefs)
     520             :      char *name;
     521             :      int nodefs;
     522             : {
     523           0 :   SHELL_VAR *var;
     524             : 
     525           0 :   var = find_function (name);
     526             : 
     527           0 :   if (var)
     528             :     {
     529           0 :       show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
     530           0 :       return (0);
     531             :     }
     532             :   else
     533             :     return (1);
     534             : }
     535             : 
     536             : void
     537          70 : set_var_attribute (name, attribute, undo)
     538             :      char *name;
     539             :      int attribute, undo;
     540             : {
     541          70 :   SHELL_VAR *var, *tv, *v, *refvar;
     542          70 :   char *tvalue;
     543             : 
     544          70 :   if (undo)
     545           0 :     var = find_variable (name);
     546             :   else
     547             :     {
     548          70 :       tv = find_tempenv_variable (name);
     549             :       /* XXX -- need to handle case where tv is a temp variable in a
     550             :          function-scope context, since function_env has been merged into
     551             :          the local variables table. */
     552          70 :       if (tv && tempvar_p (tv))
     553             :         {
     554           0 :           tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
     555             : 
     556           0 :           var = bind_variable (tv->name, tvalue, 0);
     557           0 :           if (var == 0)
     558             :             {
     559           0 :               free (tvalue);
     560           0 :               return;           /* XXX - no error message here */
     561             :             }
     562           0 :           var->attributes |= tv->attributes & ~att_tempvar;
     563             :           /* This avoids an error message when propagating a read-only var
     564             :              later on. */
     565           0 :           if (var->context == 0 && (attribute & att_readonly))
     566             :             {
     567             :               /* Don't bother to set the `propagate to the global variables
     568             :                  table' flag if we've just bound the variable in that table */
     569           0 :               v = find_global_variable (tv->name);
     570           0 :               if (v != var)
     571           0 :                 VSETATTR (tv, att_propagate);
     572             :             }
     573             :           else
     574           0 :             VSETATTR (tv, att_propagate);
     575           0 :           if (var->context != 0)
     576           0 :             VSETATTR (var, att_propagate);
     577           0 :           SETVARATTR (tv, attribute, undo);     /* XXX */
     578             : 
     579           0 :           stupidly_hack_special_variables (tv->name);
     580             : 
     581           0 :           free (tvalue);
     582             :         }
     583             :       else
     584             :         {
     585          70 :           var = find_variable_notempenv (name);
     586          70 :           if (var == 0)
     587             :             {
     588             :               /* We might have a nameref pointing to something that we can't
     589             :                  resolve to a shell variable.  If we do, skip it.  We do a little
     590             :                  checking just so we can print an error message. */
     591          54 :               refvar = find_variable_nameref_for_create (name, 0);
     592          54 :               if (refvar == INVALID_NAMEREF_VALUE)
     593             :                 return;
     594             :               /* Otherwise we probably have a nameref pointing to a variable
     595             :                  that hasn't been created yet. bind_variable will take care
     596             :                  of that. */
     597             :             }
     598          70 :           if (var == 0)
     599             :             {
     600          54 :               var = bind_variable (name, (char *)NULL, 0);
     601          54 :               if (var && no_invisible_vars == 0)
     602          54 :                 VSETATTR (var, att_invisible);
     603             :             }
     604          16 :           else if (var->context != 0)
     605           0 :             VSETATTR (var, att_propagate);
     606             :         }
     607             :     }
     608             : 
     609          70 :   if (var)
     610          70 :     SETVARATTR (var, attribute, undo);
     611             : 
     612          70 :   if (var && (exported_p (var) || (attribute & att_exported)))
     613          53 :     array_needs_making++;       /* XXX */
     614             : 
     615          70 :   if (var)
     616          70 :     stupidly_hack_special_variables (name);
     617             : }

Generated by: LCOV version 1.14.0.6.4058