Fixed bug #0000003
[public/netxms.git] / src / server / core / tools.cpp
1 /*
2 ** Project X - Network Management System
3 ** Copyright (C) 2003 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 ** $module: tools.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 #ifdef _WIN32
26 # include <io.h>
27 #else
28 # ifdef HAVE_SYS_UTSNAME_H
29 # include <sys/utsname.h>
30 # endif
31 #endif
32
33
34 //
35 // Get system error string by call to FormatMessage
36 //
37
38 #ifdef _WIN32
39
40 char NXCORE_EXPORTABLE *GetSystemErrorText(DWORD error)
41 {
42 char *msgBuf;
43 static char staticBuffer[1024];
44
45 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
46 FORMAT_MESSAGE_FROM_SYSTEM |
47 FORMAT_MESSAGE_IGNORE_INSERTS,
48 NULL,error,
49 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), // Default language
50 (LPSTR)&msgBuf,0,NULL)>0)
51 {
52 msgBuf[strcspn(msgBuf,"\r\n")]=0;
53 strncpy(staticBuffer,msgBuf,1023);
54 LocalFree(msgBuf);
55 }
56 else
57 {
58 sprintf(staticBuffer,"MSG 0x%08X - Unable to find message text",error);
59 }
60
61 return staticBuffer;
62 }
63
64 #endif /* _WIN32 */
65
66
67 //
68 // Clean interface list from unneeded entries
69 //
70
71 void CleanInterfaceList(INTERFACE_LIST *pIfList)
72 {
73 int i;
74
75 if (pIfList == NULL)
76 return;
77
78 // Delete loopback interface(s) from list
79 for(i = 0; i < pIfList->iNumEntries; i++)
80 if ((pIfList->pInterfaces[i].dwIpAddr & 0xFF000000) == 0x7F000000)
81 {
82 pIfList->iNumEntries--;
83 memmove(&pIfList->pInterfaces[i], &pIfList->pInterfaces[i + 1],
84 sizeof(INTERFACE_INFO) * (pIfList->iNumEntries - i));
85 i--;
86 }
87 }
88
89
90 //
91 // Get system information string
92 //
93
94 void GetSysInfoStr(char *pszBuffer)
95 {
96 #ifdef _WIN32
97 DWORD dwSize;
98 char computerName[MAX_COMPUTERNAME_LENGTH + 1], osVersion[256];
99 SYSTEM_INFO sysInfo;
100 OSVERSIONINFO versionInfo;
101
102 dwSize = MAX_COMPUTERNAME_LENGTH + 1;
103 GetComputerName(computerName, &dwSize);
104
105 versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
106 GetVersionEx(&versionInfo);
107 GetSystemInfo(&sysInfo);
108
109 switch(versionInfo.dwPlatformId)
110 {
111 case VER_PLATFORM_WIN32_WINDOWS:
112 sprintf(osVersion,"Windows %s-%s",versionInfo.dwMinorVersion == 0 ? "95" :
113 (versionInfo.dwMinorVersion == 10 ? "98" :
114 (versionInfo.dwMinorVersion == 90 ? "Me" : "Unknown")),versionInfo.szCSDVersion);
115 break;
116 case VER_PLATFORM_WIN32_NT:
117 if (versionInfo.dwMajorVersion != 5)
118 sprintf(osVersion,"Windows NT %d.%d %s",versionInfo.dwMajorVersion,
119 versionInfo.dwMinorVersion,versionInfo.szCSDVersion);
120 else // Windows 2000, Windows XP or Windows Server 2003
121 sprintf(osVersion,"Windows %s%s%s",versionInfo.dwMinorVersion == 0 ? "2000" :
122 (versionInfo.dwMinorVersion == 1 ? "XP" : "Server 2003"),
123 versionInfo.szCSDVersion[0] == 0 ? "" : " ", versionInfo.szCSDVersion);
124 break;
125 default:
126 strcpy(osVersion,"Windows [Unknown Version]");
127 break;
128 }
129
130 sprintf(pszBuffer, "%s %s Build %d", computerName, osVersion, versionInfo.dwBuildNumber);
131 #else
132 /* TODO: add UNIX code here */
133 # ifdef HAVE_SYS_UTSNAME_H
134 struct utsname uName;
135 if (uname(&uName) == 0)
136 {
137 sprintf(pszBuffer, "%s %s Release %d", uName.nodename, uName.sysname, uName.release);
138 }
139 else
140 {
141 // size=512 was taken from locks.cpp
142 #if HAVE_STRERROR_R
143 strerror_r(errno, pszBuffer, 512);
144 #else
145 strncpy(pszBuffer, strerror(errno), 512);
146 #endif
147 }
148 # else
149 printf("GetSysInfoStr: code not implemented\n");
150 strcpy(pszBuffer, "UNIX");
151 # endif // HAVE_SYS_UTSNAME_H
152
153 #endif
154 }
155
156
157 //
158 // Get IP address for local machine
159 //
160
161 DWORD GetLocalIpAddr(void)
162 {
163 INTERFACE_LIST *pIfList;
164 DWORD dwAddr = 0;
165 int i;
166
167 pIfList = GetLocalInterfaceList();
168 if (pIfList != NULL)
169 {
170 CleanInterfaceList(pIfList);
171
172 // Find first interface with IP address
173 for(i = 0; i < pIfList->iNumEntries; i++)
174 if (pIfList->pInterfaces[i].dwIpAddr != 0)
175 {
176 dwAddr = pIfList->pInterfaces[i].dwIpAddr;
177 break;
178 }
179 DestroyInterfaceList(pIfList);
180 }
181 return dwAddr;
182 }
183
184
185 //
186 // Execute external command
187 //
188
189 BOOL ExecCommand(char *pszCommand)
190 {
191 BOOL bSuccess = TRUE;
192
193 #ifdef _WIN32
194 STARTUPINFO si;
195 PROCESS_INFORMATION pi;
196
197 // Fill in process startup info structure
198 memset(&si, 0, sizeof(STARTUPINFO));
199 si.cb = sizeof(STARTUPINFO);
200 si.dwFlags = 0;
201
202 // Create new process
203 if (!CreateProcess(NULL, pszCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, NULL, &si, &pi))
204 {
205 WriteLog(MSG_CREATE_PROCESS_FAILED, EVENTLOG_ERROR_TYPE, "se", pszCommand, GetLastError());
206 bSuccess = FALSE;
207 }
208 else
209 {
210 // Close all handles
211 CloseHandle(pi.hThread);
212 CloseHandle(pi.hProcess);
213 }
214 #else
215 /* TODO: add UNIX code here */
216 bSuccess = FALSE;
217 #endif
218
219 return bSuccess;
220 }
221
222
223 //
224 // Load file into memory
225 //
226
227 BYTE *LoadFile(char *pszFileName, DWORD *pdwFileSize)
228 {
229 int fd, iBufPos, iNumBytes, iBytesRead;
230 BYTE *pBuffer = NULL;
231 struct stat fs;
232
233 DbgPrintf(AF_DEBUG_MISC, "Loading file \"%s\" into memory", pszFileName);
234 fd = open(pszFileName, O_RDONLY | O_BINARY);
235 if (fd != -1)
236 {
237 if (fstat(fd, &fs) != -1)
238 {
239 pBuffer = (BYTE *)malloc(fs.st_size + 1);
240 if (pBuffer != NULL)
241 {
242 *pdwFileSize = fs.st_size;
243 for(iBufPos = 0; iBufPos < fs.st_size; iBufPos += iBytesRead)
244 {
245 iNumBytes = min(16384, fs.st_size - iBufPos);
246 if ((iBytesRead = read(fd, &pBuffer[iBufPos], iNumBytes)) < 0)
247 {
248 DbgPrintf(AF_DEBUG_MISC, "File read operation failed");
249 free(pBuffer);
250 pBuffer = NULL;
251 break;
252 }
253 }
254 }
255 }
256 close(fd);
257 }
258 return pBuffer;
259 }
260
261
262 //
263 // Characters to be escaped before writing to SQL
264 //
265
266 static char m_szSpecialChars[] = "\x01\x02\x03\x04\x05\x06\x07\x08"
267 "\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
268 "\x11\x12\x13\x14\x15\x16\x17\x18"
269 "\x19\x1A\x1B\x1C\x1D\x1E\x1F"
270 "#%\"\\'\x7F";
271
272
273 //
274 // Escape some special characters in string for writing into database
275 //
276
277 char NXCORE_EXPORTABLE *EncodeSQLString(const char *pszIn)
278 {
279 char *pszOut;
280 int iPosIn, iPosOut, iStrSize;
281
282 if (*pszIn != 0)
283 {
284 // Allocate destination buffer
285 iStrSize = strlen(pszIn) + 1;
286 for(iPosIn = 0; pszIn[iPosIn] != 0; iPosIn++)
287 if (strchr(m_szSpecialChars, pszIn[iPosIn]) != NULL)
288 iStrSize += 2;
289 pszOut = (char *)malloc(iStrSize);
290
291 // Translate string
292 for(iPosIn = 0, iPosOut = 0; pszIn[iPosIn] != 0; iPosIn++)
293 if (strchr(m_szSpecialChars, pszIn[iPosIn]) != NULL)
294 {
295 pszOut[iPosOut++] = '#';
296 pszOut[iPosOut++] = bin2hex(pszIn[iPosIn] >> 4);
297 pszOut[iPosOut++] = bin2hex(pszIn[iPosIn] & 0x0F);
298 }
299 else
300 {
301 pszOut[iPosOut++] = pszIn[iPosIn];
302 }
303 pszOut[iPosOut] = 0;
304 }
305 else
306 {
307 // Encode empty strings as #00
308 pszOut = (char *)malloc(4);
309 strcpy(pszOut, "#00");
310 }
311 return pszOut;
312 }
313
314
315 //
316 // Restore characters encoded by EncodeSQLString()
317 // Characters are decoded "in place"
318 //
319
320 void NXCORE_EXPORTABLE DecodeSQLString(char *pszStr)
321 {
322 int iPosIn, iPosOut;
323
324 for(iPosIn = 0, iPosOut = 0; pszStr[iPosIn] != 0; iPosIn++)
325 {
326 if (pszStr[iPosIn] == '#')
327 {
328 iPosIn++;
329 pszStr[iPosOut] = hex2bin(pszStr[iPosIn]) << 4;
330 iPosIn++;
331 pszStr[iPosOut] |= hex2bin(pszStr[iPosIn]);
332 iPosOut++;
333 }
334 else
335 {
336 pszStr[iPosOut++] = pszStr[iPosIn];
337 }
338 }
339 pszStr[iPosOut] = 0;
340 }
341
342
343 //
344 // Send Wake-on-LAN packet (magic packet) to given IP address
345 // with given MAC address inside
346 //
347
348 BOOL SendMagicPacket(DWORD dwIpAddr, BYTE *pbMacAddr, int iNumPackets)
349 {
350 BYTE *pCurr, bPacketData[96];
351 SOCKET hSocket;
352 struct sockaddr_in addr;
353 BOOL bResult = TRUE;
354 int i;
355
356 // Create data area
357 for(i = 0, pCurr = bPacketData; i < 16; i++, pCurr += 6)
358 memcpy(pCurr, pbMacAddr, 6);
359
360 // Create socket
361 hSocket = socket(AF_INET, SOCK_DGRAM, 0);
362 if (hSocket == -1)
363 return FALSE;
364
365 memset(&addr, 0, sizeof(struct sockaddr_in));
366 addr.sin_family = AF_INET;
367 addr.sin_addr.s_addr = dwIpAddr;
368 addr.sin_port = 53;
369
370 // Send requested number of packets
371 for(i = 0; i < iNumPackets; i++)
372 if (sendto(hSocket, (char *)bPacketData, 96, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
373 bResult = FALSE;
374
375 // Cleanup
376 closesocket(hSocket);
377 return bResult;
378 }