/* **============================================================================== ** ** Open Management Infrastructure (OMI) ** ** Copyright (c) Microsoft Corporation ** ** Licensed under the Apache License, Version 2.0 (the "License"); you may not ** use this file except in compliance with the License. You may obtain a copy ** of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABLITY OR NON-INFRINGEMENT. ** ** See the Apache 2 License for the specific language governing permissions ** and limitations under the License. ** **============================================================================== */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; static const char USAGE[] = "\ Usage: %s [OPTIONS] PROVIDERLIBRARY\n\ \n\ OVERVIEW:\n\ This program generates a provider registration file (.reg) from\n\ information read from a provider library.\n\ \n\ OPTIONS:\n\ -h, --help Print this help message.\n\ -v, --version Print version information.\n\ -n, --namespace NAME Register provider for this namespace (option\n\ may be repeated to specify multiple\n\ nsDirs).\n\ -l, --link Mode for developers. Instead of copying library file\n\ link is created in lib directory.\n\ -o, --hosting HOSTING Use given hosting mode (@requestor@,@inproc@,).\n\ \n\ EXAMPLES:\n\ The following generates a provider registration file for the provider\n\ contained in 'libDogProvider.so'. It then copies the .reg file and\n\ the provider to the installed locations.\n\ \n\ $ omireg -n interop -n root/cimv2 libDogProvider.so\n\ \n\ "; using namespace std; static const char* arg0; //============================================================================== // // err() // // Writes a formatted error message to standard error (preceded by argv[0]) // and then exists. // //============================================================================== PRINTF_FORMAT(1, 2) static void FUNCTION_NEVER_RETURNS err(const char* fmt, ...) { fprintf(stderr, "%s: ", arg0); va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fputc('\n', stderr); exit(1); } //============================================================================== // // GetCommandLineOptions() // // This function processes command line options. // //============================================================================== struct Options { bool help; bool devmode; string hosting; vector nsDirs; Options() : help(false), devmode(false) { } }; static void GetCommandLineDestDirOption( int* argc_, const char* argv[]) { int argc = *argc_; int i; const char* destdir = NULL; for (i = 1; i < argc; ) { if (strcmp(argv[i], "--destdir") == 0) { if (i + 1 == argc) err("missing argument for --destdir option"); destdir = argv[i+1]; memmove((char*)&argv[i], (char*)&argv[i+2], sizeof(char*) * (argc-i-1)); argc -= 2; } else if (strncmp(argv[i], "--destdir=", 10) == 0) { destdir = argv[i] + 10; memmove((char*)&argv[i], (char*)&argv[i+1], sizeof(char*) * (argc-i)); argc -= 1; } else i++; } if (destdir) { if (SetPath(ID_DESTDIR, destdir) != 0) err("failed to set destdir"); } *argc_ = argc; } static void GetCommandLineOptions( int& argc, const char**& argv, Options& options) { GetOptState state = GETOPTSTATE_INITIALIZER; const char* opts[] = { "-h", "--help", "-v", "--version", "-n:", "--namespace:", "-l", "--link", "-o:", "--hosting:", NULL }; /* For each argument */ for (;;) { int r = GetOpt(&argc, (const char**)argv, opts, &state); if (r == 1) break; if (r == -1) err("%s", state.err); if (strcmp(state.opt, "-h") == 0 || strcmp(state.opt, "--help") == 0) { options.help = true; } else if (strcmp(state.opt, "-v") == 0 || strcmp(state.opt, "--version") == 0) { printf("%s: %s\n", arg0, CONFIG_PRODUCT "-" CONFIG_VERSION " - " CONFIG_DATE); exit(0); } else if (strcmp(state.opt, "-l") == 0 || strcmp(state.opt, "--link") == 0) { options.devmode = true; } else if (strcmp(state.opt, "-n") == 0 || strcmp(state.opt, "--namespace") == 0) { string ns = state.arg; for (size_t i = 0; i < ns.size(); i++) { if (ns[i] == '/') ns[i] = '#'; } ns = string(GetPath(ID_REGISTERDIR)) + string("/") + ns; options.nsDirs.push_back(ns); } else if (strcmp(state.opt, "-o") == 0 || strcmp(state.opt, "--hosting") == 0) { options.hosting = state.arg; } } } typedef MI_Module* (*MainProc)(MI_Server* server); static string BaseName(const string& str) { const char* start = strrchr(str.c_str(), '/'); if (start) start++; else start = str.c_str(); return string(start); } static string BaseLibName(const string& str) { const char* start = strrchr(str.c_str(), '/'); if (start) start++; else start = str.c_str(); if (strncmp(start, "lib", 3) == 0) start += 3; const char* p = start; while (*p && *p != '.') p++; return string(start, p - start); } static void PrintClassPath(FILE* os, const MI_ClassDecl* cd) { for (const MI_ClassDecl* p = cd; p; p = p->superClassDecl) { if (p != cd) fprintf(os, ":"); fprintf(os, "%s", p->name); } } static const MI_ClassDecl* FindClassDecl( const MI_SchemaDecl* sd, const char* className) { for (MI_Uint32 i = 0; i < sd->numClassDecls; i++) { const MI_ClassDecl* p = sd->classDecls[i]; if (strcmp(p->name, className) == 0) return p; } return 0; } static void GenClassLine( FILE* os, const MI_SchemaDecl* sd, const MI_ClassDecl* cd) { // Print the class path: CLASS1.CLASS2.CLASS3 fprintf(os, "CLASS="); PrintClassPath(os, cd); // Print the association classes: if (cd->flags & MI_FLAG_ASSOCIATION) { fprintf(os, "{"); MI_Uint32 n = 0; for (MI_Uint32 i = 0; i < cd->numProperties; i++) { const MI_PropertyDecl* pd = cd->properties[i]; if (pd->type == MI_REFERENCE && pd->className) { const MI_ClassDecl* rcd = FindClassDecl(sd, pd->className); if (!rcd) err("failed to find class: %s", pd->className); if (n != 0) fprintf(os, ","); PrintClassPath(os, rcd); n++; } } fprintf(os, "}"); } fprintf(os, "\n"); } static MI_Module* LoadModule(const char* path) { const char FUNC[] = "MI_Main"; // Load the library: void* handle = Lib_Open(path); if (!handle) { char* msg = Lib_Err(); err("failed to load library: %s\n", msg); Lib_Free(msg); } // Load the MI_Main() entry point: void* sym = Lib_Sym(handle, FUNC); if (!sym) { err("failed to find symbol '%s' in library '%s'\n", FUNC, path); } // Call MI_Main() to get MI_Module object. MainProc main = (MainProc)sym; MI_Module* module = (*main)(NULL); if (!module) { err("%s:%s() failed", path, FUNC); } // Check character size: if (module->charSize != sizeof(MI_Char)) { err("provider char size (%u) does not match %s char size (%u)", module->charSize, arg0, (int)sizeof(MI_Char)); } return module; } static void GenRegFile( FILE* os, int argc, const char** argv, const string& baseName, MI_Module* module, const Options& opts) { // Get schemaDecl: MI_SchemaDecl* sd = module->schemaDecl; if (!sd) { err("MI_Module.schemaDecl is null"); } // Generate header line. fprintf(os, "# "); for (int i = 0; i < argc; i++) { string arg; if (i == 0) arg = BaseName(argv[i]); else arg = argv[i]; fprintf(os, "%s", arg.c_str()); if (i + 1 != argc) fprintf(os, " "); } fprintf(os, "\n"); // Write library name: fprintf(os, "LIBRARY=%s\n", baseName.c_str()); // Hosting if (!opts.hosting.empty()) { fprintf(os, "HOSTING=%s\n", opts.hosting.c_str()); } // Find providers: for (MI_Uint32 i = 0; i < sd->numClassDecls; i++) { const MI_ClassDecl* cd = sd->classDecls[i]; if (!cd) err("null classDecl element"); // If it has a provider, print the class line. if (cd->providerFT) { GenClassLine(os, sd, cd); } } } static bool Inhale(const char* path, vector& data) { FILE* is = Fopen(path, "r"); if (!is) return false; size_t n; char buf[4096]; while ((n = fread(buf, 1, sizeof(buf), is)) != 0) { data.insert(data.end(), buf, buf + n); } data.push_back('\0'); fclose(is); return true; } static void _RefreshServer() { // check if server is running mi::Client cl; const MI_Uint64 TIMEOUT = 500 * 1000; if (cl.Connect(GetPath(ID_SOCKETFILE), MI_T(""), MI_T(""), TIMEOUT)) { // reload server's config pid_t child = fork(); if (!child) { execl(GetPath(ID_SERVERPROGRAM), GetPath(ID_SERVERPROGRAM), "-r", NULL ); exit(1); // never get here... if everything is ok } else if (child > 0) { /* wait for child */ int s; waitpid(child, &s, 0); } // wait until it restarts cl.NoOp(TIMEOUT); // wait for server to restart for ( int i = 0; i < 30; i++ ) { if (cl.Connect(GetPath(ID_SOCKETFILE), MI_T(""), MI_T(""), TIMEOUT)) break; Time_Sleep(50); } } } int main(int argc, const char** argv) { arg0 = argv[0]; // Get --destdir command-line option. GetCommandLineDestDirOption(&argc, argv); // Get command-line options. Options opts; GetCommandLineOptions(argc, argv, opts); if (opts.nsDirs.size() == 0) { string ns = CONFIG_NAMESPACE; for (size_t i = 0; i < ns.size(); i++) { if (ns[i] == '/') ns[i] = '#'; } ns = string(GetPath(ID_REGISTERDIR)) + string("/") + ns; opts.nsDirs.push_back(ns); } // Check arguments. if (opts.help) { fprintf(stderr, USAGE, arg0); exit(1); } // Check number of arguments. if (argc != 2) { fprintf(stderr, "Usage: %s PROVIDERLIBRARY\n", arg0); fprintf(stderr, "Try '%s --help' for help\n\n", arg0); exit(1); } // Check that namespace directories are writable. for (size_t i = 0; i < opts.nsDirs.size(); i++) { const string path = opts.nsDirs[i]; if (!Isdir(path.c_str())) err("no such namespace directory: %s", path.c_str()); if (access(path.c_str(), W_OK) != 0) err("namespace directory is not writable: %s", path.c_str()); } #ifdef CONFIG_OS_HPUX // HP is the only platform that locks loaded binary files // so if provider is already loaded unlink/copy will fail // force server to unload all providers before copying _RefreshServer(); #endif // Copy library to provider directory (avoid copy if file is identical // since the path could be the same). { vector data1; if (!Inhale(argv[1], data1)) err("cannot read provider library: %s", argv[1]); string path = GetPath(ID_PROVIDERDIR); path += "/"; path += Basename(argv[1]); if (opts.devmode) { unlink(path.c_str()); if (symlink(argv[1], path.c_str()) != 0) err("failed to symlink '%s' to '%s'", argv[1], path.c_str()); } else { if (File_Copy(argv[1], path.c_str()) != 0) err("failed to copy '%s' to '%s'", argv[1], path.c_str()); // set mod explicitly // w by owner only; RX for all. chmod(path.c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); printf("Created %s\n", path.c_str()); } } // Load module: MI_Module* module = LoadModule(argv[1]); if (!module) err("failed to load provider library: %s", argv[1]); // Generate .reg file in each namespace directory: for (size_t i = 0; i < opts.nsDirs.size(); i++) { // Open output file (using basename of library): string baseLibName = BaseLibName(argv[1]); string regFileName = baseLibName + ".reg"; string path = opts.nsDirs[i]; path += "/"; path += regFileName; FILE* os = fopen(path.c_str(), "wb"); if (!os) err("failed to open: %s", path.c_str()); // Generate the registration file. GenRegFile(os, argc, argv, baseLibName, module, opts); printf("Created %s\n", path.c_str()); fclose(os); } // ask server to re-read configuration _RefreshServer(); return 0; }