]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/enable.def
commit bash-20080207 snapshot
[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
9cbcc93b 4Copyright (C) 1987-2008 Free Software Foundation, Inc.
726f6388
JA
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
8Bash is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
bb70624e 10Software Foundation; either version 2, or (at your option) any later
726f6388
JA
11version.
12
13Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License along
19with Bash; see the file COPYING. If not, write to the Free Software
bb70624e 20Foundation, 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
27Enables and disables builtin shell commands. Disabling allows you to
28execute a disk command which has the same name as a shell builtin
29without using a full pathname.
30
31Options:
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
37Options controlling dynamic loading:
38 -f Load builtin NAME from shared object FILENAME
39 -d Remove a builtin loaded with -f
40
41Without options, each NAME is enabled.
42
43To use the `test' found in $PATH instead of the shell builtin
44version, 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)
82static int dyn_load_builtin __P((WORD_LIST *, int, char *));
83#endif
84
85#if defined (HAVE_DLCLOSE)
86static int dyn_unload_builtin __P((char *));
87static void delete_builtin __P((struct builtin *));
88static int local_dlclose __P((void *));
89#endif
90
91static void list_some_builtins __P((int));
92static 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 97int
726f6388
JA
98enable_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. */
218static void
219list_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. */
243static int
244enable_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
280static int
281dyn_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)
391static void
392delete_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. */
427static int
428local_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
439static int
440dyn_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