]>
Commit | Line | Data |
---|---|---|
726f6388 JA |
1 | This file is enable.def, from which is created enable.c. |
2 | It implements the builtin "enable" in Bash. | |
3 | ||
9cbcc93b | 4 | Copyright (C) 1987-2008 Free Software Foundation, Inc. |
726f6388 JA |
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 it under | |
9 | the terms of the GNU General Public License as published by the Free | |
bb70624e | 10 | Software Foundation; either version 2, or (at your option) any later |
726f6388 JA |
11 | version. |
12 | ||
13 | Bash is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License along | |
19 | with Bash; see the file COPYING. If not, write to the Free Software | |
bb70624e | 20 | Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. |
726f6388 JA |
21 | |
22 | $PRODUCES enable.c | |
23 | ||
24 | $BUILTIN enable | |
25 | $FUNCTION enable_builtin | |
d3ad40de | 26 | $SHORT_DOC enable [-a] [-dnps] [-f filename] [name ...] |
9cbcc93b CR |
27 | Enables and disables builtin shell commands. Disabling allows you to |
28 | execute a disk command which has the same name as a shell builtin | |
29 | without using a full pathname. | |
30 | ||
31 | Options: | |
32 | -a print a list of builtins showing whether or not each is enabled | |
33 | -n disable each NAME or display a list of disabled builtins | |
34 | -p print the list of builtins in a reusable format | |
35 | -s print only the names of Posix `special' builtins | |
36 | ||
37 | Options controlling dynamic loading: | |
38 | -f Load builtin NAME from shared object FILENAME | |
39 | -d Remove a builtin loaded with -f | |
40 | ||
41 | Without options, each NAME is enabled. | |
42 | ||
43 | To use the `test' found in $PATH instead of the shell builtin | |
44 | version, type `enable -n test'. | |
726f6388 JA |
45 | $END |
46 | ||
ccc6cda3 JA |
47 | #include <config.h> |
48 | ||
49 | #if defined (HAVE_UNISTD_H) | |
cce855bc JA |
50 | # ifdef _MINIX |
51 | # include <sys/types.h> | |
52 | # endif | |
ccc6cda3 JA |
53 | # include <unistd.h> |
54 | #endif | |
55 | ||
56 | #include <stdio.h> | |
57 | #include "../bashansi.h" | |
5e13499c CR |
58 | #include "../bashintl.h" |
59 | ||
726f6388 JA |
60 | #include "../shell.h" |
61 | #include "../builtins.h" | |
ccc6cda3 | 62 | #include "../flags.h" |
726f6388 | 63 | #include "common.h" |
ccc6cda3 JA |
64 | #include "bashgetopt.h" |
65 | ||
bb70624e JA |
66 | #if defined (PROGRAMMABLE_COMPLETION) |
67 | # include "../pcomplete.h" | |
68 | #endif | |
69 | ||
726f6388 JA |
70 | #define ENABLED 1 |
71 | #define DISABLED 2 | |
ccc6cda3 JA |
72 | #define SPECIAL 4 |
73 | ||
74 | #define AFLAG 0x01 | |
75 | #define DFLAG 0x02 | |
76 | #define FFLAG 0x04 | |
77 | #define NFLAG 0x08 | |
78 | #define PFLAG 0x10 | |
79 | #define SFLAG 0x20 | |
726f6388 | 80 | |
f73dda09 JA |
81 | #if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) |
82 | static int dyn_load_builtin __P((WORD_LIST *, int, char *)); | |
83 | #endif | |
84 | ||
85 | #if defined (HAVE_DLCLOSE) | |
86 | static int dyn_unload_builtin __P((char *)); | |
87 | static void delete_builtin __P((struct builtin *)); | |
88 | static int local_dlclose __P((void *)); | |
89 | #endif | |
90 | ||
91 | static void list_some_builtins __P((int)); | |
92 | static int enable_shell_command __P((char *, int)); | |
726f6388 JA |
93 | |
94 | /* Enable/disable shell commands present in LIST. If list is not specified, | |
95 | then print out a list of shell commands showing which are enabled and | |
96 | which are disabled. */ | |
ccc6cda3 | 97 | int |
726f6388 JA |
98 | enable_builtin (list) |
99 | WORD_LIST *list; | |
100 | { | |
ccc6cda3 JA |
101 | int result, flags; |
102 | int opt, filter; | |
103 | #if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) | |
104 | char *filename; | |
105 | #endif | |
726f6388 | 106 | |
ccc6cda3 JA |
107 | result = EXECUTION_SUCCESS; |
108 | flags = 0; | |
726f6388 | 109 | |
ccc6cda3 JA |
110 | reset_internal_getopt (); |
111 | while ((opt = internal_getopt (list, "adnpsf:")) != -1) | |
726f6388 | 112 | { |
ccc6cda3 | 113 | switch (opt) |
726f6388 | 114 | { |
ccc6cda3 JA |
115 | case 'a': |
116 | flags |= AFLAG; | |
117 | break; | |
118 | case 'n': | |
119 | flags |= NFLAG; | |
120 | break; | |
121 | case 'p': | |
122 | flags |= PFLAG; | |
123 | break; | |
124 | case 's': | |
125 | flags |= SFLAG; | |
126 | break; | |
127 | case 'f': | |
128 | #if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) | |
129 | flags |= FFLAG; | |
130 | filename = list_optarg; | |
131 | break; | |
132 | #else | |
5e13499c | 133 | builtin_error (_("dynamic loading not available")); |
ccc6cda3 JA |
134 | return (EX_USAGE); |
135 | #endif | |
136 | #if defined (HAVE_DLCLOSE) | |
137 | case 'd': | |
138 | flags |= DFLAG; | |
139 | break; | |
140 | #else | |
5e13499c | 141 | builtin_error (_("dynamic loading not available")); |
ccc6cda3 JA |
142 | return (EX_USAGE); |
143 | #endif /* HAVE_DLCLOSE */ | |
144 | default: | |
145 | builtin_usage (); | |
146 | return (EX_USAGE); | |
726f6388 JA |
147 | } |
148 | } | |
149 | ||
ccc6cda3 JA |
150 | list = loptend; |
151 | ||
152 | #if defined (RESTRICTED_SHELL) | |
153 | /* Restricted shells cannot load new builtins. */ | |
154 | if (restricted && (flags & (FFLAG|DFLAG))) | |
726f6388 | 155 | { |
7117c2d2 | 156 | sh_restricted ((char *)NULL); |
ccc6cda3 JA |
157 | return (EXECUTION_FAILURE); |
158 | } | |
159 | #endif | |
726f6388 | 160 | |
ccc6cda3 JA |
161 | if (list == 0 || (flags & PFLAG)) |
162 | { | |
163 | filter = (flags & AFLAG) ? (ENABLED | DISABLED) | |
164 | : (flags & NFLAG) ? DISABLED : ENABLED; | |
165 | ||
166 | if (flags & SFLAG) | |
167 | filter |= SPECIAL; | |
726f6388 JA |
168 | |
169 | list_some_builtins (filter); | |
170 | } | |
ccc6cda3 JA |
171 | #if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) |
172 | else if (flags & FFLAG) | |
173 | { | |
174 | filter = (flags & NFLAG) ? DISABLED : ENABLED; | |
175 | if (flags & SFLAG) | |
28ef6c31 | 176 | filter |= SPECIAL; |
ccc6cda3 JA |
177 | |
178 | result = dyn_load_builtin (list, filter, filename); | |
bb70624e JA |
179 | #if defined (PROGRAMMABLE_COMPLETION) |
180 | set_itemlist_dirty (&it_builtins); | |
181 | #endif | |
ccc6cda3 JA |
182 | } |
183 | #endif | |
184 | #if defined (HAVE_DLCLOSE) | |
185 | else if (flags & DFLAG) | |
186 | { | |
187 | while (list) | |
188 | { | |
189 | opt = dyn_unload_builtin (list->word->word); | |
190 | if (opt == EXECUTION_FAILURE) | |
191 | result = EXECUTION_FAILURE; | |
192 | list = list->next; | |
193 | } | |
bb70624e JA |
194 | #if defined (PROGRAMMABLE_COMPLETION) |
195 | set_itemlist_dirty (&it_builtins); | |
196 | #endif | |
ccc6cda3 JA |
197 | } |
198 | #endif | |
726f6388 JA |
199 | else |
200 | { | |
201 | while (list) | |
202 | { | |
ccc6cda3 | 203 | opt = enable_shell_command (list->word->word, flags & NFLAG); |
726f6388 | 204 | |
ccc6cda3 | 205 | if (opt == EXECUTION_FAILURE) |
726f6388 | 206 | { |
5e13499c | 207 | sh_notbuiltin (list->word->word); |
ccc6cda3 | 208 | result = EXECUTION_FAILURE; |
726f6388 JA |
209 | } |
210 | list = list->next; | |
211 | } | |
212 | } | |
ccc6cda3 | 213 | return (result); |
726f6388 JA |
214 | } |
215 | ||
216 | /* List some builtins. | |
217 | FILTER is a mask with two slots: ENABLED and DISABLED. */ | |
218 | static void | |
219 | list_some_builtins (filter) | |
220 | int filter; | |
221 | { | |
222 | register int i; | |
223 | ||
224 | for (i = 0; i < num_shell_builtins; i++) | |
225 | { | |
ccc6cda3 | 226 | if (shell_builtins[i].function == 0 || (shell_builtins[i].flags & BUILTIN_DELETED)) |
726f6388 JA |
227 | continue; |
228 | ||
ccc6cda3 JA |
229 | if ((filter & SPECIAL) && |
230 | (shell_builtins[i].flags & SPECIAL_BUILTIN) == 0) | |
231 | continue; | |
232 | ||
233 | if ((filter & ENABLED) && (shell_builtins[i].flags & BUILTIN_ENABLED)) | |
234 | printf ("enable %s\n", shell_builtins[i].name); | |
726f6388 JA |
235 | else if ((filter & DISABLED) && |
236 | ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0)) | |
ccc6cda3 | 237 | printf ("enable -n %s\n", shell_builtins[i].name); |
726f6388 JA |
238 | } |
239 | } | |
240 | ||
241 | /* Enable the shell command NAME. If DISABLE_P is non-zero, then | |
242 | disable NAME instead. */ | |
243 | static int | |
244 | enable_shell_command (name, disable_p) | |
245 | char *name; | |
246 | int disable_p; | |
247 | { | |
ccc6cda3 | 248 | struct builtin *b; |
726f6388 | 249 | |
ccc6cda3 JA |
250 | b = builtin_address_internal (name, 1); |
251 | if (b == 0) | |
252 | return (EXECUTION_FAILURE); | |
253 | ||
254 | if (disable_p) | |
255 | b->flags &= ~BUILTIN_ENABLED; | |
7117c2d2 JA |
256 | #if defined (RESTRICTED_SHELL) |
257 | else if (restricted && ((b->flags & BUILTIN_ENABLED) == 0)) | |
258 | { | |
259 | sh_restricted ((char *)NULL); | |
260 | return (EXECUTION_FAILURE); | |
261 | } | |
262 | #endif | |
ccc6cda3 JA |
263 | else |
264 | b->flags |= BUILTIN_ENABLED; | |
265 | ||
bb70624e JA |
266 | #if defined (PROGRAMMABLE_COMPLETION) |
267 | set_itemlist_dirty (&it_enabled); | |
268 | set_itemlist_dirty (&it_disabled); | |
269 | #endif | |
270 | ||
ccc6cda3 JA |
271 | return (EXECUTION_SUCCESS); |
272 | } | |
273 | ||
274 | #if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM) | |
d166f048 JA |
275 | |
276 | #if defined (HAVE_DLFCN_H) | |
277 | # include <dlfcn.h> | |
278 | #endif | |
ccc6cda3 JA |
279 | |
280 | static int | |
281 | dyn_load_builtin (list, flags, filename) | |
282 | WORD_LIST *list; | |
283 | int flags; | |
284 | char *filename; | |
285 | { | |
286 | WORD_LIST *l; | |
287 | void *handle; | |
288 | ||
289 | int total, size, new, replaced; | |
290 | char *struct_name, *name; | |
291 | struct builtin **new_builtins, *b, *new_shell_builtins, *old_builtin; | |
292 | ||
293 | if (list == 0) | |
294 | return (EXECUTION_FAILURE); | |
295 | ||
296 | #ifndef RTLD_LAZY | |
297 | #define RTLD_LAZY 1 | |
298 | #endif | |
299 | ||
300 | #if defined (_AIX) | |
301 | handle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL); | |
302 | #else | |
303 | handle = dlopen (filename, RTLD_LAZY); | |
304 | #endif /* !_AIX */ | |
305 | ||
306 | if (handle == 0) | |
726f6388 | 307 | { |
5e13499c | 308 | builtin_error (_("cannot open shared object %s: %s"), filename, dlerror ()); |
ccc6cda3 JA |
309 | return (EXECUTION_FAILURE); |
310 | } | |
726f6388 | 311 | |
ccc6cda3 JA |
312 | for (new = 0, l = list; l; l = l->next, new++) |
313 | ; | |
314 | new_builtins = (struct builtin **)xmalloc (new * sizeof (struct builtin *)); | |
726f6388 | 315 | |
ccc6cda3 JA |
316 | /* For each new builtin in the shared object, find it and its describing |
317 | structure. If this is overwriting an existing builtin, do so, otherwise | |
318 | save the loaded struct for creating the new list of builtins. */ | |
319 | for (replaced = new = 0; list; list = list->next) | |
320 | { | |
321 | name = list->word->word; | |
322 | ||
323 | size = strlen (name); | |
f73dda09 | 324 | struct_name = (char *)xmalloc (size + 8); |
ccc6cda3 JA |
325 | strcpy (struct_name, name); |
326 | strcpy (struct_name + size, "_struct"); | |
327 | ||
328 | b = (struct builtin *)dlsym (handle, struct_name); | |
329 | if (b == 0) | |
330 | { | |
5e13499c CR |
331 | builtin_error (_("cannot find %s in shared object %s: %s"), |
332 | struct_name, filename, dlerror ()); | |
ccc6cda3 JA |
333 | free (struct_name); |
334 | continue; | |
726f6388 | 335 | } |
ccc6cda3 JA |
336 | |
337 | free (struct_name); | |
338 | ||
339 | b->flags &= ~STATIC_BUILTIN; | |
340 | if (flags & SPECIAL) | |
341 | b->flags |= SPECIAL_BUILTIN; | |
342 | b->handle = handle; | |
343 | ||
344 | if (old_builtin = builtin_address_internal (name, 1)) | |
28ef6c31 JA |
345 | { |
346 | replaced++; | |
ccc6cda3 | 347 | FASTCOPY ((char *)b, (char *)old_builtin, sizeof (struct builtin)); |
28ef6c31 | 348 | } |
ccc6cda3 JA |
349 | else |
350 | new_builtins[new++] = b; | |
351 | } | |
352 | ||
353 | if (replaced == 0 && new == 0) | |
354 | { | |
355 | free (new_builtins); | |
356 | dlclose (handle); | |
357 | return (EXECUTION_FAILURE); | |
726f6388 | 358 | } |
ccc6cda3 JA |
359 | |
360 | if (new) | |
361 | { | |
362 | total = num_shell_builtins + new; | |
363 | size = (total + 1) * sizeof (struct builtin); | |
364 | ||
365 | new_shell_builtins = (struct builtin *)xmalloc (size); | |
366 | FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins, | |
367 | num_shell_builtins * sizeof (struct builtin)); | |
368 | for (replaced = 0; replaced < new; replaced++) | |
369 | FASTCOPY ((char *)new_builtins[replaced], | |
370 | (char *)&new_shell_builtins[num_shell_builtins + replaced], | |
371 | sizeof (struct builtin)); | |
372 | ||
373 | new_shell_builtins[total].name = (char *)0; | |
f73dda09 | 374 | new_shell_builtins[total].function = (sh_builtin_func_t *)0; |
ccc6cda3 JA |
375 | new_shell_builtins[total].flags = 0; |
376 | ||
377 | if (shell_builtins != static_shell_builtins) | |
378 | free (shell_builtins); | |
379 | ||
380 | shell_builtins = new_shell_builtins; | |
381 | num_shell_builtins = total; | |
382 | initialize_shell_builtins (); | |
383 | } | |
384 | ||
385 | free (new_builtins); | |
386 | return (EXECUTION_SUCCESS); | |
387 | } | |
388 | #endif | |
389 | ||
390 | #if defined (HAVE_DLCLOSE) | |
391 | static void | |
392 | delete_builtin (b) | |
393 | struct builtin *b; | |
394 | { | |
395 | int ind, size; | |
396 | struct builtin *new_shell_builtins; | |
397 | ||
398 | /* XXX - funky pointer arithmetic - XXX */ | |
d166f048 JA |
399 | #ifdef __STDC__ |
400 | ind = b - shell_builtins; | |
401 | #else | |
ccc6cda3 | 402 | ind = ((int)b - (int)shell_builtins) / sizeof (struct builtin); |
d166f048 | 403 | #endif |
ccc6cda3 JA |
404 | size = num_shell_builtins * sizeof (struct builtin); |
405 | new_shell_builtins = (struct builtin *)xmalloc (size); | |
406 | ||
407 | /* Copy shell_builtins[0]...shell_builtins[ind - 1] to new_shell_builtins */ | |
408 | if (ind) | |
409 | FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins, | |
410 | ind * sizeof (struct builtin)); | |
411 | /* Copy shell_builtins[ind+1]...shell_builtins[num_shell_builtins to | |
412 | new_shell_builtins, starting at ind. */ | |
413 | FASTCOPY ((char *)(&shell_builtins[ind+1]), | |
414 | (char *)(&new_shell_builtins[ind]), | |
415 | (num_shell_builtins - ind) * sizeof (struct builtin)); | |
416 | ||
417 | if (shell_builtins != static_shell_builtins) | |
418 | free (shell_builtins); | |
419 | ||
420 | /* The result is still sorted. */ | |
421 | num_shell_builtins--; | |
422 | shell_builtins = new_shell_builtins; | |
423 | } | |
424 | ||
b72432fd JA |
425 | /* Tenon's MachTen has a dlclose that doesn't return a value, so we |
426 | finesse it with a local wrapper. */ | |
427 | static int | |
428 | local_dlclose (handle) | |
429 | void *handle; | |
430 | { | |
431 | #if !defined (__MACHTEN__) | |
432 | return (dlclose (handle)); | |
433 | #else /* __MACHTEN__ */ | |
434 | dlclose (handle); | |
435 | return ((dlerror () != NULL) ? -1 : 0); | |
436 | #endif /* __MACHTEN__ */ | |
437 | } | |
438 | ||
ccc6cda3 JA |
439 | static int |
440 | dyn_unload_builtin (name) | |
441 | char *name; | |
442 | { | |
443 | struct builtin *b; | |
444 | void *handle; | |
445 | int ref, i; | |
446 | ||
447 | b = builtin_address_internal (name, 1); | |
448 | if (b == 0) | |
449 | { | |
5e13499c | 450 | sh_notbuiltin (name); |
ccc6cda3 JA |
451 | return (EXECUTION_FAILURE); |
452 | } | |
453 | if (b->flags & STATIC_BUILTIN) | |
454 | { | |
5e13499c | 455 | builtin_error (_("%s: not dynamically loaded"), name); |
ccc6cda3 JA |
456 | return (EXECUTION_FAILURE); |
457 | } | |
458 | ||
459 | handle = (void *)b->handle; | |
460 | for (ref = i = 0; i < num_shell_builtins; i++) | |
461 | { | |
462 | if (shell_builtins[i].handle == b->handle) | |
463 | ref++; | |
464 | } | |
465 | ||
466 | /* Don't remove the shared object unless the reference count of builtins | |
467 | using it drops to zero. */ | |
b72432fd | 468 | if (ref == 1 && local_dlclose (handle) != 0) |
ccc6cda3 | 469 | { |
5e13499c | 470 | builtin_error (_("%s: cannot delete: %s"), name, dlerror ()); |
ccc6cda3 JA |
471 | return (EXECUTION_FAILURE); |
472 | } | |
473 | ||
474 | /* Now remove this entry from the builtin table and reinitialize. */ | |
475 | delete_builtin (b); | |
476 | ||
477 | return (EXECUTION_SUCCESS); | |
726f6388 | 478 | } |
ccc6cda3 | 479 | #endif |