1 /*
2 * ScsiDeviceList.cpp - Class which provides information on installed devices.
3 *
4 * Author: Robert Nelson, August, 2006 <robertn@the-nelsons.org>
5 *
6 * Version $Id$
7 *
8 * This file was contributed to the Bacula project by Robert Nelson.
9 *
10 * Robert Nelson has been granted a perpetual, worldwide,
11 * non-exclusive, no-charge, royalty-free, irrevocable copyright
12 * license to reproduce, prepare derivative works of, publicly
13 * display, publicly perform, sublicense, and distribute the original
14 * work contributed by Robert Nelson to the Bacula project in source
15 * or object form.
16 *
17 * If you wish to license contributions from Robert Nelson
18 * under an alternate open source license please contact
19 * Robert Nelson <robertn@the-nelsons.org>.
20 */
21 /*
22 Bacula® - The Network Backup Solution
23
24 Copyright (C) 2006-2006 Free Software Foundation Europe e.V.
25
26 The main author of Bacula is Kern Sibbald, with contributions from
27 many others, a complete list can be found in the file AUTHORS.
28 This program is Free Software; you can redistribute it and/or
29 modify it under the terms of version three of the GNU Affero General Public
30 License as published by the Free Software Foundation and included
31 in the file LICENSE.
32
33 This program is distributed in the hope that it will be useful, but
34 WITHOUT ANY WARRANTY; without even the implied warranty of
35 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 General Public License for more details.
37
38 You should have received a copy of the GNU Affero General Public License
39 along with this program; if not, write to the Free Software
40 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
41 02110-1301, USA.
42
43 Bacula® is a registered trademark of Kern Sibbald.
44 The licensor of Bacula is the Free Software Foundation Europe
45 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
46 Switzerland, email:ftf@fsfeurope.org.
47 */
48
49 #if defined(_MSC_VER) && defined(_DEBUG)
50 #include <afx.h>
51 #else
52 #include <windows.h>
53 #endif
54
55 #include <stdio.h>
56 #include <tchar.h>
57
58 #include "ScsiDeviceList.h"
59
60 #if defined(_MSC_VER) && defined(_DEBUG)
61 #define new DEBUG_NEW
62 #endif
63
64 TCHAR CScsiDeviceList::c_ScsiPath[] = _T("HARDWARE\\DEVICEMAP\\Scsi");
65
66 LPCTSTR CScsiDeviceList::c_lpszFormatList[] =
67 {
68 _T("Logical Unit Id %d"),
69 _T("Target Id %d"),
70 _T("Scsi Bus %d"),
71 _T("Scsi Port %d")
72 };
73
74 LPCTSTR CScsiDeviceListEntry::c_DeviceTypes[] =
75 {
76 _T("Unknown"),
77 _T("CDRom"),
78 _T("Changer"),
79 _T("Disk"),
80 _T("Tape")
81 };
82
CScsiDeviceListEntry(const CScsiDeviceListEntry & other)83 CScsiDeviceListEntry::CScsiDeviceListEntry(const CScsiDeviceListEntry &other)
84 {
85 m_eDeviceType = other.m_eDeviceType;
86
87 m_lpszIdentifier = other.m_lpszIdentifier != NULL ? _tcsdup(other.m_lpszIdentifier) : NULL;
88
89 m_lpszDeviceName = other.m_lpszDeviceName != NULL ? _tcsdup(other.m_lpszDeviceName) : NULL;
90
91 m_dwDeviceId = other.m_dwDeviceId;
92 _tcscpy(m_szDevicePath, other.m_szDevicePath);
93 }
94
CScsiDeviceListEntry(void)95 CScsiDeviceListEntry::CScsiDeviceListEntry(void)
96 {
97 m_eDeviceType = Unknown;
98 m_lpszIdentifier = NULL;
99 m_lpszDeviceName = NULL;
100 m_dwDeviceId = 0;
101 m_szDevicePath[0] = _T('\0');
102 }
103
~CScsiDeviceListEntry(void)104 CScsiDeviceListEntry::~CScsiDeviceListEntry(void)
105 {
106 if (m_lpszIdentifier != NULL)
107 {
108 free(m_lpszIdentifier);
109 }
110
111 if (m_lpszDeviceName != NULL)
112 {
113 free(m_lpszDeviceName);
114 }
115 }
116
117 bool
Populate()118 CScsiDeviceList::Populate()
119 {
120 this->clear();
121
122 HKEY hScsiKey;
123
124 _tcscpy(m_szLastKey, _T("\\Scsi"));
125 m_dwLastKeyLength = 5;
126
127 m_lLastError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
128 c_ScsiPath,
129 0,
130 KEY_READ,
131 &hScsiKey);
132
133 if (m_lLastError != ERROR_SUCCESS) {
134 _tcscpy(m_szLastOperation, _T("Opening key "));
135 _tcscpy(m_szLastKey, c_ScsiPath);
136 return false;
137 }
138
139 if (!ProcessKey(hScsiKey, c_MaxKeyDepth - 1, 0)) {
140 return false;
141 }
142
143 #if defined(_DEBUG)
144 _fputtc(_T('\n'), stderr);
145 #endif
146
147 return true;
148 }
149
150 bool
ProcessKey(HKEY hKey,int iLevel,DWORD dwDeviceId)151 CScsiDeviceList::ProcessKey(HKEY hKey, int iLevel, DWORD dwDeviceId)
152 {
153 #if defined(_DEBUG)
154 switch (iLevel)
155 {
156 case 3:
157 _ftprintf( stderr,
158 _T("%-64s\n"),
159 &m_szLastKey[1]);
160 break;
161
162 case 2:
163 _ftprintf( stderr,
164 _T("%-64s%d\n"),
165 &m_szLastKey[1],
166 dwDeviceId & 0xFF);
167 break;
168
169 case 1:
170 _ftprintf( stderr,
171 _T("%-64s%d:%d\n"),
172 &m_szLastKey[1],
173 (dwDeviceId >> 8) & 0xFF,
174 dwDeviceId & 0xFF);
175 break;
176
177 case 0:
178 _ftprintf( stderr,
179 _T("%-64s%d:%d:%d\n"),
180 &m_szLastKey[1],
181 (dwDeviceId >> 16) & 0xFF,
182 (dwDeviceId >> 8) & 0xFF,
183 dwDeviceId & 0xFF);
184 break;
185 }
186 #endif
187
188 for (int idxSubkey = 0; ; idxSubkey++) {
189
190 TCHAR szSubkeyName[c_MaxSubkeyLength + 1];
191 DWORD dwLength;
192
193 dwLength = sizeof(szSubkeyName);
194
195 m_lLastError = RegEnumKeyEx( hKey,
196 idxSubkey,
197 szSubkeyName,
198 &dwLength,
199 NULL,
200 NULL,
201 NULL,
202 NULL);
203
204 if (m_lLastError == ERROR_NO_MORE_ITEMS) {
205 break;
206 } else if (m_lLastError == ERROR_MORE_DATA) {
207 #if defined(_DEBUG)
208 _tcscpy(m_szLastOperation, _T("Enumerating subkeys of "));
209 PrintLastError();
210 #endif
211 // Subkey name is too long
212 continue;
213 } else if (m_lLastError != ERROR_SUCCESS) {
214 // Unexpected Error
215 _tcscpy(m_szLastOperation, _T("Enumerating subkeys of "));
216 return false;
217 }
218
219 int iValue;
220
221 if (_stscanf(szSubkeyName, c_lpszFormatList[iLevel], &iValue) != 1) {
222 // Ignore this subkey, it is probably Initiator Id n
223 continue;
224 }
225
226 m_szLastKey[m_dwLastKeyLength++] = _T('\\');
227
228 DWORD dwSubkeyLength = (DWORD)_tcslen(szSubkeyName);
229 memcpy(&m_szLastKey[m_dwLastKeyLength], szSubkeyName, (dwSubkeyLength + 1) * sizeof(TCHAR));
230 m_dwLastKeyLength += dwSubkeyLength;
231
232 HKEY hSubkey;
233
234 m_lLastError = RegOpenKeyEx(hKey, szSubkeyName, 0, KEY_READ, &hSubkey);
235
236 if (m_lLastError != ERROR_SUCCESS) {
237 _tcscpy(m_szLastOperation, _T("Opening key "));
238 return false;
239 }
240
241 if (iLevel == 0) {
242 #if defined(_DEBUG)
243 _ftprintf( stderr,
244 _T("%-64s%d:%d:%d:%d\n"),
245 &m_szLastKey[1],
246 (dwDeviceId >> 16) & 0xFF,
247 (dwDeviceId >> 8) & 0xFF,
248 dwDeviceId & 0xFF,
249 iValue);
250 #endif
251
252 ProcessValues(hSubkey, (dwDeviceId << 8) | iValue);
253 } else {
254 if (!ProcessKey(hSubkey, iLevel - 1, (dwDeviceId << 8) | iValue)) {
255 return false;
256 }
257 }
258
259 m_dwLastKeyLength -= dwSubkeyLength;
260 m_dwLastKeyLength--;
261 m_szLastKey[m_dwLastKeyLength] = _T('\0');
262 }
263
264 return true;
265 }
266
267 bool
ProcessValues(HKEY hKey,DWORD dwDeviceId)268 CScsiDeviceList::ProcessValues(HKEY hKey, DWORD dwDeviceId)
269 {
270 CScsiDeviceListEntry EntryTemplate;
271 DWORD dwType;
272 DWORD dwSize;
273 TCHAR szValue[c_MaxValueLength + 1];
274
275 this->push_back(EntryTemplate);
276 CScsiDeviceListEntry & entry = this->back();
277
278 dwSize = sizeof(szValue);
279
280 m_lLastError = RegQueryValueEx( hKey,
281 _T("Identifier"),
282 NULL,
283 &dwType,
284 (LPBYTE)&szValue[0],
285 &dwSize);
286
287 if (m_lLastError == ERROR_SUCCESS) {
288 entry.m_lpszIdentifier = _tcsdup(szValue);
289 } else {
290 #if defined(_DEBUG)
291 _tcscpy(m_szLastOperation, _T("Reading value "));
292 PrintLastError(_T("Identifier"));
293 #endif
294 }
295
296 dwSize = sizeof(szValue);
297
298 m_lLastError = RegQueryValueEx( hKey,
299 _T("DeviceName"),
300 NULL,
301 &dwType,
302 (LPBYTE)&szValue[0],
303 &dwSize);
304
305 if (m_lLastError == ERROR_SUCCESS) {
306 entry.m_lpszDeviceName = _tcsdup(szValue);
307 } else {
308 #if defined(_DEBUG)
309 _tcscpy(m_szLastOperation, _T("Reading value "));
310 PrintLastError(_T("DeviceName"));
311 #endif
312 }
313
314 dwSize = sizeof(szValue);
315
316 m_lLastError = RegQueryValueEx( hKey,
317 _T("Type"),
318 NULL,
319 &dwType,
320 (LPBYTE)&szValue[0],
321 &dwSize);
322
323 if (m_lLastError == ERROR_SUCCESS) {
324 if (_tcscmp(_T("CdRomPeripheral"), szValue) == 0) {
325 entry.m_eDeviceType = CScsiDeviceListEntry::CDRom;
326 } else if (_tcscmp(_T("DiskPeripheral"), szValue) == 0) {
327 entry.m_eDeviceType = CScsiDeviceListEntry::Disk;
328 } else if (_tcscmp(_T("MediumChangerPeripheral"), szValue) == 0) {
329 entry.m_eDeviceType = CScsiDeviceListEntry::Changer;
330 } else if (_tcscmp(_T("TapePeripheral"), szValue) == 0) {
331 entry.m_eDeviceType = CScsiDeviceListEntry::Tape;
332 }
333 } else {
334 #if defined(_DEBUG)
335 _tcscpy(m_szLastOperation, _T("Reading value "));
336 PrintLastError(_T("Type"));
337 #endif
338 }
339
340 entry.m_dwDeviceId = dwDeviceId;
341
342 return true;
343 }
344
345 void
PrintLastError(LPTSTR lpszName)346 CScsiDeviceList::PrintLastError(LPTSTR lpszName)
347 {
348 LPTSTR lpszMessage = NULL;
349
350 _fputts(_T("Error: "), stderr);
351 _fputts(m_szLastOperation, stderr);
352 _fputtc(_T('"'), stderr);
353 _fputts(lpszName != NULL ? lpszName : m_szLastKey, stderr);
354 _fputts(_T("\" - "), stderr);
355
356 FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
357 NULL, m_lLastError, 0, (LPTSTR)&lpszMessage, 0, NULL);
358
359 if (lpszMessage != NULL) {
360 _fputts(lpszMessage, stderr);
361 LocalFree(lpszMessage);
362 }
363 }
364