2 * Copyright (C) 2009-2011, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3 * Copyright 2006-2008, V.
4 * For WinAoE contact information, see http://winaoe.org/
6 * This file is part of WinVBlock, derived from WinAoE.
8 * WinVBlock is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * WinVBlock is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with WinVBlock. If not, see <http://www.gnu.org/licenses/>.
25 * WinVBlock user-mode utility.
33 #include "winvblock.h"
38 /* Command function. */
39 typedef int STDCALL (WVU_F_CMD_)(void);
40 typedef WVU_F_CMD_ * WVU_FP_CMD_;
42 winvblock__def_struct(option) {
48 /* Handle to the device. */
49 static HANDLE boot_bus = NULL;
51 static option opt_h1 = {
55 static option opt_h2 = {
59 static option opt_cmd = {
63 static option opt_cyls = {
67 static option opt_heads = {
71 static option opt_spt = {
75 static option opt_disknum = {
79 static option opt_media = {
83 static option opt_uri = {
87 static option opt_mac = {
91 static option *options[] = {
104 static char present[] = "";
105 static char *invalid_opt = NULL;
107 static int WvuShowLastErr(void) {
108 DWORD err_code = GetLastError();
112 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
115 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
121 printf("GetLastError():\n %s", buf);
127 static void cmdline_options(int argc, char **argv) {
131 char *cur_arg = argv[cur];
134 /* Check if the argument is an option. Look for '-', '--', or '/'. */
147 invalid_opt = cur_arg;
150 /* Convert possible option to upper-case. */
151 { char *walker = cur_arg;
154 *walker = toupper(*walker);
158 /* Check if the argument is a _valid_ option. */
160 while (opt < sizeof (options) / sizeof (option *)) {
161 if (strcmp(cur_arg, options[opt]->name) == 0) {
164 * Check if the option was already specified.
166 if (options[opt]->value != NULL) {
168 "%s specified more than once, making it invalid.\n",
171 invalid_opt = cur_arg;
175 * The option's value is the next argument. For boolean
176 * options, we ignore the value anyway, but need to know the
180 options[opt]->value = present;
182 options[opt]->value = argv[cur + 1];
183 cur += options[opt]->has_arg;
188 /* Did we find no valid option match? */
189 if (opt == sizeof (options) / sizeof (option *)) {
190 invalid_opt = cur_arg;
197 static int STDCALL cmd_help(void) {
198 char help_text[] = "\n\
199 WinVBlock user-land utility for disk control. (C) 2006-2008 V.,\n\
200 (C) 2009-2010 Shao Miller\n\
202 winvblk -cmd <command> [-d <disk number>] [-m <media>] [-u <uri or path>]\n\
203 [-mac <client mac address>] [-c <cyls>] [-h <heads>] [-s <sects per track>]\n\
207 <command> is one of:\n\
208 scan - Shows the reachable AoE targets.\n\
209 show - Shows the mounted AoE targets.\n\
210 mount - Mounts an AoE target. Requires -mac and -u\n\
211 umount - Unmounts an AoE disk. Requires -d\n\
212 attach - Attaches <filepath> disk image file. Requires -u and -m.\n\
213 -c, -h, -s are optional.\n\
214 detach - Detaches file-backed disk. Requires -d\n\
215 <uri or path> is something like:\n\
216 aoe:eX.Y - Where X is the \"major\" (shelf) and Y is\n\
217 the \"minor\" (slot)\n\
218 c:\\my_disk.hdd - The path to a disk image file or .ISO\n\
219 <media> is one of 'c' for CD/DVD, 'f' for floppy, 'h' for hard disk drive\n\
225 static int STDCALL cmd_scan(void) {
226 aoe__mount_targets_ptr targets;
227 DWORD bytes_returned;
229 winvblock__uint8 string[256];
233 sizeof (aoe__mount_targets) +
234 (32 * sizeof (aoe__mount_target))
236 if (targets == NULL) {
237 printf("Out of memory\n");
241 if (!DeviceIoControl(
247 sizeof (aoe__mount_targets) + (32 * sizeof (aoe__mount_target)),
255 if (targets->Count == 0) {
256 printf("No AoE targets found.\n");
259 printf("Client NIC Target Server MAC Size\n");
260 for (i = 0; i < targets->Count && i < 10; i++) {
264 targets->Target[i].Major,
265 targets->Target[i].Minor
269 " %02x:%02x:%02x:%02x:%02x:%02x %s "
270 " %02x:%02x:%02x:%02x:%02x:%02x %I64uM\n",
271 targets->Target[i].ClientMac[0],
272 targets->Target[i].ClientMac[1],
273 targets->Target[i].ClientMac[2],
274 targets->Target[i].ClientMac[3],
275 targets->Target[i].ClientMac[4],
276 targets->Target[i].ClientMac[5],
278 targets->Target[i].ServerMac[0],
279 targets->Target[i].ServerMac[1],
280 targets->Target[i].ServerMac[2],
281 targets->Target[i].ServerMac[3],
282 targets->Target[i].ServerMac[4],
283 targets->Target[i].ServerMac[5],
284 targets->Target[i].LBASize / 2048
300 static int STDCALL cmd_show(void) {
301 aoe__mount_disks_ptr mounted_disks;
302 DWORD bytes_returned;
304 winvblock__uint8 string[256];
307 mounted_disks = malloc(
308 sizeof (aoe__mount_disks) +
309 (32 * sizeof (aoe__mount_disk))
311 if (mounted_disks == NULL) {
312 printf("Out of memory\n");
315 if (!DeviceIoControl(
321 sizeof (aoe__mount_disks) + (32 * sizeof (aoe__mount_disk)),
331 if (mounted_disks->Count == 0) {
332 printf("No AoE disks mounted.\n");
335 printf("Disk Client NIC Server MAC Target Size\n");
336 for (i = 0; i < mounted_disks->Count && i < 10; i++) {
340 mounted_disks->Disk[i].Major,
341 mounted_disks->Disk[i].Minor
345 " %-4lu %02x:%02x:%02x:%02x:%02x:%02x "
346 "%02x:%02x:%02x:%02x:%02x:%02x %s %I64uM\n",
347 mounted_disks->Disk[i].Disk,
348 mounted_disks->Disk[i].ClientMac[0],
349 mounted_disks->Disk[i].ClientMac[1],
350 mounted_disks->Disk[i].ClientMac[2],
351 mounted_disks->Disk[i].ClientMac[3],
352 mounted_disks->Disk[i].ClientMac[4],
353 mounted_disks->Disk[i].ClientMac[5],
354 mounted_disks->Disk[i].ServerMac[0],
355 mounted_disks->Disk[i].ServerMac[1],
356 mounted_disks->Disk[i].ServerMac[2],
357 mounted_disks->Disk[i].ServerMac[3],
358 mounted_disks->Disk[i].ServerMac[4],
359 mounted_disks->Disk[i].ServerMac[5],
361 mounted_disks->Disk[i].LBASize / 2048
375 static int STDCALL cmd_mount(void) {
376 winvblock__uint8 mac_addr[6];
377 winvblock__uint32 ver_major, ver_minor;
378 winvblock__uint8 in_buf[sizeof (mount__filedisk) + 1024];
379 DWORD bytes_returned;
381 if (opt_mac.value == NULL || opt_uri.value == NULL) {
382 printf("-mac and -u options required. See -? for help.\n");
387 "%02x:%02x:%02x:%02x:%02x:%02x",
388 (int *) (mac_addr + 0),
389 (int *) (mac_addr + 1),
390 (int *) (mac_addr + 2),
391 (int *) (mac_addr + 3),
392 (int *) (mac_addr + 4),
393 (int *) (mac_addr + 5)
402 "mounting e%lu.%lu from %02x:%02x:%02x:%02x:%02x:%02x\n",
412 memcpy(in_buf, mac_addr, 6);
413 *((winvblock__uint16_ptr) (in_buf + 6)) = (winvblock__uint16) ver_major;
414 *((winvblock__uint8_ptr) (in_buf + 8)) = (winvblock__uint8) ver_minor;
415 if (!DeviceIoControl(
431 static int STDCALL cmd_umount(void) {
432 winvblock__uint32 disk_num;
433 winvblock__uint8 in_buf[sizeof (mount__filedisk) + 1024];
434 DWORD bytes_returned;
436 if (opt_disknum.value == NULL) {
437 printf("-d option required. See -? for help.\n");
440 sscanf(opt_disknum.value, "%d", (int *) &disk_num);
441 printf("unmounting disk %d\n", (int) disk_num);
442 memcpy(in_buf, &disk_num, 4);
443 if (!DeviceIoControl(
459 static int STDCALL cmd_attach(void) {
460 mount__filedisk filedisk;
461 char obj_path_prefix[] = "\\??\\";
462 winvblock__uint8 in_buf[sizeof (mount__filedisk) + 1024];
463 DWORD bytes_returned;
465 if (opt_uri.value == NULL || opt_media.value == NULL) {
466 printf("-u and -m options required. See -? for help.\n");
469 filedisk.type = opt_media.value[0];
470 if (opt_cyls.value != NULL)
471 sscanf(opt_cyls.value, "%d", (int *) &filedisk.cylinders);
472 if (opt_heads.value != NULL)
473 sscanf(opt_heads.value, "%d", (int *) &filedisk.heads);
474 if (opt_spt.value != NULL)
475 sscanf(opt_spt.value, "%d", (int *) &filedisk.sectors);
476 memcpy(in_buf, &filedisk, sizeof (mount__filedisk));
478 in_buf + sizeof (mount__filedisk),
480 sizeof (obj_path_prefix)
483 in_buf + sizeof (mount__filedisk) + sizeof (obj_path_prefix) - 1,
485 strlen(opt_uri.value) + 1
487 if (!DeviceIoControl(
503 static int STDCALL cmd_detach(void) {
504 winvblock__uint32 disk_num;
505 winvblock__uint8 in_buf[sizeof (mount__filedisk) + 1024];
506 DWORD bytes_returned;
508 if (opt_disknum.value == NULL) {
509 printf("-d option required. See -? for help.\n");
512 sscanf(opt_disknum.value, "%d", (int *) &disk_num);
513 printf("Detaching file-backed disk %d\n", (int) disk_num);
514 memcpy(in_buf, &disk_num, 4);
515 if (!DeviceIoControl(
531 int main(int argc, char **argv, char **envp) {
532 WVU_FP_CMD_ cmd = cmd_help;
534 char winvblock[] = "\\\\.\\" WVL_M_LIT;
535 char aoe[] = "\\\\.\\AoE";
538 cmdline_options(argc, argv);
539 /* Check for invalid option. */
540 if (invalid_opt != NULL) {
541 printf("Use -? for help. Invalid option: %s\n", invalid_opt);
544 /* Check for cry for help. */
545 if (opt_h1.value || opt_h2.value)
547 /* Check for no command. */
548 if (opt_cmd.value == NULL)
550 /* Check given command. */
551 if (strcmp(opt_cmd.value, "scan") == 0) {
555 if (strcmp(opt_cmd.value, "show") == 0) {
559 if (strcmp(opt_cmd.value, "mount" ) == 0) {
563 if (strcmp(opt_cmd.value, "umount") == 0) {
567 if (strcmp(opt_cmd.value, "attach") == 0) {
569 bus_name = winvblock;
571 if (strcmp(opt_cmd.value, "detach") == 0) {
573 bus_name = winvblock;
575 /* Check for invalid command. */
579 boot_bus = CreateFile(
581 GENERIC_READ | GENERIC_WRITE,
582 FILE_SHARE_READ | FILE_SHARE_WRITE,
588 if (boot_bus == INVALID_HANDLE_VALUE) {
596 if (boot_bus != NULL)
597 CloseHandle(boot_bus);