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 : }
|