//%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 #include #include #include #include #include #include #include #include #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& types, const Array& 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 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 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& 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 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& 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 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; }