blob: 8e8d0f3ca088db92ec5cb9c4cf8843159b6e18d2 [file] [log] [blame]
Dan Pasanenc6e37862014-10-02 14:08:59 -05001/* enable.c, created from enable.def. */
2#line 22 "./enable.def"
3
4#line 50 "./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