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