Commit | Line | Data |
---|---|---|
9a19737f | 1 | /* |
f4c99d5a VK |
2 | ** NetXMS - Network Management System |
3 | ** Copyright (C) 2003, 2004 NetXMS Team | |
9a19737f VK |
4 | ** |
5 | ** This program is free software; you can redistribute it and/or modify | |
6 | ** it under the terms of the GNU General Public License as published by | |
7 | ** the Free Software Foundation; either version 2 of the License, or | |
8 | ** (at your option) any later version. | |
9 | ** | |
10 | ** This program is distributed in the hope that it will be useful, | |
11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | ** GNU General Public License for more details. | |
14 | ** | |
15 | ** You should have received a copy of the GNU General Public License | |
16 | ** along with this program; if not, write to the Free Software | |
17 | ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | ** | |
19 | ** $module: main.cpp | |
20 | ** | |
21 | **/ | |
22 | ||
23 | #include "nms_core.h" | |
2260ffe5 | 24 | #include <netxmsdb.h> |
78bf9c68 | 25 | |
fb1a5953 VK |
26 | #if !defined(_WIN32) && HAVE_READLINE_READLINE_H |
27 | #include <readline/readline.h> | |
28 | #include <readline/history.h> | |
29 | #define USE_READLINE 1 | |
30 | #endif | |
31 | ||
06e7be2f | 32 | #ifdef _WIN32 |
c9ccd685 AK |
33 | # include <direct.h> |
34 | # include <errno.h> | |
35 | #else | |
36 | # include <sys/stat.h> | |
0fca1cc3 | 37 | # include <signal.h> |
06e7be2f VK |
38 | #endif |
39 | ||
3a2f672c VK |
40 | |
41 | // | |
42 | // Thread functions | |
43 | // | |
44 | ||
ccdbbb52 VK |
45 | THREAD_RESULT THREAD_CALL HouseKeeper(void *pArg); |
46 | THREAD_RESULT THREAD_CALL DiscoveryThread(void *pArg); | |
47 | THREAD_RESULT THREAD_CALL Syncer(void *pArg); | |
48 | THREAD_RESULT THREAD_CALL NodePoller(void *pArg); | |
49 | THREAD_RESULT THREAD_CALL StatusPoller(void *pArg); | |
50 | THREAD_RESULT THREAD_CALL ConfigurationPoller(void *pArg); | |
51 | THREAD_RESULT THREAD_CALL EventProcessor(void *pArg); | |
52 | THREAD_RESULT THREAD_CALL WatchdogThread(void *pArg); | |
53 | THREAD_RESULT THREAD_CALL ClientListener(void *pArg); | |
54 | THREAD_RESULT THREAD_CALL LocalAdminListener(void *pArg); | |
37c4d6aa | 55 | THREAD_RESULT THREAD_CALL SNMPTrapReceiver(void *pArg); |
9a19737f VK |
56 | |
57 | ||
58 | // | |
59 | // Global variables | |
60 | // | |
61 | ||
3e4e127f | 62 | DWORD g_dwFlags = AF_USE_EVENT_LOG; |
4385fa12 VK |
63 | char g_szConfigFile[MAX_PATH] = DEFAULT_CONFIG_FILE; |
64 | char g_szLogFile[MAX_PATH] = DEFAULT_LOG_FILE; | |
9e9d381c VK |
65 | #ifndef _WIN32 |
66 | char g_szPIDFile[MAX_PATH] = "/var/run/netxmsd.pid"; | |
67 | #endif | |
3a2f672c | 68 | DB_HANDLE g_hCoreDB = 0; |
48b1c0ac | 69 | DWORD g_dwDiscoveryPollingInterval; |
f00307b7 | 70 | DWORD g_dwStatusPollingInterval; |
364aa19a | 71 | DWORD g_dwConfigurationPollingInterval; |
06e7be2f | 72 | char g_szDataDir[MAX_PATH]; |
3a2f672c VK |
73 | |
74 | ||
75 | // | |
76 | // Static data | |
77 | // | |
78 | ||
d16cf8a5 | 79 | static CONDITION m_hEventShutdown; |
9a19737f VK |
80 | |
81 | ||
d627ae40 VK |
82 | // |
83 | // Sleep for specified number of seconds or until system shutdown arrives | |
84 | // Function will return TRUE if shutdown event occurs | |
85 | // | |
86 | ||
87 | BOOL SleepAndCheckForShutdown(int iSeconds) | |
88 | { | |
d16cf8a5 | 89 | return ConditionWait(m_hEventShutdown, iSeconds * 1000); |
d627ae40 VK |
90 | } |
91 | ||
92 | ||
06e7be2f VK |
93 | // |
94 | // Check data directory for existence | |
95 | // | |
96 | ||
97 | static BOOL CheckDataDir(void) | |
98 | { | |
99 | char szBuffer[MAX_PATH]; | |
100 | ||
101 | if (chdir(g_szDataDir) == -1) | |
102 | { | |
103 | WriteLog(MSG_INVALID_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", g_szDataDir); | |
104 | return FALSE; | |
105 | } | |
106 | ||
c9ccd685 AK |
107 | #ifdef _WIN32 |
108 | # define MKDIR(name) mkdir(name) | |
109 | #else | |
110 | # define MKDIR(name) mkdir(name, 0700) | |
111 | #endif | |
112 | ||
e641b7d0 VK |
113 | // Create directory for mib files if it doesn't exist |
114 | strcpy(szBuffer, g_szDataDir); | |
115 | strcat(szBuffer, DDIR_MIBS); | |
c9ccd685 | 116 | if (MKDIR(szBuffer) == -1) |
06e7be2f VK |
117 | if (errno != EEXIST) |
118 | { | |
119 | WriteLog(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer); | |
120 | return FALSE; | |
121 | } | |
e641b7d0 VK |
122 | |
123 | // Create directory for image files if it doesn't exist | |
124 | strcpy(szBuffer, g_szDataDir); | |
125 | strcat(szBuffer, DDIR_IMAGES); | |
126 | if (MKDIR(szBuffer) == -1) | |
127 | if (errno != EEXIST) | |
128 | { | |
129 | WriteLog(MSG_ERROR_CREATING_DATA_DIR, EVENTLOG_ERROR_TYPE, "s", szBuffer); | |
130 | return FALSE; | |
131 | } | |
132 | ||
c9ccd685 | 133 | #undef MKDIR |
06e7be2f VK |
134 | |
135 | return TRUE; | |
136 | } | |
137 | ||
138 | ||
48b1c0ac VK |
139 | // |
140 | // Load global configuration parameters | |
141 | // | |
142 | ||
d627ae40 | 143 | static void LoadGlobalConfig() |
48b1c0ac | 144 | { |
364aa19a | 145 | g_dwDiscoveryPollingInterval = ConfigReadInt("DiscoveryPollingInterval", 900); |
f00307b7 | 146 | g_dwStatusPollingInterval = ConfigReadInt("StatusPollingInterval", 60); |
364aa19a | 147 | g_dwConfigurationPollingInterval = ConfigReadInt("ConfigurationPollingInterval", 3600); |
3e4e127f VK |
148 | if (ConfigReadInt("EnableAccessControl", 1)) |
149 | g_dwFlags |= AF_ENABLE_ACCESS_CONTROL; | |
150 | if (ConfigReadInt("EnableEventsAccessControl", 1)) | |
151 | g_dwFlags |= AF_ENABLE_EVENTS_ACCESS_CONTROL; | |
3ea35b38 VK |
152 | if (ConfigReadInt("DeleteEmptySubnets", 1)) |
153 | g_dwFlags |= AF_DELETE_EMPTY_SUBNETS; | |
5add75d8 VK |
154 | if (ConfigReadInt("EnableSNMPTraps", 1)) |
155 | g_dwFlags |= AF_ENABLE_SNMP_TRAPD; | |
06e7be2f | 156 | ConfigReadStr("DataDirectory", g_szDataDir, MAX_PATH, DEFAULT_DATA_DIR); |
48b1c0ac VK |
157 | } |
158 | ||
159 | ||
9a19737f VK |
160 | // |
161 | // Server initialization | |
162 | // | |
163 | ||
164 | BOOL Initialize(void) | |
165 | { | |
2260ffe5 | 166 | int i, iNumThreads, iDBVersion; |
c7ca9142 VK |
167 | DWORD dwAddr; |
168 | char szInfo[256]; | |
347b5bc6 | 169 | |
9cc9ea72 | 170 | InitLog(g_dwFlags & AF_USE_EVENT_LOG, g_szLogFile, g_dwFlags & AF_STANDALONE); |
0ee0c807 VK |
171 | |
172 | #ifdef _WIN32 | |
173 | WSADATA wsaData; | |
174 | WSAStartup(0x0002, &wsaData); | |
175 | #endif | |
176 | ||
b688074e VK |
177 | InitLocalNetInfo(); |
178 | ||
067f2689 VK |
179 | // Create queue for delayed SQL queries |
180 | g_pLazyRequestQueue = new Queue(64, 16); | |
181 | ||
d9c2934a | 182 | // Initialize database driver and connect to database |
9cc9ea72 | 183 | if (!DBInit(TRUE, g_dwFlags & AF_LOG_SQL_ERRORS)) |
3a2f672c VK |
184 | return FALSE; |
185 | ||
186 | g_hCoreDB = DBConnect(); | |
187 | if (g_hCoreDB == 0) | |
188 | { | |
189 | WriteLog(MSG_DB_CONNFAIL, EVENTLOG_ERROR_TYPE, NULL); | |
190 | return FALSE; | |
191 | } | |
b1dd534d | 192 | DbgPrintf(AF_DEBUG_MISC, "Successfully connected to database %s@%s", g_szDbName, g_szDbServer); |
3a2f672c | 193 | |
2260ffe5 VK |
194 | // Check database version |
195 | iDBVersion = ConfigReadInt("DBFormatVersion", 0); | |
196 | if (iDBVersion != DB_FORMAT_VERSION) | |
197 | { | |
198 | WriteLog(MSG_WRONG_DB_VERSION, EVENTLOG_ERROR_TYPE, "dd", iDBVersion, DB_FORMAT_VERSION); | |
199 | return FALSE; | |
200 | } | |
201 | ||
c7ca9142 VK |
202 | // Initialize locks |
203 | if (!InitLocks(&dwAddr, szInfo)) | |
204 | { | |
205 | if (dwAddr == UNLOCKED) // Some SQL problems | |
206 | WriteLog(MSG_INIT_LOCKS_FAILED, EVENTLOG_ERROR_TYPE, NULL); | |
207 | else // Database already locked by another server instance | |
208 | WriteLog(MSG_DB_LOCKED, EVENTLOG_ERROR_TYPE, "as", dwAddr, szInfo); | |
209 | return FALSE; | |
210 | } | |
2260ffe5 | 211 | g_dwFlags |= AF_DB_LOCKED; |
c7ca9142 | 212 | |
48b1c0ac VK |
213 | // Load global configuration parameters |
214 | LoadGlobalConfig(); | |
b1dd534d | 215 | DbgPrintf(AF_DEBUG_MISC, "Global configuration loaded"); |
48b1c0ac | 216 | |
18e26ff8 VK |
217 | // Initialize SNMP stuff |
218 | SnmpInit(); | |
219 | ||
06e7be2f VK |
220 | // Check data directory |
221 | if (!CheckDataDir()) | |
222 | return FALSE; | |
223 | ||
e641b7d0 VK |
224 | // Update hashes for image files |
225 | UpdateImageHashes(); | |
226 | ||
3a2f672c | 227 | // Create synchronization stuff |
d16cf8a5 | 228 | m_hEventShutdown = ConditionCreate(TRUE); |
3a2f672c | 229 | |
3ea35b38 VK |
230 | // Setup unique identifiers table |
231 | if (!InitIdTable()) | |
232 | return FALSE; | |
233 | ||
b86ba1c0 VK |
234 | // Initialize mailer |
235 | InitMailer(); | |
236 | ||
da54bd8d VK |
237 | // Load users from database |
238 | if (!LoadUsers()) | |
347b5bc6 VK |
239 | { |
240 | WriteLog(MSG_ERROR_LOADING_USERS, EVENTLOG_ERROR_TYPE, NULL); | |
da54bd8d | 241 | return FALSE; |
347b5bc6 | 242 | } |
da54bd8d | 243 | |
2da1357c | 244 | // Initialize objects infrastructure and load objects from database |
74b83361 | 245 | ObjectsInit(); |
2da1357c VK |
246 | if (!LoadObjects()) |
247 | return FALSE; | |
b1dd534d | 248 | DbgPrintf(AF_DEBUG_MISC, "Objects loaded and initialized"); |
74b83361 | 249 | |
c9363772 VK |
250 | // Initialize and load event actions |
251 | if (!InitActions()) | |
252 | { | |
253 | WriteLog(MSG_ACTION_INIT_ERROR, EVENTLOG_ERROR_TYPE, NULL); | |
7e495d97 | 254 | return FALSE; |
c9363772 | 255 | } |
7e495d97 | 256 | |
c7ca9142 VK |
257 | // Initialize event handling subsystem |
258 | if (!InitEventSubsystem()) | |
259 | return FALSE; | |
260 | ||
2260ffe5 VK |
261 | // Initialize alarms |
262 | if (!g_alarmMgr.Init()) | |
263 | return FALSE; | |
264 | ||
1275c750 VK |
265 | // Initialize data collection subsystem |
266 | if (!InitDataCollector()) | |
267 | return FALSE; | |
268 | ||
f91fa4c2 VK |
269 | // Initialize watchdog |
270 | WatchdogInit(); | |
271 | ||
3a2f672c | 272 | // Start threads |
f91fa4c2 | 273 | ThreadCreate(WatchdogThread, 0, NULL); |
3a2f672c | 274 | ThreadCreate(HouseKeeper, 0, NULL); |
74b83361 | 275 | ThreadCreate(Syncer, 0, NULL); |
a68e217b | 276 | ThreadCreate(NodePoller, 0, NULL); |
f00307b7 | 277 | ThreadCreate(StatusPoller, 0, NULL); |
323f8bec | 278 | ThreadCreate(ConfigurationPoller, 0, NULL); |
5d0ff6bd | 279 | ThreadCreate(ClientListener, 0, NULL); |
3e4e127f VK |
280 | |
281 | // Start network discovery thread if required | |
b688074e | 282 | CheckForMgmtNode(); |
3e4e127f VK |
283 | if (ConfigReadInt("RunNetworkDiscovery", 1)) |
284 | ThreadCreate(DiscoveryThread, 0, NULL); | |
3e4e127f | 285 | |
f9b7e653 VK |
286 | // Start event processors |
287 | iNumThreads = ConfigReadInt("NumberOfEventProcessors", 1); | |
288 | for(i = 0; i < iNumThreads; i++) | |
d09b1909 | 289 | ThreadCreate(EventProcessor, 0, (void *)(i + 1)); |
4385fa12 | 290 | |
37c4d6aa VK |
291 | // Start SNMP trapper |
292 | if (ConfigReadInt("EnableSNMPTraps", 1)) | |
293 | ThreadCreate(SNMPTrapReceiver, 0, NULL); | |
294 | ||
067f2689 | 295 | // Start database "lazy" write thread |
ccdbbb52 | 296 | StartDBWriter(); |
067f2689 | 297 | |
3e4e127f VK |
298 | // Start local administartive interface listener if required |
299 | if (ConfigReadInt("EnableAdminInterface", 1)) | |
300 | ThreadCreate(LocalAdminListener, 0, NULL); | |
301 | ||
b1dd534d | 302 | DbgPrintf(AF_DEBUG_MISC, "Server initialization completed"); |
9a19737f VK |
303 | return TRUE; |
304 | } | |
305 | ||
306 | ||
83f0529c VK |
307 | // |
308 | // Handler for client notification | |
309 | // | |
310 | ||
3421c063 | 311 | void NotifyClient(ClientSession *pSession, void *pArg) |
83f0529c | 312 | { |
3421c063 | 313 | pSession->Notify((DWORD)pArg); |
83f0529c VK |
314 | } |
315 | ||
316 | ||
9a19737f VK |
317 | // |
318 | // Server shutdown | |
319 | // | |
320 | ||
321 | void Shutdown(void) | |
322 | { | |
d09b1909 | 323 | DWORD i, dwNumThreads; |
e0d3b217 | 324 | |
83f0529c | 325 | // Notify clients |
3421c063 | 326 | EnumerateClientSessions(NotifyClient, (void *)NX_NOTIFY_SHUTDOWN); |
83f0529c | 327 | |
3a2f672c | 328 | WriteLog(MSG_SERVER_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL); |
c7ca9142 | 329 | g_dwFlags |= AF_SHUTDOWN; // Set shutdown flag |
d16cf8a5 | 330 | ConditionSet(m_hEventShutdown); |
c7ca9142 | 331 | |
d09b1909 VK |
332 | // Stop event processor(s) |
333 | g_pEventQueue->Clear(); | |
334 | dwNumThreads = ConfigReadInt("NumberOfEventProcessors", 1); | |
335 | for(i = 0; i < dwNumThreads; i++) | |
336 | g_pEventQueue->Put(INVALID_POINTER_VALUE); | |
337 | ||
b86ba1c0 VK |
338 | ShutdownMailer(); |
339 | ||
340 | ThreadSleep(3); // Give other threads a chance to terminate in a safe way | |
b1dd534d | 341 | DbgPrintf(AF_DEBUG_MISC, "All threads was notified, continue with shutdown"); |
d09b1909 | 342 | |
d627ae40 | 343 | SaveObjects(); |
b1dd534d | 344 | DbgPrintf(AF_DEBUG_MISC, "All objects saved to database"); |
ff550544 | 345 | SaveUsers(); |
b1dd534d | 346 | DbgPrintf(AF_DEBUG_MISC, "All users saved to database"); |
83f0529c | 347 | StopDBWriter(); |
b1dd534d | 348 | DbgPrintf(AF_DEBUG_MISC, "Database writer stopped"); |
c7ca9142 VK |
349 | |
350 | // Remove database lock | |
b4895bbe | 351 | UnlockDB(); |
c7ca9142 VK |
352 | |
353 | // Disconnect from database and unload driver | |
3a2f672c VK |
354 | if (g_hCoreDB != 0) |
355 | DBDisconnect(g_hCoreDB); | |
cc140cce | 356 | DBUnloadDriver(); |
2b9c1c41 | 357 | DbgPrintf(AF_DEBUG_MISC, "Database driver unloaded"); |
c7ca9142 | 358 | |
c9363772 | 359 | CleanupActions(); |
e0d3b217 | 360 | ShutdownEventSubsystem(); |
2b9c1c41 | 361 | DbgPrintf(AF_DEBUG_MISC, "Event processing stopped"); |
e0d3b217 VK |
362 | |
363 | // Delete all objects | |
364 | for(i = 0; i < g_dwIdIndexSize; i++) | |
365 | delete g_pIndexById[i].pObject; | |
7e495d97 | 366 | |
4385fa12 | 367 | CloseLog(); |
9e9d381c VK |
368 | |
369 | // Remove PID file | |
370 | #ifndef _WIN32 | |
371 | remove(g_szPIDFile); | |
372 | #endif | |
9a19737f VK |
373 | } |
374 | ||
375 | ||
c868331f VK |
376 | // |
377 | // Compare given string to command template with abbreviation possibility | |
378 | // | |
379 | ||
380 | static BOOL IsCommand(char *pszTemplate, char *pszString, int iMinChars) | |
381 | { | |
382 | int i; | |
383 | ||
384 | // Convert given string to uppercase | |
385 | strupr(pszString); | |
386 | ||
387 | for(i = 0; pszString[i] != 0; i++) | |
388 | if (pszString[i] != pszTemplate[i]) | |
389 | return FALSE; | |
390 | if (i < iMinChars) | |
391 | return FALSE; | |
392 | return TRUE; | |
393 | } | |
394 | ||
395 | ||
396 | // | |
397 | // Process command entered from command line in standalone mode | |
398 | // Return TRUE if command was "down" | |
399 | // | |
400 | ||
401 | static BOOL ProcessCommand(char *pszCmdLine) | |
402 | { | |
403 | char *pArg; | |
404 | char szBuffer[256]; | |
405 | BOOL bExitCode = FALSE; | |
406 | ||
407 | // Get command | |
408 | pArg = ExtractWord(pszCmdLine, szBuffer); | |
409 | ||
410 | if (IsCommand("DOWN", szBuffer, 4)) | |
411 | { | |
412 | bExitCode = TRUE; | |
413 | } | |
414 | else if (IsCommand("DUMP", szBuffer, 2)) | |
415 | { | |
416 | // Get argument | |
417 | pArg = ExtractWord(pArg, szBuffer); | |
418 | ||
419 | if (IsCommand("OBJECTS", szBuffer, 1)) | |
420 | { | |
04738fd8 | 421 | DumpObjects(); |
c868331f VK |
422 | } |
423 | else if (IsCommand("SESSIONS", szBuffer, 1)) | |
424 | { | |
425 | DumpSessions(); | |
426 | } | |
427 | else if (IsCommand("USERS", szBuffer, 1)) | |
428 | { | |
429 | DumpUsers(); | |
430 | } | |
431 | else | |
432 | { | |
433 | printf("ERROR: Invalid command argument\n\n"); | |
434 | } | |
435 | } | |
436 | else if (IsCommand("HELP", szBuffer, 2)) | |
437 | { | |
438 | printf("Valid commands are:\n" | |
439 | " down - Down NetXMS server\n" | |
440 | " dump objects - Dump network objects to screen\n" | |
441 | " dump sessions - Dump active client sessions to screen\n" | |
442 | " dump users - Dump users to screen\n" | |
443 | " mutex - Display mutex status\n" | |
444 | " wd - Display watchdog information\n" | |
445 | "\nAlmost all commands can be abbreviated to 2 or 3 characters\n" | |
446 | "\n"); | |
447 | } | |
448 | else if (IsCommand("MUTEX", szBuffer, 2)) | |
449 | { | |
450 | printf("Mutex status:\n"); | |
dbe67493 VK |
451 | DbgTestRWLock(g_rwlockIdIndex, "g_hMutexIdIndex"); |
452 | DbgTestRWLock(g_rwlockNodeIndex, "g_hMutexNodeIndex"); | |
453 | DbgTestRWLock(g_rwlockSubnetIndex, "g_hMutexSubnetIndex"); | |
454 | DbgTestRWLock(g_rwlockInterfaceIndex, "g_hMutexInterfaceIndex"); | |
c868331f VK |
455 | DbgTestMutex(g_hMutexObjectAccess, "g_hMutexObjectAccess"); |
456 | printf("\n"); | |
457 | } | |
458 | else if (IsCommand("WD", szBuffer, 2)) | |
459 | { | |
460 | WatchdogPrintStatus(); | |
461 | printf("\n"); | |
462 | } | |
463 | else | |
464 | { | |
465 | printf("INVALID COMMAND\n\n"); | |
466 | } | |
467 | ||
468 | return bExitCode; | |
469 | } | |
470 | ||
471 | ||
0fca1cc3 VK |
472 | // |
473 | // Signal handler for UNIX platforms | |
474 | // | |
475 | ||
476 | #ifndef _WIN32 | |
477 | ||
478 | void OnSignal(int iSignal) | |
479 | { | |
480 | WriteLog(MSG_SIGNAL_RECEIVED, EVENTLOG_WARNING_TYPE, "d", iSignal); | |
35e1d81f VK |
481 | switch(iSignal) |
482 | { | |
483 | case SIGTERM: | |
484 | if (!IsStandalone()) | |
485 | ConditionSet(m_hEventShutdown); | |
486 | break; | |
487 | case SIGSEGV: | |
488 | exit(5); | |
489 | break; | |
490 | default: | |
491 | break; | |
492 | } | |
0fca1cc3 VK |
493 | } |
494 | ||
495 | #endif | |
496 | ||
497 | ||
9a19737f VK |
498 | // |
499 | // Common main() | |
500 | // | |
501 | ||
502 | void Main(void) | |
503 | { | |
3a2f672c VK |
504 | WriteLog(MSG_SERVER_STARTED, EVENTLOG_INFORMATION_TYPE, NULL); |
505 | ||
3a2f672c VK |
506 | if (IsStandalone()) |
507 | { | |
c868331f | 508 | char *ptr, szCommand[256]; |
3a2f672c | 509 | |
c868331f VK |
510 | printf("\nNetXMS Server V" NETXMS_VERSION_STRING " Ready\n" |
511 | "Enter \"help\" for command list or \"down\" for server shutdown\n" | |
512 | "System Console\n\n"); | |
fb1a5953 VK |
513 | |
514 | #if USE_READLINE | |
515 | // Initialize readline library if we use it | |
516 | rl_bind_key('\t', rl_insert); | |
517 | #endif | |
c868331f | 518 | |
3a2f672c VK |
519 | while(1) |
520 | { | |
fb1a5953 VK |
521 | #if USE_READLINE |
522 | ptr = readline("netxmsd: "); | |
523 | #else | |
c868331f VK |
524 | printf("netxmsd: "); |
525 | fflush(stdout); | |
526 | fgets(szCommand, 255, stdin); | |
527 | ptr = strchr(szCommand, '\n'); | |
528 | if (ptr != NULL) | |
529 | *ptr = 0; | |
fb1a5953 VK |
530 | ptr = szCommand; |
531 | #endif | |
c868331f | 532 | |
fb1a5953 VK |
533 | if (ptr != NULL) |
534 | { | |
535 | StrStrip(ptr); | |
536 | if (*ptr != 0) | |
537 | { | |
538 | if (ProcessCommand(ptr)) | |
539 | break; | |
540 | #if USE_READLINE | |
541 | add_history(ptr); | |
542 | #endif | |
543 | } | |
544 | #if USE_READLINE | |
545 | free(ptr); | |
546 | #endif | |
547 | } | |
548 | else | |
549 | { | |
550 | printf("\n"); | |
551 | } | |
3a2f672c VK |
552 | } |
553 | ||
fb1a5953 VK |
554 | #if USE_READLINE |
555 | free(ptr); | |
556 | #endif | |
3a2f672c VK |
557 | Shutdown(); |
558 | } | |
559 | else | |
560 | { | |
d16cf8a5 | 561 | ConditionWait(m_hEventShutdown, INFINITE); |
0fca1cc3 VK |
562 | // On Win32, Shutdown() will be called by service control handler |
563 | #ifndef _WIN32 | |
564 | Shutdown(); | |
565 | #endif | |
3a2f672c | 566 | } |
9a19737f VK |
567 | } |
568 | ||
569 | ||
570 | // | |
571 | // Startup code | |
572 | // | |
573 | ||
574 | int main(int argc, char *argv[]) | |
575 | { | |
0fca1cc3 VK |
576 | #ifndef _WIN32 |
577 | int i; | |
9e9d381c | 578 | FILE *fp; |
0fca1cc3 VK |
579 | #endif |
580 | ||
4385fa12 | 581 | if (!ParseCommandLine(argc, argv)) |
9a19737f VK |
582 | return 1; |
583 | ||
4385fa12 | 584 | if (!LoadConfig()) |
77312b6f VK |
585 | { |
586 | if (IsStandalone()) | |
587 | printf("Error loading configuration file\n"); | |
9a19737f | 588 | return 1; |
77312b6f | 589 | } |
9a19737f | 590 | |
b7271ccb | 591 | #ifdef _WIN32 |
9a19737f VK |
592 | if (!IsStandalone()) |
593 | { | |
594 | InitService(); | |
595 | } | |
596 | else | |
597 | { | |
598 | if (!Initialize()) | |
599 | { | |
600 | printf("NMS Core initialization failed\n"); | |
06e7be2f VK |
601 | |
602 | // Remove database lock | |
2260ffe5 | 603 | if (g_dwFlags & AF_DB_LOCKED) |
06e7be2f | 604 | { |
b4895bbe | 605 | UnlockDB(); |
06e7be2f VK |
606 | DBDisconnect(g_hCoreDB); |
607 | } | |
b7271ccb | 608 | return 3; |
9a19737f VK |
609 | } |
610 | Main(); | |
611 | } | |
0fca1cc3 | 612 | #else /* not _WIN32 */ |
b7271ccb VK |
613 | if (!IsStandalone()) |
614 | { | |
615 | if (daemon(0, 0) == -1) | |
616 | { | |
617 | perror("Call to daemon() failed"); | |
618 | return 2; | |
619 | } | |
0fca1cc3 | 620 | } |
85303064 | 621 | |
9e9d381c VK |
622 | // Write PID file |
623 | fp = fopen(g_szPIDFile, "w"); | |
624 | if (fp != NULL) | |
625 | { | |
626 | fprintf(fp, "%d", getpid()); | |
627 | fclose(fp); | |
628 | } | |
629 | ||
0fca1cc3 VK |
630 | // Setup signal handlers |
631 | for(i = 0; i < 32; i++) | |
632 | signal(i, SIG_IGN); | |
633 | signal(SIGTERM, OnSignal); | |
634 | signal(SIGSEGV, OnSignal); | |
85303064 | 635 | |
0fca1cc3 | 636 | // Initialize server |
b7271ccb | 637 | if (!Initialize()) |
06e7be2f VK |
638 | { |
639 | // Remove database lock | |
2260ffe5 | 640 | if (g_dwFlags & AF_DB_LOCKED) |
06e7be2f | 641 | { |
b4895bbe | 642 | UnlockDB(); |
06e7be2f VK |
643 | DBDisconnect(g_hCoreDB); |
644 | } | |
b7271ccb | 645 | return 3; |
06e7be2f | 646 | } |
0fca1cc3 VK |
647 | |
648 | // Everything is OK, start common main loop | |
b7271ccb VK |
649 | Main(); |
650 | #endif /* _WIN32 */ | |
9a19737f VK |
651 | return 0; |
652 | } |