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