1 /*
2 * Copyright (c) 2006-2014 Douglas Gilbert.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #ifdef SG_LIB_WIN32
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stddef.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <ctype.h>
43 #include <getopt.h>
44
45
46 #include "sg_lib.h"
47
48 #ifdef _WIN32_WINNT
49 #if _WIN32_WINNT < 0x0602
50 #undef _WIN32_WINNT
51 #define _WIN32_WINNT 0x0602
52 #endif
53 #else
54 #define _WIN32_WINNT 0x0602
55 /* claim its W8 */
56 #endif
57
58 #include "sg_pt_win32.h"
59
60 #include "ddpt.h"
61
62 /*
63 * This is called when the '--wscan' option is given to ddpt. It is
64 * Win32 only code and shows the relationship between various device names
65 * and volumes in Windows OSes (Windows 2000, 2003, XP, Vista, W7 and W8).
66 * There is an optional scsi adapter scan.
67 */
68
69 #define MAX_SCSI_ELEMS 1024
70 #define MAX_ADAPTER_NUM 64
71 #define MAX_PHYSICALDRIVE_NUM 512
72 #define MAX_CDROM_NUM 512
73 #define MAX_TAPE_NUM 512
74 #define MAX_HOLE_COUNT 8
75
76 // IOCTL_STORAGE_QUERY_PROPERTY
77
78 #define FILE_DEVICE_MASS_STORAGE 0x0000002d
79 #define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE
80 #define FILE_ANY_ACCESS 0
81
82 // #define METHOD_BUFFERED 0
83
84 #define IOCTL_STORAGE_QUERY_PROPERTY \
85 CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
86
87
88 #ifndef _DEVIOCTL_
89 typedef enum _STORAGE_BUS_TYPE {
90 BusTypeUnknown = 0x00,
91 BusTypeScsi = 0x01,
92 BusTypeAtapi = 0x02,
93 BusTypeAta = 0x03,
94 BusType1394 = 0x04,
95 BusTypeSsa = 0x05,
96 BusTypeFibre = 0x06,
97 BusTypeUsb = 0x07,
98 BusTypeRAID = 0x08,
99 BusTypeiScsi = 0x09,
100 BusTypeSas = 0x0A,
101 BusTypeSata = 0x0B,
102 BusTypeSd = 0x0C,
103 BusTypeMmc = 0x0D,
104 BusTypeVirtual = 0xE,
105 BusTypeFileBackedVirtual = 0xF,
106 BusTypeMax,
107 BusTypeMaxReserved = 0x7F
108 } STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;
109
110 typedef struct _STORAGE_DEVICE_DESCRIPTOR {
111 ULONG Version;
112 ULONG Size;
113 UCHAR DeviceType;
114 UCHAR DeviceTypeModifier;
115 BOOLEAN RemovableMedia;
116 BOOLEAN CommandQueueing;
117 ULONG VendorIdOffset; /* 0 if not available */
118 ULONG ProductIdOffset; /* 0 if not available */
119 ULONG ProductRevisionOffset;/* 0 if not available */
120 ULONG SerialNumberOffset; /* -1 if not available ?? */
121 STORAGE_BUS_TYPE BusType;
122 ULONG RawPropertiesLength;
123 UCHAR RawDeviceProperties[1];
124 } STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;
125 #endif
126
127 typedef struct _STORAGE_DEVICE_UNIQUE_IDENTIFIER {
128 ULONG Version;
129 ULONG Size;
130 ULONG StorageDeviceIdOffset;
131 ULONG StorageDeviceOffset;
132 ULONG DriveLayoutSignatureOffset;
133 } STORAGE_DEVICE_UNIQUE_IDENTIFIER, *PSTORAGE_DEVICE_UNIQUE_IDENTIFIER;
134
135 // Use CompareStorageDuids(PSTORAGE_DEVICE_UNIQUE_IDENTIFIER duid1, duid2)
136 // to test for equality
137
138 #ifndef _DEVIOCTL_
139 typedef enum _STORAGE_QUERY_TYPE {
140 PropertyStandardQuery = 0,
141 PropertyExistsQuery,
142 PropertyMaskQuery,
143 PropertyQueryMaxDefined
144 } STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;
145
146 typedef enum _STORAGE_PROPERTY_ID {
147 StorageDeviceProperty = 0,
148 StorageAdapterProperty,
149 StorageDeviceIdProperty,
150 StorageDeviceUniqueIdProperty,
151 StorageDeviceWriteCacheProperty,
152 StorageMiniportProperty,
153 StorageAccessAlignmentProperty
154 } STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
155
156 typedef struct _STORAGE_PROPERTY_QUERY {
157 STORAGE_PROPERTY_ID PropertyId;
158 STORAGE_QUERY_TYPE QueryType;
159 UCHAR AdditionalParameters[1];
160 } STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
161 #endif
162
163
164 /////////////////////////////////////////////////////////////////////////////
165
166 union STORAGE_DEVICE_DESCRIPTOR_DATA {
167 STORAGE_DEVICE_DESCRIPTOR desc;
168 char raw[256];
169 };
170
171 union STORAGE_DEVICE_UID_DATA {
172 STORAGE_DEVICE_UNIQUE_IDENTIFIER desc;
173 char raw[1060];
174 };
175
176 struct storage_elem {
177 char name[32];
178 char volume_letters[32];
179 int qp_descriptor_valid;
180 int qp_uid_valid;
181 union STORAGE_DEVICE_DESCRIPTOR_DATA qp_descriptor;
182 union STORAGE_DEVICE_UID_DATA qp_uid;
183 };
184
185
186 static struct storage_elem * storage_arr;
187 static int next_unused_elem = 0;
188 static int verbose = 0;
189
190
191 static char *
get_err_str(DWORD err,int max_b_len,char * b)192 get_err_str(DWORD err, int max_b_len, char * b)
193 {
194 LPVOID lpMsgBuf;
195 int k, num, ch;
196
197 if (max_b_len < 2) {
198 if (1 == max_b_len)
199 b[0] = '\0';
200 return b;
201 }
202 memset(b, 0, max_b_len);
203 FormatMessage(
204 FORMAT_MESSAGE_ALLOCATE_BUFFER |
205 FORMAT_MESSAGE_FROM_SYSTEM,
206 NULL, err,
207 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
208 (LPTSTR) &lpMsgBuf, 0, NULL );
209 num = lstrlen((LPCTSTR)lpMsgBuf);
210 if (num < 1)
211 return b;
212 num = (num < max_b_len) ? num : (max_b_len - 1);
213 for (k = 0; k < num; ++k) {
214 ch = *((LPCTSTR)lpMsgBuf + k);
215 if ((ch >= 0x0) && (ch < 0x7f))
216 b[k] = ch & 0x7f;
217 else
218 b[k] = '?';
219 }
220 return b;
221 }
222
223 static const char *
get_bus_type(int bt)224 get_bus_type(int bt)
225 {
226 switch (bt)
227 {
228 case BusTypeUnknown:
229 return "Unkno";
230 case BusTypeScsi:
231 return "Scsi ";
232 case BusTypeAtapi:
233 return "Atapi";
234 case BusTypeAta:
235 return "Ata ";
236 case BusType1394:
237 return "1394 ";
238 case BusTypeSsa:
239 return "Ssa ";
240 case BusTypeFibre:
241 return "Fibre";
242 case BusTypeUsb:
243 return "Usb ";
244 case BusTypeRAID:
245 return "RAID ";
246 case BusTypeiScsi:
247 return "iScsi";
248 case BusTypeSas:
249 return "Sas ";
250 case BusTypeSata:
251 return "Sata ";
252 case BusTypeSd:
253 return "Sd ";
254 case BusTypeMmc:
255 return "Mmc ";
256 case BusTypeVirtual:
257 return "Virt ";
258 case BusTypeFileBackedVirtual:
259 return "FBVir";
260 case BusTypeMax:
261 return "Max ";
262 default:
263 return "_unkn";
264 }
265 }
266
267 static int
query_dev_property(HANDLE hdevice,union STORAGE_DEVICE_DESCRIPTOR_DATA * data)268 query_dev_property(HANDLE hdevice,
269 union STORAGE_DEVICE_DESCRIPTOR_DATA * data)
270 {
271 DWORD num_out, err;
272 char b[256];
273 STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty,
274 PropertyStandardQuery, {0} };
275
276 memset(data, 0, sizeof(*data));
277 if (! DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
278 &query, sizeof(query), data, sizeof(*data),
279 &num_out, NULL)) {
280 if (verbose > 2) {
281 err = GetLastError();
282 pr2serr(" IOCTL_STORAGE_QUERY_PROPERTY(Devprop) failed, "
283 "Error=%u %s\n", (unsigned int)err,
284 get_err_str(err, sizeof(b), b));
285 }
286 return -ENOSYS;
287 }
288
289 if (verbose > 3)
290 pr2serr(" IOCTL_STORAGE_QUERY_PROPERTY(DevProp) num_out=%u\n",
291 (unsigned int)num_out);
292 return 0;
293 }
294
295 static int
query_dev_uid(HANDLE hdevice,union STORAGE_DEVICE_UID_DATA * data)296 query_dev_uid(HANDLE hdevice,
297 union STORAGE_DEVICE_UID_DATA * data)
298 {
299 DWORD num_out, err;
300 char b[256];
301 STORAGE_PROPERTY_QUERY query = {StorageDeviceUniqueIdProperty,
302 PropertyStandardQuery, {0} };
303
304 memset(data, 0, sizeof(*data));
305 num_out = 0;
306 query.QueryType = PropertyExistsQuery;
307 if (! DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
308 &query, sizeof(query), NULL, 0, &num_out, NULL)) {
309 if (verbose > 2) {
310 err = GetLastError();
311 fprintf(stderr, " IOCTL_STORAGE_QUERY_PROPERTY(DevUid(exists)) "
312 "failed, Error=%u %s\n", (unsigned int)err,
313 get_err_str(err, sizeof(b), b));
314 }
315 if (verbose > 3)
316 fprintf(stderr, " num_out=%u\n", (unsigned int)num_out);
317 /* interpret any error to mean this property doesn't exist */
318 return 0;
319 }
320
321 query.QueryType = PropertyStandardQuery;
322 if (! DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY,
323 &query, sizeof(query), data, sizeof(*data),
324 &num_out, NULL)) {
325 if (verbose > 2) {
326 err = GetLastError();
327 fprintf(stderr, " IOCTL_STORAGE_QUERY_PROPERTY(DevUid) failed, "
328 "Error=%u %s\n", (unsigned int)err,
329 get_err_str(err, sizeof(b), b));
330 }
331 return -ENOSYS;
332 }
333 if (verbose > 3)
334 fprintf(stderr, " IOCTL_STORAGE_QUERY_PROPERTY(DevUid) num_out=%u\n",
335 (unsigned int)num_out);
336 return 0;
337 }
338
339 /* Updates storage_arr based on sep. Returns 1 if update occurred, 0 if
340 * no update occured. */
341 static int
check_devices(const struct storage_elem * sep)342 check_devices(const struct storage_elem * sep)
343 {
344 int k, j;
345 struct storage_elem * sarr = storage_arr;
346
347 for (k = 0; k < next_unused_elem; ++k, ++sarr) {
348 if ('\0' == sarr->name[0])
349 continue;
350 if (sep->qp_uid_valid && sarr->qp_uid_valid) {
351 if (0 == memcmp(&sep->qp_uid, &sarr->qp_uid,
352 sizeof(sep->qp_uid))) {
353 for (j = 0; j < (int)sizeof(sep->volume_letters); ++j) {
354 if ('\0' == sarr->volume_letters[j]) {
355 sarr->volume_letters[j] = sep->name[0];
356 break;
357 }
358 }
359 return 1;
360 }
361 } else if (sep->qp_descriptor_valid && sarr->qp_descriptor_valid) {
362 if (0 == memcmp(&sep->qp_descriptor, &sarr->qp_descriptor,
363 sizeof(sep->qp_descriptor))) {
364 for (j = 0; j < (int)sizeof(sep->volume_letters); ++j) {
365 if ('\0' == sarr->volume_letters[j]) {
366 sarr->volume_letters[j] = sep->name[0];
367 break;
368 }
369 }
370 return 1;
371 }
372 }
373 }
374 return 0;
375 }
376
377 static int
enum_scsi_adapters(void)378 enum_scsi_adapters(void)
379 {
380 int k, j;
381 int hole_count = 0;
382 HANDLE fh;
383 ULONG dummy;
384 DWORD err;
385 BYTE bus;
386 BOOL success;
387 char adapter_name[64];
388 char inqDataBuff[8192];
389 PSCSI_ADAPTER_BUS_INFO ai;
390 char b[256];
391
392 for (k = 0; k < MAX_ADAPTER_NUM; ++k) {
393 snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\SCSI%d:", k);
394 fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE,
395 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
396 OPEN_EXISTING, 0, NULL);
397 if (fh != INVALID_HANDLE_VALUE) {
398 hole_count = 0;
399 success = DeviceIoControl(fh, IOCTL_SCSI_GET_INQUIRY_DATA,
400 NULL, 0, inqDataBuff,
401 sizeof(inqDataBuff), &dummy, NULL);
402 if (success) {
403 PSCSI_BUS_DATA pbd;
404 PSCSI_INQUIRY_DATA pid;
405 int num_lus, off;
406
407 ai = (PSCSI_ADAPTER_BUS_INFO)inqDataBuff;
408 for (bus = 0; bus < ai->NumberOfBusses; bus++) {
409 pbd = ai->BusData + bus;
410 num_lus = pbd->NumberOfLogicalUnits;
411 off = pbd->InquiryDataOffset;
412 for (j = 0; j < num_lus; ++j) {
413 if ((off < (int)sizeof(SCSI_ADAPTER_BUS_INFO)) ||
414 (off > ((int)sizeof(inqDataBuff) -
415 (int)sizeof(SCSI_INQUIRY_DATA))))
416 break;
417 pid = (PSCSI_INQUIRY_DATA)(inqDataBuff + off);
418 snprintf(b, sizeof(b) - 1, "SCSI%d:%d,%d,%d ", k,
419 pid->PathId, pid->TargetId, pid->Lun);
420 printf("%-15s", b);
421 snprintf(b, sizeof(b) - 1, "claimed=%d pdt=%xh %s ",
422 pid->DeviceClaimed,
423 pid->InquiryData[0] % 0x3f,
424 ((0 == pid->InquiryData[4]) ? "dubious" :
425 ""));
426 printf("%-26s", b);
427 printf("%.8s %.16s %.4s\n", pid->InquiryData + 8,
428 pid->InquiryData + 16, pid->InquiryData + 32);
429 off = pid->NextInquiryDataOffset;
430 }
431 }
432 } else {
433 err = GetLastError();
434 pr2serr("%s: IOCTL_SCSI_GET_INQUIRY_DATA failed err=%u\n"
435 "\t%s", adapter_name, (unsigned int)err,
436 get_err_str(err, sizeof(b), b));
437 }
438 CloseHandle(fh);
439 } else {
440 err = GetLastError();
441 if (ERROR_SHARING_VIOLATION == err)
442 fprintf(stderr, "%s: in use by other process (sharing "
443 "violation [34])\n", adapter_name);
444 else if (verbose > 3)
445 pr2serr("%s: CreateFile failed err=%u\n\t%s", adapter_name,
446 (unsigned int)err, get_err_str(err, sizeof(b), b));
447 if (++hole_count >= MAX_HOLE_COUNT)
448 break;
449 }
450 }
451 return 0;
452 }
453
454 static int
enum_volumes(char letter)455 enum_volumes(char letter)
456 {
457 int k;
458 HANDLE fh;
459 char adapter_name[64];
460 struct storage_elem tmp_se;
461
462 if (verbose > 2)
463 pr2serr("%s: enter\n", __func__ );
464 for (k = 0; k < 24; ++k) {
465 memset(&tmp_se, 0, sizeof(tmp_se));
466 snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\%c:", 'C' + k);
467 tmp_se.name[0] = 'C' + k;
468 fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE,
469 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
470 OPEN_EXISTING, 0, NULL);
471 if (fh != INVALID_HANDLE_VALUE) {
472 if (query_dev_property(fh, &tmp_se.qp_descriptor) < 0)
473 pr2serr("%s: query_dev_property failed\n", __func__ );
474 else
475 tmp_se.qp_descriptor_valid = 1;
476 if (query_dev_uid(fh, &tmp_se.qp_uid) < 0) {
477 if (verbose > 2)
478 pr2serr("%s: query_dev_uid failed\n", __func__ );
479 } else
480 tmp_se.qp_uid_valid = 1;
481 if (('\0' == letter) || (letter == tmp_se.name[0]))
482 check_devices(&tmp_se);
483 CloseHandle(fh);
484 }
485 }
486 return 0;
487 }
488
489 static int
enum_pds(void)490 enum_pds(void)
491 {
492 int k;
493 int hole_count = 0;
494 HANDLE fh;
495 DWORD err;
496 char adapter_name[64];
497 char b[256];
498 struct storage_elem tmp_se;
499
500 if (verbose > 2)
501 pr2serr("%s: enter\n", __func__ );
502 for (k = 0; k < MAX_PHYSICALDRIVE_NUM; ++k) {
503 memset(&tmp_se, 0, sizeof(tmp_se));
504 snprintf(adapter_name, sizeof (adapter_name),
505 "\\\\.\\PhysicalDrive%d", k);
506 snprintf(tmp_se.name, sizeof(tmp_se.name), "PD%d", k);
507 fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE,
508 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
509 OPEN_EXISTING, 0, NULL);
510 if (fh != INVALID_HANDLE_VALUE) {
511 if (query_dev_property(fh, &tmp_se.qp_descriptor) < 0)
512 pr2serr("%s: query_dev_property failed\n", __func__ );
513 else
514 tmp_se.qp_descriptor_valid = 1;
515 if (query_dev_uid(fh, &tmp_se.qp_uid) < 0) {
516 if (verbose > 2)
517 pr2serr("%s: query_dev_uid failed\n", __func__ );
518 } else
519 tmp_se.qp_uid_valid = 1;
520 hole_count = 0;
521 memcpy(&storage_arr[next_unused_elem++], &tmp_se, sizeof(tmp_se));
522 CloseHandle(fh);
523 } else {
524 err = GetLastError();
525 if (ERROR_SHARING_VIOLATION == err)
526 fprintf(stderr, "%s: in use by other process (sharing "
527 "violation [34])\n", adapter_name);
528 else if (verbose > 3)
529 pr2serr("%s: CreateFile failed err=%u\n\t%s", adapter_name,
530 (unsigned int)err, get_err_str(err, sizeof(b), b));
531 if (++hole_count >= MAX_HOLE_COUNT)
532 break;
533 }
534 }
535 return 0;
536 }
537
538 static int
enum_cdroms(void)539 enum_cdroms(void)
540 {
541 int k;
542 int hole_count = 0;
543 HANDLE fh;
544 DWORD err;
545 char adapter_name[64];
546 char b[256];
547 struct storage_elem tmp_se;
548
549 if (verbose > 2)
550 pr2serr("%s: enter\n", __func__ );
551 for (k = 0; k < MAX_CDROM_NUM; ++k) {
552 memset(&tmp_se, 0, sizeof(tmp_se));
553 snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\CDROM%d", k);
554 snprintf(tmp_se.name, sizeof(tmp_se.name), "CDROM%d", k);
555 fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE,
556 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
557 OPEN_EXISTING, 0, NULL);
558 if (fh != INVALID_HANDLE_VALUE) {
559 if (query_dev_property(fh, &tmp_se.qp_descriptor) < 0)
560 pr2serr("%s: query_dev_property failed\n", __func__ );
561 else
562 tmp_se.qp_descriptor_valid = 1;
563 if (query_dev_uid(fh, &tmp_se.qp_uid) < 0) {
564 if (verbose > 2)
565 pr2serr("%s: query_dev_uid failed\n", __func__ );
566 } else
567 tmp_se.qp_uid_valid = 1;
568 hole_count = 0;
569 memcpy(&storage_arr[next_unused_elem++], &tmp_se, sizeof(tmp_se));
570 CloseHandle(fh);
571 } else {
572 err = GetLastError();
573 if (ERROR_SHARING_VIOLATION == err)
574 fprintf(stderr, "%s: in use by other process (sharing "
575 "violation [34])\n", adapter_name);
576 else if (verbose > 3)
577 pr2serr("%s: CreateFile failed err=%u\n\t%s", adapter_name,
578 (unsigned int)err, get_err_str(err, sizeof(b), b));
579 if (++hole_count >= MAX_HOLE_COUNT)
580 break;
581 }
582 }
583 return 0;
584 }
585
586 static int
enum_tapes(void)587 enum_tapes(void)
588 {
589 int k;
590 int hole_count = 0;
591 HANDLE fh;
592 DWORD err;
593 char adapter_name[64];
594 char b[256];
595 struct storage_elem tmp_se;
596
597 if (verbose > 2)
598 pr2serr("%s: enter\n", __func__ );
599 for (k = 0; k < MAX_TAPE_NUM; ++k) {
600 memset(&tmp_se, 0, sizeof(tmp_se));
601 snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\TAPE%d", k);
602 snprintf(tmp_se.name, sizeof(tmp_se.name), "TAPE%d", k);
603 fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE,
604 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
605 OPEN_EXISTING, 0, NULL);
606 if (fh != INVALID_HANDLE_VALUE) {
607 if (query_dev_property(fh, &tmp_se.qp_descriptor) < 0)
608 pr2serr("%s: query_dev_property failed\n", __func__ );
609 else
610 tmp_se.qp_descriptor_valid = 1;
611 if (query_dev_uid(fh, &tmp_se.qp_uid) < 0) {
612 if (verbose > 2)
613 pr2serr("%s: query_dev_uid failed\n", __func__ );
614 } else
615 tmp_se.qp_uid_valid = 1;
616 hole_count = 0;
617 memcpy(&storage_arr[next_unused_elem++], &tmp_se, sizeof(tmp_se));
618 CloseHandle(fh);
619 } else {
620 err = GetLastError();
621 if (ERROR_SHARING_VIOLATION == err)
622 fprintf(stderr, "%s: in use by other process (sharing "
623 "violation [34])\n", adapter_name);
624 else if (verbose > 3)
625 pr2serr("%s: CreateFile failed err=%u\n\t%s", adapter_name,
626 (unsigned int)err, get_err_str(err, sizeof(b), b));
627 if (++hole_count >= MAX_HOLE_COUNT)
628 break;
629 }
630 }
631 return 0;
632 }
633
634 static int
do_wscan(char letter,int show_bt,int scsi_scan)635 do_wscan(char letter, int show_bt, int scsi_scan)
636 {
637 int k, j, n;
638 struct storage_elem * sp;
639
640 if (scsi_scan < 2) {
641 k = enum_pds();
642 if (k)
643 return k;
644 k = enum_cdroms();
645 if (k)
646 return k;
647 k = enum_tapes();
648 if (k)
649 return k;
650 k = enum_volumes(letter);
651 if (k)
652 return k;
653
654 for (k = 0; k < next_unused_elem; ++k) {
655 sp = storage_arr + k;
656 if ('\0' == sp->name[0])
657 continue;
658 printf("%-7s ", sp->name);
659 n = strlen(sp->volume_letters);
660 if (0 == n)
661 printf(" ");
662 else if (1 == n)
663 printf("[%s] ", sp->volume_letters);
664 else if (2 == n)
665 printf("[%s] ", sp->volume_letters);
666 else if (3 == n)
667 printf("[%s] ", sp->volume_letters);
668 else if (4 == n)
669 printf("[%s] ", sp->volume_letters);
670 else
671 printf("[%4s+] ", sp->volume_letters);
672 if (sp->qp_descriptor_valid) {
673 if (show_bt)
674 printf("<%s> ",
675 get_bus_type(sp->qp_descriptor.desc.BusType));
676 j = sp->qp_descriptor.desc.VendorIdOffset;
677 if (j > 0)
678 printf("%s ", sp->qp_descriptor.raw + j);
679 j = sp->qp_descriptor.desc.ProductIdOffset;
680 if (j > 0)
681 printf("%s ", sp->qp_descriptor.raw + j);
682 j = sp->qp_descriptor.desc.ProductRevisionOffset;
683 if (j > 0)
684 printf("%s ", sp->qp_descriptor.raw + j);
685 j = sp->qp_descriptor.desc.SerialNumberOffset;
686 if (j > 0)
687 printf("%s", sp->qp_descriptor.raw + j);
688 printf("\n");
689 if (verbose > 2)
690 dStrHexErr(sp->qp_descriptor.raw, 144, 0);
691 } else
692 printf("\n");
693 if ((verbose > 3) && sp->qp_uid_valid) {
694 printf(" UID valid, in hex:\n");
695 dStrHexErr(sp->qp_uid.raw, sizeof(sp->qp_uid.raw), 1);
696 }
697 }
698 }
699
700 if (scsi_scan) {
701 if (scsi_scan < 2)
702 printf("\n");
703 enum_scsi_adapters();
704 }
705 return 0;
706 }
707
708
709 int
sg_do_wscan(char letter,int do_scan,int verb)710 sg_do_wscan(char letter, int do_scan, int verb)
711 {
712 int ret, show_bt, scsi_scan;
713
714 verbose = verb;
715 show_bt = (do_scan > 1);
716 scsi_scan = (do_scan > 2) ? (do_scan - 2) : 0;
717 storage_arr = calloc(sizeof(struct storage_elem) * MAX_SCSI_ELEMS, 1);
718 if (storage_arr) {
719 ret = do_wscan(letter, show_bt, scsi_scan);
720 free(storage_arr);
721 } else {
722 pr2serr("Failed to allocate storage_arr on heap\n");
723 ret = SG_LIB_SYNTAX_ERROR;
724 }
725 return ret;
726 }
727
728 #endif
729