blob: 40cbb440accf9b3c12788e11b3cd88b5234052f9 [file] [log] [blame]
Jari Aalto726f6381996-08-26 18:22:31 +00001This file is enable.def, from which is created enable.c.
2It implements the builtin "enable" in Bash.
3
Jari Aalto31859422009-01-12 13:36:28 +00004Copyright (C) 1987-2009 Free Software Foundation, Inc.
Jari Aalto726f6381996-08-26 18:22:31 +00005
6This file is part of GNU Bash, the Bourne Again SHell.
7
Jari Aalto31859422009-01-12 13:36:28 +00008Bash 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.
Jari Aalto726f6381996-08-26 18:22:31 +000012
Jari Aalto31859422009-01-12 13:36:28 +000013Bash 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.
Jari Aalto726f6381996-08-26 18:22:31 +000017
Jari Aalto31859422009-01-12 13:36:28 +000018You should have received a copy of the GNU General Public License
19along with Bash. If not, see <http://www.gnu.org/licenses/>.
Jari Aalto726f6381996-08-26 18:22:31 +000020
21$PRODUCES enable.c
22
23$BUILTIN enable
24$FUNCTION enable_builtin
Jari Aalto31859422009-01-12 13:36:28 +000025$SHORT_DOC enable [-a] [-dnps] [-f filename] [name ...]
26Enable and disable shell builtins.
27
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'.
46
47Exit Status:
48Returns success unless NAME is not a shell builtin or an error occurs.
Jari Aalto726f6381996-08-26 18:22:31 +000049$END
50
Jari Aaltoccc6cda1996-12-23 17:02:34 +000051#include <config.h>
52
53#if defined (HAVE_UNISTD_H)
Jari Aaltocce855b1998-04-17 19:52:44 +000054# ifdef _MINIX
55# include <sys/types.h>
56# endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +000057# include <unistd.h>
58#endif
59
60#include <stdio.h>
61#include "../bashansi.h"
Jari Aaltob80f6442004-07-27 13:29:18 +000062#include "../bashintl.h"
63
Jari Aalto726f6381996-08-26 18:22:31 +000064#include "../shell.h"
65#include "../builtins.h"
Jari Aaltoccc6cda1996-12-23 17:02:34 +000066#include "../flags.h"
Jari Aalto726f6381996-08-26 18:22:31 +000067#include "common.h"
Jari Aaltoccc6cda1996-12-23 17:02:34 +000068#include "bashgetopt.h"
69
Jari Aaltobb706242000-03-17 21:46:59 +000070#if defined (PROGRAMMABLE_COMPLETION)
71# include "../pcomplete.h"
72#endif
73
Jari Aalto726f6381996-08-26 18:22:31 +000074#define ENABLED 1
75#define DISABLED 2
Jari Aaltoccc6cda1996-12-23 17:02:34 +000076#define SPECIAL 4
77
78#define AFLAG 0x01
79#define DFLAG 0x02
80#define FFLAG 0x04
81#define NFLAG 0x08
82#define PFLAG 0x10
83#define SFLAG 0x20
Jari Aalto726f6381996-08-26 18:22:31 +000084
Jari Aaltof73dda02001-11-13 17:56:06 +000085#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
86static int dyn_load_builtin __P((WORD_LIST *, int, char *));
87#endif
88
89#if defined (HAVE_DLCLOSE)
90static int dyn_unload_builtin __P((char *));
91static void delete_builtin __P((struct builtin *));
92static int local_dlclose __P((void *));
93#endif
94
95static void list_some_builtins __P((int));
96static int enable_shell_command __P((char *, int));
Jari Aalto726f6381996-08-26 18:22:31 +000097
98/* Enable/disable shell commands present in LIST. If list is not specified,
99 then print out a list of shell commands showing which are enabled and
100 which are disabled. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000101int
Jari Aalto726f6381996-08-26 18:22:31 +0000102enable_builtin (list)
103 WORD_LIST *list;
104{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000105 int result, flags;
106 int opt, filter;
107#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
108 char *filename;
109#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000110
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000111 result = EXECUTION_SUCCESS;
112 flags = 0;
Jari Aalto726f6381996-08-26 18:22:31 +0000113
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000114 reset_internal_getopt ();
115 while ((opt = internal_getopt (list, "adnpsf:")) != -1)
Jari Aalto726f6381996-08-26 18:22:31 +0000116 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000117 switch (opt)
Jari Aalto726f6381996-08-26 18:22:31 +0000118 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000119 case 'a':
120 flags |= AFLAG;
121 break;
122 case 'n':
123 flags |= NFLAG;
124 break;
125 case 'p':
126 flags |= PFLAG;
127 break;
128 case 's':
129 flags |= SFLAG;
130 break;
131 case 'f':
132#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
133 flags |= FFLAG;
134 filename = list_optarg;
135 break;
136#else
Jari Aaltob80f6442004-07-27 13:29:18 +0000137 builtin_error (_("dynamic loading not available"));
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000138 return (EX_USAGE);
139#endif
140#if defined (HAVE_DLCLOSE)
141 case 'd':
142 flags |= DFLAG;
143 break;
144#else
Jari Aaltob80f6442004-07-27 13:29:18 +0000145 builtin_error (_("dynamic loading not available"));
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000146 return (EX_USAGE);
147#endif /* HAVE_DLCLOSE */
148 default:
149 builtin_usage ();
150 return (EX_USAGE);
Jari Aalto726f6381996-08-26 18:22:31 +0000151 }
152 }
153
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000154 list = loptend;
Jari Aalto726f6381996-08-26 18:22:31 +0000155
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000156#if defined (RESTRICTED_SHELL)
157 /* Restricted shells cannot load new builtins. */
158 if (restricted && (flags & (FFLAG|DFLAG)))
159 {
Jari Aalto7117c2d2002-07-17 14:10:11 +0000160 sh_restricted ((char *)NULL);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000161 return (EXECUTION_FAILURE);
162 }
163#endif
164
165 if (list == 0 || (flags & PFLAG))
166 {
167 filter = (flags & AFLAG) ? (ENABLED | DISABLED)
168 : (flags & NFLAG) ? DISABLED : ENABLED;
169
170 if (flags & SFLAG)
171 filter |= SPECIAL;
Jari Aalto726f6381996-08-26 18:22:31 +0000172
173 list_some_builtins (filter);
174 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000175#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
176 else if (flags & FFLAG)
177 {
178 filter = (flags & NFLAG) ? DISABLED : ENABLED;
179 if (flags & SFLAG)
Jari Aalto28ef6c32001-04-06 19:14:31 +0000180 filter |= SPECIAL;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000181
182 result = dyn_load_builtin (list, filter, filename);
Jari Aaltobb706242000-03-17 21:46:59 +0000183#if defined (PROGRAMMABLE_COMPLETION)
184 set_itemlist_dirty (&it_builtins);
185#endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000186 }
187#endif
188#if defined (HAVE_DLCLOSE)
189 else if (flags & DFLAG)
190 {
191 while (list)
192 {
193 opt = dyn_unload_builtin (list->word->word);
194 if (opt == EXECUTION_FAILURE)
195 result = EXECUTION_FAILURE;
196 list = list->next;
197 }
Jari Aaltobb706242000-03-17 21:46:59 +0000198#if defined (PROGRAMMABLE_COMPLETION)
199 set_itemlist_dirty (&it_builtins);
200#endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000201 }
202#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000203 else
204 {
205 while (list)
206 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000207 opt = enable_shell_command (list->word->word, flags & NFLAG);
Jari Aalto726f6381996-08-26 18:22:31 +0000208
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000209 if (opt == EXECUTION_FAILURE)
Jari Aalto726f6381996-08-26 18:22:31 +0000210 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000211 sh_notbuiltin (list->word->word);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000212 result = EXECUTION_FAILURE;
Jari Aalto726f6381996-08-26 18:22:31 +0000213 }
214 list = list->next;
215 }
216 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000217 return (result);
Jari Aalto726f6381996-08-26 18:22:31 +0000218}
219
220/* List some builtins.
221 FILTER is a mask with two slots: ENABLED and DISABLED. */
222static void
223list_some_builtins (filter)
224 int filter;
225{
226 register int i;
227
228 for (i = 0; i < num_shell_builtins; i++)
229 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000230 if (shell_builtins[i].function == 0 || (shell_builtins[i].flags & BUILTIN_DELETED))
Jari Aalto726f6381996-08-26 18:22:31 +0000231 continue;
232
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000233 if ((filter & SPECIAL) &&
234 (shell_builtins[i].flags & SPECIAL_BUILTIN) == 0)
235 continue;
236
237 if ((filter & ENABLED) && (shell_builtins[i].flags & BUILTIN_ENABLED))
238 printf ("enable %s\n", shell_builtins[i].name);
Jari Aalto726f6381996-08-26 18:22:31 +0000239 else if ((filter & DISABLED) &&
240 ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0))
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000241 printf ("enable -n %s\n", shell_builtins[i].name);
Jari Aalto726f6381996-08-26 18:22:31 +0000242 }
243}
244
245/* Enable the shell command NAME. If DISABLE_P is non-zero, then
246 disable NAME instead. */
247static int
248enable_shell_command (name, disable_p)
249 char *name;
250 int disable_p;
251{
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000252 struct builtin *b;
Jari Aalto726f6381996-08-26 18:22:31 +0000253
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000254 b = builtin_address_internal (name, 1);
255 if (b == 0)
256 return (EXECUTION_FAILURE);
Jari Aalto726f6381996-08-26 18:22:31 +0000257
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000258 if (disable_p)
259 b->flags &= ~BUILTIN_ENABLED;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000260#if defined (RESTRICTED_SHELL)
261 else if (restricted && ((b->flags & BUILTIN_ENABLED) == 0))
262 {
263 sh_restricted ((char *)NULL);
264 return (EXECUTION_FAILURE);
265 }
266#endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000267 else
268 b->flags |= BUILTIN_ENABLED;
Jari Aalto726f6381996-08-26 18:22:31 +0000269
Jari Aaltobb706242000-03-17 21:46:59 +0000270#if defined (PROGRAMMABLE_COMPLETION)
271 set_itemlist_dirty (&it_enabled);
272 set_itemlist_dirty (&it_disabled);
273#endif
274
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000275 return (EXECUTION_SUCCESS);
Jari Aalto726f6381996-08-26 18:22:31 +0000276}
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000277
278#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
Jari Aaltod166f041997-06-05 14:59:13 +0000279
280#if defined (HAVE_DLFCN_H)
281# include <dlfcn.h>
282#endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000283
284static int
285dyn_load_builtin (list, flags, filename)
286 WORD_LIST *list;
287 int flags;
288 char *filename;
289{
290 WORD_LIST *l;
291 void *handle;
292
293 int total, size, new, replaced;
294 char *struct_name, *name;
295 struct builtin **new_builtins, *b, *new_shell_builtins, *old_builtin;
296
297 if (list == 0)
298 return (EXECUTION_FAILURE);
299
300#ifndef RTLD_LAZY
301#define RTLD_LAZY 1
302#endif
303
304#if defined (_AIX)
305 handle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL);
306#else
307 handle = dlopen (filename, RTLD_LAZY);
308#endif /* !_AIX */
309
310 if (handle == 0)
311 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000312 builtin_error (_("cannot open shared object %s: %s"), filename, dlerror ());
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000313 return (EXECUTION_FAILURE);
314 }
315
316 for (new = 0, l = list; l; l = l->next, new++)
317 ;
318 new_builtins = (struct builtin **)xmalloc (new * sizeof (struct builtin *));
319
320 /* For each new builtin in the shared object, find it and its describing
321 structure. If this is overwriting an existing builtin, do so, otherwise
322 save the loaded struct for creating the new list of builtins. */
323 for (replaced = new = 0; list; list = list->next)
324 {
325 name = list->word->word;
326
327 size = strlen (name);
Jari Aaltof73dda02001-11-13 17:56:06 +0000328 struct_name = (char *)xmalloc (size + 8);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000329 strcpy (struct_name, name);
330 strcpy (struct_name + size, "_struct");
331
332 b = (struct builtin *)dlsym (handle, struct_name);
333 if (b == 0)
334 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000335 builtin_error (_("cannot find %s in shared object %s: %s"),
336 struct_name, filename, dlerror ());
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000337 free (struct_name);
338 continue;
339 }
340
341 free (struct_name);
342
343 b->flags &= ~STATIC_BUILTIN;
344 if (flags & SPECIAL)
345 b->flags |= SPECIAL_BUILTIN;
346 b->handle = handle;
347
348 if (old_builtin = builtin_address_internal (name, 1))
Jari Aalto28ef6c32001-04-06 19:14:31 +0000349 {
350 replaced++;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000351 FASTCOPY ((char *)b, (char *)old_builtin, sizeof (struct builtin));
Jari Aalto28ef6c32001-04-06 19:14:31 +0000352 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000353 else
354 new_builtins[new++] = b;
355 }
356
357 if (replaced == 0 && new == 0)
358 {
359 free (new_builtins);
360 dlclose (handle);
361 return (EXECUTION_FAILURE);
362 }
363
364 if (new)
365 {
366 total = num_shell_builtins + new;
367 size = (total + 1) * sizeof (struct builtin);
368
369 new_shell_builtins = (struct builtin *)xmalloc (size);
370 FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins,
371 num_shell_builtins * sizeof (struct builtin));
372 for (replaced = 0; replaced < new; replaced++)
373 FASTCOPY ((char *)new_builtins[replaced],
374 (char *)&new_shell_builtins[num_shell_builtins + replaced],
375 sizeof (struct builtin));
376
377 new_shell_builtins[total].name = (char *)0;
Jari Aaltof73dda02001-11-13 17:56:06 +0000378 new_shell_builtins[total].function = (sh_builtin_func_t *)0;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000379 new_shell_builtins[total].flags = 0;
380
381 if (shell_builtins != static_shell_builtins)
382 free (shell_builtins);
383
384 shell_builtins = new_shell_builtins;
385 num_shell_builtins = total;
386 initialize_shell_builtins ();
387 }
388
389 free (new_builtins);
390 return (EXECUTION_SUCCESS);
391}
392#endif
393
394#if defined (HAVE_DLCLOSE)
395static void
396delete_builtin (b)
397 struct builtin *b;
398{
399 int ind, size;
400 struct builtin *new_shell_builtins;
401
402 /* XXX - funky pointer arithmetic - XXX */
Jari Aaltod166f041997-06-05 14:59:13 +0000403#ifdef __STDC__
404 ind = b - shell_builtins;
405#else
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000406 ind = ((int)b - (int)shell_builtins) / sizeof (struct builtin);
Jari Aaltod166f041997-06-05 14:59:13 +0000407#endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000408 size = num_shell_builtins * sizeof (struct builtin);
409 new_shell_builtins = (struct builtin *)xmalloc (size);
410
411 /* Copy shell_builtins[0]...shell_builtins[ind - 1] to new_shell_builtins */
412 if (ind)
413 FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins,
414 ind * sizeof (struct builtin));
415 /* Copy shell_builtins[ind+1]...shell_builtins[num_shell_builtins to
416 new_shell_builtins, starting at ind. */
417 FASTCOPY ((char *)(&shell_builtins[ind+1]),
418 (char *)(&new_shell_builtins[ind]),
419 (num_shell_builtins - ind) * sizeof (struct builtin));
420
421 if (shell_builtins != static_shell_builtins)
422 free (shell_builtins);
423
424 /* The result is still sorted. */
425 num_shell_builtins--;
426 shell_builtins = new_shell_builtins;
427}
428
Jari Aaltob72432f1999-02-19 17:11:39 +0000429/* Tenon's MachTen has a dlclose that doesn't return a value, so we
430 finesse it with a local wrapper. */
431static int
432local_dlclose (handle)
433 void *handle;
434{
435#if !defined (__MACHTEN__)
436 return (dlclose (handle));
437#else /* __MACHTEN__ */
438 dlclose (handle);
439 return ((dlerror () != NULL) ? -1 : 0);
440#endif /* __MACHTEN__ */
441}
442
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000443static int
444dyn_unload_builtin (name)
445 char *name;
446{
447 struct builtin *b;
448 void *handle;
449 int ref, i;
450
451 b = builtin_address_internal (name, 1);
452 if (b == 0)
453 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000454 sh_notbuiltin (name);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000455 return (EXECUTION_FAILURE);
456 }
457 if (b->flags & STATIC_BUILTIN)
458 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000459 builtin_error (_("%s: not dynamically loaded"), name);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000460 return (EXECUTION_FAILURE);
461 }
462
463 handle = (void *)b->handle;
464 for (ref = i = 0; i < num_shell_builtins; i++)
465 {
466 if (shell_builtins[i].handle == b->handle)
467 ref++;
468 }
469
470 /* Don't remove the shared object unless the reference count of builtins
471 using it drops to zero. */
Jari Aaltob72432f1999-02-19 17:11:39 +0000472 if (ref == 1 && local_dlclose (handle) != 0)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000473 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000474 builtin_error (_("%s: cannot delete: %s"), name, dlerror ());
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000475 return (EXECUTION_FAILURE);
476 }
477
478 /* Now remove this entry from the builtin table and reinitialize. */
479 delete_builtin (b);
480
481 return (EXECUTION_SUCCESS);
482}
483#endif