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