BUG#: 4594
[tpot/pegasus/.git] / src / Pegasus / DynListener / Service / cimlistener.cpp
1 //%2005////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
6 // IBM Corp.; EMC Corporation, The Open Group.
7 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
9 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining a copy
13 // of this software and associated documentation files (the "Software"), to
14 // deal in the Software without restriction, including without limitation the
15 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
16 // sell copies of the Software, and to permit persons to whom the Software is
17 // furnished to do so, subject to the following conditions:
18 //
19 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
20 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
21 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
22 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
23 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 //==============================================================================
29 //
30 // Author: Mike Brasher (mbrasher@bmc.com)
31 //
32 // Modified By: Mike Day (mdday@us.ibm.com)
33 //              Karl Schopmeyer (k.schopmeyer@opengroup.org)
34 //              Nag Boranna (nagaraja_boranna@hp.com)
35 //              Jenny Yu (jenny_yu@hp.com)
36 //              Sushma Fernandes (sushma_fernandes@hp.com)
37 //              Carol Ann Krug Graves, Hewlett-Packard Company
38 //                  (carolann_graves@hp.com)
39 //              Yi Zhou, Hewlett-Packard Company (yi_zhou@hp.com)
40 //              Dave Rosckes (rosckes@us.ibm.com)
41 //              Humberto Rivero (hurivero@us.ibm.com)
42 //              Steve Hills (steve.hills@ncr.com)
43 //              Amit K Arora, IBM (amitarora@in.ibm.com) - pep 167
44 //              Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) - Bug#2555
45 //              Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) - Bug#2032
46 //              Heather Sterling, IBM (hsterl@us.ibm.com) - PEP#197 CIMListener,
47 //                      PEP#222 Service Refactoring
48 //              Amit K Arora, IBM (amita@in.ibm.com) Bug#3028
49 //              David Dillard, VERITAS Software Corp.
50 //                  (david.dillard@veritas.com)
51 //
52 //%/////////////////////////////////////////////////////////////////////////////
53
54
55 //////////////////////////////////////////////////////////////////////
56 //
57 // Notes on deamon operation (Unix) and service operation (Win 32):
58 //
59 // To run pegasus listener as a daemon on Unix platforms:
60 //
61 // cimlistener
62 //
63 // To NOT run pegasus listener as a daemon on Unix platforms:
64 //
65 // cimlistener --nodaemon
66 //
67 // The daemon setting has no effect on windows operation.
68 //
69 // To shutdown pegasus listener, use the -s option:
70 //
71 // cimlistener -s
72 //
73 // To run pegasus listener as an NT service, there are FOUR  different possibilities:
74 //
75 // To INSTALL the Pegasus service,
76 //
77 // cimlistener -install
78 //
79 // To REMOVE the Pegasus service,
80 //
81 // cimlistener -remove
82 //
83 // To START the Pegasus service,
84 //
85 // net start cimlistener
86 // or
87 // cimlistener -start
88 //
89 // To STOP the Pegasus service,
90 //
91 // net stop cimlistener
92 // or
93 // cimlistener -stop
94 //
95 // Alternatively, you can use the windows service manager. Pegasus listener shows up
96 // in the service database as "Pegasus CIM Listener"
97 //
98 // Mike Day, mdday@us.ibm.com
99 //
100 //////////////////////////////////////////////////////////////////////
101
102
103 #include <Pegasus/Common/Config.h>
104 #include <Pegasus/Common/Constants.h>
105 #include <Pegasus/Common/PegasusAssert.h>
106 #include <cstdlib>
107 #include <Pegasus/Common/FileSystem.h>
108 #include <Pegasus/Common/Logger.h>
109 #include <Pegasus/Common/System.h>
110 #include <Pegasus/Common/Tracer.h>
111 #include <Pegasus/Common/Thread.h>
112 #include <Pegasus/Common/LanguageParser.h>
113 #include <Pegasus/Common/PegasusVersion.h>
114 #include <Pegasus/DynListener/DynamicListener.h>
115 #include <Pegasus/DynListener/DynamicListenerConfig.h>
116 #include <Service/ServerProcess.h>
117
118 PEGASUS_USING_PEGASUS;
119 PEGASUS_USING_STD;
120
121 #define PEGASUS_LISTENER_PROCESS_NAME "cimlistener";
122
123 //Windows service variables are not defined elsewhere in the product
124 //enable ability to override these
125 #ifndef PEGASUS_LISTENER_PRODUCT_NAME
126 #define PEGASUS_LISTENER_PRODUCT_NAME "CIM Listener"
127 #endif
128 #ifndef PEGASUS_LISTENER_SERVICE_NAME
129 #define PEGASUS_LISTENER_SERVICE_NAME "Pegasus CIM Listener"
130 #endif
131 #ifndef PEGASUS_LISTENER_SERVICE_DESCRIPTION
132 #define PEGASUS_LISTENER_SERVICE_DESCRIPTION "Pegasus CIM Listener Service"
133 #endif
134
135 //The start file is created as soon the child forks and notifies the parent.
136 //This file is used to detect whether the cimserver is running and thus,
137 //it must exist until right before the child process exits.
138 #ifndef LISTENER_START_FILE
139 #define LISTENER_START_FILE "/tmp/cimlistener_start.conf"
140 #endif
141 //The stop file is created to signal the cimserver to shutdown.
142 //We cannot use the earlier file and delete it to "signal shutdown"
143 //because then another cimserver process could be started while we
144 //were still shutting down.  This is a workaround for the fact that
145 //signals are not implemented on all platforms.  Theoretically,
146 //we should be blocking until the calling process signalled the child
147 //to shutdown.
148 #ifndef LISTENER_STOP_FILE
149 #define LISTENER_STOP_FILE "/tmp/cimlistener_stop.conf"
150 #endif
151
152 class CIMListenerProcess : public ServerProcess
153 {
154 public:
155
156     CIMListenerProcess(void)
157     {
158         cimserver_set_process(this);
159     }
160
161     virtual ~CIMListenerProcess(void)
162     {
163     }
164
165     virtual const char* getProductName() const
166     {
167         return PEGASUS_LISTENER_PRODUCT_NAME;
168     }
169
170     virtual const char* getExtendedName() const
171     {
172         return PEGASUS_LISTENER_SERVICE_NAME;
173     }
174
175     virtual const char* getDescription() const
176     {
177         return PEGASUS_LISTENER_SERVICE_DESCRIPTION;
178     }
179
180     //defined in PegasusVersion.h
181     virtual const char* getVersion() const
182     {
183         return PEGASUS_PRODUCT_VERSION;
184     }
185
186     virtual const char* getProcessName() const
187     {
188         return PEGASUS_LISTENER_PROCESS_NAME;
189     }
190
191     virtual const char* getPIDFileName() const
192     {
193         return LISTENER_START_FILE;
194     }
195
196     int cimserver_run(int argc, char** argv, bool shutdownOption);
197
198     void cimserver_stop(void);
199 };
200
201 AutoPtr<CIMListenerProcess> _cimListenerProcess(new CIMListenerProcess());
202 AutoPtr<DynamicListenerConfig> configManager(DynamicListenerConfig::getInstance());
203 static DynamicListener* _cimListener = 0;
204
205
206 //
207 //  The command name.
208 //
209 static const char COMMAND_NAME []    = "cimlistener";
210
211 //
212 //  The constant defining usage string.
213 //
214 static const char USAGE []           = "Usage: ";
215
216 /**
217 Constants representing the command line options.
218 */
219 static const char OPTION_VERSION     = 'v';
220
221 static const char OPTION_HELP        = 'h';
222
223 static const char OPTION_HOME        = 'D';
224
225 static const char OPTION_SHUTDOWN    = 's';
226
227 static const char OPTION_NO_DAEMON [] = "--nodaemon";
228
229 static const char   LONG_HELP []  = "help";
230
231 static const char   LONG_VERSION []  = "version";
232
233 #if defined(PEGASUS_OS_HPUX)
234 static const char OPTION_BINDVERBOSE = 'X';
235 #endif
236
237 static const String PROPERTY_TIMEOUT = "shutdownTimeout";
238
239 static const String DEFAULT_CONFIG_FILE = "cimlistener.conf";
240
241
242 /* PrintHelp - This is temporary until we expand the options manager to allow
243    options help to be defined with the OptionRow entries and presented from
244    those entries.
245 */
246 void PrintHelp(const char* arg0)
247 {
248     String usage = String (USAGE);
249     usage.append (COMMAND_NAME);
250     usage.append (" [ [ options ] ]\n");
251     usage.append ("  options\n");
252     usage.append ("    -v, --version   - displays CIM Listener version number\n");
253     usage.append ("    -h, --help      - prints this help message\n");
254     usage.append ("    -s              - shuts down CIM Listener\n");
255     usage.append ("    -D [home]       - sets pegasus home directory\n");
256 #if defined(PEGASUS_OS_TYPE_WINDOWS)
257     usage.append ("    -install [name] - installs pegasus as a Windows Service\n");
258     usage.append ("                      [name] is optional and overrides the\n");
259     usage.append ("                      default CIM Listener Service Name\n");
260     usage.append ("    -remove [name]  - removes pegasus as a Windows Service\n");
261     usage.append ("                      [name] is optional and overrides the\n");
262     usage.append ("                      default CIM Listener Service Name\n");
263     usage.append ("    -start [name]   - starts pegasus as a Windows Service\n");
264     usage.append ("                      [name] is optional and overrides the\n");
265     usage.append ("                      default CIM Listener Service Name\n");
266     usage.append ("    -stop [name]    - stops pegasus as a Windows Service\n");
267     usage.append ("                      [name] is optional and overrides the\n");
268     usage.append ("                      default CIM Listener Service Name\n\n");
269 #endif
270 #if !defined(PEGASUS_OS_TYPE_WINDOWS)
271     usage.append ("    --nodaemon       - do NOT run as a daemon\n");
272 #endif
273
274     cout << endl;
275     cout << _cimListenerProcess->getProductName() << " " << _cimListenerProcess->getVersion() << endl;
276     cout << endl;
277
278 //ATTN: Add menu items to Server bundle for listener
279 /*#if defined(PEGASUS_OS_TYPE_WINDOWS)
280     MessageLoaderParms parms("src.Server.cimserver.MENU.WINDOWS", usage);
281 #elif defined(PEGASUS_OS_USE_RELEASE_DIRS)
282     MessageLoaderParms parms("src.Server.cimserver.MENU.HPUXLINUXIA64GNU", usage);
283 #else
284     MessageLoaderParms parms("src.Server.cimserver.MENU.STANDARD", usage);
285 #endif
286     cout << MessageLoader::getMessage(parms) << endl;
287 */
288     cout << usage;
289 }
290
291 // l10n
292 //
293 // Dummy function for the Thread object associated with the initial thread.
294 // Since the initial thread is used to process CIM requests, this is
295 // needed to localize the exceptions thrown during CIM request processing.
296 // Note: This function should never be called!
297 //
298 PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL dummyThreadFunc(void *parm)
299 {
300    return((PEGASUS_THREAD_RETURN)0);
301 }
302
303
304
305
306 /////////////////////////////////////////////////////////////////////////
307 //  MAIN
308 //////////////////////////////////////////////////////////////////////////
309 int main(int argc, char** argv)
310 {
311     String pegasusHome  = String::EMPTY;
312     Boolean shutdownOption = false;
313
314 //l10n
315 // Set Message loading to process locale
316 MessageLoader::_useProcessLocale = true;
317 //l10n
318
319 //l10n
320 #if defined(PEGASUS_OS_AIX) && defined(PEGASUS_HAS_MESSAGES)
321 setlocale(LC_ALL, "");
322 #endif
323
324 #ifdef PEGASUS_OS_OS400
325
326   VFYPTRS_INCDCL;               // VFYPTRS local variables
327
328   // verify pointers
329   #pragma exception_handler (qsyvp_excp_hndlr,qsyvp_excp_comm_area,\
330     0,_C2_MH_ESCAPE)
331     for( int arg_index = 1; arg_index < argc; arg_index++ ){
332     VFYPTRS(VERIFY_SPP_NULL(argv[arg_index]));
333     }
334   #pragma disable_handler
335
336     // Convert the args to ASCII
337     for(Uint32 i = 0;i< argc;++i)
338     {
339     EtoA(argv[i]);
340     }
341
342     // Initialize Pegasus home to the shipped OS/400 directory.
343     pegasusHome = OS400_DEFAULT_PEGASUS_HOME;
344 #endif
345
346
347 #ifndef PEGASUS_OS_TYPE_WINDOWS
348     //
349     // Get environment variables:
350     //
351 #ifdef PEGASUS_OS_OS400
352 #pragma convert(37)
353     const char* tmp = getenv("PEGASUS_HOME");
354 #pragma convert(0)
355     char home[256] = {0};
356     if (tmp && strlen(tmp) < 256)
357     {
358     strcpy(home, tmp);
359     EtoA(home);
360     pegasusHome = home;
361     }
362 #else
363   #if defined(PEGASUS_OS_AIX) && defined(PEGASUS_USE_RELEASE_DIRS)
364     pegasusHome = AIX_RELEASE_PEGASUS_HOME;
365   #elif !defined(PEGASUS_USE_RELEASE_DIRS)
366     const char* tmp = getenv("PEGASUS_HOME");
367
368     if (tmp)
369     {
370         pegasusHome = tmp;
371     }
372   #endif
373 #endif
374
375     FileSystem::translateSlashes(pegasusHome);
376 #else
377
378   // windows only
379         char exeDir[MAX_PATH];
380         HMODULE hExe = GetModuleHandle(NULL);
381         GetModuleFileName(hExe, exeDir, sizeof(exeDir));
382         *strrchr(exeDir, '\\') = '\0';
383         pegasusHome = String(exeDir);
384
385 #endif
386
387         // Get help, version, and shutdown options
388
389         for (int i = 1; i < argc; )
390         {
391             const char* arg = argv[i];
392             if(String::equal(arg,"--help"))
393             {
394                     PrintHelp(argv[0]);
395                     exit(0);
396             }
397             else if(String::equal(arg,"--version"))
398             {
399                 cout << _cimListenerProcess->getVersion() << endl;
400                 exit(0);
401             }
402             // Check for -option
403             else if (*arg == '-')
404             {
405                 // Get the option
406                 const char* option = arg + 1;
407
408                 //
409                 // Check to see if user asked for the version (-v option):
410                 //
411                 if (*option == OPTION_VERSION &&
412                     strlen(option) == 1)
413                 {
414                     cout << _cimListenerProcess->getVersion() << endl;
415                     exit(0);
416                 }
417                 //
418                 // Check to see if user asked for help (-h option):
419                 //
420                 else if (*option == OPTION_HELP &&
421                         (strlen(option) == 1))
422                 {
423                     PrintHelp(argv[0]);
424                     exit(0);
425                 }
426 #if !defined(PEGASUS_USE_RELEASE_DIRS)
427                 else if (*option == OPTION_HOME &&
428                         (strlen(option) == 1))
429                 {
430                     if (i + 1 < argc)
431                     {
432                         pegasusHome.assign(argv[i + 1]);
433                     }
434                     else
435                     {
436                         //l10n
437                         //cout << "Missing argument for option -" << option << endl;
438                         String opt(option);
439                         MessageLoaderParms parms("src.Server.cimserver.MISSING_ARGUMENT",
440                                          "Missing argument for option -$0",
441                                          opt);
442                         cout << MessageLoader::getMessage(parms) << endl;
443                         exit(0);
444                     }
445
446                     memmove(&argv[i], &argv[i + 2], (argc-i-1) * sizeof(char*));
447                     argc -= 2;
448                 }
449 #endif
450 #if defined(PEGASUS_OS_HPUX)
451                 //
452                 // Check to see if user asked for the version (-X option):
453                 //
454                 if (*option == OPTION_BINDVERBOSE &&
455                         (strlen(option) == 1))
456                 {
457             System::bindVerbose = true;
458                     //l10n
459                     //cout << "Unsupported debug option, BIND_VERBOSE, enabled."
460                          //<< endl;
461                     MessageLoaderParms parms("src.Server.cimserver.UNSUPPORTED_DEBUG_OPTION",
462                                          "Unsupported debug option, BIND_VERBOSE, enabled.");
463                     cout << MessageLoader::getMessage(parms) << endl;
464                     // remove the option from the command line
465                     memmove(&argv[i], &argv[i + 1], (argc-i) * sizeof(char*));
466                     argc--;
467                 }
468 #endif
469                 //
470                 // Check to see if user asked for shutdown (-s option):
471                 //
472                 else if (*option == OPTION_SHUTDOWN &&
473                         (strlen(option) == 1))
474                 {
475                     //
476                     // Check to see if shutdown has already been specified:
477                     //
478                     if (shutdownOption)
479                     {
480                         //l10n
481                         //cout << "Duplicate shutdown option specified." << endl;
482                         MessageLoaderParms parms("DynListener.cimlistener.DUPLICATE_SHUTDOWN_OPTION",
483                                                  "Duplicate shutdown option specified.");
484
485                         cout << MessageLoader::getMessage(parms) << endl;
486                         exit(0);
487                     }
488
489                     shutdownOption = true;
490
491                     // remove the option from the command line
492                     memmove(&argv[i], &argv[i + 1], (argc-i) * sizeof(char*));
493                     argc--;
494                 }
495                 else
496                     i++;
497             }
498             else
499                 i++;
500         }
501
502     //
503     // Set the value for pegasusHome property
504     //
505     DynamicListenerConfig::setListenerHome(pegasusHome);
506
507     //
508     // Do the plaform specific run
509     //
510
511     return _cimListenerProcess->platform_run( argc, argv, shutdownOption );
512 }
513
514 void CIMListenerProcess::cimserver_stop()
515 {
516     _cimListener->stop();
517 }
518
519 //
520 // The main, common, running code
521 //
522 // NOTE: Do NOT call exit().  Use return(), otherwise some platforms
523 // will fail to shutdown properly/cleanly.
524 //
525 // TODO: Current change minimal for platform "service" shutdown bug fixes.
526 // Perhpas further extract out common stuff and put into main(), put
527 // daemon stuff into platform specific platform_run(), etc.
528 // Note: make sure to not put error handling stuff that platform
529 // specific runs may need to deal with bettter (instead of exit(), etc).
530 //
531
532 int CIMListenerProcess::cimserver_run( int argc, char** argv, Boolean shutdownOption )
533 {
534     String logsDirectory = String::EMPTY;
535         String homeDir = configManager->getListenerHome();
536
537     //
538     // Get an instance of the Config Manager.
539     //
540     //configManager = DynamicListenerConfig::getInstance();
541
542     //
543     // Check to see if we should Pegasus as a daemon
544     //
545     Boolean daemonOption;
546 #if defined(PEGASUS_OS_TYPE_WINDOWS)
547     daemonOption = false;
548 #else
549     daemonOption = true;
550     for (int i=1; i < argc; i++)
551     {
552         if (strcmp(argv[i], OPTION_NO_DAEMON) == 0)
553         {
554             daemonOption = false;
555             break;
556         }
557     }
558 #endif
559
560 #ifdef PEGASUS_OS_OS400
561     // In a special startup case for IBM OS400, when the server is
562     // automatically started when the machine starts up the config
563     // file cannot be read because of access restrictions for the
564     // user starting the server.  In this case, we need to skip
565     // reading the config options and therefore any use of the config
566     // manager also.  To make this determinations we will check to see
567     // if the daemon flag is set to true.  If so, then there will be a
568     // series of checks to bracket all the calls to the configManager
569     // which would otherwise fail.  All this will only be done for
570     // IBM OS400.
571
572     Boolean os400StartupOption = daemonOption ? true : false;
573 #endif
574
575     //
576     // Get options (from command line and from configuration file); this
577     // removes corresponding options and their arguments from the command
578     // line.
579     //
580     try
581     {
582 #ifdef PEGASUS_OS_OS400
583     if (os400StartupOption == false)
584 #endif
585                 String configFilePath = homeDir + "/" + DEFAULT_CONFIG_FILE;
586                 FileSystem::translateSlashes(configFilePath);
587         configManager->initOptions(configFilePath);
588     }
589     catch (Exception& e)
590     {
591         Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, Logger::SEVERE,
592             "src.Server.cimserver.SERVER_NOT_STARTED",
593             "cimserver not started:  $0", e.getMessage());
594
595 #if !defined(PEGASUS_OS_OS400)
596         MessageLoaderParms parms("DynListener.cimlistener.LISTENER_NOT_STARTED",
597                                  "CIM Listener not started: $0", e.getMessage());
598
599         PEGASUS_STD(cerr) << argv[0] << ": " << MessageLoader::getMessage(parms)
600             << PEGASUS_STD(endl);
601 #endif
602
603         return(1);
604     }
605
606 // l10n
607     // Set the home directory, msg sub-dir, into the MessageLoader.
608     // This will be the default directory where the resource bundles
609     // are found.
610         String msgHome = homeDir + "/msg";
611         FileSystem::translateSlashes(msgHome);
612         MessageLoader::setPegasusMsgHome(msgHome);
613
614     //
615     // Check to see if we need to shutdown CIMOM
616     //
617     if (shutdownOption)
618     {
619         //gracefully exit
620         //Uncomment the following line when signals are implemented on all platforms.
621         //The workaround is to use a file.
622         //cimserver_kill(1);
623
624 #if defined(PEGASUS_OS_HPUX) || defined(PEGASUS_OS_LINUX) || defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) \
625     || defined(PEGASUS_OS_AIX) || defined(PEGASUS_OS_SOLARIS) \
626     || defined(PEGASUS_OS_VMS)
627
628         // Check to see if the CIM Listener is running. No need to stop if not running.
629         if(_cimListenerProcess->isCIMServerRunning())
630         {
631             // remove the old file if it exists
632             System::removeFile(LISTENER_STOP_FILE);
633
634             // open the file
635             FILE *pid_file = fopen(LISTENER_STOP_FILE, "w");
636
637             if (pid_file)
638             {
639                 // save the pid in the file
640                 fprintf(pid_file, "%ld\n", _cimListenerProcess->get_server_pid());
641                 fclose(pid_file);
642             }
643         } else {
644             printf("CIM Listener may not be running.\n");
645             return(0);
646         }
647 #endif
648
649 #ifdef PEGASUS_OS_OS400
650     //l10n
651     //Logger::put(Logger::ERROR_LOG, System::CIMSERVER, Logger::INFORMATION,
652         //"CIM Server stopped.");
653     Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, Logger::INFORMATION,
654         "src.Server.cimserver.SERVER_STOPPED",
655         "CIM Server stopped.");
656         cimserver_exitRC(0);
657 #else
658         //l10n
659         //cout << "CIM Server stopped." << endl;
660         MessageLoaderParms parms("DynListener.cimlistener.LISTENER_STOPPED",
661                                  "CIM Listener stopped.");
662         cout << MessageLoader::getMessage(parms) << endl;
663         return(0);
664 #endif
665     }
666
667         //get config options.  note that the paths will be converted to homedPaths in the lookup calls.
668     Uint32 listenerPort;
669     Boolean httpsConnection;
670     String sslKeyFilePath;
671     String sslCertificateFilePath;
672     String consumerDir;
673     String consumerConfigDir;
674     Boolean enableConsumerUnload;
675     Uint32 consumerIdleTimeout;
676     Uint32 shutdownTimeout;
677     String traceFile;
678     Uint32 traceLevel;
679     String traceComponents;
680
681 #ifdef PEGASUS_OS_OS400
682     if (os400StartupOption)
683     {
684         //set fixed values for OS400
685         listenerPort = 5999;
686         httpsConnection = false;
687         sslKeyFilePath = "";
688         sslCertificateFilePath = "";
689         consumerDir = "";
690         consumerConfigDir = "";
691         enableConsumerUnload = false;
692         consumerIdleTimeout = 0;
693         shutdownTimeout = 10;
694         traceFile = "cimlistener.trc";
695         traceLevel = 0;
696         traceComponents = "LISTENER";
697     } else
698     {
699 #endif
700         try
701     {
702     configManager->lookupIntegerValue("listenerPort", listenerPort);
703     httpsConnection = configManager->isTrue("enableHttpsListenerConnection");
704     configManager->lookupValue("sslKeyFilePath", sslKeyFilePath);
705     configManager->lookupValue("sslCertificateFilePath", sslCertificateFilePath);
706     configManager->lookupValue("consumerDir", consumerDir);
707     configManager->lookupValue("consumerConfigDir", consumerConfigDir);
708     enableConsumerUnload = configManager->isTrue("enableConsumerUnload");
709     configManager->lookupIntegerValue("consumerIdleTimeout", consumerIdleTimeout);
710     configManager->lookupIntegerValue("consumerIdleTimeout", consumerIdleTimeout);
711     configManager->lookupIntegerValue("shutdownTimeout", shutdownTimeout);
712     configManager->lookupValue("traceFilePath", traceFile);
713     configManager->lookupIntegerValue("traceLevel", traceLevel);
714     configManager->lookupValue("traceComponents", traceComponents);
715
716         } catch (Exception& ex)
717         {
718                 MessageLoaderParms parms("src.Server.cimserver.INVALID_CONFIG_OPTION",
719                                                                  "Invalid configuration option: $0",
720                                                                  ex.getMessage());
721                 cout << MessageLoader::getMessage(parms) << endl;
722                 exit(0);
723         }
724 #ifdef PEGASUS_OS_OS400
725     }
726 #endif
727
728     //Check listener port validity
729     //ATTN: Do we need this?
730     /*CString portString = listenerPort.getCString();
731     char* end = 0;
732     Uint32 port = strtol(portString, &end, 10);
733     if(!(end != 0 && *end == '\0'))
734     {
735         PEGASUS_STD(cerr) << "Bad HTTP/HTTPS Port Value" << PEGASUS_STD(endl);
736         exit(1);
737     }*/
738
739     //Configure trace options
740     if (traceLevel > 0)
741     {
742         Uint32 traceLevelArg = 0;
743
744         switch (traceLevel)
745         {
746         case 1: traceLevelArg = Tracer::LEVEL1; break;
747         case 2: traceLevelArg = Tracer::LEVEL2; break;
748         case 3: traceLevelArg = Tracer::LEVEL3; break;
749         case 4: traceLevelArg = Tracer::LEVEL4; break;
750         default: break;
751         }
752
753         Tracer::setTraceFile((const char*)traceFile.getCString());
754         Tracer::setTraceComponents(traceComponents);
755         Tracer::setTraceLevel(traceLevelArg);
756     }
757 #if defined(PEGASUS_DEBUG)
758     // Put out startup up message.
759     cout << _cimListenerProcess->getProductName() << " " << _cimListenerProcess->getVersion() << endl;
760     //l10n
761     //cout << "Built " << __DATE__ << " " << __TIME__ << endl;
762     //cout <<"Starting..."
763     MessageLoaderParms parms("DynListener.cimlistener.STARTUP_MESSAGE",
764                              "CIM Listener built $0 $1\nCIM Listener starting...",
765                              __DATE__,
766                              __TIME__);
767 #endif
768
769 //l10n
770 // reset message loading to NON-process locale
771 MessageLoader::_useProcessLocale = false;
772 //l10n
773
774     // Get the parent's PID before forking
775     _cimListenerProcess->set_parent_pid(System::getPID());
776
777     // do we need to run as a daemon ?
778     if (daemonOption)
779     {
780         if(-1 == _cimListenerProcess->cimserver_fork())
781 #ifndef PEGASUS_OS_OS400
782     {
783         return(-1);
784     }
785 #else
786     {
787             return(-1);
788     }
789     else
790     {
791         return(0);
792     }
793 #endif
794
795     }
796
797 // l10n
798     // Now we are after the fork...
799     // Create a dummy Thread object that can be used to store the
800     // AcceptLanguages object for CIM requests that are serviced
801     // by this thread (initial thread of server).  Need to do this
802     // because this thread is not in a ThreadPool, but is used
803     // to service CIM requests.
804     // The run function for the dummy Thread should never be called,
805     Thread *dummyInitialThread = new Thread(dummyThreadFunc, NULL, false);
806     Thread::setCurrent(dummyInitialThread);
807     AcceptLanguages default_al;
808     try{
809          default_al = LanguageParser::getDefaultAcceptLanguages();
810          Thread::setLanguages(new AcceptLanguages(default_al));
811     }catch(InvalidAcceptLanguageHeader& e){
812           Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, Logger::SEVERE,
813                   "src.Server.cimserver.FAILED_TO_SET_PROCESS_LOCALE",
814                   "Could not convert the system process locale into a valid AcceptLanguage format.");
815           Logger::put(Logger::ERROR_LOG, System::CIMSERVER, Logger::SEVERE,
816                              e.getMessage());
817     }
818
819
820
821 #ifdef PEGASUS_OS_OS400
822     // Special server initialization code for OS/400.
823     if (_cimListenerProcess->cimserver_initialize() != 0)
824     {
825     // do some logging here!
826     //l10n
827     //Logger::put(Logger::ERROR_LOG, System::CIMSERVER, Logger::SEVERE,
828             //"CIM Server failed to initialize");
829     Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, Logger::SEVERE,
830                   "src.Server.cimserver.SERVER_FAILED_TO_INITIALIZE",
831                   "CIM Server failed to initialize");
832     return(-1);
833     }
834 #endif
835
836
837 #if defined(PEGASUS_OS_HPUX) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) \
838 || defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_OS_AIX) \
839 || defined(PEGASUS_OS_SOLARIS) || defined (PEGASUS_OS_VMS)
840     umask(S_IWGRP|S_IWOTH);
841
842     //
843     // check if CIMServer is already running
844     // if CIMServer is already running, print message and
845     // notify parent process (if there is a parent process) to terminate
846     //
847     if(_cimListenerProcess->isCIMServerRunning())
848     {
849     //l10n
850         //cout << "Unable to start CIMServer." << endl;
851         //cout << "CIMServer is already running." << endl;
852         MessageLoaderParms parms("DynListener.cimlistener.UNABLE_TO_START_LISTENER_ALREADY_RUNNING",
853                                  "Unable to start CIM Listener.\nCIM Listener is already running.");
854     PEGASUS_STD(cerr) << MessageLoader::getMessage(parms) << PEGASUS_STD(endl);
855
856     //
857         // notify parent process (if there is a parent process) to terminate
858         //
859         if (daemonOption)
860                 _cimListenerProcess->notify_parent(1);
861
862         return(1);
863     }
864
865 #endif
866
867     // try loop to bind the address, and run the server
868     try
869     {
870         //ATTN: Need to handle SSL cases
871
872         //create DynListener
873         _cimListener = new DynamicListener(listenerPort,
874                                            consumerDir,
875                                            consumerConfigDir,
876                                            enableConsumerUnload,
877                                            consumerIdleTimeout,
878                                            shutdownTimeout);
879
880         _cimListener->start();
881
882         Logger::put_l(Logger::STANDARD_LOG, System::CIMSERVER, Logger::INFORMATION,
883                 "src.Server.cimserver.LISTENING_ON_PORT",
884                 "Listening on port $0.", listenerPort);
885
886
887
888 #if defined(PEGASUS_DEBUG)
889         //Log startup options
890         printf("Starting CIMListener with the following options\n");
891         printf("\tlistenerPort %d\n", listenerPort);
892         printf("\thttpsConnection %d\n", httpsConnection);
893         printf("\tsslKeyFilePath %s\n", (const char*)sslKeyFilePath.getCString());
894         printf("\tsslCertificateFilePath %s\n", (const char*)sslCertificateFilePath.getCString());
895         printf("\tconsumerDir %s\n", (const char*)consumerDir.getCString());
896         printf("\tconsumerConfigDir %s\n", (const char*)consumerConfigDir.getCString());
897         printf("\tenableConsumerUnload %d\n", enableConsumerUnload);
898         printf("\tconsumerIdleTimeout %d\n", consumerIdleTimeout);
899         printf("\tshutdownTimeout %d\n", shutdownTimeout);
900         printf("\ttraceFilePath %s\n", (const char*)traceFile.getCString());
901         printf("\ttraceLevel %d\n", traceLevel);
902         printf("\ttraceComponents %s\n", (const char*)traceComponents.getCString());
903                 printf("\tMessage home is %s\n", (const char*)msgHome.getCString());
904 #endif
905
906     // notify parent process (if there is a parent process) to terminate
907         // so user knows that there is cimserver ready to serve CIM requests.
908     if (daemonOption)
909         _cimListenerProcess->notify_parent(0);
910
911     time_t last = 0;
912
913 #if defined(PEGASUS_OS_HPUX) || defined(PEGASUS_OS_LINUX) || defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) \
914     || defined(PEGASUS_OS_AIX) || defined(PEGASUS_OS_SOLARIS) \
915     || defined(PEGASUS_OS_VMS)
916         //
917         // create a file to indicate that the cimserver has started and
918         // save the process id of the cimserver process in the file
919         //
920         // remove the old file if it exists
921         System::removeFile(_cimListenerProcess->getPIDFileName());
922
923         // open the file
924         FILE *pid_file = fopen(_cimListenerProcess->getPIDFileName(), "w");
925
926         if (pid_file)
927         {
928             // save the pid in the file
929             fprintf(pid_file, "%ld\n", _cimListenerProcess->get_server_pid());
930             fclose(pid_file);
931         }
932 #endif
933
934 //#if defined(PEGASUS_DEBUG)
935     cout << "Started. " << endl;
936 //#endif
937
938         // Put server started message to the logger
939         Logger::put_l(Logger::STANDARD_LOG, System::CIMSERVER,
940             Logger::INFORMATION,
941             "src.Server.cimserver.STARTED_VERSION",
942             "Started $0 version $1.",
943             _cimListenerProcess->getProductName(), _cimListenerProcess->getVersion());
944
945 #if !defined(PEGASUS_OS_TYPE_WINDOWS)
946
947 #if defined(PEGASUS_DEBUG)
948         printf("Blocking until shutdown signal\n");
949 #endif
950         while (true)
951         {
952             if (FileSystem::exists(LISTENER_STOP_FILE))
953             {
954                 break;
955             }
956
957             pegasus_sleep(500);
958         }
959
960 #if defined(PEGASUS_DEBUG)
961         printf("Received signal to shutdown\n");
962 #endif
963         FileSystem::removeFile(LISTENER_STOP_FILE);
964         _cimListener->stop();
965
966
967         //Uncomment this block of code when signals are implemented on all platforms.
968         //Temporary workaround is to use a file, as specified above.
969         //wait until signalled to terminate
970         /*int sig = _cimListenerProcess->cimserver_wait();
971         printf("Returned from sigwait %d\n", sig);
972
973         if (sig == SIGUSR1)
974         {
975             printf("Graceful shutdown\n");
976             _cimListener->stop();
977         }
978         */
979 #else
980         //ATTN: Implement cimserver_wait for windows so we don't have to loop here
981         //The listener is stopped in the cimserver_stop method by the service control manager
982         while (true)
983         {
984             if (!_cimListener->isAlive())
985             {
986                 break;
987             }
988
989             Sleep(500);
990         }
991 #endif
992
993 #if defined(PEGASUS_DEBUG)
994     PEGASUS_STD(cout) << "Stopped\n";
995 #endif
996
997         //
998         // normal termination
999         //
1000
1001         // Put server shutdown message to the logger
1002         Logger::put_l(Logger::STANDARD_LOG, System::CIMSERVER,
1003             Logger::INFORMATION, "src.Server.cimserver.STOPPED",
1004             "$0 stopped.", _cimListenerProcess->getProductName());
1005
1006 #if defined(PEGASUS_OS_HPUX) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) \
1007 || defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_OS_AIX) \
1008 || defined(PEGASUS_OS_SOLARIS) || defined(PEGASUS_OS_VMS)
1009         //
1010         // close the file created at startup time to indicate that the
1011         // cimserver has terminated normally.
1012         //
1013         FileSystem::removeFile(_cimListenerProcess->getPIDFileName());
1014 #endif
1015     }
1016     catch(Exception& e)
1017     {
1018
1019     //l10n
1020     //Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::WARNING,
1021             //"Error: $0", e.getMessage());
1022     Logger::put_l(Logger::STANDARD_LOG, System::CIMSERVER, Logger::WARNING,
1023             "src.Server.cimserver.ERROR",
1024             "Error: $0", e.getMessage());
1025
1026 #ifndef PEGASUS_OS_OS400
1027     //l10n
1028     //PEGASUS_STD(cerr) << "Error: " << e.getMessage() << PEGASUS_STD(endl);
1029     MessageLoaderParms parms("DynListener.cimlistener.ERROR",
1030                              "CIM Listener error: $0");
1031     PEGASUS_STD(cerr) << MessageLoader::getMessage(parms) << PEGASUS_STD(endl);
1032
1033 #endif
1034
1035     //
1036         // notify parent process (if there is a parent process) to terminate
1037         //
1038         if (daemonOption)
1039                 _cimListenerProcess->notify_parent(1);
1040
1041         if (_cimListener)
1042         {
1043             delete _cimListener;
1044             _cimListener = 0;
1045         }
1046
1047         return 1;
1048     }
1049
1050     if (_cimListener)
1051     {
1052         delete _cimListener;
1053         _cimListener = 0;
1054     }
1055
1056 #if defined(PEGASUS_DEBUG)
1057     printf("Exiting child process\n");
1058 #endif
1059
1060     return 0;
1061 }
1062
1063
1064
1065