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