]>
Commit | Line | Data |
---|---|---|
726f6388 JA |
1 | This file is setattr.def, from which is created setattr.c. |
2 | It implements the builtins "export" and "readonly", in Bash. | |
3 | ||
495aee44 | 4 | Copyright (C) 1987-2010 Free Software Foundation, Inc. |
726f6388 JA |
5 | |
6 | This file is part of GNU Bash, the Bourne Again SHell. | |
7 | ||
3185942a JA |
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. | |
726f6388 | 12 | |
3185942a JA |
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. | |
726f6388 | 17 | |
3185942a JA |
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/>. | |
726f6388 JA |
20 | |
21 | $PRODUCES setattr.c | |
22 | ||
ccc6cda3 JA |
23 | #include <config.h> |
24 | ||
25 | #if defined (HAVE_UNISTD_H) | |
cce855bc JA |
26 | # ifdef _MINIX |
27 | # include <sys/types.h> | |
28 | # endif | |
ccc6cda3 JA |
29 | # include <unistd.h> |
30 | #endif | |
31 | ||
32 | #include <stdio.h> | |
33 | #include "../bashansi.h" | |
b80f6443 | 34 | #include "../bashintl.h" |
ccc6cda3 | 35 | |
726f6388 JA |
36 | #include "../shell.h" |
37 | #include "common.h" | |
38 | #include "bashgetopt.h" | |
39 | ||
d166f048 | 40 | extern int posixly_correct; |
726f6388 JA |
41 | extern int array_needs_making; |
42 | extern char *this_command_name; | |
f73dda09 | 43 | extern sh_builtin_func_t *this_shell_builtin; |
d166f048 JA |
44 | |
45 | #ifdef ARRAY_VARS | |
7117c2d2 | 46 | extern int declare_builtin __P((WORD_LIST *)); |
d166f048 JA |
47 | #endif |
48 | ||
49 | #define READONLY_OR_EXPORT \ | |
50 | (this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin) | |
726f6388 JA |
51 | |
52 | $BUILTIN export | |
53 | $FUNCTION export_builtin | |
3185942a JA |
54 | $SHORT_DOC export [-fn] [name[=value] ...] or export -p |
55 | Set export attribute for shell variables. | |
56 | ||
57 | Marks each NAME for automatic export to the environment of subsequently | |
58 | executed commands. If VALUE is supplied, assign VALUE before exporting. | |
59 | ||
60 | Options: | |
61 | -f refer to shell functions | |
62 | -n remove the export property from each NAME | |
63 | -p display a list of all exported variables and functions | |
64 | ||
65 | An argument of `--' disables further option processing. | |
66 | ||
67 | Exit Status: | |
68 | Returns success unless an invalid option is given or NAME is invalid. | |
726f6388 JA |
69 | $END |
70 | ||
71 | /* For each variable name in LIST, make that variable appear in the | |
72 | environment passed to simple commands. If there is no LIST, then | |
73 | print all such variables. An argument of `-n' says to remove the | |
74 | exported attribute from variables named in LIST. An argument of | |
75 | -f indicates that the names present in LIST refer to functions. */ | |
ccc6cda3 | 76 | int |
726f6388 JA |
77 | export_builtin (list) |
78 | register WORD_LIST *list; | |
79 | { | |
ccc6cda3 | 80 | return (set_or_show_attributes (list, att_exported, 0)); |
726f6388 JA |
81 | } |
82 | ||
83 | $BUILTIN readonly | |
84 | $FUNCTION readonly_builtin | |
495aee44 | 85 | $SHORT_DOC readonly [-aAf] [name[=value] ...] or readonly -p |
3185942a JA |
86 | Mark shell variables as unchangeable. |
87 | ||
88 | Mark each NAME as read-only; the values of these NAMEs may not be | |
89 | changed by subsequent assignment. If VALUE is supplied, assign VALUE | |
90 | before marking as read-only. | |
91 | ||
92 | Options: | |
93 | -a refer to indexed array variables | |
94 | -A refer to associative array variables | |
95 | -f refer to shell functions | |
96 | -p display a list of all readonly variables and functions | |
97 | ||
98 | An argument of `--' disables further option processing. | |
99 | ||
100 | Exit Status: | |
101 | Returns success unless an invalid option is given or NAME is invalid. | |
726f6388 JA |
102 | $END |
103 | ||
104 | /* For each variable name in LIST, make that variable readonly. Given an | |
105 | empty LIST, print out all existing readonly variables. */ | |
ccc6cda3 | 106 | int |
726f6388 JA |
107 | readonly_builtin (list) |
108 | register WORD_LIST *list; | |
109 | { | |
ccc6cda3 | 110 | return (set_or_show_attributes (list, att_readonly, 0)); |
726f6388 JA |
111 | } |
112 | ||
7117c2d2 | 113 | #if defined (ARRAY_VARS) |
3185942a | 114 | # define ATTROPTS "aAfnp" |
7117c2d2 JA |
115 | #else |
116 | # define ATTROPTS "fnp" | |
117 | #endif | |
118 | ||
726f6388 JA |
119 | /* For each variable name in LIST, make that variable have the specified |
120 | ATTRIBUTE. An arg of `-n' says to remove the attribute from the the | |
b80f6443 | 121 | remaining names in LIST (doesn't work for readonly). */ |
726f6388 | 122 | int |
ccc6cda3 | 123 | set_or_show_attributes (list, attribute, nodefs) |
726f6388 | 124 | register WORD_LIST *list; |
ccc6cda3 | 125 | int attribute, nodefs; |
726f6388 JA |
126 | { |
127 | register SHELL_VAR *var; | |
3185942a JA |
128 | int assign, undo, any_failed, assign_error, opt; |
129 | int functions_only, arrays_only, assoc_only; | |
95732b49 | 130 | int aflags; |
ccc6cda3 | 131 | char *name; |
d166f048 JA |
132 | #if defined (ARRAY_VARS) |
133 | WORD_LIST *nlist, *tlist; | |
134 | WORD_DESC *w; | |
135 | #endif | |
726f6388 | 136 | |
3185942a JA |
137 | functions_only = arrays_only = assoc_only = 0; |
138 | undo = any_failed = assign_error = 0; | |
726f6388 JA |
139 | /* Read arguments from the front of the list. */ |
140 | reset_internal_getopt (); | |
7117c2d2 | 141 | while ((opt = internal_getopt (list, ATTROPTS)) != -1) |
726f6388 JA |
142 | { |
143 | switch (opt) | |
144 | { | |
145 | case 'n': | |
146 | undo = 1; | |
147 | break; | |
148 | case 'f': | |
149 | functions_only = 1; | |
150 | break; | |
ccc6cda3 JA |
151 | #if defined (ARRAY_VARS) |
152 | case 'a': | |
3185942a JA |
153 | arrays_only = 1; |
154 | break; | |
155 | case 'A': | |
156 | assoc_only = 1; | |
157 | break; | |
ccc6cda3 | 158 | #endif |
726f6388 JA |
159 | case 'p': |
160 | break; | |
161 | default: | |
ccc6cda3 | 162 | builtin_usage (); |
726f6388 JA |
163 | return (EX_USAGE); |
164 | } | |
165 | } | |
166 | list = loptend; | |
167 | ||
168 | if (list) | |
169 | { | |
170 | if (attribute & att_exported) | |
171 | array_needs_making = 1; | |
172 | ||
ccc6cda3 | 173 | /* Cannot undo readonly status, silently disallowed. */ |
726f6388 JA |
174 | if (undo && (attribute & att_readonly)) |
175 | attribute &= ~att_readonly; | |
176 | ||
177 | while (list) | |
178 | { | |
ccc6cda3 | 179 | name = list->word->word; |
726f6388 | 180 | |
ccc6cda3 | 181 | if (functions_only) /* xxx -f name */ |
726f6388 JA |
182 | { |
183 | var = find_function (name); | |
ccc6cda3 | 184 | if (var == 0) |
726f6388 | 185 | { |
b80f6443 | 186 | builtin_error (_("%s: not a function"), name); |
726f6388 JA |
187 | any_failed++; |
188 | } | |
189 | else | |
ccc6cda3 JA |
190 | SETVARATTR (var, attribute, undo); |
191 | ||
726f6388 | 192 | list = list->next; |
726f6388 JA |
193 | continue; |
194 | } | |
195 | ||
ccc6cda3 | 196 | /* xxx [-np] name[=value] */ |
b80f6443 | 197 | assign = assignment (name, 0); |
726f6388 | 198 | |
95732b49 | 199 | aflags = 0; |
28ef6c31 | 200 | if (assign) |
95732b49 JA |
201 | { |
202 | name[assign] = '\0'; | |
203 | if (name[assign - 1] == '+') | |
204 | { | |
205 | aflags |= ASS_APPEND; | |
206 | name[assign - 1] = '\0'; | |
207 | } | |
208 | } | |
ccc6cda3 | 209 | |
726f6388 JA |
210 | if (legal_identifier (name) == 0) |
211 | { | |
7117c2d2 | 212 | sh_invalidid (name); |
d166f048 JA |
213 | if (assign) |
214 | assign_error++; | |
215 | else | |
216 | any_failed++; | |
726f6388 JA |
217 | list = list->next; |
218 | continue; | |
219 | } | |
220 | ||
ccc6cda3 | 221 | if (assign) /* xxx [-np] name=value */ |
726f6388 JA |
222 | { |
223 | name[assign] = '='; | |
95732b49 JA |
224 | if (aflags & ASS_APPEND) |
225 | name[assign - 1] = '+'; | |
d166f048 JA |
226 | #if defined (ARRAY_VARS) |
227 | /* Let's try something here. Turn readonly -a xxx=yyy into | |
228 | declare -ra xxx=yyy and see what that gets us. */ | |
3185942a | 229 | if (arrays_only || assoc_only) |
d166f048 JA |
230 | { |
231 | tlist = list->next; | |
232 | list->next = (WORD_LIST *)NULL; | |
3185942a | 233 | w = arrays_only ? make_word ("-ra") : make_word ("-rA"); |
d166f048 JA |
234 | nlist = make_word_list (w, list); |
235 | opt = declare_builtin (nlist); | |
236 | if (opt != EXECUTION_SUCCESS) | |
237 | assign_error++; | |
238 | list->next = tlist; | |
239 | dispose_word (w); | |
240 | free (nlist); | |
241 | } | |
242 | else | |
243 | #endif | |
726f6388 JA |
244 | /* This word has already been expanded once with command |
245 | and parameter expansion. Call do_assignment_no_expand (), | |
ccc6cda3 JA |
246 | which does not do command or parameter substitution. If |
247 | the assignment is not performed correctly, flag an error. */ | |
248 | if (do_assignment_no_expand (name) == 0) | |
249 | assign_error++; | |
726f6388 | 250 | name[assign] = '\0'; |
95732b49 JA |
251 | if (aflags & ASS_APPEND) |
252 | name[assign - 1] = '\0'; | |
726f6388 JA |
253 | } |
254 | ||
ccc6cda3 | 255 | set_var_attribute (name, attribute, undo); |
726f6388 JA |
256 | list = list->next; |
257 | } | |
258 | } | |
259 | else | |
260 | { | |
261 | SHELL_VAR **variable_list; | |
262 | register int i; | |
263 | ||
264 | if ((attribute & att_function) || functions_only) | |
265 | { | |
266 | variable_list = all_shell_functions (); | |
267 | if (attribute != att_function) | |
268 | attribute &= ~att_function; /* so declare -xf works, for example */ | |
269 | } | |
270 | else | |
271 | variable_list = all_shell_variables (); | |
272 | ||
ccc6cda3 JA |
273 | #if defined (ARRAY_VARS) |
274 | if (attribute & att_array) | |
28ef6c31 JA |
275 | { |
276 | arrays_only++; | |
277 | if (attribute != att_array) | |
ccc6cda3 | 278 | attribute &= ~att_array; |
28ef6c31 | 279 | } |
3185942a JA |
280 | else if (attribute & att_assoc) |
281 | { | |
282 | assoc_only++; | |
283 | if (attribute != att_assoc) | |
284 | attribute &= ~att_assoc; | |
285 | } | |
ccc6cda3 JA |
286 | #endif |
287 | ||
726f6388 JA |
288 | if (variable_list) |
289 | { | |
290 | for (i = 0; var = variable_list[i]; i++) | |
291 | { | |
ccc6cda3 JA |
292 | #if defined (ARRAY_VARS) |
293 | if (arrays_only && array_p (var) == 0) | |
28ef6c31 | 294 | continue; |
3185942a JA |
295 | else if (assoc_only && assoc_p (var) == 0) |
296 | continue; | |
ccc6cda3 | 297 | #endif |
f73dda09 | 298 | if ((var->attributes & attribute)) |
3185942a JA |
299 | { |
300 | show_var_attributes (var, READONLY_OR_EXPORT, nodefs); | |
301 | if (any_failed = sh_chkwrite (any_failed)) | |
302 | break; | |
303 | } | |
ccc6cda3 JA |
304 | } |
305 | free (variable_list); | |
306 | } | |
307 | } | |
308 | ||
309 | return (assign_error ? EX_BADASSIGN | |
310 | : ((any_failed == 0) ? EXECUTION_SUCCESS | |
311 | : EXECUTION_FAILURE)); | |
312 | } | |
313 | ||
3185942a JA |
314 | /* Show all variable variables (v == 1) or functions (v == 0) with |
315 | attributes. */ | |
316 | int | |
317 | show_all_var_attributes (v, nodefs) | |
318 | int v, nodefs; | |
319 | { | |
320 | SHELL_VAR **variable_list, *var; | |
321 | int any_failed; | |
322 | register int i; | |
323 | ||
324 | variable_list = v ? all_shell_variables () : all_shell_functions (); | |
325 | if (variable_list == 0) | |
326 | return (EXECUTION_SUCCESS); | |
327 | ||
328 | for (i = any_failed = 0; var = variable_list[i]; i++) | |
329 | { | |
330 | show_var_attributes (var, READONLY_OR_EXPORT, nodefs); | |
331 | if (any_failed = sh_chkwrite (any_failed)) | |
332 | break; | |
333 | } | |
334 | free (variable_list); | |
335 | return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE); | |
336 | } | |
337 | ||
d166f048 JA |
338 | /* Show the attributes for shell variable VAR. If NODEFS is non-zero, |
339 | don't show function definitions along with the name. If PATTR is | |
340 | non-zero, it indicates we're being called from `export' or `readonly'. | |
341 | In POSIX mode, this prints the name of the calling builtin (`export' | |
342 | or `readonly') instead of `declare', and doesn't print function defs | |
343 | when called by `export' or `readonly'. */ | |
ccc6cda3 | 344 | int |
d166f048 | 345 | show_var_attributes (var, pattr, nodefs) |
ccc6cda3 | 346 | SHELL_VAR *var; |
d166f048 | 347 | int pattr, nodefs; |
ccc6cda3 | 348 | { |
3185942a | 349 | char flags[16], *x; |
ccc6cda3 | 350 | int i; |
726f6388 | 351 | |
ccc6cda3 | 352 | i = 0; |
726f6388 | 353 | |
d166f048 JA |
354 | /* pattr == 0 means we are called from `declare'. */ |
355 | if (pattr == 0 || posixly_correct == 0) | |
356 | { | |
ccc6cda3 | 357 | #if defined (ARRAY_VARS) |
d166f048 JA |
358 | if (array_p (var)) |
359 | flags[i++] = 'a'; | |
3185942a JA |
360 | |
361 | if (assoc_p (var)) | |
362 | flags[i++] = 'A'; | |
ccc6cda3 | 363 | #endif |
726f6388 | 364 | |
d166f048 | 365 | if (function_p (var)) |
28ef6c31 | 366 | flags[i++] = 'f'; |
726f6388 | 367 | |
d166f048 | 368 | if (integer_p (var)) |
28ef6c31 | 369 | flags[i++] = 'i'; |
726f6388 | 370 | |
d166f048 | 371 | if (readonly_p (var)) |
28ef6c31 | 372 | flags[i++] = 'r'; |
726f6388 | 373 | |
7117c2d2 JA |
374 | if (trace_p (var)) |
375 | flags[i++] = 't'; | |
376 | ||
d166f048 | 377 | if (exported_p (var)) |
28ef6c31 | 378 | flags[i++] = 'x'; |
3185942a JA |
379 | |
380 | if (capcase_p (var)) | |
381 | flags[i++] = 'c'; | |
382 | ||
383 | if (lowercase_p (var)) | |
384 | flags[i++] = 'l'; | |
385 | ||
386 | if (uppercase_p (var)) | |
387 | flags[i++] = 'u'; | |
d166f048 JA |
388 | } |
389 | else | |
390 | { | |
391 | #if defined (ARRAY_VARS) | |
392 | if (array_p (var)) | |
393 | flags[i++] = 'a'; | |
3185942a JA |
394 | |
395 | if (assoc_p (var)) | |
396 | flags[i++] = 'A'; | |
d166f048 JA |
397 | #endif |
398 | ||
399 | if (function_p (var)) | |
28ef6c31 | 400 | flags[i++] = 'f'; |
d166f048 | 401 | } |
726f6388 | 402 | |
ccc6cda3 | 403 | flags[i] = '\0'; |
726f6388 | 404 | |
7117c2d2 JA |
405 | /* If we're printing functions with definitions, print the function def |
406 | first, then the attributes, instead of printing output that can't be | |
407 | reused as input to recreate the current state. */ | |
408 | if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0)) | |
409 | { | |
3185942a | 410 | printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL)); |
7117c2d2 JA |
411 | nodefs++; |
412 | if (pattr == 0 && i == 1 && flags[0] == 'f') | |
413 | return 0; /* don't print `declare -f name' */ | |
414 | } | |
415 | ||
d166f048 JA |
416 | if (pattr == 0 || posixly_correct == 0) |
417 | printf ("declare -%s ", i ? flags : "-"); | |
418 | else if (i) | |
419 | printf ("%s -%s ", this_command_name, flags); | |
420 | else | |
421 | printf ("%s ", this_command_name); | |
ccc6cda3 JA |
422 | |
423 | #if defined (ARRAY_VARS) | |
3185942a | 424 | if (array_p (var)) |
ccc6cda3 | 425 | print_array_assignment (var, 1); |
3185942a JA |
426 | else if (assoc_p (var)) |
427 | print_assoc_assignment (var, 1); | |
ccc6cda3 JA |
428 | else |
429 | #endif | |
7117c2d2 | 430 | /* force `readonly' and `export' to not print out function definitions |
d166f048 JA |
431 | when in POSIX mode. */ |
432 | if (nodefs || (function_p (var) && pattr != 0 && posixly_correct)) | |
ccc6cda3 JA |
433 | printf ("%s\n", var->name); |
434 | else if (function_p (var)) | |
3185942a | 435 | printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL)); |
495aee44 | 436 | else if (invisible_p (var) || var_isset (var) == 0) |
f73dda09 | 437 | printf ("%s\n", var->name); |
ccc6cda3 JA |
438 | else |
439 | { | |
495aee44 | 440 | x = sh_double_quote (value_cell (var)); |
ccc6cda3 JA |
441 | printf ("%s=%s\n", var->name, x); |
442 | free (x); | |
443 | } | |
444 | return (0); | |
445 | } | |
446 | ||
447 | int | |
448 | show_name_attributes (name, nodefs) | |
449 | char *name; | |
450 | int nodefs; | |
451 | { | |
452 | SHELL_VAR *var; | |
453 | ||
7117c2d2 | 454 | var = find_variable_internal (name, 1); |
ccc6cda3 JA |
455 | |
456 | if (var && invisible_p (var) == 0) | |
457 | { | |
d166f048 | 458 | show_var_attributes (var, READONLY_OR_EXPORT, nodefs); |
ccc6cda3 JA |
459 | return (0); |
460 | } | |
461 | else | |
462 | return (1); | |
463 | } | |
464 | ||
465 | void | |
466 | set_var_attribute (name, attribute, undo) | |
467 | char *name; | |
468 | int attribute, undo; | |
469 | { | |
470 | SHELL_VAR *var, *tv; | |
7117c2d2 | 471 | char *tvalue; |
ccc6cda3 JA |
472 | |
473 | if (undo) | |
474 | var = find_variable (name); | |
475 | else | |
476 | { | |
7117c2d2 JA |
477 | tv = find_tempenv_variable (name); |
478 | /* XXX -- need to handle case where tv is a temp variable in a | |
479 | function-scope context, since function_env has been merged into | |
480 | the local variables table. */ | |
481 | if (tv && tempvar_p (tv)) | |
ccc6cda3 | 482 | { |
7117c2d2 JA |
483 | tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring (""); |
484 | ||
95732b49 | 485 | var = bind_variable (tv->name, tvalue, 0); |
7117c2d2 JA |
486 | var->attributes |= tv->attributes & ~att_tempvar; |
487 | VSETATTR (tv, att_propagate); | |
488 | if (var->context != 0) | |
489 | VSETATTR (var, att_propagate); | |
490 | SETVARATTR (tv, attribute, undo); /* XXX */ | |
491 | ||
95732b49 JA |
492 | stupidly_hack_special_variables (tv->name); |
493 | ||
7117c2d2 | 494 | free (tvalue); |
ccc6cda3 JA |
495 | } |
496 | else | |
ccc6cda3 | 497 | { |
7117c2d2 JA |
498 | var = find_variable_internal (name, 0); |
499 | if (var == 0) | |
500 | { | |
95732b49 | 501 | var = bind_variable (name, (char *)NULL, 0); |
7117c2d2 JA |
502 | VSETATTR (var, att_invisible); |
503 | } | |
504 | else if (var->context != 0) | |
505 | VSETATTR (var, att_propagate); | |
726f6388 JA |
506 | } |
507 | } | |
ccc6cda3 JA |
508 | |
509 | if (var) | |
510 | SETVARATTR (var, attribute, undo); | |
511 | ||
bb70624e | 512 | if (var && (exported_p (var) || (attribute & att_exported))) |
ccc6cda3 | 513 | array_needs_making++; /* XXX */ |
726f6388 | 514 | } |