75eebaa62e09030b418c04b25dfd1fb06fd634d3
[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 #endif
217
218 return bSuccess;
219 }
220
221
222 //
223 // Load file into memory
224 //
225
226 BYTE *LoadFile(char *pszFileName, DWORD *pdwFileSize)
227 {
228 int fd, iBufPos, iNumBytes, iBytesRead;
229 BYTE *pBuffer = NULL;
230 struct stat fs;
231
232 DbgPrintf(AF_DEBUG_MISC, "Loading file \"%s\" into memory", pszFileName);
233 fd = open(pszFileName, O_RDONLY | O_BINARY);
234 if (fd != -1)
235 {
236 if (fstat(fd, &fs) != -1)
237 {
238 pBuffer = (BYTE *)malloc(fs.st_size + 1);
239 if (pBuffer != NULL)
240 {
241 *pdwFileSize = fs.st_size;
242 for(iBufPos = 0; iBufPos < fs.st_size; iBufPos += iBytesRead)
243 {
244 iNumBytes = min(16384, fs.st_size - iBufPos);
245 if ((iBytesRead = read(fd, &pBuffer[iBufPos], iNumBytes)) < 0)
246 {
247 DbgPrintf(AF_DEBUG_MISC, "File read operation failed");
248 free(pBuffer);
249 pBuffer = NULL;
250 break;
251 }
252 }
253 }
254 }
255 close(fd);
256 }
257 return pBuffer;
258 }
259
260
261 //
262 // Characters to be escaped before writing to SQL
263 //
264
265 static char m_szSpecialChars[] = "\x01\x02\x03\x04\x05\x06\x07\x08"
266 "\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
267 "\x11\x12\x13\x14\x15\x16\x17\x18"
268 "\x19\x1A\x1B\x1C\x1D\x1E\x1F"
269 "#%\"\\'\x7F";
270
271
272 //
273 // Escape some special characters in string for writing into database
274 //
275
276 char NXCORE_EXPORTABLE *EncodeSQLString(const char *pszIn)
277 {
278 char *pszOut;
279 int iPosIn, iPosOut, iStrSize;
280
281 // Allocate destination buffer
282 iStrSize = strlen(pszIn) + 1;
283 for(iPosIn = 0; pszIn[iPosIn] != 0; iPosIn++)
284 if (strchr(m_szSpecialChars, pszIn[iPosIn]) != NULL)
285 iStrSize += 2;
286 pszOut = (char *)malloc(iStrSize);
287
288 // TRanslate string
289 for(iPosIn = 0, iPosOut = 0; pszIn[iPosIn] != 0; iPosIn++)
290 if (strchr(m_szSpecialChars, pszIn[iPosIn]) != NULL)
291 {
292 pszOut[iPosOut++] = '#';
293 pszOut[iPosOut++] = bin2hex(pszIn[iPosIn] >> 4);
294 pszOut[iPosOut++] = bin2hex(pszIn[iPosIn] & 0x0F);
295 }
296 else
297 {
298 pszOut[iPosOut++] = pszIn[iPosIn];
299 }
300 pszOut[iPosOut] = 0;
301 return pszOut;
302 }
303
304
305 //
306 // Restore characters encoded by EncodeSQLString()
307 // Characters are decoded "in place"
308 //
309
310 void NXCORE_EXPORTABLE DecodeSQLString(char *pszStr)
311 {
312 int iPosIn, iPosOut;
313
314 for(iPosIn = 0, iPosOut = 0; pszStr[iPosIn] != 0; iPosIn++)
315 {
316 if (pszStr[iPosIn] == '#')
317 {
318 iPosIn++;
319 pszStr[iPosOut] = hex2bin(pszStr[iPosIn]) << 4;
320 iPosIn++;
321 pszStr[iPosOut] |= hex2bin(pszStr[iPosIn]);
322 iPosOut++;
323 }
324 else
325 {
326 pszStr[iPosOut++] = pszStr[iPosIn];
327 }
328 }
329 pszStr[iPosOut] = 0;
330 }
331
332
333 //
334 // Send Wake-on-LAN packet (magic packet) to given IP address
335 // with given MAC address inside
336 //
337
338 BOOL SendMagicPacket(DWORD dwIpAddr, BYTE *pbMacAddr, int iNumPackets)
339 {
340 BYTE *pCurr, bPacketData[96];
341 SOCKET hSocket;
342 struct sockaddr_in addr;
343 BOOL bResult = TRUE;
344 int i;
345
346 // Create data area
347 for(i = 0, pCurr = bPacketData; i < 16; i++, pCurr += 6)
348 memcpy(pCurr, pbMacAddr, 6);
349
350 // Create socket
351 hSocket = socket(AF_INET, SOCK_DGRAM, 0);
352 if (hSocket == -1)
353 return FALSE;
354
355 memset(&addr, 0, sizeof(struct sockaddr_in));
356 addr.sin_family = AF_INET;
357 addr.sin_addr.s_addr = dwIpAddr;
358 addr.sin_port = 53;
359
360 // Send requested number of packets
361 for(i = 0; i < iNumPackets; i++)
362 if (sendto(hSocket, (char *)bPacketData, 96, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
363 bResult = FALSE;
364
365 // Cleanup
366 closesocket(hSocket);
367 return bResult;
368 }