111910cf726d5df60584da78fe391aaa6da82c1a
[public/netxms.git] / src / server / tools / nxdbmgr / nxdbmgr.cpp
1 /*
2 ** nxdbmgr - NetXMS database manager
3 ** Copyright (C) 2004-2017 Victor Kirhenshtein
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 ** File: nxdbmgr.cpp
20 **
21 **/
22
23 #include "nxdbmgr.h"
24 #include <nxconfig.h>
25
26 #ifdef _WIN32
27 #include <conio.h>
28 #endif
29
30 /**
31 * Global variables
32 */
33 DB_HANDLE g_hCoreDB;
34 BOOL g_bIgnoreErrors = FALSE;
35 BOOL g_bTrace = FALSE;
36 bool g_isGuiMode = false;
37 bool g_checkData = false;
38 bool g_checkDataTablesOnly = false;
39 bool g_dataOnlyMigration = false;
40 bool g_skipDataMigration = false;
41 bool g_skipDataSchemaMigration = false;
42 int g_migrationTxnSize = 4096;
43 int g_dbSyntax;
44 const TCHAR *g_pszTableSuffix = _T("");
45 const TCHAR *g_pszSqlType[6][3] =
46 {
47 { _T("longtext"), _T("text"), _T("bigint") }, // MySQL
48 { _T("text"), _T("varchar(4000)"), _T("bigint") }, // PostgreSQL
49 { _T("text"), _T("varchar(4000)"), _T("bigint") }, // Microsoft SQL
50 { _T("clob"), _T("varchar(4000)"), _T("number(20)") }, // Oracle
51 { _T("varchar"), _T("varchar(4000)"), _T("number(20)") }, // SQLite
52 { _T("long varchar"), _T("varchar(4000)"), _T("bigint") } // DB/2
53 };
54
55 /**
56 * Static data
57 */
58 static char m_szCodePage[MAX_PATH] = ICONV_DEFAULT_CODEPAGE;
59 static TCHAR s_dbDriver[MAX_PATH] = _T("");
60 static TCHAR s_dbDrvParams[MAX_PATH] = _T("");
61 static TCHAR s_dbServer[MAX_PATH] = _T("127.0.0.1");
62 static TCHAR s_dbLogin[MAX_DB_LOGIN] = _T("netxms");
63 static TCHAR s_dbPassword[MAX_PASSWORD] = _T("");
64 static TCHAR s_dbName[MAX_DB_NAME] = _T("netxms_db");
65 static TCHAR s_dbSchema[MAX_DB_NAME] = _T("");
66 static NX_CFG_TEMPLATE m_cfgTemplate[] =
67 {
68 { _T("CodePage"), CT_MB_STRING, 0, 0, MAX_PATH, 0, m_szCodePage },
69 { _T("DBDriver"), CT_STRING, 0, 0, MAX_PATH, 0, s_dbDriver },
70 { _T("DBDrvParams"), CT_STRING, 0, 0, MAX_PATH, 0, s_dbDrvParams },
71 { _T("DBLogin"), CT_STRING, 0, 0, MAX_DB_LOGIN, 0, s_dbLogin },
72 { _T("DBName"), CT_STRING, 0, 0, MAX_DB_NAME, 0, s_dbName },
73 { _T("DBPassword"), CT_STRING, 0, 0, MAX_PASSWORD, 0, s_dbPassword },
74 { _T("DBEncryptedPassword"), CT_STRING, 0, 0, MAX_PASSWORD, 0, s_dbPassword },
75 { _T("DBSchema"), CT_STRING, 0, 0, MAX_DB_NAME, 0, s_dbSchema },
76 { _T("DBServer"), CT_STRING, 0, 0, MAX_PATH, 0, s_dbServer },
77 { _T(""), CT_END_OF_LIST, 0, 0, 0, 0, NULL }
78 };
79 static BOOL m_bForce = FALSE;
80 static DB_DRIVER s_driver = NULL;
81 static bool m_operationInProgress = false;
82
83 /**
84 * Show query if trace mode is ON
85 */
86 void ShowQuery(const TCHAR *pszQuery)
87 {
88 WriteToTerminalEx(_T("\x1b[1m>>> \x1b[32;1m%s\x1b[0m\n"), pszQuery);
89 }
90
91 /**
92 * Set "operation in progress" flag
93 */
94 void SetOperationInProgress(bool inProgress)
95 {
96 m_operationInProgress = inProgress;
97 }
98
99 /**
100 * Get Yes or No answer from keyboard
101 */
102 bool GetYesNo(const TCHAR *format, ...)
103 {
104 va_list args;
105
106 if (g_isGuiMode)
107 {
108 if (m_bForce)
109 return true;
110
111 TCHAR message[4096];
112 va_start(args, format);
113 _vsntprintf(message, 4096, format, args);
114 va_end(args);
115
116 #ifdef _WIN32
117 return MessageBox(NULL, message, _T("NetXMS Database Manager"), MB_YESNO | MB_ICONQUESTION) == IDYES;
118 #else
119 return false;
120 #endif
121 }
122 else
123 {
124 if (m_operationInProgress)
125 _tprintf(_T("\n"));
126 va_start(args, format);
127 _vtprintf(format, args);
128 va_end(args);
129 _tprintf(_T(" (Y/N) "));
130
131 if (m_bForce)
132 {
133 _tprintf(_T("Y\n"));
134 return true;
135 }
136 else
137 {
138 #ifdef _WIN32
139 int ch;
140
141 while(1)
142 {
143 ch = _getch();
144 if ((ch == 'y') || (ch == 'Y'))
145 {
146 _tprintf(_T("Y\n"));
147 return true;
148 }
149 if ((ch == 'n') || (ch == 'N'))
150 {
151 _tprintf(_T("N\n"));
152 return false;
153 }
154 }
155 #else
156 TCHAR szBuffer[16];
157
158 fflush(stdout);
159 _fgetts(szBuffer, 16, stdin);
160 StrStrip(szBuffer);
161 return ((szBuffer[0] == 'y') || (szBuffer[0] == 'Y'));
162 #endif
163 }
164 }
165 }
166
167 /**
168 * Execute SQL SELECT query and print error message on screen if query failed
169 */
170 DB_RESULT SQLSelect(const TCHAR *pszQuery)
171 {
172 DB_RESULT hResult;
173 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
174
175 if (g_bTrace)
176 ShowQuery(pszQuery);
177
178 hResult = DBSelectEx(g_hCoreDB, pszQuery, errorText);
179 if (hResult == NULL)
180 WriteToTerminalEx(_T("SQL query failed (%s):\n\x1b[33;1m%s\x1b[0m\n"), errorText, pszQuery);
181 return hResult;
182 }
183
184 /**
185 * Execute SQL SELECT query via DBSelectUnbuffered and print error message on screen if query failed
186 */
187 DB_UNBUFFERED_RESULT SQLSelectUnbuffered(const TCHAR *pszQuery)
188 {
189 if (g_bTrace)
190 ShowQuery(pszQuery);
191
192 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
193 DB_UNBUFFERED_RESULT hResult = DBSelectUnbufferedEx(g_hCoreDB, pszQuery, errorText);
194 if (hResult == NULL)
195 WriteToTerminalEx(_T("SQL query failed (%s):\n\x1b[33;1m%s\x1b[0m\n"), errorText, pszQuery);
196 return hResult;
197 }
198
199 /**
200 * Execute prepared statement and print error message on screen if query failed
201 */
202 bool SQLExecute(DB_STATEMENT hStmt)
203 {
204 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
205
206 if (g_bTrace)
207 ShowQuery(DBGetStatementSource(hStmt));
208
209 bool result = DBExecuteEx(hStmt, errorText);
210 if (!result)
211 WriteToTerminalEx(_T("SQL query failed (%s):\n\x1b[33;1m%s\x1b[0m\n"), errorText, DBGetStatementSource(hStmt));
212 return result;
213 }
214
215 /**
216 * Execute SQL query and print error message on screen if query failed
217 */
218 bool SQLQuery(const TCHAR *pszQuery)
219 {
220 if (*pszQuery == 0)
221 return true;
222
223 String query(pszQuery);
224
225 query.replace(_T("$SQL:TEXT"), g_pszSqlType[g_dbSyntax][SQL_TYPE_TEXT]);
226 query.replace(_T("$SQL:TXT4K"), g_pszSqlType[g_dbSyntax][SQL_TYPE_TEXT4K]);
227 query.replace(_T("$SQL:INT64"), g_pszSqlType[g_dbSyntax][SQL_TYPE_INT64]);
228
229 if (g_bTrace)
230 ShowQuery(query);
231
232 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
233 bool success = DBQueryEx(g_hCoreDB, (const TCHAR *)query, errorText);
234 if (!success)
235 WriteToTerminalEx(_T("SQL query failed (%s):\n\x1b[33;1m%s\x1b[0m\n"), errorText, (const TCHAR *)query);
236 return success;
237 }
238
239 /**
240 * Execute SQL batch
241 */
242 bool SQLBatch(const TCHAR *pszBatch)
243 {
244 String batch(pszBatch);
245 TCHAR *pszBuffer, *pszQuery, *ptr;
246 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
247 bool success = true;
248 TCHAR table[128], column[128];
249
250 batch.replace(_T("$SQL:TEXT"), g_pszSqlType[g_dbSyntax][SQL_TYPE_TEXT]);
251 batch.replace(_T("$SQL:TXT4K"), g_pszSqlType[g_dbSyntax][SQL_TYPE_TEXT4K]);
252 batch.replace(_T("$SQL:INT64"), g_pszSqlType[g_dbSyntax][SQL_TYPE_INT64]);
253
254 pszQuery = pszBuffer = batch.getBuffer();
255 while(true)
256 {
257 ptr = _tcschr(pszQuery, _T('\n'));
258 if (ptr != NULL)
259 *ptr = 0;
260 if (!_tcscmp(pszQuery, _T("<END>")))
261 break;
262
263 if (_stscanf(pszQuery, _T("ALTER TABLE %128s DROP COLUMN %128s"), table, column) == 2)
264 {
265 if (!DBDropColumn(g_hCoreDB, table, column))
266 {
267 WriteToTerminalEx(_T("Cannot drop column \x1b[37;1m%s.%s\x1b[0m\n"), table, column);
268 if (!g_bIgnoreErrors)
269 {
270 success = false;
271 break;
272 }
273 }
274 }
275 else
276 {
277 if (g_bTrace)
278 ShowQuery(pszQuery);
279
280 if (!DBQueryEx(g_hCoreDB, pszQuery, errorText))
281 {
282 WriteToTerminalEx(_T("SQL query failed (%s):\n\x1b[33;1m%s\x1b[0m\n"), errorText, pszQuery);
283 if (!g_bIgnoreErrors)
284 {
285 success = false;
286 break;
287 }
288 }
289 }
290
291 if (ptr == NULL)
292 break;
293 ptr++;
294 pszQuery = ptr;
295 }
296 return success;
297 }
298
299 /**
300 * Read string value from metadata table
301 */
302 BOOL MetaDataReadStr(const TCHAR *pszVar, TCHAR *pszBuffer, int iBufSize, const TCHAR *pszDefault)
303 {
304 DB_RESULT hResult;
305 TCHAR szQuery[256];
306 BOOL bSuccess = FALSE;
307
308 nx_strncpy(pszBuffer, pszDefault, iBufSize);
309 if (_tcslen(pszVar) > 127)
310 return FALSE;
311
312 _sntprintf(szQuery, 256, _T("SELECT var_value FROM metadata WHERE var_name='%s'"), pszVar);
313 hResult = SQLSelect(szQuery);
314 if (hResult == NULL)
315 return FALSE;
316
317 if (DBGetNumRows(hResult) > 0)
318 {
319 DBGetField(hResult, 0, 0, pszBuffer, iBufSize);
320 bSuccess = TRUE;
321 }
322
323 DBFreeResult(hResult);
324 return bSuccess;
325 }
326
327 /**
328 * Read integer value from configuration table
329 */
330 int MetaDataReadInt(const TCHAR *pszVar, int iDefault)
331 {
332 TCHAR szBuffer[64];
333
334 if (MetaDataReadStr(pszVar, szBuffer, 64, _T("")))
335 return _tcstol(szBuffer, NULL, 0);
336 else
337 return iDefault;
338 }
339
340 /**
341 * Read string value from configuration table
342 */
343 BOOL ConfigReadStr(const TCHAR *pszVar, TCHAR *pszBuffer, int iBufSize, const TCHAR *pszDefault)
344 {
345 DB_RESULT hResult;
346 TCHAR szQuery[256];
347 BOOL bSuccess = FALSE;
348
349 nx_strncpy(pszBuffer, pszDefault, iBufSize);
350 if (_tcslen(pszVar) > 127)
351 return FALSE;
352
353 _sntprintf(szQuery, 256, _T("SELECT var_value FROM config WHERE var_name='%s'"), pszVar);
354 hResult = SQLSelect(szQuery);
355 if (hResult == NULL)
356 return FALSE;
357
358 if (DBGetNumRows(hResult) > 0)
359 {
360 DBGetField(hResult, 0, 0, pszBuffer, iBufSize);
361 bSuccess = TRUE;
362 }
363
364 DBFreeResult(hResult);
365 return bSuccess;
366 }
367
368 /**
369 * Read integer value from configuration table
370 */
371 int ConfigReadInt(const TCHAR *pszVar, int iDefault)
372 {
373 TCHAR szBuffer[64];
374
375 if (ConfigReadStr(pszVar, szBuffer, 64, _T("")))
376 return _tcstol(szBuffer, NULL, 0);
377 else
378 return iDefault;
379 }
380
381 /**
382 * Read unsigned long value from configuration table
383 */
384 DWORD ConfigReadULong(const TCHAR *pszVar, DWORD dwDefault)
385 {
386 TCHAR szBuffer[64];
387
388 if (ConfigReadStr(pszVar, szBuffer, 64, _T("")))
389 return _tcstoul(szBuffer, NULL, 0);
390 else
391 return dwDefault;
392 }
393
394 /**
395 * Check if given record exists in database
396 */
397 bool IsDatabaseRecordExist(const TCHAR *table, const TCHAR *idColumn, UINT32 id)
398 {
399 bool exist = false;
400
401 TCHAR query[256];
402 _sntprintf(query, 256, _T("SELECT %s FROM %s WHERE %s=?"), idColumn, table, idColumn);
403
404 DB_STATEMENT hStmt = DBPrepare(g_hCoreDB, query);
405 if (hStmt != NULL)
406 {
407 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, id);
408 DB_RESULT hResult = DBSelectPrepared(hStmt);
409 if (hResult != NULL)
410 {
411 exist = (DBGetNumRows(hResult) > 0);
412 DBFreeResult(hResult);
413 }
414 DBFreeStatement(hStmt);
415 }
416 return exist;
417 }
418
419 /**
420 * Check that database has correct schema version and is not locked
421 */
422 bool ValidateDatabase()
423 {
424 DB_RESULT hResult;
425 LONG nVersion = 0;
426 BOOL bLocked = FALSE;
427 TCHAR szLockStatus[MAX_DB_STRING], szLockInfo[MAX_DB_STRING];
428
429 // Get database format version
430 INT32 major, minor;
431 if (!DBGetSchemaVersion(g_hCoreDB, &major, &minor))
432 {
433 _tprintf(_T("Unable to determine database schema version\n"));
434 return false;
435 }
436 if ((major > DB_SCHEMA_VERSION_MAJOR) || ((major == DB_SCHEMA_VERSION_MAJOR) && (minor > DB_SCHEMA_VERSION_MINOR)))
437 {
438 _tprintf(_T("Your database has format version %d.%d, this tool is compiled for version %d.%d.\n")
439 _T("You need to upgrade your server before using this database.\n"),
440 major, minor, DB_SCHEMA_VERSION_MAJOR, DB_SCHEMA_VERSION_MINOR);
441 return false;
442 }
443 if ((major < DB_SCHEMA_VERSION_MAJOR) || ((major == DB_SCHEMA_VERSION_MAJOR) && (minor < DB_SCHEMA_VERSION_MINOR)))
444 {
445 _tprintf(_T("Your database has format version %d.%d, this tool is compiled for version %d.%d.\nUse \"upgrade\" command to upgrade your database first.\n"),
446 major, minor, DB_SCHEMA_VERSION_MAJOR, DB_SCHEMA_VERSION_MINOR);
447 return false;
448 }
449
450 // Check if database is locked
451 hResult = DBSelect(g_hCoreDB, _T("SELECT var_value FROM config WHERE var_name='DBLockStatus'"));
452 if (hResult != NULL)
453 {
454 if (DBGetNumRows(hResult) > 0)
455 {
456 DBGetField(hResult, 0, 0, szLockStatus, MAX_DB_STRING);
457 bLocked = _tcscmp(szLockStatus, _T("UNLOCKED"));
458 }
459 DBFreeResult(hResult);
460
461 if (bLocked)
462 {
463 hResult = DBSelect(g_hCoreDB, _T("SELECT var_value FROM config WHERE var_name='DBLockInfo'"));
464 if (hResult != NULL)
465 {
466 if (DBGetNumRows(hResult) > 0)
467 {
468 DBGetField(hResult, 0, 0, szLockInfo, MAX_DB_STRING);
469 }
470 DBFreeResult(hResult);
471 }
472 }
473 }
474
475 if (bLocked)
476 {
477 _tprintf(_T("Database is locked by server %s [%s]\n"), szLockStatus, szLockInfo);
478 return false;
479 }
480
481 return true;
482 }
483
484 /**
485 * Open database connection
486 */
487 DB_HANDLE ConnectToDatabase()
488 {
489 TCHAR errorText[DBDRV_MAX_ERROR_TEXT];
490 DB_HANDLE hdb = DBConnect(s_driver, s_dbServer, s_dbName, s_dbLogin, s_dbPassword, s_dbSchema, errorText);
491 if (hdb == NULL)
492 {
493 _tprintf(_T("Unable to connect to database %s@%s as %s: %s\n"), s_dbName, s_dbServer, s_dbLogin, errorText);
494 }
495 return hdb;
496 }
497
498 /**
499 * Startup
500 */
501 int main(int argc, char *argv[])
502 {
503 BOOL bStart = TRUE, bQuiet = FALSE;
504 bool replaceValue = true;
505 bool skipAudit = false;
506 bool skipAlarms = false;
507 bool skipEvent = false;
508 bool skipSysLog = false;
509 bool skipTrapLog = false;
510 int ch;
511
512 InitNetXMSProcess(true);
513
514 TCHAR configFile[MAX_PATH] = _T("");
515
516 // Try to read config location
517 #ifdef _WIN32
518 HKEY hKey;
519 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NetXMS\\Server"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
520 {
521 DWORD dwSize = MAX_PATH * sizeof(TCHAR);
522 RegQueryValueEx(hKey, _T("ConfigFile"), NULL, NULL, (BYTE *)configFile, &dwSize);
523 RegCloseKey(hKey);
524 }
525 #else
526 const TCHAR *env = _tgetenv(_T("NETXMSD_CONFIG"));
527 if ((env != NULL) && (*env != 0))
528 nx_strncpy(configFile, env, MAX_PATH);
529 #endif
530
531 // Search for config
532 if (configFile[0] == 0)
533 {
534 #ifdef _WIN32
535 TCHAR path[MAX_PATH];
536 GetNetXMSDirectory(nxDirEtc, path);
537 _tcscat(path, _T("\\netxmsd.conf"));
538 if (_taccess(path, 4) == 0)
539 {
540 _tcscpy(configFile, path);
541 }
542 else
543 {
544 _tcscpy(configFile, _T("C:\\netxmsd.conf"));
545 }
546 #else
547 const TCHAR *homeDir = _tgetenv(_T("NETXMS_HOME"));
548 if ((homeDir != NULL) && (*homeDir != 0))
549 {
550 TCHAR config[MAX_PATH];
551 _sntprintf(config, MAX_PATH, _T("%s/etc/netxmsd.conf"), homeDir);
552 if (_taccess(config, 4) == 0)
553 {
554 _tcscpy(configFile, config);
555 goto stop_search;
556 }
557 }
558 if (_taccess(PREFIX _T("/etc/netxmsd.conf"), 4) == 0)
559 {
560 _tcscpy(configFile, PREFIX _T("/etc/netxmsd.conf"));
561 }
562 else if (_taccess(_T("/usr/etc/netxmsd.conf"), 4) == 0)
563 {
564 _tcscpy(configFile, _T("/usr/etc/netxmsd.conf"));
565 }
566 else
567 {
568 _tcscpy(configFile, _T("/etc/netxmsd.conf"));
569 }
570 stop_search:
571 ;
572 #endif
573 }
574
575 // Parse command line
576 opterr = 1;
577 while((ch = getopt(argc, argv, "Ac:dDEfGhILMNqRsStT:vXY")) != -1)
578 {
579 switch(ch)
580 {
581 case 'h': // Display help and exit
582 _tprintf(_T("NetXMS Database Manager Version ") NETXMS_VERSION_STRING _T(" Build ") NETXMS_VERSION_BUILD_STRING _T(" (") NETXMS_BUILD_TAG _T(")") IS_UNICODE_BUILD_STRING _T("\n\n"));
583 _tprintf(_T("Usage: nxdbmgr [<options>] <command> [<options>]\n")
584 _T("Valid commands are:\n")
585 _T(" batch <file> : Run SQL batch file\n")
586 _T(" check : Check database for errors\n")
587 _T(" check-data-tables : Check database for missing data tables\n")
588 _T(" export <file> : Export database to file\n")
589 _T(" get <name> : Get value of server configuration variable\n")
590 _T(" import <file> : Import database from file\n")
591 _T(" init <file> : Initialize database\n")
592 _T(" migrate <source> : Migrate database from given source\n")
593 _T(" reset-system-account : Unlock user \"system\" and reset it's password to default\n")
594 _T(" set <name> <value> : Set value of server configuration variable\n")
595 _T(" unlock : Forced database unlock\n")
596 _T(" upgrade : Upgrade database to new version\n")
597 _T("Valid options are:\n")
598 _T(" -A : Skip export of audit log\n")
599 _T(" -c <config> : Use alternate configuration file. Default is %s\n")
600 _T(" -d : Check collected data (may take very long time).\n")
601 _T(" -D : Migrate only collected data.\n")
602 _T(" -E : Skip export of event log\n")
603 _T(" -f : Force repair - do not ask for confirmation.\n")
604 #ifdef _WIN32
605 _T(" -G : GUI mode.\n")
606 #endif
607 _T(" -h : Display help and exit.\n")
608 _T(" -I : MySQL only - specify TYPE=InnoDB for new tables.\n")
609 _T(" -L : Skip export of alarms.\n")
610 _T(" -M : MySQL only - specify TYPE=MyISAM for new tables.\n")
611 _T(" -N : Do not replace existing configuration value (\"set\" command only).\n")
612 _T(" -q : Quiet mode (don't show startup banner).\n")
613 _T(" -R : Skip export of SNMP trap log.\n")
614 _T(" -s : Skip collected data during migration on export.\n")
615 _T(" -S : Skip collected data during migration on export and do not clear or create data tables.\n")
616 _T(" -t : Enable trace mode (show executed SQL queries).\n")
617 _T(" -T <recs> : Transaction size for migration.\n")
618 _T(" -v : Display version and exit.\n")
619 _T(" -X : Ignore SQL errors when upgrading (USE WITH CAUTION!!!)\n")
620 _T(" -Y : Skip export of collected syslog records.\n")
621 _T("\n"), configFile);
622 bStart = FALSE;
623 break;
624 case 'v': // Print version and exit
625 _tprintf(_T("NetXMS Database Manager Version ") NETXMS_VERSION_STRING _T(" Build ") NETXMS_VERSION_BUILD_STRING _T(" (") NETXMS_BUILD_TAG _T(")") IS_UNICODE_BUILD_STRING _T("\n\n"));
626 bStart = FALSE;
627 break;
628 case 'A':
629 skipAudit = true;
630 break;
631 case 'c':
632 #ifdef UNICODE
633 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, configFile, MAX_PATH);
634 configFile[MAX_PATH - 1] = 0;
635 #else
636 nx_strncpy(configFile, optarg, MAX_PATH);
637 #endif
638 break;
639 case 'd':
640 g_checkData = true;
641 break;
642 case 'D':
643 g_dataOnlyMigration = true;
644 break;
645 case 'E':
646 skipEvent = true;
647 break;
648 case 'f':
649 m_bForce = TRUE;
650 break;
651 case 'G':
652 g_isGuiMode = true;
653 break;
654 case 'N':
655 replaceValue = false;
656 break;
657 case 'q':
658 bQuiet = TRUE;
659 break;
660 case 'R':
661 skipTrapLog = true;
662 break;
663 case 's':
664 g_skipDataMigration = true;
665 break;
666 case 'S':
667 g_skipDataMigration = true;
668 g_skipDataSchemaMigration = true;
669 break;
670 case 't':
671 g_bTrace = TRUE;
672 break;
673 case 'T':
674 g_migrationTxnSize = strtol(optarg, NULL, 0);
675 if ((g_migrationTxnSize < 1) || (g_migrationTxnSize > 100000))
676 {
677 _tprintf(_T("WARNING: invalid transaction size, reset to default"));
678 g_migrationTxnSize = 4096;
679 }
680 break;
681 case 'I':
682 g_pszTableSuffix = _T(" TYPE=InnoDB");
683 break;
684 case 'L':
685 skipAlarms = true;
686 break;
687 case 'M':
688 g_pszTableSuffix = _T(" TYPE=MyISAM");
689 break;
690 case 'X':
691 g_bIgnoreErrors = TRUE;
692 break;
693 case 'Y':
694 skipSysLog = true;
695 break;
696 case '?':
697 bStart = FALSE;
698 break;
699 default:
700 break;
701 }
702 }
703
704 if (!bStart)
705 return 1;
706
707 if (!bQuiet)
708 _tprintf(_T("NetXMS Database Manager Version ") NETXMS_VERSION_STRING _T(" Build ") NETXMS_VERSION_BUILD_STRING _T(" (") NETXMS_BUILD_TAG _T(")") IS_UNICODE_BUILD_STRING _T("\n\n"));
709
710 // Check parameter correctness
711 if (argc - optind == 0)
712 {
713 _tprintf(_T("Command missing. Type nxdbmgr -h for command line syntax.\n"));
714 return 1;
715 }
716 if (strcmp(argv[optind], "batch") &&
717 strcmp(argv[optind], "check") &&
718 strcmp(argv[optind], "check-data-tables") &&
719 strcmp(argv[optind], "export") &&
720 strcmp(argv[optind], "get") &&
721 strcmp(argv[optind], "import") &&
722 strcmp(argv[optind], "init") &&
723 strcmp(argv[optind], "migrate") &&
724 strcmp(argv[optind], "reset-system-account") &&
725 strcmp(argv[optind], "set") &&
726 strcmp(argv[optind], "unlock") &&
727 strcmp(argv[optind], "upgrade"))
728 {
729 _tprintf(_T("Invalid command \"%hs\". Type nxdbmgr -h for command line syntax.\n"), argv[optind]);
730 return 1;
731 }
732 if (((!strcmp(argv[optind], "init") || !strcmp(argv[optind], "batch") || !strcmp(argv[optind], "export") || !strcmp(argv[optind], "import") || !strcmp(argv[optind], "get") || !strcmp(argv[optind], "migrate")) && (argc - optind < 2)) ||
733 (!strcmp(argv[optind], "set") && (argc - optind < 3)))
734 {
735 _tprintf(_T("Required command argument(s) missing\n"));
736 return 1;
737 }
738
739 // Read configuration file
740 Config *config = new Config();
741 if (!config->loadIniConfig(configFile, _T("server")) || !config->parseTemplate(_T("server"), m_cfgTemplate))
742 {
743 _tprintf(_T("Error loading configuration file\n"));
744 return 2;
745 }
746 delete config;
747
748 // Read and decrypt password
749 if (!_tcscmp(s_dbPassword, _T("?")))
750 {
751 if (!ReadPassword(_T("Database password: "), s_dbPassword, MAX_PASSWORD))
752 {
753 _tprintf(_T("Cannot read password from terminal\n"));
754 return 3;
755 }
756 }
757 DecryptPassword(s_dbLogin, s_dbPassword, s_dbPassword, MAX_PASSWORD);
758
759 #ifndef _WIN32
760 SetDefaultCodepage(m_szCodePage);
761 #endif
762
763 // Connect to database
764 if (!DBInit(0, 0))
765 {
766 _tprintf(_T("Unable to initialize database library\n"));
767 return 3;
768 }
769
770 s_driver = DBLoadDriver(s_dbDriver, s_dbDrvParams, false, NULL, NULL);
771 if (s_driver == NULL)
772 {
773 _tprintf(_T("Unable to load and initialize database driver \"%s\"\n"), s_dbDriver);
774 return 3;
775 }
776
777 g_hCoreDB = ConnectToDatabase();
778 if (g_hCoreDB == NULL)
779 {
780 DBUnloadDriver(s_driver);
781 return 4;
782 }
783
784 if (!strcmp(argv[optind], "init"))
785 {
786 InitDatabase(argv[optind + 1]);
787 }
788 else
789 {
790 // Get database syntax
791 g_dbSyntax = DBGetSyntax(g_hCoreDB);
792 if (g_dbSyntax == DB_SYNTAX_UNKNOWN)
793 {
794 _tprintf(_T("Unable to determine database syntax\n"));
795 DBDisconnect(g_hCoreDB);
796 DBUnloadDriver(s_driver);
797 return 5;
798 }
799
800 // Do requested operation
801 if (!strcmp(argv[optind], "batch"))
802 {
803 ExecSQLBatch(argv[optind + 1]);
804 }
805 else if (!strcmp(argv[optind], "check"))
806 {
807 CheckDatabase();
808 }
809 else if (!strcmp(argv[optind], "check-data-tables"))
810 {
811 g_checkDataTablesOnly = true;
812 CheckDatabase();
813 }
814 else if (!strcmp(argv[optind], "upgrade"))
815 {
816 UpgradeDatabase();
817 }
818 else if (!strcmp(argv[optind], "unlock"))
819 {
820 UnlockDatabase();
821 }
822 else if (!strcmp(argv[optind], "export"))
823 {
824 ExportDatabase(argv[optind + 1], skipAudit, skipAlarms, skipEvent, skipSysLog, skipTrapLog);
825 }
826 else if (!strcmp(argv[optind], "import"))
827 {
828 ImportDatabase(argv[optind + 1]);
829 }
830 else if (!strcmp(argv[optind], "migrate"))
831 {
832 #ifdef UNICODE
833 WCHAR *sourceConfig = WideStringFromMBString(argv[optind + 1]);
834 #else
835 char *sourceConfig = argv[optind + 1];
836 #endif
837 TCHAR destConfFields[2048];
838 _sntprintf(destConfFields, 2048, _T("\tDB Name: %s\n\tDB Server: %s\n\tDB Login: %s"), s_dbName, s_dbServer, s_dbLogin);
839 MigrateDatabase(sourceConfig, destConfFields);
840 #ifdef UNICODE
841 free(sourceConfig);
842 #endif
843 }
844 else if (!strcmp(argv[optind], "get"))
845 {
846 #ifdef UNICODE
847 WCHAR *var = WideStringFromMBString(argv[optind + 1]);
848 #else
849 char *var = argv[optind + 1];
850 #endif
851 TCHAR buffer[MAX_CONFIG_VALUE];
852 ConfigReadStr(var, buffer, MAX_CONFIG_VALUE, _T(""));
853 _tprintf(_T("%s\n"), buffer);
854 #ifdef UNICODE
855 free(var);
856 #endif
857 }
858 else if (!strcmp(argv[optind], "set"))
859 {
860 #ifdef UNICODE
861 WCHAR *var = WideStringFromMBString(argv[optind + 1]);
862 WCHAR *value = WideStringFromMBString(argv[optind + 2]);
863 #else
864 char *var = argv[optind + 1];
865 char *value = argv[optind + 2];
866 #endif
867 CreateConfigParam(var, value, true, false, replaceValue);
868 #ifdef UNICODE
869 free(var);
870 free(value);
871 #endif
872 }
873 else if (!strcmp(argv[optind], "reset-system-account"))
874 {
875 ResetSystemAccount();
876 }
877 }
878
879 // Shutdown
880 DBDisconnect(g_hCoreDB);
881 DBUnloadDriver(s_driver);
882 return 0;
883 }