(file) Return to main.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus_unsupported / utils / cimreg

File: [Pegasus] / pegasus_unsupported / utils / cimreg / main.cpp (download)
Revision: 1.6, Tue Mar 27 15:26:02 2007 UTC (17 years, 2 months ago) by mike
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +45 -33 lines
BUG#: 9999
TITLE: CMIREG

DESCRIPTION: CMPI support

//%2006////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
// Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
// IBM Corp.; EMC Corporation, The Open Group.
// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
// Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
// EMC Corporation; VERITAS Software Corporation; The Open Group.
// Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
// EMC Corporation; Symantec Corporation; The Open Group.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
// ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//%/////////////////////////////////////////////////////////////////////////////

#include <Pegasus/Common/Config.h>
#include <Pegasus/Common/System.h>
#include <Pegasus/Client/CIMClient.h>
#include <Pegasus/Common/FileSystem.h>
#include <cstring>
#include <cstdarg>
#include <cctype>
#include <fstream>
#include <dlfcn.h>

#define REGISTRATION_NAMESPACE "root/PG_InterOp"

PEGASUS_USING_PEGASUS;
PEGASUS_USING_STD;

static const char* arg0;

//==============================================================================
//
// options:
//
//==============================================================================

bool opt_help = false;
bool opt_unregister = false;
bool opt_verbose = false;
bool opt_what = false;

//==============================================================================
//
// err()
//
//==============================================================================

void err(const char* format, ...)
{
    fputc('\n', stderr);
    va_list ap;
    fprintf(stderr, "%s: ", arg0);
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    va_end(ap);
    fputc('\n', stderr);
    fputc('\n', stderr);
    exit(1);
}

//==============================================================================
//
// warn()
//
//==============================================================================

void warn(const char* format, ...)
{
    va_list ap;
    fprintf(stderr, "%s: warning: ", arg0);
    va_start(ap, format);
    vfprintf(stderr, format, ap);
    fputc('\n', stderr);
    va_end(ap);
}

//==============================================================================
//
// get_opt()
//
//==============================================================================

static char *opt_arg = NULL;
static int opt_ind = 1;
static int opt_err = 1;
static int opt_opt;

static int get_opt(int argc, char** argv, const char* optstring)
{
    for (int i = opt_ind; i < argc; i++)
    {
	char* arg = argv[i];

	if (arg[0] == '-' && arg[1] != '\0')
	{
	    int opt = arg[1];
	    const char* p = strchr(optstring, opt);
	    opt_arg = NULL;

	    if (p == NULL)
	    {
		if (opt_err)
		    fprintf(stderr, "%s: invalid option -- %c\n", argv[0], opt);

		opt_opt = opt;
		opt = '?';
	    }
	    else if (p[1] == ':')
	    {
		if ((opt_arg = argv[i+1]) == NULL)
		{
		    if (opt_err)
		    {
			fprintf(stderr, 
			    "%s: option requires an argument -- %c\n", 
			    argv[0], opt);
		    }

		    opt_opt = opt;

		    if (*optstring == ':')
			opt = ':';
		    else
			opt = '?';
		}
	    }

	    int n = opt_arg ? 2 : 1;

	    memmove(
		argv + opt_ind + n, 
		argv + opt_ind, 
		(i - opt_ind) * sizeof(char*));

	    argv[opt_ind++] = arg;

	    if (opt_arg)
		argv[opt_ind++] = opt_arg;

	    return opt;
	}
    }

    return -1;
}

//==============================================================================
//
// is_absolute()
//
//==============================================================================

bool is_absolute(const char* path)
{
    if (path[0] == '/')
	return true;

#ifdef PEGASUS_OS_TYPE_WINDOWS
    if (isalpha(path[0]) && path[0] == ':' && path[0] == '/')
	return true;
#endif

    return false;
}

//==============================================================================
//
// has_pegasus_entry_point() 
//
//     If provider lacks a PegasusCreateProvider() entry point, we assume it
//     is a CMPI provider.
//
//==============================================================================

bool has_pegasus_entry_point(const char* path)
{
    void* handle = dlopen(path, RTLD_NOW | RTLD_GLOBAL);

    if (!handle)
	err("dynamic load failed: %s", dlerror());

    void* symbol = dlsym(handle, "PegasusCreateProvider");

    dlclose(handle);

    return symbol;
}

//==============================================================================
//
// unregister_module()
//
//==============================================================================

void unregister_module(
    CIMClient& client,
    const String& module_name)
{
    CString cstr = module_name.getCString();

    char buf[1024];
    sprintf(buf, "PG_ProviderModule.Name=\"%s\"", (const char*)cstr);

    try
    {
	client.deleteInstance(REGISTRATION_NAMESPACE, CIMObjectPath(buf));
    }
    catch (...)
    {
	// Ignore the eror since it may not exist anyway.
    }
}

//==============================================================================
//
// register_module()
//
//==============================================================================

void register_module(
    CIMClient& client,
    const String& short_library_name,
    int provider_type,
    const String& module_name)
{
    if (opt_verbose)
    {
	CString cstr = module_name.getCString();
	char buf[1024];
	sprintf(buf, "PG_ProviderModule.Name=\"%s\"", (const char*)cstr);
	printf("Creating %s\n", buf);
    }

    try
    {
	CIMInstance i("PG_ProviderModule");
	i.addProperty(CIMProperty("Name", module_name));
	i.addProperty(CIMProperty("Vendor", String("Pegasus")));

        if (provider_type == 'P')
        {
            i.addProperty(CIMProperty("Version", String("2.5.0")));
            i.addProperty(CIMProperty("InterfaceType", String("C++Default")));
            i.addProperty(CIMProperty("InterfaceVersion", String("2.5.0")));
        }
        else
        {
            i.addProperty(CIMProperty("Version", String("2.0.0")));
            i.addProperty(CIMProperty("InterfaceType", String("CMPI")));
            i.addProperty(CIMProperty("InterfaceVersion", String("2.0.0")));
        }

	i.addProperty(CIMProperty("Location", short_library_name));
	client.createInstance(REGISTRATION_NAMESPACE, i);
    }
    catch (CIMException& e)
    {
        CString msg = e.getMessage().getCString();
	err("failed to create instance of PG_ProviderModule instance: %s",
            (const char*)msg);
    }
    catch (...)
    {
	err("failed to create instance of PG_ProviderModule");
    }
}

//==============================================================================
//
// unregister_provider()
//
//==============================================================================

void unregister_provider(
    CIMClient& client,
    const String& module_name,
    const String& provider_name,
    const String& class_name)
{
    char buf[1024];
    CString pn = provider_name.getCString();
    CString mn = module_name.getCString();

    try
    {
	sprintf(buf, 
	    "PG_Provider.Name=\"%s\"," 
	    "ProviderModuleName=\"%s\"",
	    (const char*)pn, 
	    (const char*)mn);

	client.deleteInstance(REGISTRATION_NAMESPACE, CIMObjectPath(buf));
    }
    catch (...)
    {
    }

    try
    {
	sprintf(buf, 
	    "PG_ProviderCapabilities."
	    "ProviderName=\"%s\","
	    "ProviderModuleName=\"%s\","
	    "CapabilityID=\"1\"", 
	    (const char*)pn,
	    (const char*)mn);

	client.deleteInstance(REGISTRATION_NAMESPACE, CIMObjectPath(buf));
    }
    catch (...)
    {
        // Ignore!
    }
}

//==============================================================================
//
// register_provider()
//
//==============================================================================

void register_provider(
    CIMClient& client,
    const String& module_name,
    const String& provider_name,
    const String& class_name,
    const Array<Uint16>& types,
    const Array<String>& name_spaces)
{
    char buf[1024];
    CString pn = provider_name.getCString();
    CString mn = module_name.getCString();

    try
    {
        if (opt_verbose)
        {
            sprintf(buf, 
                "PG_Provider.Name=\"%s\"," 
                "ProviderModuleName=\"%s\"",
                (const char*)pn, 
                (const char*)mn);

            printf("Creating %s\n", buf);
        }

        CIMInstance i("PG_Provider");
        i.addProperty(CIMProperty("Name", provider_name));
        i.addProperty(CIMProperty("ProviderModuleName", module_name));
        client.createInstance(REGISTRATION_NAMESPACE, i);
    }
    catch (CIMException& e)
    {
        CString msg = e.getMessage().getCString();
	err("failed to create instance of PG_Provider instance: %s",
            (const char*)msg);
    }
    catch (...)
    {
	err("failed to create instance of PG_Provider");
    }

    try 
    {
        if (opt_verbose)
        {
            sprintf(buf, 
                "PG_ProviderCapabilities."
                "ProviderName=\"%s\","
                "ProviderModuleName=\"%s\","
                "CapabilityID=\"1\"", 
                (const char*)pn,
                (const char*)mn);

            printf("Creating %s\n", buf);
        }

        CIMInstance i("PG_ProviderCapabilities");
        i.addProperty(CIMProperty("CapabilityID", String("1")));
        i.addProperty(CIMProperty("ProviderModuleName", module_name));
        i.addProperty(CIMProperty("ProviderName", provider_name));
        i.addProperty(CIMProperty("ClassName", class_name));
        i.addProperty(CIMProperty("Namespaces", name_spaces));
        i.addProperty(CIMProperty("ProviderType", types));

        CIMValue supportedProperties;
        supportedProperties.setNullValue(CIMTYPE_STRING, true, 0);
        i.addProperty(
            CIMProperty("supportedProperties", supportedProperties));

        CIMValue supportedMethods;
        supportedMethods.setNullValue(CIMTYPE_STRING, true, 0);
        assert(supportedMethods.isNull());
        i.addProperty(
            CIMProperty("supportedMethods", supportedMethods));

        client.createInstance(REGISTRATION_NAMESPACE, i);
    }
    catch (CIMException& e)
    {
        CString msg = e.getMessage().getCString();
	err("failed to create instance of PG_Provider instance: %s",
            (const char*)msg);
    }
    catch (...)
    {
	err("failed to create instance of PG_Provider");
    }
}

//==============================================================================
//
// shlib_basename()
//
//==============================================================================

String shlib_basename(const char* path)
{
    const char* p = strrchr(path, '/');

    if (p)
	p++;
    else
	p = path;

#ifdef PEGASUS_OS_TYPE_UNIX
    if (p[0] == 'l' && p[1] == 'i' && p[2] == 'b')
	p += 3;
    else
	err("illegal library name: %s", path);
#endif

    const char* q = strchr(p, '.');

    if (!q)
	err("illegal library name: %s", path);

    return String(p, q - p);
}

//==============================================================================
//
// parse_provider_string
//
//==============================================================================

struct Provider_Info
{
    String provider_name;
    String class_name;
    Array<Uint16> types;
};

struct Type
{
    const char* name;
    size_t number;
};

static const Type type_table[] =
{
    { "Class", 1 },
    { "Instance", 2 },
    { "Association", 3 },
    { "Indication", 4 },
    { "Method", 5 },
    { "Consumer", 6 },
    { "Query", 7 },
};

const size_t type_table_size = sizeof(type_table) / sizeof(type_table[0]);

size_t type_to_number(const char* type)
{
    for (size_t i = 0; i < type_table_size; i++)
    {
	if (strcmp(type, type_table[i].name) == 0)
	    return type_table[i].number;
    }

    return (size_t)-1;
}

void parse_provider_string(
    const String& str,
    Provider_Info& provider_info)
{
    // Get provider name:

    String tmp = str;
    Uint32 pos = tmp.find(',');

    if (pos == (Uint32)-1)
    {
	CString cstr = str.getCString();
	err("corrupt PEGASUS_PROVIDER string: %s", (const char*)cstr);
    }

    provider_info.provider_name = tmp.subString(0, pos);

    // Get class name.

    tmp = tmp.subString(pos + 1);
    pos = tmp.find(',');

    if (pos == (Uint32)-1)
    {
	CString cstr = str.getCString();
	err("corrupt PEGASUS_PROVIDER string: %s", 
	    (const char*)cstr);
    }

    provider_info.class_name = tmp.subString(0, pos);

    // Get each type:

    tmp = tmp.subString(pos + 1);
    CString cstr = tmp.getCString();
    char* p = (char*)(const char*)cstr;

    for (p = strtok(p, ":"); p; p = strtok(NULL, ":"))
    {
	size_t number = type_to_number(p);

	if (number == (size_t)-1)
	{
	    err("Bad provider type in PEGASUS_PROVIDER string: %s", 
		p);
	}

	provider_info.types.append(number);
    }

    if (provider_info.types.size() == 0)
	err("corrupt PEGASUS_PROVIDER string: %s", 
	    (const char*)cstr);
}

//==============================================================================
//
// load_info_from_module()
//
//==============================================================================

struct Module_Info
{
    String module_name;
    Array<Provider_Info> providers;
};

void load_info_from_module(
    const char* library_path,
    Module_Info& info)
{
    // Load whole library into memory.

    Buffer buffer;

    try
    {
	FileSystem::loadFileToMemory(buffer, library_path);
    }
    catch(...)
    {
	err("failed to read %s", library_path);
    }

    buffer.append('\0');

    // Search for hints, introduced by "@(#)" sequence and terminated by
    // a null character.

    bool found_module = false;
    bool found_provider = false;

    for (size_t i = 0; i < buffer.size(); )
    {
	const char* start = &buffer[i];
	const char* p = start;

	if (p[0] == '@' && p[1] == '(' && p[2] == '#' && p[3] == ')')
	{
	    if (opt_what)
	    {
		printf("%s\n", p);
		i += strlen(p);
		continue;
	    }

	    p += 4;

	    String str;
	     
	    while (*p)
		str.append(*p++);

	    const char MODULE[] = "PEGASUS_MODULE";
	    const char PROVIDER[] = "PEGASUS_PROVIDER";

	    if (str.subString(0, sizeof(MODULE)-1) == MODULE)
	    {
		if (found_module)
		{
		    err("found more than one PEGASUS_MODULE macro "
			"in the same library: %s", library_path);
		}

		info.module_name = str.subString(sizeof(MODULE));
		found_module = true;
	    }
	    else if (str.subString(0, sizeof(PROVIDER)-1) == PROVIDER)
	    {
		// "@(#)PEGASUS_PROVIDER:FanProvider,Fan,instance:method"

		// Get provider info.

		String tmp = str.subString(sizeof(PROVIDER));

		Provider_Info provider_info;
		parse_provider_string(tmp, provider_info);

		found_provider = true;

		info.providers.append(provider_info);
	    }

	    i += p - start;
	}
	else
	    i++;
    }

    if (opt_what)
	return;

    if (!found_module)
	err("found no PEGASUS_MODULE macro in %s", library_path);

    if (!found_provider)
	err("found no PEGASUS_PROVIDER macros in %s", library_path);
}

//==============================================================================
//
// load_config_file()
//
//==============================================================================

struct Name_Value_Pair
{
    String name;
    String value;
};

void load_config_file(
    const char* file_path,
    Array<Name_Value_Pair>& pairs)
{
    // Open input file:

    ifstream is(file_path);

    if (!is)
	err("failed to open %s", file_path);

    // Read line by line.

    String line;
    Uint32 line_number = 1;

    while (GetLine(is, line))
    {
	// Skip comment lines:

	if (line[0] == '#')
	    continue;

	// Skip leading whitespace:

	const Char16* p = line.getChar16Data();

	while (isspace(*p))
	    p++;

	if (*p == '\0')
	{
	    // Skip blank lines:
	    continue;
	}

	// Get name:

	const Char16* q = p;

	if (!isalpha(*q) && *q != '_')
	    err("%s: syntax error on line %u", file_path, line_number);

	while (*q && isalnum(*q) || *q == '_')
	    q++;

	String name(p, q - p);

	// Get equal sign:

	p = q;

	while (*p && isspace(*p))
	    p++;

	if (*p != '=')
	    err("%s: expected '=' on line %u", file_path, line_number);

	p++;

	// Get value:

	while (*p && isspace(*p))
	    p++;

	q = p;

	while (*q && !isspace(*q))
	    q++;

	if (q == p)
	    err("%s: expected value on line %u", file_path, line_number);

	String value(p, q - p);

	p = q;

	while (*p && isspace(*p))
	    p++;

	if (*p != '\0')
	    err("%s: illegal value on line %u", file_path, line_number);

	// Append to pairs:

	Name_Value_Pair pair;
	pair.name = name;
	pair.value = value;
	pairs.append(pair);

	line_number++;
    }
}

//==============================================================================
//
// load_info_from_file()
//
//==============================================================================

void load_info_from_file(
    const char* file_path,
    Module_Info& info)
{
    // Load config file vars:

    Array<Name_Value_Pair> pairs;
    load_config_file(file_path, pairs);

    // Process lines:

    bool found_module = false;
    bool found_provider = false;

    for (Uint32 i = 0; i < pairs.size(); i++)
    {
	if (pairs[i].name == "MODULE")
	{
	    if (found_module)
		err("%s: duplicate MODULE line", file_path);

	    info.module_name = pairs[i].value;
	    found_module = true;
	}
	else if (pairs[i].name == "PROVIDER")
	{
	    Provider_Info provider_info;
	    parse_provider_string(pairs[i].value, provider_info);
	    info.providers.append(provider_info);
	    found_provider = true;
	}
	else
	{
	    CString cstr = pairs[i].name.getCString();
	    err("%s: unknown variable: %s", file_path, (const char*)cstr);
	}
    }

    if (!found_module)
	err("%s: found no MODULE registration line");

    if (!found_provider)
	err("%s: found no PROVIDER registration line");
}

//==============================================================================
//
// create_registration_instances()
//
//==============================================================================

void create_registration_instances(
    CIMClient& client,
    const char* library_path,
    int provider_type,
    const Module_Info& info,
    const Array<String>& name_spaces)
{
    // Make short library name:

    String short_library_name = shlib_basename(library_path);

    // Unregister and then register the module.

    unregister_module(client, info.module_name);

    if (!opt_unregister)
	register_module(
            client, short_library_name, provider_type, info.module_name);

    // Register provider instances.

    for (size_t i = 0; i < info.providers.size(); i++)
    {
	unregister_provider(
	    client,
	    info.module_name, 
	    info.providers[i].provider_name, 
	    info.providers[i].class_name);

	if (!opt_unregister)
	{
	    register_provider(
		client,
		info.module_name, 
		info.providers[i].provider_name, 
		info.providers[i].class_name, 
		info.providers[i].types, 
		name_spaces);
	}
    }
}

//==============================================================================
//
// help()
//
//==============================================================================

const char USAGE[] = "\
\n\
Usage: %s [options] library-path\n\
\n\
Description:\n\
    The cimreg utility automatically registers a provider module library\n\
    with OpenPegasus. It obtains the registration details by either scanning\n\
    the library for special macro definitions (macro registration) or by\n\
    reading a registration file (file registration). Macro registration is\n\
    the default. It scans the library for registration strings, which\n\
    are defined with the PEGASUS_MODULE and PEGASUS_PROVIDER macros. For\n\
    example, an instance-method provider for the Fan class may contain the\n\
    following definitions (the provider must include cimreg.h):\n\
\n\
	PEGASUS_MODULE(\"FanModule\");\n\
	PEGASUS_PROVIDER(\"FanProvider\", \"Fan\", \"Instance:Method\");\n\
\n\
    The PEGASUS_MODULE macro defines the module name. The PEGASUS_PROVIDER\n\
    macro defines a provider name, class name, and provider-type list.\n\
    The PEGASUS_PROVIDER macro may appear once for each provider contained\n\
    in the module. The definitions above inject the following strings into\n\
    the library.\n\
\n\
	\"@(#)PEGASUS_MODULE=FanModule\"\n\
	\"@(#)PEGASUS_PROVIDER=FanProvider,Fan,Instance:Method\"\n"

"\n\
    These strings can be examined with the -w (what) option (see below).\n\
\n\
    File registration requires the -f option (see below). The following\n\
    file achieves the same effect as the module registration example shown\n\
    above.\n\
\n\
	MODULE=FanModule\n\
	PROVIDER=FanProvider,Fan,Instance:Method\n\
\n\
    Cimreg also performs the following sanity checks:\n\
\n\
	1.  Checks whether the library can be loaded (and reports any errors\n\
	    including unresolved symbols).\n\
	2.  Checks whether the class named in the PEGASUS_PROVIDER macro\n\
	    exists in the repository.\n\
	3.  Checks whether the OpenPegasus repository exists.\n\
	4.  Verifies that each target namespace exists (see -n).\n\
\n\
Options:\n\
    -h             print this help message.\n\
    -n namespace   namespaces supported by provider; may appear many times\n\
                   (defaults to \"root/cimv2\").\n\
    -w             just print the module's embedded registration strings to \n\
                   standard output, but do not register the module.\n\
    -u             unregister the module and its providers.\n\
    -f filename    read registration info from this file rather than module.\n\
    -v             verbose\n\
\n";

void help()
{
    printf(USAGE, arg0);
    exit(0);
}

//==============================================================================
//
// main()
//
//==============================================================================

int main(int argc, char** argv)
{
    arg0 = argv[0];

    // Process options:

    int opt;
    Array<String> name_spaces;
    const char* file_path = 0;

    while ((opt = get_opt(argc, argv, "n:hvwuf:")) != -1)
    {
	switch (opt)
	{
	    case 'n':
		name_spaces.append(opt_arg);
		break;

	    case 'h':
		opt_help = true;
		break;

	    case 'v':
		opt_verbose = true;
		break;

	    case 'w':
		opt_what = true;
		break;

	    case 'u':
		opt_unregister = true;
		break;

	    case 'f':
		file_path = opt_arg;
		break;

	    case '?':
	    case ':':
		exit(1);

	    default:
		err("unexpected");
	}
    }

    argc -= opt_ind - 1;
    argv += opt_ind - 1;

    // Help!

    if (opt_help)
	help();

    // Check arguments (we expect once)

    if (argc != 2)
	err("wrong number of arguments; try -h for help");

    // Create client.

    CIMClient client;

    try
    {
        client.connectLocal();
    }
    catch (CIMException& e)
    {
	CString msg = e.getMessage().getCString();
        err("failed to connect to CIM server: %s", (const char*)msg);
    }
    catch (...)
    {
        err("failed to connect to CIM server");
    }

    // If no namespaces given, use default.

    if (name_spaces.size() == 0)
	name_spaces.append("root/cimv2");

    // Be sure that library-path argument is an absolute path.

    const char* library_path = argv[1];

    if (!is_absolute(library_path))
	err("library path argument must be absolute: %s", library_path);

    // Determine provider type.

    int provider_type;

    if (has_pegasus_entry_point(library_path))
    {
        printf("Registering Pegasus C++ provider");
        provider_type = 'P';
    }
    else
    {
        printf("Registering CMPI provider");
        provider_type = 'C';
    }

    // Carry out the registraion:

    Module_Info info;

    if (file_path)
	load_info_from_file(file_path, info);
    else
	load_info_from_module(library_path, info);

    // Register module:

    if (!opt_what)
         create_registration_instances(
             client, library_path, provider_type, info, name_spaces);

    return 0;
}

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2