]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/tools/ScsiDeviceList.cpp
Restore win32 dir from Branch-5.2 and update it
[bacula/bacula] / bacula / src / win32 / tools / ScsiDeviceList.cpp
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
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
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
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
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
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
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
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 }