Blame extensions.c

Packit bf408e
/* extensions.c - core analysis suite
Packit bf408e
 *
Packit bf408e
 * Copyright (C) 2001, 2002 Mission Critical Linux, Inc.
Packit bf408e
 * Copyright (C) 2002-2013, 2018 David Anderson
Packit bf408e
 * Copyright (C) 2002-2013, 2018 Red Hat, Inc. All rights reserved.
Packit bf408e
 *
Packit bf408e
 * This program is free software; you can redistribute it and/or modify
Packit bf408e
 * it under the terms of the GNU General Public License as published by
Packit bf408e
 * the Free Software Foundation; either version 2 of the License, or
Packit bf408e
 * (at your option) any later version.
Packit bf408e
 *
Packit bf408e
 * This program is distributed in the hope that it will be useful,
Packit bf408e
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit bf408e
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit bf408e
 * GNU General Public License for more details.
Packit bf408e
 */
Packit bf408e
Packit bf408e
#include "defs.h"
Packit bf408e
#include <dlfcn.h>
Packit bf408e
Packit bf408e
static int in_extensions_library(char *, char *);
Packit bf408e
static char *get_extensions_directory(char *);
Packit Service 2d41f0
static void show_all_extensions(void);
Packit Service 2d41f0
static void show_extensions(char *);
Packit bf408e
Packit Service 2d41f0
#define DUMP_EXTENSIONS        (0)
Packit Service 2d41f0
#define LOAD_EXTENSION         (1)
Packit Service 2d41f0
#define UNLOAD_EXTENSION       (2)
Packit Service 2d41f0
#define SHOW_ALL_EXTENSIONS    (4)
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Load, unload, or list the extension libaries.
Packit bf408e
 */
Packit bf408e
void
Packit bf408e
cmd_extend(void)
Packit bf408e
{
Packit bf408e
        int c;
Packit bf408e
	int flag;
Packit bf408e
Packit bf408e
	flag = DUMP_EXTENSIONS;
Packit bf408e
Packit Service 2d41f0
        while ((c = getopt(argcnt, args, "lus")) != EOF) {
Packit bf408e
                switch(c)
Packit bf408e
                {
Packit Service 2d41f0
		case 's':
Packit Service 2d41f0
			if (flag & UNLOAD_EXTENSION) {
Packit Service 2d41f0
				error(INFO,
Packit Service 2d41f0
					"-s and -u are mutually exclusive\n");
Packit Service 2d41f0
				argerrs++;
Packit Service 2d41f0
			}else if (flag & LOAD_EXTENSION) {
Packit Service 2d41f0
				error(INFO,
Packit Service 2d41f0
					"-s and -l are mutually exclusive\n");
Packit Service 2d41f0
				argerrs++;
Packit Service 2d41f0
			} else
Packit Service 2d41f0
				flag |= SHOW_ALL_EXTENSIONS;
Packit Service 2d41f0
			break;
Packit bf408e
		case 'l':
Packit bf408e
			if (flag & UNLOAD_EXTENSION) {
Packit bf408e
				error(INFO, 
Packit bf408e
					"-l and -u are mutually exclusive\n");
Packit bf408e
				argerrs++;
Packit Service 2d41f0
			} else if (flag & SHOW_ALL_EXTENSIONS) {
Packit Service 2d41f0
				error(INFO, 
Packit Service 2d41f0
					"-l and -s are mutually exclusive\n");
Packit Service 2d41f0
				argerrs++;
Packit bf408e
			} else
Packit bf408e
				flag |= LOAD_EXTENSION;
Packit bf408e
			break;
Packit bf408e
Packit bf408e
		case 'u':
Packit bf408e
                        if (flag & LOAD_EXTENSION) {
Packit bf408e
                                error(INFO, 
Packit bf408e
                                        "-u and -l are mutually exclusive\n");
Packit bf408e
                                argerrs++;
Packit Service 2d41f0
			} else if (flag & SHOW_ALL_EXTENSIONS) {
Packit Service 2d41f0
				error(INFO, 
Packit Service 2d41f0
					"-u and -s are mutually exclusive\n");
Packit Service 2d41f0
				argerrs++;
Packit bf408e
                        } else
Packit bf408e
                                flag |= UNLOAD_EXTENSION;
Packit bf408e
			break;
Packit bf408e
Packit bf408e
                default:
Packit bf408e
                        argerrs++;
Packit bf408e
                        break;
Packit bf408e
                }
Packit bf408e
        }
Packit bf408e
Packit bf408e
        if (argerrs)
Packit bf408e
                cmd_usage(pc->curcmd, SYNOPSIS);
Packit bf408e
Packit bf408e
	switch (flag)
Packit bf408e
	{
Packit bf408e
	case DUMP_EXTENSIONS:
Packit bf408e
		if (!args[optind]) {
Packit bf408e
			dump_extension_table(!VERBOSE);
Packit bf408e
			return;
Packit bf408e
		}
Packit bf408e
		/* FALLTHROUGH */
Packit bf408e
Packit bf408e
	case LOAD_EXTENSION:
Packit bf408e
		if (!args[optind]) { 
Packit bf408e
			error(INFO, 
Packit bf408e
		       "-l requires one or more extension library arguments\n");
Packit bf408e
			cmd_usage(pc->curcmd, SYNOPSIS);
Packit bf408e
			break;
Packit bf408e
		}
Packit bf408e
Packit bf408e
        	while (args[optind]) {
Packit bf408e
			load_extension(args[optind]);
Packit bf408e
			optind++;
Packit bf408e
		}
Packit bf408e
		break;
Packit bf408e
Packit bf408e
	case UNLOAD_EXTENSION:
Packit bf408e
		if (!args[optind]) { 
Packit bf408e
			unload_extension(NULL);
Packit bf408e
			break;
Packit bf408e
		}
Packit bf408e
Packit bf408e
        	while (args[optind]) {
Packit bf408e
			unload_extension(args[optind]);
Packit bf408e
			optind++;
Packit bf408e
		}
Packit bf408e
		break;
Packit Service 2d41f0
Packit Service 2d41f0
	case SHOW_ALL_EXTENSIONS:
Packit Service 2d41f0
		show_all_extensions();
Packit Service 2d41f0
		break;
Packit Service 2d41f0
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  List all extension libaries and their commands in either the extend
Packit bf408e
 *  command format or for "help -e" (verbose).
Packit bf408e
 */
Packit bf408e
void 
Packit bf408e
dump_extension_table(int verbose)
Packit bf408e
{
Packit bf408e
	int i;
Packit bf408e
	struct extension_table *ext;
Packit bf408e
	struct command_table_entry *cp;
Packit bf408e
	char buf[BUFSIZE];
Packit bf408e
	int longest, others;
Packit bf408e
Packit bf408e
	if (!extension_table)
Packit bf408e
		return;
Packit bf408e
Packit bf408e
	if (verbose) {
Packit bf408e
       		for (ext = extension_table; ext; ext = ext->next) {
Packit bf408e
                        fprintf(fp, "        filename: %s\n", ext->filename);
Packit bf408e
                        fprintf(fp, "          handle: %lx\n", (ulong)ext->handle);
Packit bf408e
Packit bf408e
Packit bf408e
			fprintf(fp, "           flags: %lx (", ext->flags);
Packit bf408e
			others = 0;
Packit bf408e
			if (ext->flags & REGISTERED)
Packit bf408e
				fprintf(fp, "%sREGISTERED", others++ ?
Packit bf408e
					"|" : "");
Packit bf408e
			fprintf(fp, ")\n");
Packit bf408e
                        fprintf(fp, "            next: %lx\n", (ulong)ext->next);
Packit bf408e
                        fprintf(fp, "            prev: %lx\n", (ulong)ext->prev);
Packit bf408e
Packit bf408e
                        for (i = 0, cp = ext->command_table; cp->name; cp++, i++) {
Packit bf408e
                        	fprintf(fp, "command_table[%d]: %lx\n", i, (ulong)cp); 
Packit bf408e
				fprintf(fp, "                  name: %s\n", cp->name);
Packit bf408e
				fprintf(fp, "                  func: %lx\n", (ulong)cp->func);
Packit bf408e
				fprintf(fp, "             help_data: %lx\n", (ulong)cp->help_data); 
Packit bf408e
				fprintf(fp, "                 flags: %lx (", cp->flags);
Packit bf408e
				others = 0;
Packit bf408e
				if (cp->flags & CLEANUP)
Packit bf408e
					fprintf(fp, "%sCLEANUP", others++ ? "|" : "");
Packit bf408e
				if (cp->flags & REFRESH_TASK_TABLE)
Packit bf408e
					fprintf(fp, "%sREFRESH_TASK_TABLE", others++ ? "|" : "");
Packit bf408e
				if (cp->flags & HIDDEN_COMMAND)
Packit bf408e
					fprintf(fp, "%sHIDDEN_COMMAND", others++ ? "|" : "");
Packit bf408e
				fprintf(fp, ")\n");
Packit bf408e
			}
Packit bf408e
Packit bf408e
			if (ext->next) 
Packit bf408e
				fprintf(fp, "\n");
Packit bf408e
		}
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
Packit bf408e
       /*
Packit bf408e
	*  Print them out in the order they were loaded.
Packit bf408e
	*/
Packit bf408e
	for (longest = 0, ext = extension_table; ext; ext = ext->next) {
Packit bf408e
		if (strlen(ext->filename) > longest)
Packit bf408e
			longest = strlen(ext->filename);
Packit bf408e
	}
Packit bf408e
Packit bf408e
	fprintf(fp, "%s  COMMANDS\n", 
Packit bf408e
		mkstring(buf, longest, LJUST, "SHARED OBJECT"));
Packit bf408e
	longest = MAX(longest, strlen("SHARED OBJECT"));
Packit bf408e
Packit bf408e
	for (ext = extension_table; ext; ext = ext->next) 
Packit bf408e
		if (ext->next == NULL)
Packit bf408e
			break;
Packit bf408e
Packit bf408e
	do {
Packit bf408e
                fprintf(fp, "%s  ", 
Packit bf408e
                        mkstring(buf, longest, LJUST, ext->filename));
Packit bf408e
                for (cp = ext->command_table; cp->name; cp++)
Packit bf408e
                        fprintf(fp, "%s ", cp->name);
Packit bf408e
		fprintf(fp, "\n");
Packit bf408e
	} while ((ext = ext->prev));
Packit bf408e
}
Packit bf408e
Packit Service 2d41f0
static void
Packit Service 2d41f0
show_extensions(char *dir) {
Packit Service 2d41f0
	DIR *dirp;
Packit Service 2d41f0
	struct dirent *dp;
Packit Service 2d41f0
	char filename[BUFSIZE*2];
Packit Service 2d41f0
Packit Service 2d41f0
        dirp = opendir(dir);
Packit Service 2d41f0
	if (!dirp)
Packit Service 2d41f0
		return;
Packit Service 2d41f0
Packit Service 2d41f0
        for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
Packit Service 2d41f0
		sprintf(filename, "%s%s%s", dir,
Packit Service 2d41f0
			LASTCHAR(dir) == '/' ? "" : "/",
Packit Service 2d41f0
			dp->d_name);
Packit Service 2d41f0
Packit Service 2d41f0
		if (!is_shared_object(filename))
Packit Service 2d41f0
			continue;
Packit Service 2d41f0
		fprintf(fp, "%s\n", filename);
Packit Service 2d41f0
	}
Packit Service 2d41f0
Packit Service 2d41f0
	closedir(dirp);
Packit Service 2d41f0
}
Packit Service 2d41f0
Packit Service 2d41f0
static void
Packit Service 2d41f0
show_all_extensions(void)
Packit Service 2d41f0
{
Packit Service 2d41f0
	char *dir;
Packit Service 2d41f0
Packit Service 2d41f0
	show_extensions("./");
Packit Service 2d41f0
Packit Service 2d41f0
	if ((dir = getenv("CRASH_EXTENSIONS")))
Packit Service 2d41f0
		show_extensions(dir);
Packit Service 2d41f0
Packit Service 2d41f0
	if (BITS64())
Packit Service 2d41f0
		show_extensions("/usr/lib64/crash/extensions/");
Packit Service 2d41f0
Packit Service 2d41f0
	show_extensions("/usr/lib/crash/extensions/");
Packit Service 2d41f0
	show_extensions("./extensions/");
Packit Service 2d41f0
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Load an extension library.
Packit bf408e
 */
Packit bf408e
void 
Packit bf408e
load_extension(char *lib)
Packit bf408e
{
Packit bf408e
	struct extension_table *ext, *curext;
Packit bf408e
	char buf[BUFSIZE];
Packit bf408e
	size_t size;
Packit bf408e
	char *env;
Packit bf408e
	int env_len;
Packit bf408e
Packit bf408e
	if ((env = getenv("CRASH_EXTENSIONS")))
Packit bf408e
		env_len = strlen(env)+1;
Packit bf408e
	else
Packit bf408e
		env_len = 0;	
Packit bf408e
Packit bf408e
	size = sizeof(struct extension_table) + strlen(lib) + 
Packit bf408e
		MAX(env_len, strlen("/usr/lib64/crash/extensions/")) + 1;
Packit bf408e
Packit bf408e
	if ((ext = (struct extension_table *)malloc(size)) == NULL) 
Packit bf408e
		error(FATAL, "cannot malloc extension_table space.");
Packit bf408e
Packit bf408e
	BZERO(ext, size);
Packit bf408e
Packit bf408e
	ext->filename = (char *)((ulong)ext + sizeof(struct extension_table));
Packit bf408e
	
Packit bf408e
       /*
Packit bf408e
	*  If the library is not specified by an absolute pathname, dlopen() 
Packit bf408e
        *  does not look in the current directory, so modify the filename.
Packit bf408e
	*  If it's not in the current directory, check the extensions library
Packit bf408e
	*  directory.
Packit bf408e
        */
Packit bf408e
	if ((*lib != '.') && (*lib != '/')) {
Packit bf408e
		if (file_exists(lib, NULL))
Packit bf408e
			sprintf(ext->filename, "./%s", lib);
Packit bf408e
		else if (in_extensions_library(lib, buf))
Packit bf408e
			strcpy(ext->filename, buf);
Packit bf408e
		else {
Packit bf408e
			error(INFO, "%s: %s\n", lib, strerror(ENXIO));
Packit bf408e
			free(ext);
Packit bf408e
			return;
Packit bf408e
		}
Packit bf408e
	} else 
Packit bf408e
		strcpy(ext->filename, lib);
Packit bf408e
Packit bf408e
	if (!is_shared_object(ext->filename)) {
Packit bf408e
		error(INFO, "%s: not an ELF format object file\n",
Packit bf408e
			ext->filename);
Packit bf408e
		free(ext);
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	for (curext = extension_table; curext; curext = curext->next) {
Packit bf408e
		if (same_file(curext->filename, ext->filename)) {
Packit bf408e
			fprintf(fp, "%s: shared object already loaded\n", 
Packit bf408e
				ext->filename);
Packit bf408e
			free(ext);
Packit bf408e
			return;
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
Packit bf408e
       /*
Packit bf408e
        *  register_extension() will be called by the shared object's
Packit bf408e
        *  _init() function before dlopen() returns below.
Packit bf408e
	*/
Packit bf408e
	pc->curext = ext;
Packit bf408e
	ext->handle = dlopen(ext->filename, RTLD_NOW|RTLD_GLOBAL); 
Packit bf408e
Packit bf408e
	if (!ext->handle) {
Packit bf408e
		strcpy(buf, dlerror());
Packit bf408e
		error(INFO, "%s\n", buf);
Packit bf408e
		if (strstr(buf, "undefined symbol: register_extension")) {
Packit bf408e
			error(INFO, "%s may be statically linked: ",
Packit bf408e
				pc->program_name);
Packit bf408e
			fprintf(fp, "recompile without the -static flag\n");
Packit bf408e
		}
Packit bf408e
		free(ext);
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (!(ext->flags & REGISTERED)) {
Packit bf408e
		dlclose(ext->handle);
Packit bf408e
		if (ext->flags & (DUPLICATE_COMMAND_NAME | NO_MINIMAL_COMMANDS))
Packit bf408e
			error(INFO, 
Packit bf408e
		         "%s: shared object unloaded\n", ext->filename);
Packit bf408e
		else
Packit bf408e
			error(INFO, 
Packit bf408e
		         "%s: no commands registered: shared object unloaded\n",
Packit bf408e
				ext->filename);
Packit bf408e
		free(ext);
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	fprintf(fp, "%s: shared object loaded\n", ext->filename);
Packit bf408e
Packit bf408e
	/*
Packit bf408e
	 *  Put new libraries at the head of the list.
Packit bf408e
         */
Packit bf408e
	if (extension_table) {
Packit bf408e
		extension_table->prev = ext;
Packit bf408e
		ext->next = extension_table;
Packit bf408e
	}
Packit bf408e
	extension_table = ext;
Packit bf408e
Packit bf408e
	help_init();
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Check the extensions library directories.
Packit bf408e
 */
Packit bf408e
static int
Packit bf408e
in_extensions_library(char *lib, char *buf)
Packit bf408e
{
Packit bf408e
	char *env;
Packit bf408e
Packit bf408e
	if ((env = getenv("CRASH_EXTENSIONS"))) {
Packit bf408e
		sprintf(buf, "%s%s%s", env,
Packit bf408e
			LASTCHAR(env) == '/' ? "" : "/",
Packit bf408e
			lib);
Packit bf408e
		if (file_exists(buf, NULL))
Packit bf408e
			return TRUE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (BITS64()) {
Packit bf408e
		sprintf(buf, "/usr/lib64/crash/extensions/%s", lib);
Packit bf408e
		if (file_exists(buf, NULL))
Packit bf408e
			return TRUE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
       	sprintf(buf, "/usr/lib/crash/extensions/%s", lib);
Packit bf408e
	if (file_exists(buf, NULL))
Packit bf408e
		return TRUE;
Packit bf408e
 
Packit bf408e
       	sprintf(buf, "./extensions/%s", lib);
Packit bf408e
	if (file_exists(buf, NULL))
Packit bf408e
		return TRUE;
Packit bf408e
Packit bf408e
	return FALSE;
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * Look for an extensions directory using the proper order. 
Packit bf408e
 */
Packit bf408e
static char *
Packit bf408e
get_extensions_directory(char *dirbuf)
Packit bf408e
{
Packit bf408e
	char *env;
Packit bf408e
Packit bf408e
	if ((env = getenv("CRASH_EXTENSIONS"))) {
Packit bf408e
		if (is_directory(env)) {
Packit bf408e
			strcpy(dirbuf, env);
Packit bf408e
			return dirbuf;
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (BITS64()) {
Packit bf408e
		sprintf(dirbuf, "/usr/lib64/crash/extensions");
Packit bf408e
		if (is_directory(dirbuf))
Packit bf408e
			return dirbuf;
Packit bf408e
	}
Packit bf408e
Packit bf408e
       	sprintf(dirbuf, "/usr/lib/crash/extensions");
Packit bf408e
	if (is_directory(dirbuf))
Packit bf408e
		return dirbuf;
Packit bf408e
 
Packit bf408e
       	sprintf(dirbuf, "./extensions");
Packit bf408e
	if (is_directory(dirbuf))
Packit bf408e
		return dirbuf;
Packit bf408e
Packit bf408e
	return NULL;
Packit bf408e
}
Packit bf408e
Packit bf408e
Packit bf408e
void
Packit bf408e
preload_extensions(void)
Packit bf408e
{
Packit bf408e
	DIR *dirp;
Packit bf408e
	struct dirent *dp;
Packit bf408e
	char dirbuf[BUFSIZE];
Packit bf408e
	char filename[BUFSIZE*2];
Packit bf408e
	int found;
Packit bf408e
Packit bf408e
	if (!get_extensions_directory(dirbuf))
Packit bf408e
		return;
Packit bf408e
Packit bf408e
        dirp = opendir(dirbuf);
Packit bf408e
	if (!dirp) {
Packit bf408e
		error(INFO, "%s: %s\n", dirbuf, strerror(errno));
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	pc->curcmd = pc->program_name;
Packit bf408e
Packit bf408e
        for (found = 0, dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
Packit bf408e
		sprintf(filename, "%s%s%s", dirbuf, 
Packit bf408e
			LASTCHAR(dirbuf) == '/' ? "" : "/",
Packit bf408e
			dp->d_name);
Packit bf408e
Packit bf408e
		if (!is_shared_object(filename))
Packit bf408e
			continue;
Packit bf408e
Packit bf408e
		found++;
Packit bf408e
Packit bf408e
		load_extension(dp->d_name);
Packit bf408e
	}
Packit bf408e
Packit bf408e
	closedir(dirp);
Packit bf408e
	
Packit bf408e
	if (found)
Packit bf408e
		fprintf(fp, "\n");
Packit bf408e
	else
Packit bf408e
		error(NOTE, 
Packit bf408e
		    "%s: no extension modules found in directory\n\n",
Packit bf408e
			dirbuf);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Unload all, or as specified, extension libraries.
Packit bf408e
 */
Packit bf408e
void 
Packit bf408e
unload_extension(char *lib)
Packit bf408e
{
Packit bf408e
        struct extension_table *ext;
Packit bf408e
	int found;
Packit bf408e
	char buf[BUFSIZE];
Packit bf408e
Packit bf408e
	if (!lib) {
Packit bf408e
		while (extension_table) {
Packit bf408e
			ext = extension_table;
Packit bf408e
                        if (dlclose(ext->handle))
Packit bf408e
                                error(FATAL,
Packit bf408e
                                    "dlclose: %s: shared object not open\n",
Packit bf408e
                                        ext->filename);
Packit bf408e
Packit bf408e
			fprintf(fp, "%s: shared object unloaded\n", 
Packit bf408e
				ext->filename);
Packit bf408e
Packit bf408e
			extension_table = ext->next;
Packit bf408e
			free(ext);
Packit bf408e
		}
Packit bf408e
Packit bf408e
		help_init();
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if ((*lib != '.') && (*lib != '/')) {
Packit bf408e
		if (!file_exists(lib, NULL) &&
Packit bf408e
		    in_extensions_library(lib, buf))
Packit bf408e
			lib = buf;
Packit bf408e
	} 
Packit bf408e
Packit bf408e
	if (!file_exists(lib, NULL)) {
Packit bf408e
		error(INFO, "%s: %s\n", lib, strerror(ENXIO));
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
        for (ext = extension_table, found = FALSE; ext; ext = ext->next) {
Packit bf408e
                if (same_file(lib, ext->filename)) {
Packit bf408e
			found = TRUE;
Packit bf408e
			if (dlclose(ext->handle))
Packit bf408e
				error(INFO, 
Packit bf408e
				    "dlclose: %s: shared object not open\n", 
Packit bf408e
					ext->filename);
Packit bf408e
			else {
Packit bf408e
				fprintf(fp, "%s: shared object unloaded\n",
Packit bf408e
					ext->filename);
Packit bf408e
Packit bf408e
				if (extension_table == ext) {       /* first */
Packit bf408e
					extension_table = ext->next;
Packit bf408e
					if (ext->next)
Packit bf408e
						ext->next->prev = NULL;
Packit bf408e
				} else if (ext->next == NULL)       /* last */
Packit bf408e
					ext->prev->next = NULL;
Packit bf408e
				else {                              /* middle */
Packit bf408e
					ext->prev->next = ext->next;
Packit bf408e
					ext->next->prev = ext->prev;
Packit bf408e
				}
Packit bf408e
Packit bf408e
				free(ext);
Packit bf408e
				help_init();
Packit bf408e
				break;
Packit bf408e
			}
Packit bf408e
		}
Packit bf408e
		else if (STREQ(basename(lib), basename(ext->filename))) {
Packit bf408e
			error(INFO, "%s and %s are different object files\n",
Packit bf408e
				lib, ext->filename);
Packit bf408e
			found = TRUE;
Packit bf408e
		}
Packit bf408e
        }
Packit bf408e
Packit bf408e
	if (!found)
Packit bf408e
		error(INFO, "%s: not loaded\n", lib);
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 *  Register the command_table as long as there are no command namespace
Packit bf408e
 *  clashes with the currently-existing command set.  Also delete any aliases
Packit bf408e
 *  that clash, giving the registered command name priority.
Packit bf408e
 *
Packit bf408e
 *  This function is called from the shared object's _init() function
Packit bf408e
 *  before the dlopen() call returns back to load_extension() above.  
Packit bf408e
 *  The mark of approval for load_extension() is the setting of the 
Packit bf408e
 *  REGISTERED bit in the "current" extension_table structure flags.
Packit bf408e
 */ 
Packit bf408e
void 
Packit bf408e
register_extension(struct command_table_entry *command_table)
Packit bf408e
{
Packit bf408e
	struct command_table_entry *cp;
Packit bf408e
Packit bf408e
	pc->curext->flags |= NO_MINIMAL_COMMANDS;
Packit bf408e
Packit bf408e
        for (cp = command_table; cp->name; cp++) {
Packit bf408e
		if (get_command_table_entry(cp->name)) {
Packit bf408e
			error(INFO, 
Packit bf408e
                  "%s: \"%s\" is a duplicate of a currently-existing command\n",
Packit bf408e
				pc->curext->filename, cp->name);
Packit bf408e
			pc->curext->flags |= DUPLICATE_COMMAND_NAME;
Packit bf408e
			return;
Packit bf408e
		}
Packit bf408e
		if (cp->flags & MINIMAL)
Packit bf408e
			pc->curext->flags &= ~NO_MINIMAL_COMMANDS;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if ((pc->flags & MINIMAL_MODE) && (pc->curext->flags & NO_MINIMAL_COMMANDS)) {
Packit bf408e
		error(INFO, 
Packit bf408e
		      "%s: does not contain any commands which support minimal mode\n",
Packit bf408e
		      pc->curext->filename);
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (pc->flags & MINIMAL_MODE) {
Packit bf408e
		for (cp = command_table; cp->name; cp++) {
Packit bf408e
			if (!(cp->flags & MINIMAL)) {
Packit bf408e
				error(WARNING, 
Packit bf408e
				      "%s: command \"%s\" does not support minimal mode\n",
Packit bf408e
				      pc->curext->filename, cp->name);
Packit bf408e
			}
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
Packit bf408e
        for (cp = command_table; cp->name; cp++) {
Packit bf408e
		if (is_alias(cp->name)) {
Packit bf408e
			error(INFO, 
Packit bf408e
               "alias \"%s\" deleted: name clash with extension command\n",
Packit bf408e
				cp->name);
Packit bf408e
			deallocate_alias(cp->name);
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
Packit bf408e
	pc->curext->command_table = command_table;   
Packit bf408e
	pc->curext->flags |= REGISTERED;             /* Mark of approval */
Packit bf408e
}
Packit bf408e
Packit bf408e
/* 
Packit bf408e
 *  Hooks for sial.
Packit bf408e
 */
Packit bf408e
unsigned long 
Packit bf408e
get_curtask(void) 
Packit bf408e
{ 
Packit bf408e
	return CURRENT_TASK(); 
Packit bf408e
}
Packit bf408e
Packit bf408e
char *
Packit bf408e
crash_global_cmd(void) 
Packit bf408e
{ 
Packit bf408e
	return pc->curcmd;
Packit bf408e
}
Packit bf408e
Packit bf408e
struct command_table_entry *
Packit bf408e
crash_cmd_table(void) 
Packit bf408e
{ 
Packit bf408e
	return pc->cmd_table; 
Packit bf408e
}