37c4f2b9ab72c66bd68141e76d15650236fef94a
[platform/upstream/bash.git] / builtins / enable.def
1 This file is enable.def, from which is created enable.c.
2 It implements the builtin "enable" in Bash.
3
4 Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
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
10 Software Foundation; either version 1, or (at your option) any later
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
20 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 $PRODUCES enable.c
23
24 $BUILTIN enable
25 $FUNCTION enable_builtin
26 $SHORT_DOC enable [-pnds] [-a] [-f filename] [name ...]
27 Enable and disable builtin shell commands.  This allows
28 you to use a disk command which has the same name as a shell
29 builtin.  If -n is used, the NAMEs become disabled; otherwise
30 NAMEs are enabled.  For example, to use the `test' found on your
31 path instead of the shell builtin version, type `enable -n test'.
32 On systems supporting dynamic loading, the -f option may be used
33 to load new builtins from the shared object FILENAME.  The -d
34 option will delete a builtin previously loaded with -f.  If no
35 non-option names are given, or the -p option is supplied, a list
36 of builtins is printed.  The -a option means to print every builtin
37 with an indication of whether or not it is enabled.  The -s option
38 restricts the output to the Posix.2 `special' builtins.  The -n
39 option displays a list of all disabled builtins.
40 $END
41
42 #include <config.h>
43
44 #if defined (HAVE_UNISTD_H)
45 #  include <unistd.h>
46 #endif
47
48 #include <stdio.h>
49 #include "../bashansi.h"
50 #include "../shell.h"
51 #include "../builtins.h"
52 #include "../flags.h"
53 #include "common.h"
54 #include "bashgetopt.h"
55
56 #if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
57 static int dyn_load_builtin ();
58 #endif
59
60 #if defined (HAVE_DLCLOSE)
61 static int dyn_unload_builtin ();
62 #endif
63
64 #define ENABLED  1
65 #define DISABLED 2
66 #define SPECIAL  4
67
68 #define AFLAG   0x01
69 #define DFLAG   0x02
70 #define FFLAG   0x04
71 #define NFLAG   0x08
72 #define PFLAG   0x10
73 #define SFLAG   0x20
74
75 static int enable_shell_command ();
76 static void list_some_builtins ();
77
78 /* Enable/disable shell commands present in LIST.  If list is not specified,
79    then print out a list of shell commands showing which are enabled and
80    which are disabled. */
81 int
82 enable_builtin (list)
83      WORD_LIST *list;
84 {
85   int result, flags;
86   int opt, filter;
87 #if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
88   char *filename;
89 #endif
90
91   result = EXECUTION_SUCCESS;
92   flags = 0;
93
94   reset_internal_getopt ();
95   while ((opt = internal_getopt (list, "adnpsf:")) != -1)
96     {
97       switch (opt)
98         {
99         case 'a':
100           flags |= AFLAG;
101           break;
102         case 'n':
103           flags |= NFLAG;
104           break;
105         case 'p':
106           flags |= PFLAG;
107           break;
108         case 's':
109           flags |= SFLAG;
110           break;
111         case 'f':
112 #if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
113           flags |= FFLAG;
114           filename = list_optarg;
115           break;
116 #else
117           builtin_error ("dynamic loading not available");
118           return (EX_USAGE);
119 #endif
120 #if defined (HAVE_DLCLOSE)
121         case 'd':
122           flags |= DFLAG;
123           break;
124 #else
125           builtin_error ("dynamic loading not available");
126           return (EX_USAGE);
127 #endif /* HAVE_DLCLOSE */
128         default:
129           builtin_usage ();
130           return (EX_USAGE);
131         }
132     }
133
134   list = loptend;
135
136 #if defined (RESTRICTED_SHELL)
137   /* Restricted shells cannot load new builtins. */
138   if (restricted && (flags & (FFLAG|DFLAG)))
139     {
140       builtin_error ("restricted");
141       return (EXECUTION_FAILURE);
142     }
143 #endif
144
145   if (list == 0 || (flags & PFLAG))
146     {
147       filter = (flags & AFLAG) ? (ENABLED | DISABLED)
148                                : (flags & NFLAG) ? DISABLED : ENABLED;
149
150       if (flags & SFLAG)
151         filter |= SPECIAL;
152
153       list_some_builtins (filter);
154     }
155 #if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
156   else if (flags & FFLAG)
157     {
158       filter = (flags & NFLAG) ? DISABLED : ENABLED;
159       if (flags & SFLAG)
160         filter |= SPECIAL;
161
162       result = dyn_load_builtin (list, filter, filename);
163     }
164 #endif
165 #if defined (HAVE_DLCLOSE)
166   else if (flags & DFLAG)
167     {
168       while (list)
169         {
170           opt = dyn_unload_builtin (list->word->word);
171           if (opt == EXECUTION_FAILURE)
172             result = EXECUTION_FAILURE;
173           list = list->next;
174         }
175     }
176 #endif
177   else
178     {
179       while (list)
180         {
181           opt = enable_shell_command (list->word->word, flags & NFLAG);
182
183           if (opt == EXECUTION_FAILURE)
184             {
185               builtin_error ("%s: not a shell builtin", list->word->word);
186               result = EXECUTION_FAILURE;
187             }
188           list = list->next;
189         }
190     }
191   return (result);
192 }
193
194 /* List some builtins.
195    FILTER is a mask with two slots: ENABLED and DISABLED. */
196 static void
197 list_some_builtins (filter)
198      int filter;
199 {
200   register int i;
201
202   for (i = 0; i < num_shell_builtins; i++)
203     {
204       if (shell_builtins[i].function == 0 || (shell_builtins[i].flags & BUILTIN_DELETED))
205         continue;
206
207       if ((filter & SPECIAL) &&
208           (shell_builtins[i].flags & SPECIAL_BUILTIN) == 0)
209         continue;
210
211       if ((filter & ENABLED) && (shell_builtins[i].flags & BUILTIN_ENABLED))
212         printf ("enable %s\n", shell_builtins[i].name);
213       else if ((filter & DISABLED) &&
214                ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0))
215         printf ("enable -n %s\n", shell_builtins[i].name);
216     }
217 }
218
219 /* Enable the shell command NAME.  If DISABLE_P is non-zero, then
220    disable NAME instead. */
221 static int
222 enable_shell_command (name, disable_p)
223      char *name;
224      int disable_p;
225 {
226   struct builtin *b;
227
228   b = builtin_address_internal (name, 1);
229   if (b == 0)
230     return (EXECUTION_FAILURE);
231
232   if (disable_p)
233     b->flags &= ~BUILTIN_ENABLED;
234   else
235     b->flags |= BUILTIN_ENABLED;
236
237   return (EXECUTION_SUCCESS);
238 }
239
240 #if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
241 #include <dlfcn.h>
242
243 static int
244 dyn_load_builtin (list, flags, filename)
245      WORD_LIST *list;
246      int flags;
247      char *filename;
248 {
249   WORD_LIST *l;
250   void *handle;
251   
252   int total, size, new, replaced;
253   char *struct_name, *name;
254   struct builtin **new_builtins, *b, *new_shell_builtins, *old_builtin;
255
256   if (list == 0)
257     return (EXECUTION_FAILURE);
258
259 #ifndef RTLD_LAZY
260 #define RTLD_LAZY 1
261 #endif
262
263 #if defined (_AIX)
264   handle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL);
265 #else
266   handle = dlopen (filename, RTLD_LAZY);
267 #endif /* !_AIX */
268
269   if (handle == 0)
270     {
271       builtin_error ("cannot open shared object %s: %s", filename, dlerror ());
272       return (EXECUTION_FAILURE);
273     }
274
275   for (new = 0, l = list; l; l = l->next, new++)
276     ;
277   new_builtins = (struct builtin **)xmalloc (new * sizeof (struct builtin *));
278
279   /* For each new builtin in the shared object, find it and its describing
280      structure.  If this is overwriting an existing builtin, do so, otherwise
281      save the loaded struct for creating the new list of builtins. */
282   for (replaced = new = 0; list; list = list->next)
283     {
284       name = list->word->word;
285
286       size = strlen (name);
287       struct_name = xmalloc (size + 8);
288       strcpy (struct_name, name);
289       strcpy (struct_name + size, "_struct");
290
291       b = (struct builtin *)dlsym (handle, struct_name);
292       if (b == 0)
293         {
294           builtin_error ("cannot find %s in shared object %s: %s", struct_name,
295                           filename, dlerror ());
296           free (struct_name);
297           continue;
298         }
299
300       free (struct_name);
301
302       b->flags &= ~STATIC_BUILTIN;
303       if (flags & SPECIAL)
304         b->flags |= SPECIAL_BUILTIN;
305       b->handle = handle;
306
307       if (old_builtin = builtin_address_internal (name, 1))
308         {
309           replaced++;
310           FASTCOPY ((char *)b, (char *)old_builtin, sizeof (struct builtin));
311         }
312       else
313           new_builtins[new++] = b;
314     }
315
316   if (replaced == 0 && new == 0)
317     {
318       free (new_builtins);
319       dlclose (handle);
320       return (EXECUTION_FAILURE);
321     }
322
323   if (new)
324     {
325       total = num_shell_builtins + new;
326       size = (total + 1) * sizeof (struct builtin);
327
328       new_shell_builtins = (struct builtin *)xmalloc (size);
329       FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins,
330                 num_shell_builtins * sizeof (struct builtin));
331       for (replaced = 0; replaced < new; replaced++)
332         FASTCOPY ((char *)new_builtins[replaced],
333                   (char *)&new_shell_builtins[num_shell_builtins + replaced],
334                   sizeof (struct builtin));
335
336       new_shell_builtins[total].name = (char *)0;
337       new_shell_builtins[total].function = (Function *)0;
338       new_shell_builtins[total].flags = 0;
339
340       if (shell_builtins != static_shell_builtins)
341         free (shell_builtins);
342
343       shell_builtins = new_shell_builtins;
344       num_shell_builtins = total;
345       initialize_shell_builtins ();
346     }
347
348   free (new_builtins);
349   return (EXECUTION_SUCCESS);
350 }
351 #endif
352
353 #if defined (HAVE_DLCLOSE)
354 static void
355 delete_builtin (b)
356      struct builtin *b;
357 {
358   int ind, size;
359   struct builtin *new_shell_builtins;
360
361   /* XXX - funky pointer arithmetic - XXX */
362   ind = ((int)b - (int)shell_builtins) / sizeof (struct builtin);
363   size = num_shell_builtins * sizeof (struct builtin);
364   new_shell_builtins = (struct builtin *)xmalloc (size);
365
366   /* Copy shell_builtins[0]...shell_builtins[ind - 1] to new_shell_builtins */
367   if (ind)
368     FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins,
369               ind * sizeof (struct builtin));
370   /* Copy shell_builtins[ind+1]...shell_builtins[num_shell_builtins to
371      new_shell_builtins, starting at ind. */
372   FASTCOPY ((char *)(&shell_builtins[ind+1]),
373             (char *)(&new_shell_builtins[ind]),
374             (num_shell_builtins - ind) * sizeof (struct builtin));
375
376   if (shell_builtins != static_shell_builtins)
377     free (shell_builtins);
378
379   /* The result is still sorted. */
380   num_shell_builtins--;
381   shell_builtins = new_shell_builtins;
382 }
383
384 static int
385 dyn_unload_builtin (name)
386      char *name;
387 {
388   struct builtin *b;
389   void *handle;
390   int ref, i;
391
392   b = builtin_address_internal (name, 1);
393   if (b == 0)
394     {
395       builtin_error ("%s: not a shell builtin", name);
396       return (EXECUTION_FAILURE);
397     }
398   if (b->flags & STATIC_BUILTIN)
399     {
400       builtin_error ("%s: not dynamically loaded", name);
401       return (EXECUTION_FAILURE);
402     }
403
404   handle = (void *)b->handle;
405   for (ref = i = 0; i < num_shell_builtins; i++)
406     {
407       if (shell_builtins[i].handle == b->handle)
408         ref++;
409     }
410
411   /* Don't remove the shared object unless the reference count of builtins
412      using it drops to zero. */
413   if (ref == 1 && dlclose (handle) != 0)
414     {
415       builtin_error ("cannot delete %s: %s", name, dlerror ());
416       return (EXECUTION_FAILURE);
417     }
418
419   /* Now remove this entry from the builtin table and reinitialize. */
420   delete_builtin (b);
421
422   return (EXECUTION_SUCCESS);
423 }
424 #endif