(file) Return to omireg.cpp CVS log (file) (dir) Up to [OMI] / omi / omireg

  1 mike  1.1 /*
  2           **==============================================================================
  3           **
  4           ** Open Management Infrastructure (OMI)
  5           **
  6           ** Copyright (c) Microsoft Corporation
  7           ** 
  8           ** Licensed under the Apache License, Version 2.0 (the "License"); you may not 
  9           ** use this file except in compliance with the License. You may obtain a copy 
 10           ** of the License at 
 11           **
 12           **     http://www.apache.org/licenses/LICENSE-2.0 
 13           **
 14           ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15           ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
 16           ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
 17           ** MERCHANTABLITY OR NON-INFRINGEMENT. 
 18           **
 19           ** See the Apache 2 License for the specific language governing permissions 
 20           ** and limitations under the License.
 21           **
 22 mike  1.1 **==============================================================================
 23           */
 24           
 25           #include <common.h>
 26           #include <base/args.h>
 27           #include <string>
 28           #include <vector>
 29           #include <base/lib.h>
 30           #include <unistd.h>
 31           #include <base/getopt.h>
 32           #include <base/paths.h>
 33           #include <base/dir.h>
 34           #include <base/io.h>
 35           #include <base/file.h>
 36           #include <base/time.h>
 37           #include <dlfcn.h>
 38           #include <unistd.h>
 39           #include <sys/wait.h>
 40           #include <omiclient/client.h>
 41           
 42           using namespace std;
 43 mike  1.1 
 44           static const char USAGE[] = "\
 45           Usage: %s [OPTIONS] PROVIDERLIBRARY\n\
 46           \n\
 47           OVERVIEW:\n\
 48               This program generates a provider registration file (.reg) from\n\
 49               information read from a provider library.\n\
 50           \n\
 51           OPTIONS:\n\
 52               -h, --help                  Print this help message.\n\
 53               -v, --version               Print version information.\n\
 54               -n, --namespace NAME        Register provider for this namespace (option\n\
 55                                           may be repeated to specify multiple\n\
 56                                           nsDirs).\n\
 57               -l, --link                  Mode for developers. Instead of copying library file\n\
 58                                           link is created in lib directory.\n\
 59               -o, --hosting HOSTING       Use given hosting mode (@requestor@,@inproc@,<user>).\n\
 60           \n\
 61           EXAMPLES:\n\
 62               The following generates a provider registration file for the provider\n\
 63               contained in 'libDogProvider.so'. It then copies the .reg file and\n\
 64 mike  1.1     the provider to the installed locations.\n\
 65           \n\
 66                   $ omireg -n interop -n root/cimv2 libDogProvider.so\n\
 67           \n\
 68           ";
 69           
 70           using namespace std;
 71           
 72           static const char* arg0;
 73           
 74           //==============================================================================
 75           //
 76           // err()
 77           //
 78           //     Writes a formatted error message to standard error (preceded by argv[0])
 79           //     and then exists.
 80           //
 81           //==============================================================================
 82           
 83           PRINTF_FORMAT(1, 2)
 84           static void FUNCTION_NEVER_RETURNS err(const char* fmt, ...)
 85 mike  1.1 {
 86               fprintf(stderr, "%s: ", arg0);
 87           
 88               va_list ap;
 89               va_start(ap, fmt);
 90               vfprintf(stderr, fmt, ap);
 91               va_end(ap);
 92           
 93               fputc('\n', stderr);
 94               exit(1);
 95           }
 96           
 97           //==============================================================================
 98           //
 99           // GetCommandLineOptions()
100           //
101           //     This function processes command line options.
102           //
103           //==============================================================================
104           
105           struct Options
106 mike  1.1 {
107               bool help;
108               bool devmode;
109               string  hosting;
110               vector<string> nsDirs;
111           
112               Options() : help(false), devmode(false)
113               {
114               }
115           }; 
116           
117           static void GetCommandLineDestDirOption(
118               int* argc_,
119               const char* argv[])
120           {
121               int argc = *argc_;
122               int i;
123               const char* destdir = NULL;
124           
125               for (i = 1; i < argc; )
126               {
127 mike  1.1         if (strcmp(argv[i], "--destdir") == 0)
128                   {
129                       if (i + 1 == argc)
130                           err("missing argument for --destdir option");
131           
132                       destdir = argv[i+1];
133                       memmove((char*)&argv[i], (char*)&argv[i+2], 
134                           sizeof(char*) * (argc-i-1));
135                       argc -= 2;
136                   }
137                   else if (strncmp(argv[i], "--destdir=", 10) == 0)
138                   {
139                       destdir = argv[i] + 10;
140                       memmove((char*)&argv[i], (char*)&argv[i+1], 
141                           sizeof(char*) * (argc-i));
142           
143                       argc -= 1;
144                   }
145                   else
146                       i++;
147               }
148 mike  1.1 
149               if (destdir)
150               {
151                   if (SetPath(ID_DESTDIR, destdir) != 0)
152                       err("failed to set destdir");
153               }
154           
155               *argc_ = argc;
156           }
157           
158           static void GetCommandLineOptions( 
159               int& argc, 
160               const char**& argv, 
161               Options& options)
162           {
163               GetOptState state = GETOPTSTATE_INITIALIZER;
164               const char* opts[] =
165               {
166                   "-h",
167                   "--help",
168                   "-v",
169 mike  1.1         "--version",
170                   "-n:",
171                   "--namespace:",
172                   "-l",
173                   "--link",
174                   "-o:",
175                   "--hosting:",
176                   NULL
177               };
178           
179               /* For each argument */
180               for (;;)
181               {
182                   int r = GetOpt(&argc, (const char**)argv, opts, &state);
183           
184                   if (r == 1)
185                       break;
186           
187                   if (r == -1)
188                       err("%s", state.err);
189           
190 mike  1.1         if (strcmp(state.opt, "-h") == 0 || 
191                       strcmp(state.opt, "--help") == 0)
192                   {
193                       options.help = true;
194                   }
195                   else if (strcmp(state.opt, "-v") == 0 ||
196                            strcmp(state.opt, "--version") == 0)
197                   {
198                       printf("%s: %s\n", arg0,
199                           CONFIG_PRODUCT "-" CONFIG_VERSION " - " CONFIG_DATE);
200                       exit(0);
201                   }
202                   else if (strcmp(state.opt, "-l") == 0 || 
203                       strcmp(state.opt, "--link") == 0)
204                   {
205                       options.devmode = true;
206                   }
207                   else if (strcmp(state.opt, "-n") == 0 || 
208                       strcmp(state.opt, "--namespace") == 0)
209                   {
210                       string ns = state.arg;
211 mike  1.1 
212                       for (size_t i = 0; i < ns.size(); i++)
213                       {
214                           if (ns[i] == '/')
215                               ns[i] = '#';
216                       }
217           
218                       ns = string(GetPath(ID_REGISTERDIR)) + string("/") + ns;
219                       options.nsDirs.push_back(ns);
220                   }
221                   else if (strcmp(state.opt, "-o") == 0 || 
222                       strcmp(state.opt, "--hosting") == 0)
223                   {
224                       options.hosting = state.arg;
225                   }
226               }
227           }
228           
229           typedef MI_Module* (*MainProc)(MI_Server* server);
230           
231           static string BaseName(const string& str)
232 mike  1.1 {
233               const char* start = strrchr(str.c_str(), '/');
234           
235               if (start)
236                   start++;
237               else
238                   start = str.c_str();
239           
240               return string(start);
241           }
242           
243           static string BaseLibName(const string& str)
244           {
245               const char* start = strrchr(str.c_str(), '/');
246           
247               if (start)
248                   start++;
249               else
250                   start = str.c_str();
251           
252               if (strncmp(start, "lib", 3) == 0)
253 mike  1.1         start += 3;
254           
255               const char* p = start;
256           
257               while (*p && *p != '.')
258                   p++;
259           
260               return string(start, p - start);
261           }
262           
263           static void PrintClassPath(FILE* os, const MI_ClassDecl* cd)
264           {
265               for (const MI_ClassDecl* p = cd; p; p = p->superClassDecl)
266               {
267                   if (p != cd)
268                       fprintf(os, ":");
269                   fprintf(os, "%s", p->name);
270               }
271           }
272           
273           static const MI_ClassDecl* FindClassDecl(
274 mike  1.1     const MI_SchemaDecl* sd, 
275               const char* className)
276           {
277               for (MI_Uint32 i = 0; i < sd->numClassDecls; i++)
278               {
279                   const MI_ClassDecl* p = sd->classDecls[i];
280           
281                   if (strcmp(p->name, className) == 0)
282                       return p;
283               }
284           
285               return 0;
286           }
287           
288           static void GenClassLine(
289               FILE* os, 
290               const MI_SchemaDecl* sd, 
291               const MI_ClassDecl* cd)
292           {
293               // Print the class path: CLASS1.CLASS2.CLASS3
294               fprintf(os, "CLASS=");
295 mike  1.1     PrintClassPath(os, cd);
296           
297               // Print the association classes:
298               if (cd->flags & MI_FLAG_ASSOCIATION)
299               {
300                   fprintf(os, "{");
301           
302                   MI_Uint32 n = 0;
303           
304                   for (MI_Uint32 i = 0; i < cd->numProperties; i++)
305                   {
306                       const MI_PropertyDecl* pd = cd->properties[i];
307           
308                       if (pd->type == MI_REFERENCE && pd->className)
309                       {
310                           const MI_ClassDecl* rcd = FindClassDecl(sd, pd->className);
311           
312                           if (!rcd)
313                               err("failed to find class: %s", pd->className);
314           
315                           if (n != 0)
316 mike  1.1                     fprintf(os, ",");
317                           PrintClassPath(os, rcd);
318                           n++;
319                       }
320                   }
321           
322                   fprintf(os, "}");
323               }
324           
325               fprintf(os, "\n");
326           }
327           
328           static MI_Module* LoadModule(const char* path)
329           {
330               const char FUNC[] = "MI_Main";
331           
332               // Load the library:
333               void* handle = Lib_Open(path);
334               if (!handle)
335               {
336                   char* msg = Lib_Err();
337 mike  1.1         err("failed to load library: %s\n", msg);
338                   Lib_Free(msg);
339               }
340           
341               // Load the MI_Main() entry point:
342               void* sym = Lib_Sym(handle, FUNC);
343               if (!sym)
344               {
345                   err("failed to find symbol '%s' in library '%s'\n", FUNC, path);
346               }
347           
348               // Call MI_Main() to get MI_Module object.
349               MainProc main = (MainProc)sym;
350               MI_Module* module = (*main)(NULL);
351               if (!module)
352               {
353                   err("%s:%s() failed", path, FUNC);
354               }
355           
356               // Check character size:
357               if (module->charSize != sizeof(MI_Char))
358 mike  1.1     {
359                   err("provider char size (%u) does not match %s char size (%u)", 
360                       module->charSize, arg0, (int)sizeof(MI_Char));
361               }
362           
363               return module;
364           }
365           
366           static void GenRegFile(
367               FILE* os, 
368               int argc, 
369               const char** argv, 
370               const string& baseName,
371               MI_Module* module,
372               const Options& opts)
373           {
374               // Get schemaDecl:
375               MI_SchemaDecl* sd = module->schemaDecl;
376               if (!sd)
377               {
378                   err("MI_Module.schemaDecl is null");
379 mike  1.1     }
380           
381               // Generate header line.
382               fprintf(os, "# ");
383               for (int i = 0; i < argc; i++)
384               {
385                   string arg;
386           
387                   if (i == 0)
388                       arg = BaseName(argv[i]);
389                   else
390                       arg = argv[i];
391           
392                   fprintf(os, "%s", arg.c_str());
393                   if (i + 1 != argc)
394                       fprintf(os, " ");
395               }
396               fprintf(os, "\n");
397           
398               // Write library name:
399               fprintf(os, "LIBRARY=%s\n", baseName.c_str());
400 mike  1.1 
401               // Hosting
402               if (!opts.hosting.empty())
403               {
404                   fprintf(os, "HOSTING=%s\n", opts.hosting.c_str());
405               }
406           
407               // Find providers:
408               for (MI_Uint32 i = 0; i < sd->numClassDecls; i++)
409               {
410                   const MI_ClassDecl* cd = sd->classDecls[i];
411           
412                   if (!cd)
413                       err("null classDecl element");
414           
415                   // If it has a provider, print the class line.
416                   if (cd->providerFT)
417                   {
418                       GenClassLine(os, sd, cd);
419                   }
420               }
421 mike  1.1 }
422           
423           static bool Inhale(const char* path, vector<char>& data)
424           {
425               FILE* is = Fopen(path, "r");
426           
427               if (!is)
428                   return false;
429           
430               size_t n;
431               char buf[4096];
432           
433               while ((n = fread(buf, 1, sizeof(buf), is)) != 0)
434               {
435                   data.insert(data.end(), buf, buf + n);
436               }
437           
438               data.push_back('\0');
439           
440               fclose(is);
441           
442 mike  1.1     return true;
443           }
444           
445           static void _RefreshServer()
446           {
447               // check if server is running
448               mi::Client cl;
449               const MI_Uint64 TIMEOUT = 500 * 1000;
450           
451               if (cl.Connect(GetPath(ID_SOCKETFILE), MI_T(""), MI_T(""), TIMEOUT))
452               {
453                   // reload server's config
454                   pid_t child = fork();
455                   if (!child)
456                   {
457                       execl(GetPath(ID_SERVERPROGRAM), GetPath(ID_SERVERPROGRAM), "-r",
458                           NULL );
459                       exit(1); // never get here... if everything is ok
460                   }
461                   else if (child > 0)
462                   {
463 mike  1.1             /* wait for child */
464                       int s;
465                       waitpid(child, &s, 0);
466                   }
467           
468                   // wait until it restarts
469                   cl.NoOp(TIMEOUT);
470           
471                   // wait for server to restart
472                   for ( int i = 0; i < 30; i++ )
473                   {
474                       if (cl.Connect(GetPath(ID_SOCKETFILE), MI_T(""), MI_T(""), TIMEOUT))
475                           break;
476           
477                       Time_Sleep(50);
478                   }
479               }
480           }
481           
482           int main(int argc, const char** argv)
483           {
484 mike  1.1     arg0 = argv[0];
485           
486               // Get --destdir command-line option.
487               GetCommandLineDestDirOption(&argc, argv);
488           
489               // Get command-line options.
490               Options opts;
491               GetCommandLineOptions(argc, argv, opts);
492           
493               if (opts.nsDirs.size() == 0)
494               {
495                   string ns = CONFIG_NAMESPACE;
496           
497                   for (size_t i = 0; i < ns.size(); i++)
498                   {
499                       if (ns[i] == '/')
500                           ns[i] = '#';
501                   }
502           
503                   ns = string(GetPath(ID_REGISTERDIR)) + string("/") + ns;
504                   opts.nsDirs.push_back(ns);
505 mike  1.1     }
506           
507               // Check arguments.
508               if (opts.help)
509               {
510                   fprintf(stderr, USAGE, arg0);
511                   exit(1);
512               }
513               
514               // Check number of arguments.
515               if (argc != 2)
516               {
517                   fprintf(stderr, "Usage: %s PROVIDERLIBRARY\n", arg0);
518                   fprintf(stderr, "Try '%s --help' for help\n\n", arg0);
519                   exit(1);
520               }
521           
522               // Check that namespace directories are writable.
523               for (size_t i = 0; i < opts.nsDirs.size(); i++)
524               {
525                   const string path = opts.nsDirs[i];
526 mike  1.1 
527                   if (!Isdir(path.c_str()))
528                       err("no such namespace directory: %s", path.c_str());
529           
530                   if (access(path.c_str(), W_OK) != 0)
531                       err("namespace directory is not writable: %s", path.c_str());
532               }
533           
534           #ifdef CONFIG_OS_HPUX
535               // HP is the only platform that locks loaded binary files 
536               // so if provider is already loaded unlink/copy will fail 
537               // force server to unload all providers before copying
538               _RefreshServer();
539           #endif
540           
541               // Copy library to provider directory (avoid copy if file is identical
542               // since the path could be the same).
543               {
544                   vector<char> data1;
545           
546                   if (!Inhale(argv[1], data1))
547 mike  1.1             err("cannot read provider library: %s", argv[1]);
548           
549                   string path = GetPath(ID_PROVIDERDIR);
550                   path += "/";
551                   path += Basename(argv[1]);
552           
553                   if (opts.devmode)
554                   {
555                       unlink(path.c_str());
556                       if (symlink(argv[1], path.c_str()) != 0)
557                           err("failed to symlink '%s' to '%s'", argv[1], path.c_str());
558                   }
559                   else
560                   {
561                       if (File_Copy(argv[1], path.c_str()) != 0)
562                           err("failed to copy '%s' to '%s'", argv[1], path.c_str());
563           
564                       // set mod explicitly
565                       // w by owner only; RX for all.
566                       chmod(path.c_str(), 
567                           S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
568 mike  1.1 
569                       printf("Created %s\n", path.c_str());
570                   }
571               }
572           
573               // Load module:
574               MI_Module* module = LoadModule(argv[1]);
575               if (!module)
576                   err("failed to load provider library: %s", argv[1]);
577           
578               // Generate .reg file in each namespace directory:
579               for (size_t i = 0; i < opts.nsDirs.size(); i++)
580               {
581                   // Open output file (using basename of library):
582                   string baseLibName = BaseLibName(argv[1]);
583                   string regFileName = baseLibName + ".reg";
584           
585                   string path = opts.nsDirs[i];
586                   path += "/";
587                   path += regFileName;
588           
589 mike  1.1         FILE* os = fopen(path.c_str(), "wb");
590           
591                   if (!os)
592                       err("failed to open: %s", path.c_str());
593           
594                   // Generate the registration file.
595                   GenRegFile(os, argc, argv, baseLibName, module, opts);
596           
597                   printf("Created %s\n", path.c_str());
598           
599                   fclose(os);
600               }
601           
602               // ask server to re-read configuration
603               _RefreshServer();
604           
605               return 0;
606           }

ViewCVS 0.9.2