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