Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #ifdef HAVE_CONFIG_H
32 : : #include "config.h"
33 : : #endif
34 : :
35 : : #include <stdio.h>
36 : : #include <stdlib.h>
37 : : #include <string.h>
38 : : #include <unistd.h>
39 : : #include <getopt.h>
40 : : #include <signal.h>
41 : : #include <sys/time.h>
42 : :
43 : : #include "tap-ctl.h"
44 : :
45 : : #define MAX_AES_XTS_PLAIN_KEYSIZE 1024
46 : :
47 : : typedef int (*tap_ctl_func_t) (int, char **);
48 : :
49 : : struct command {
50 : : char *name;
51 : : tap_ctl_func_t func;
52 : : };
53 : :
54 : : static void
55 : 0 : tap_cli_list_usage(FILE *stream)
56 : : {
57 : : fprintf(stream,
58 : : "usage: list [-h] [-p pid] [-m minor] [-t type] [-f file]\n"
59 : : "\n"
60 : : "Lists tapdisks in the following format:\n"
61 : : "%8s %4s %4s %10s %s\n", "pid", "minor", "state", "type", "file");
62 : 0 : }
63 : :
64 : : static void
65 : 0 : tap_cli_list_row(tap_list_t *entry)
66 : : {
67 : 0 : char minor_str[10] = "-";
68 : 0 : char state_str[10] = "-";
69 : 0 : char pid_str[10] = "-";
70 : :
71 : 0 : if (entry->pid != -1)
72 : 0 : sprintf(pid_str, "%d", entry->pid);
73 : :
74 : 0 : if (entry->minor != -1)
75 : 0 : sprintf(minor_str, "%d", entry->minor);
76 : :
77 : 0 : if (entry->state != -1)
78 : 0 : sprintf(state_str, "%#x", entry->state);
79 : :
80 : 0 : printf("%8s %4s %4s %10s %s\n",
81 : : pid_str, minor_str, state_str,
82 : 0 : entry->type ? : "-", entry->path ? : "-");
83 : 0 : }
84 : :
85 : : static void
86 : 0 : tap_cli_list_dict(tap_list_t *entry)
87 : : {
88 : 0 : int d = 0;
89 : :
90 : 0 : if (entry->pid != -1) {
91 : : if (d) putc(' ', stdout);
92 : 0 : d = printf("pid=%d", entry->pid);
93 : : }
94 : :
95 : 0 : if (entry->minor != -1) {
96 : 0 : if (d) putc(' ', stdout);
97 : 0 : d = printf("minor=%d", entry->minor);
98 : : }
99 : :
100 : 0 : if (entry->state != -1) {
101 : 0 : if (d) putc(' ', stdout);
102 : 0 : d = printf("state=%#x", entry->state);
103 : : }
104 : :
105 : 0 : if (entry->type && entry->path) {
106 : 0 : if (d) putc(' ', stdout);
107 : 0 : printf("args=%s:%s", entry->type, entry->path);
108 : : }
109 : :
110 : 0 : putc('\n', stdout);
111 : 0 : }
112 : :
113 : : int
114 : 0 : tap_cli_list(int argc, char **argv)
115 : : {
116 : 0 : struct list_head list = LIST_HEAD_INIT(list);
117 : : int c, minor, tty, err;
118 : : const char *type, *file;
119 : : tap_list_t *entry;
120 : : pid_t pid;
121 : :
122 : 0 : pid = -1;
123 : 0 : minor = -1;
124 : 0 : type = NULL;
125 : 0 : file = NULL;
126 : :
127 : 0 : while ((c = getopt(argc, argv, "m:p:t:f:h")) != -1) {
128 : 0 : switch (c) {
129 : : case 'm':
130 : 0 : minor = atoi(optarg);
131 : 0 : break;
132 : : case 'p':
133 : 0 : pid = atoi(optarg);
134 : 0 : break;
135 : : case 't':
136 : 0 : type = optarg;
137 : 0 : break;
138 : : case 'f':
139 : 0 : file = optarg;
140 : 0 : break;
141 : : case '?':
142 : : goto usage;
143 : : case 'h':
144 : 0 : tap_cli_list_usage(stdout);
145 : 0 : return 0;
146 : : }
147 : : }
148 : :
149 : 0 : if (pid != -1)
150 : 0 : err = tap_ctl_list_pid(pid, &list);
151 : : else
152 : 0 : err = tap_ctl_list(&list);
153 : 0 : if (err)
154 : 0 : return -err;
155 : :
156 : 0 : tty = isatty(STDOUT_FILENO);
157 : :
158 : 0 : tap_list_for_each_entry(entry, &list) {
159 : 0 : if (minor >= 0 && entry->minor != minor)
160 : 0 : continue;
161 : :
162 : 0 : if (pid >= 0 && entry->pid != pid)
163 : 0 : continue;
164 : :
165 : 0 : if (type) {
166 : 0 : if (!entry->type)
167 : 0 : continue;
168 : :
169 : 0 : if (strcmp(entry->type, type))
170 : 0 : continue;
171 : : }
172 : :
173 : 0 : if (file) {
174 : 0 : if (!entry->path)
175 : 0 : continue;
176 : :
177 : 0 : if (strcmp(entry->path, file))
178 : 0 : continue;
179 : : }
180 : :
181 : 0 : if (tty)
182 : 0 : tap_cli_list_row(entry);
183 : : else
184 : 0 : tap_cli_list_dict(entry);
185 : : }
186 : :
187 : 0 : tap_ctl_list_free(&list);
188 : :
189 : : return 0;
190 : :
191 : : usage:
192 : 0 : tap_cli_list_usage(stderr);
193 : : return EINVAL;
194 : : }
195 : :
196 : : static void
197 : : tap_cli_allocate_usage(FILE *stream)
198 : : {
199 : : fprintf(stream, "usage: allocate [-d device name]>\n");
200 : : }
201 : :
202 : : static int
203 : 0 : tap_cli_allocate(int argc, char **argv)
204 : : {
205 : : char *devname;
206 : : int c, minor, err;
207 : 0 : char d_flag = 0;
208 : :
209 : 0 : devname = NULL;
210 : :
211 : 0 : optind = 0;
212 : 0 : while ((c = getopt(argc, argv, "d:h")) != -1) {
213 : 0 : switch (c) {
214 : : case 'd':
215 : 0 : devname = optarg;
216 : 0 : d_flag = 1;
217 : 0 : break;
218 : : case '?':
219 : : goto usage;
220 : : case 'h':
221 : 0 : tap_cli_allocate_usage(stdout);
222 : 0 : return 0;
223 : : }
224 : : }
225 : :
226 : 0 : err = tap_ctl_allocate(&minor, &devname);
227 : 0 : if (!err)
228 : 0 : printf("%s\n", devname);
229 : :
230 : 0 : if (!d_flag)
231 : 0 : free(devname);
232 : :
233 : 0 : return err;
234 : :
235 : : usage:
236 : 0 : tap_cli_allocate_usage(stderr);
237 : : return EINVAL;
238 : : }
239 : :
240 : : static void
241 : : tap_cli_free_usage(FILE *stream)
242 : : {
243 : : fprintf(stream, "usage: free <-m minor>\n");
244 : : }
245 : :
246 : : static int
247 : 0 : tap_cli_free(int argc, char **argv)
248 : : {
249 : : int c, minor;
250 : :
251 : 0 : minor = -1;
252 : :
253 : 0 : optind = 0;
254 : 0 : while ((c = getopt(argc, argv, "m:h")) != -1) {
255 : 0 : switch (c) {
256 : : case 'm':
257 : 0 : minor = atoi(optarg);
258 : 0 : break;
259 : : case '?':
260 : : goto usage;
261 : : case 'h':
262 : 0 : tap_cli_free_usage(stdout);
263 : 0 : return 0;
264 : : }
265 : : }
266 : :
267 : 0 : if (minor == -1)
268 : : goto usage;
269 : :
270 : 0 : return tap_ctl_free(minor);
271 : :
272 : : usage:
273 : 0 : tap_cli_free_usage(stderr);
274 : 0 : return EINVAL;
275 : : }
276 : :
277 : : static void
278 : : tap_cli_create_usage(FILE *stream)
279 : : {
280 : : fprintf(stream, "usage: create <-a type:/path/to/file> [-d device name] [-R readonly] "
281 : : "[-e <minor> stack on existing tapdisk for the parent chain] "
282 : : "[-r turn on read caching into leaf node] [-2 <path> "
283 : : "use secondary image (in mirror mode if no -s)] [-s "
284 : : "fail over to the secondary image on ENOSPC] "
285 : : "[-t request timeout in seconds] [-D no O_DIRECT] "
286 : : "[-C <path/to/logfile> insert log layer to track changed blocks]\n");
287 : : }
288 : :
289 : : static int
290 : 0 : tap_cli_create(int argc, char **argv)
291 : : {
292 : : int c, err, flags, prt_minor, timeout;
293 : : char *args, *devname, *secondary;
294 : 0 : char d_flag = 0;
295 : 0 : char *logpath = NULL;
296 : :
297 : 0 : args = NULL;
298 : 0 : devname = NULL;
299 : 0 : secondary = NULL;
300 : 0 : prt_minor = -1;
301 : 0 : flags = 0;
302 : 0 : timeout = 0;
303 : :
304 : 0 : optind = 0;
305 : 0 : while ((c = getopt(argc, argv, "a:RDd:e:r2:st:C:h")) != -1) {
306 : 0 : switch (c) {
307 : : case 'a':
308 : 0 : args = optarg;
309 : 0 : break;
310 : : case 'd':
311 : 0 : devname = optarg;
312 : 0 : d_flag = 1;
313 : 0 : break;
314 : : case 'R':
315 : 0 : flags |= TAPDISK_MESSAGE_FLAG_RDONLY;
316 : 0 : break;
317 : : case 'D':
318 : 0 : flags |= TAPDISK_MESSAGE_FLAG_NO_O_DIRECT;
319 : 0 : break;
320 : : case 'r':
321 : 0 : flags |= TAPDISK_MESSAGE_FLAG_ADD_LCACHE;
322 : 0 : break;
323 : : case 'e':
324 : 0 : flags |= TAPDISK_MESSAGE_FLAG_REUSE_PRT;
325 : 0 : prt_minor = atoi(optarg);
326 : 0 : break;
327 : : case '2':
328 : 0 : flags |= TAPDISK_MESSAGE_FLAG_SECONDARY;
329 : 0 : secondary = optarg;
330 : 0 : break;
331 : : case 's':
332 : 0 : flags |= TAPDISK_MESSAGE_FLAG_STANDBY;
333 : 0 : break;
334 : : case 't':
335 : 0 : timeout = atoi(optarg);
336 : 0 : break;
337 : : case 'C':
338 : 0 : logpath = optarg;
339 : 0 : flags |= TAPDISK_MESSAGE_FLAG_ADD_LOG;
340 : 0 : break;
341 : : case '?':
342 : : goto usage;
343 : : case 'h':
344 : 0 : tap_cli_create_usage(stdout);
345 : 0 : return 0;
346 : : }
347 : : }
348 : :
349 : 0 : if (!args)
350 : : goto usage;
351 : :
352 : 0 : err = tap_ctl_create(args, &devname, flags, prt_minor, secondary,
353 : : timeout, logpath);
354 : 0 : if (!err)
355 : 0 : printf("%s\n", devname);
356 : :
357 : 0 : if (!d_flag)
358 : 0 : free(devname);
359 : :
360 : 0 : return err;
361 : :
362 : : usage:
363 : 0 : tap_cli_create_usage(stderr);
364 : : return EINVAL;
365 : : }
366 : :
367 : : static void
368 : : tap_cli_destroy_usage(FILE *stream)
369 : : {
370 : : fprintf(stream, "usage: destroy <-p pid> <-m minor> [-t timeout secs]\n");
371 : : }
372 : :
373 : : static struct timeval*
374 : : tap_cli_timeout(const char *optarg)
375 : : {
376 : : static struct timeval tv;
377 : :
378 : 0 : tv.tv_sec = atoi(optarg);
379 : 0 : tv.tv_usec = 0;
380 : :
381 : : return &tv;
382 : : }
383 : :
384 : : static int
385 : 0 : tap_cli_destroy(int argc, char **argv)
386 : : {
387 : : int c, pid, minor;
388 : : struct timeval *timeout;
389 : :
390 : 0 : pid = -1;
391 : 0 : minor = -1;
392 : 0 : timeout = NULL;
393 : :
394 : 0 : optind = 0;
395 : 0 : while ((c = getopt(argc, argv, "p:m:t:h")) != -1) {
396 : 0 : switch (c) {
397 : : case 'p':
398 : 0 : pid = atoi(optarg);
399 : 0 : break;
400 : : case 'm':
401 : 0 : minor = atoi(optarg);
402 : 0 : break;
403 : : case 't':
404 : 0 : timeout = tap_cli_timeout(optarg);
405 : : if (!timeout)
406 : : goto usage;
407 : : break;
408 : : case '?':
409 : : goto usage;
410 : : case 'h':
411 : 0 : tap_cli_destroy_usage(stdout);
412 : 0 : return 0;
413 : : }
414 : : }
415 : :
416 : 0 : if (pid == -1 || minor == -1)
417 : : goto usage;
418 : :
419 : 0 : return tap_ctl_destroy(pid, minor, 0, timeout);
420 : :
421 : : usage:
422 : 0 : tap_cli_destroy_usage(stderr);
423 : 0 : return EINVAL;
424 : : }
425 : :
426 : : static void
427 : : tap_cli_spawn_usage(FILE *stream)
428 : : {
429 : : fprintf(stream, "usage: spawn\n");
430 : : }
431 : :
432 : : static int
433 : 0 : tap_cli_spawn(int argc, char **argv)
434 : : {
435 : : int c, tty;
436 : : pid_t pid;
437 : :
438 : 0 : optind = 0;
439 : 0 : while ((c = getopt(argc, argv, "h")) != -1) {
440 : 0 : switch (c) {
441 : : case '?':
442 : : goto usage;
443 : : case 'h':
444 : 0 : tap_cli_spawn_usage(stdout);
445 : 0 : return 0;
446 : : }
447 : : }
448 : :
449 : 0 : pid = tap_ctl_spawn();
450 : 0 : if (pid < 0)
451 : : return pid;
452 : :
453 : 0 : tty = isatty(STDOUT_FILENO);
454 : 0 : if (tty)
455 : : printf("tapdisk spawned with pid %d\n", pid);
456 : : else
457 : : printf("%d\n", pid);
458 : :
459 : : return 0;
460 : :
461 : : usage:
462 : 0 : tap_cli_spawn_usage(stderr);
463 : 0 : return EINVAL;
464 : : }
465 : :
466 : : static void
467 : : tap_cli_attach_usage(FILE *stream)
468 : : {
469 : : fprintf(stream, "usage: attach <-p pid> <-m minor>\n");
470 : : }
471 : :
472 : : static int
473 : 0 : tap_cli_attach(int argc, char **argv)
474 : : {
475 : : int c, pid, minor;
476 : :
477 : 0 : pid = -1;
478 : 0 : minor = -1;
479 : :
480 : 0 : optind = 0;
481 : 0 : while ((c = getopt(argc, argv, "p:m:h")) != -1) {
482 : 0 : switch (c) {
483 : : case 'p':
484 : 0 : pid = atoi(optarg);
485 : 0 : break;
486 : : case 'm':
487 : 0 : minor = atoi(optarg);
488 : 0 : break;
489 : : case '?':
490 : : goto usage;
491 : : case 'h':
492 : 0 : tap_cli_attach_usage(stderr);
493 : 0 : return 0;
494 : : }
495 : : }
496 : :
497 : 0 : if (pid == -1 || minor == -1)
498 : : goto usage;
499 : :
500 : 0 : return tap_ctl_attach(pid, minor);
501 : :
502 : : usage:
503 : 0 : tap_cli_attach_usage(stderr);
504 : 0 : return EINVAL;
505 : : }
506 : :
507 : : static void
508 : : tap_cli_detach_usage(FILE *stream)
509 : : {
510 : : fprintf(stream, "usage: detach <-p pid> <-m minor>\n");
511 : : }
512 : :
513 : : static int
514 : 0 : tap_cli_detach(int argc, char **argv)
515 : : {
516 : : int c, pid, minor;
517 : :
518 : 0 : pid = -1;
519 : 0 : minor = -1;
520 : :
521 : 0 : optind = 0;
522 : 0 : while ((c = getopt(argc, argv, "p:m:h")) != -1) {
523 : 0 : switch (c) {
524 : : case 'p':
525 : 0 : pid = atoi(optarg);
526 : 0 : break;
527 : : case 'm':
528 : 0 : minor = atoi(optarg);
529 : 0 : break;
530 : : case '?':
531 : : goto usage;
532 : : case 'h':
533 : 0 : tap_cli_detach_usage(stdout);
534 : 0 : return 0;
535 : : }
536 : : }
537 : :
538 : 0 : if (pid == -1 || minor == -1)
539 : : goto usage;
540 : :
541 : 0 : return tap_ctl_detach(pid, minor);
542 : :
543 : : usage:
544 : 0 : tap_cli_detach_usage(stderr);
545 : 0 : return EINVAL;
546 : : }
547 : :
548 : : static void
549 : : tap_cli_close_usage(FILE *stream)
550 : : {
551 : : fprintf(stream, "usage: close <-p pid> <-m minor> [-f force] [-t timeout secs]\n");
552 : : }
553 : :
554 : : static int
555 : 0 : tap_cli_close(int argc, char **argv)
556 : : {
557 : : int c, pid, minor, force;
558 : : struct timeval *timeout;
559 : :
560 : 0 : pid = -1;
561 : 0 : minor = -1;
562 : 0 : force = 0;
563 : 0 : timeout = NULL;
564 : :
565 : 0 : optind = 0;
566 : 0 : while ((c = getopt(argc, argv, "p:m:ft:h")) != -1) {
567 : 0 : switch (c) {
568 : : case 'p':
569 : 0 : pid = atoi(optarg);
570 : 0 : break;
571 : : case 'm':
572 : 0 : minor = atoi(optarg);
573 : 0 : break;
574 : : case 'f':
575 : 0 : force = -1;
576 : 0 : break;
577 : : case 't':
578 : 0 : timeout = tap_cli_timeout(optarg);
579 : : if (!timeout)
580 : : goto usage;
581 : : break;
582 : : case '?':
583 : : goto usage;
584 : : case 'h':
585 : 0 : tap_cli_close_usage(stdout);
586 : 0 : return 0;
587 : : }
588 : : }
589 : :
590 : 0 : if (pid == -1 || minor == -1)
591 : : goto usage;
592 : :
593 : 0 : return tap_ctl_close(pid, minor, force, timeout);
594 : :
595 : : usage:
596 : 0 : tap_cli_close_usage(stderr);
597 : 0 : return EINVAL;
598 : : }
599 : :
600 : : static void
601 : : tap_cli_pause_usage(FILE *stream)
602 : : {
603 : : fprintf(stream, "usage: pause <-p pid> <-m minor> [-t timeout secs]\n");
604 : : }
605 : :
606 : : static int
607 : 0 : tap_cli_pause(int argc, char **argv)
608 : : {
609 : : int c, pid, minor;
610 : : struct timeval *timeout;
611 : :
612 : 0 : pid = -1;
613 : 0 : minor = -1;
614 : 0 : timeout = NULL;
615 : :
616 : 0 : optind = 0;
617 : 0 : while ((c = getopt(argc, argv, "p:m:t:h")) != -1) {
618 : 0 : switch (c) {
619 : : case 'p':
620 : 0 : pid = atoi(optarg);
621 : 0 : break;
622 : : case 'm':
623 : 0 : minor = atoi(optarg);
624 : 0 : break;
625 : : case 't':
626 : 0 : timeout = tap_cli_timeout(optarg);
627 : : if (!timeout)
628 : : goto usage;
629 : : case '?':
630 : : goto usage;
631 : : case 'h':
632 : 0 : tap_cli_pause_usage(stdout);
633 : 0 : return 0;
634 : : }
635 : : }
636 : :
637 : 0 : if (pid == -1 || minor == -1)
638 : : goto usage;
639 : :
640 : 0 : return tap_ctl_pause(pid, minor, timeout);
641 : :
642 : : usage:
643 : 0 : tap_cli_pause_usage(stderr);
644 : 0 : return EINVAL;
645 : : }
646 : :
647 : : static void
648 : : tap_cli_unpause_usage(FILE *stream)
649 : : {
650 : : fprintf(stream, "usage: unpause <-p pid> <-m minor> [-a type:/path/to/file] "
651 : : "[-2 secondary] "
652 : : "[-c </path/to/logfile> insert log layer to track changed blocks]\n");
653 : : }
654 : :
655 : : int
656 : 0 : tap_cli_unpause(int argc, char **argv)
657 : : {
658 : : const char *args, *logpath;
659 : : char *secondary;
660 : : int c, pid, minor, flags;
661 : :
662 : 0 : pid = -1;
663 : 0 : minor = -1;
664 : 0 : args = NULL;
665 : 0 : secondary = NULL;
666 : 0 : flags = 0;
667 : 0 : logpath = NULL;
668 : :
669 : 0 : optind = 0;
670 : 0 : while ((c = getopt(argc, argv, "p:m:a:2:c:h")) != -1) {
671 : 0 : switch (c) {
672 : : case 'p':
673 : 0 : pid = atoi(optarg);
674 : 0 : break;
675 : : case 'm':
676 : 0 : minor = atoi(optarg);
677 : 0 : break;
678 : : case 'a':
679 : 0 : args = optarg;
680 : 0 : break;
681 : : case '2':
682 : 0 : flags |= TAPDISK_MESSAGE_FLAG_SECONDARY;
683 : 0 : secondary = optarg;
684 : 0 : break;
685 : : case 'c':
686 : 0 : logpath = optarg;
687 : 0 : flags |= TAPDISK_MESSAGE_FLAG_ADD_LOG;
688 : 0 : break;
689 : : case '?':
690 : : goto usage;
691 : : case 'h':
692 : 0 : tap_cli_unpause_usage(stdout);
693 : 0 : return 0;
694 : : }
695 : : }
696 : :
697 : 0 : if (pid == -1 || minor == -1)
698 : : goto usage;
699 : :
700 : 0 : return tap_ctl_unpause(pid, minor, args, flags, secondary, logpath);
701 : :
702 : : usage:
703 : 0 : tap_cli_unpause_usage(stderr);
704 : 0 : return EINVAL;
705 : : }
706 : :
707 : : static void
708 : : tap_cli_major_usage(FILE *stream)
709 : : {
710 : : fprintf(stream, "usage: major [-h]\n");
711 : : }
712 : :
713 : : static int
714 : 0 : tap_cli_major(int argc, char **argv)
715 : : {
716 : : int c, chr, major;
717 : :
718 : 0 : chr = 0;
719 : :
720 : 0 : while ((c = getopt(argc, argv, "bch")) != -1) {
721 : 0 : switch (c) {
722 : : case 'b':
723 : : chr = 0;
724 : : break;
725 : : case 'c':
726 : 0 : chr = 1;
727 : 0 : break;
728 : : case '?':
729 : : goto usage;
730 : : case 'h':
731 : 0 : tap_cli_major_usage(stdout);
732 : 0 : return 0;
733 : : default:
734 : : goto usage;
735 : : }
736 : : }
737 : :
738 : 0 : if (chr)
739 : : major = -EINVAL;
740 : : else
741 : 0 : major = tap_ctl_blk_major();
742 : :
743 : 0 : if (major < 0)
744 : 0 : return -major;
745 : :
746 : : printf("%d\n", major);
747 : :
748 : 0 : return 0;
749 : :
750 : : usage:
751 : 0 : tap_cli_major_usage(stderr);
752 : 0 : return EINVAL;
753 : : }
754 : :
755 : : static void
756 : : tap_cli_open_usage(FILE *stream)
757 : : {
758 : : fprintf(stream, "usage: open <-p pid> <-m minor> <-a type:/path/to/file> [-R readonly] "
759 : : "[-e <minor> stack on existing tapdisk for the parent chain] "
760 : : "[-r turn on read caching into leaf node] [-2 <path> "
761 : : "use secondary image (in mirror mode if no -s)] [-s "
762 : : "fail over to the secondary image on ENOSPC] "
763 : : "[-t request timeout in seconds] [-D no O_DIRECT] "
764 : : "[-C </path/to/logfile> insert log layer to track changed blocks] "
765 : : "[-E read encryption key from stdin]\n");
766 : : }
767 : :
768 : : static int
769 : 0 : tap_cli_open(int argc, char **argv)
770 : : {
771 : : const char *args, *secondary, *logpath;
772 : : int c, pid, minor, flags, prt_minor, timeout;
773 : : uint8_t *encryption_key;
774 : 0 : ssize_t key_size = 0;
775 : :
776 : 0 : flags = 0;
777 : 0 : pid = -1;
778 : 0 : minor = -1;
779 : 0 : prt_minor = -1;
780 : 0 : timeout = 0;
781 : 0 : args = NULL;
782 : 0 : secondary = NULL;
783 : 0 : logpath = NULL;
784 : 0 : encryption_key = NULL;
785 : :
786 : 0 : optind = 0;
787 : 0 : while ((c = getopt(argc, argv, "a:RDm:p:e:r2:st:C:Eh")) != -1) {
788 : 0 : switch (c) {
789 : : case 'p':
790 : 0 : pid = atoi(optarg);
791 : 0 : break;
792 : : case 'm':
793 : 0 : minor = atoi(optarg);
794 : 0 : break;
795 : : case 'a':
796 : 0 : args = optarg;
797 : 0 : break;
798 : : case 'R':
799 : 0 : flags |= TAPDISK_MESSAGE_FLAG_RDONLY;
800 : 0 : break;
801 : : case 'D':
802 : 0 : flags |= TAPDISK_MESSAGE_FLAG_NO_O_DIRECT;
803 : 0 : break;
804 : : case 'r':
805 : 0 : flags |= TAPDISK_MESSAGE_FLAG_ADD_LCACHE;
806 : 0 : break;
807 : : case 'e':
808 : 0 : flags |= TAPDISK_MESSAGE_FLAG_REUSE_PRT;
809 : 0 : prt_minor = atoi(optarg);
810 : 0 : break;
811 : : case '2':
812 : 0 : flags |= TAPDISK_MESSAGE_FLAG_SECONDARY;
813 : 0 : secondary = optarg;
814 : 0 : break;
815 : : case 's':
816 : 0 : flags |= TAPDISK_MESSAGE_FLAG_STANDBY;
817 : 0 : break;
818 : : case 't':
819 : 0 : timeout = atoi(optarg);
820 : 0 : break;
821 : : case 'C':
822 : 0 : logpath = optarg;
823 : 0 : flags |= TAPDISK_MESSAGE_FLAG_ADD_LOG;
824 : 0 : break;
825 : : case 'E':
826 : 0 : if (encryption_key) {
827 : 0 : fprintf(stderr, "Only supply -E once\n");
828 : 0 : exit(1);
829 : : }
830 : : /* Allocate the space for the key, */
831 : 0 : encryption_key = malloc(MAX_AES_XTS_PLAIN_KEYSIZE / sizeof(uint8_t));
832 : 0 : if (!encryption_key) {
833 : 0 : fprintf(stderr, "Failed to allocate space for encrpytion key\n");
834 : 0 : exit(1);
835 : : }
836 : 0 : key_size = read(STDIN_FILENO, (void*)encryption_key, MAX_AES_XTS_PLAIN_KEYSIZE / sizeof(uint8_t));
837 : 0 : if (key_size != 32 && key_size != 64){
838 : 0 : fprintf(stderr, "Unsupported keysize, use either 256 bit or 512 bit key\n");
839 : 0 : free(encryption_key);
840 : 0 : exit(1);
841 : : }
842 : 0 : flags |= TAPDISK_MESSAGE_FLAG_OPEN_ENCRYPTED;
843 : 0 : break;
844 : : case '?':
845 : : goto usage;
846 : : case 'h':
847 : 0 : tap_cli_open_usage(stdout);
848 : 0 : if (encryption_key) {
849 : 0 : free(encryption_key);
850 : : }
851 : : return 0;
852 : : }
853 : : }
854 : :
855 : 0 : if (pid == -1 || minor == -1 || !args)
856 : : goto usage;
857 : :
858 : 0 : return tap_ctl_open(pid, minor, args, flags, prt_minor, secondary,
859 : 0 : timeout, logpath, (uint8_t)key_size, encryption_key);
860 : :
861 : : usage:
862 : 0 : tap_cli_open_usage(stderr);
863 : 0 : if (encryption_key) {
864 : 0 : free(encryption_key);
865 : : }
866 : : return EINVAL;
867 : : }
868 : :
869 : : static void
870 : : tap_cli_stats_usage(FILE *stream)
871 : : {
872 : : fprintf(stream, "usage: stats <-p pid> <-m minor>\n"
873 : : "\n"
874 : : "Prints a Python dictionary with the VBD stats. The images are "
875 : : "listed in reverse order (leaf to root)\n");
876 : : }
877 : :
878 : : static int
879 : 0 : tap_cli_stats(int argc, char **argv)
880 : : {
881 : : pid_t pid;
882 : : int c, minor, err;
883 : :
884 : 0 : pid = -1;
885 : 0 : minor = -1;
886 : :
887 : 0 : optind = 0;
888 : 0 : while ((c = getopt(argc, argv, "p:m:h")) != -1) {
889 : 0 : switch (c) {
890 : : case 'p':
891 : 0 : pid = atoi(optarg);
892 : 0 : break;
893 : : case 'm':
894 : 0 : minor = atoi(optarg);
895 : 0 : break;
896 : : case '?':
897 : : goto usage;
898 : : case 'h':
899 : 0 : tap_cli_stats_usage(stdout);
900 : 0 : return 0;
901 : : }
902 : : }
903 : :
904 : 0 : if (pid == -1 || minor == -1)
905 : : goto usage;
906 : :
907 : 0 : err = tap_ctl_stats_fwrite(pid, minor, stdout);
908 : 0 : if (err)
909 : : return err;
910 : :
911 : 0 : fprintf(stdout, "\n");
912 : :
913 : 0 : return 0;
914 : :
915 : : usage:
916 : 0 : tap_cli_stats_usage(stderr);
917 : 0 : return EINVAL;
918 : : }
919 : :
920 : : static void
921 : : tap_cli_check_usage(FILE *stream)
922 : : {
923 : : fprintf(stream, "usage: check\n"
924 : : "(checks whether environment is suitable for tapdisk2)\n");
925 : : }
926 : :
927 : : static int
928 : 0 : tap_cli_check(int argc, char **argv)
929 : : {
930 : : int err;
931 : : const char *msg;
932 : :
933 : 0 : if (argc != 1)
934 : : goto usage;
935 : :
936 : 0 : err = tap_ctl_check(&msg);
937 : 0 : printf("%s\n", msg);
938 : :
939 : 0 : return err;
940 : :
941 : : usage:
942 : 0 : tap_cli_check_usage(stderr);
943 : : return EINVAL;
944 : : }
945 : :
946 : : struct command commands[] = {
947 : : { .name = "list", .func = tap_cli_list },
948 : : { .name = "allocate", .func = tap_cli_allocate },
949 : : { .name = "free", .func = tap_cli_free },
950 : : { .name = "create", .func = tap_cli_create },
951 : : { .name = "destroy", .func = tap_cli_destroy },
952 : : { .name = "spawn", .func = tap_cli_spawn },
953 : : { .name = "attach", .func = tap_cli_attach },
954 : : { .name = "detach", .func = tap_cli_detach },
955 : : { .name = "open", .func = tap_cli_open },
956 : : { .name = "close", .func = tap_cli_close },
957 : : { .name = "pause", .func = tap_cli_pause },
958 : : { .name = "unpause", .func = tap_cli_unpause },
959 : : { .name = "stats", .func = tap_cli_stats },
960 : : { .name = "major", .func = tap_cli_major },
961 : : { .name = "check", .func = tap_cli_check },
962 : : };
963 : :
964 : : #define print_commands() \
965 : : do { \
966 : : int i, n; \
967 : : n = sizeof(commands) / sizeof(struct command); \
968 : : printf("COMMAND := { "); \
969 : : printf("%s", commands[0].name); \
970 : : for (i = 1; i < n; i++) \
971 : : printf(" | %s", commands[i].name); \
972 : : printf(" }\n"); \
973 : : } while (0)
974 : :
975 : : void
976 : 0 : help(void)
977 : : {
978 : : printf("usage: tap-ctl COMMAND [OPTIONS]\n");
979 : 0 : print_commands();
980 : 0 : exit(0);
981 : : }
982 : :
983 : : struct command *
984 : 0 : get_command(char *command)
985 : : {
986 : : int i, n;
987 : :
988 : 0 : if (strnlen(command, 25) >= 25)
989 : : return NULL;
990 : :
991 : : n = sizeof(commands) / sizeof (struct command);
992 : :
993 : 0 : for (i = 0; i < n; i++)
994 : 0 : if (!strcmp(command, commands[i].name))
995 : 0 : return &commands[i];
996 : :
997 : : return NULL;
998 : : }
999 : :
1000 : : int
1001 : 0 : main(int argc, char *argv[])
1002 : : {
1003 : : char **cargv;
1004 : : const char *msg;
1005 : : struct command *cmd;
1006 : : int cargc, i, cnt, ret;
1007 : 0 : char *path = NULL, *prgname = NULL;
1008 : :
1009 : 0 : path = strdup(argv[0]);
1010 : 0 : if (path)
1011 : 0 : prgname = basename(path);
1012 : : else
1013 : : prgname = "tap-ctl";
1014 : 0 : openlog(prgname, LOG_PID, LOG_USER);
1015 : :
1016 : : #ifdef CORE_DUMP
1017 : : #include <sys/resource.h>
1018 : : struct rlimit rlim;
1019 : : rlim.rlim_cur = RLIM_INFINITY;
1020 : : rlim.rlim_max = RLIM_INFINITY;
1021 : : if (setrlimit(RLIMIT_CORE, &rlim) < 0)
1022 : : PERROR("setrlimit failed");
1023 : : #endif
1024 : :
1025 : 0 : signal(SIGPIPE, SIG_IGN);
1026 : :
1027 : 0 : ret = 0;
1028 : :
1029 : 0 : if (argc < 2)
1030 : 0 : help();
1031 : :
1032 : 0 : cargc = argc - 1;
1033 : 0 : cmd = get_command(argv[1]);
1034 : 0 : if (!cmd) {
1035 : 0 : EPRINTF("invalid COMMAND %s", argv[1]);
1036 : 0 : help();
1037 : : }
1038 : :
1039 : 0 : ret = tap_ctl_check(&msg);
1040 : 0 : if (ret) {
1041 : 0 : printf("%s\n", msg);
1042 : 0 : free(path);
1043 : 0 : return ret;
1044 : : }
1045 : :
1046 : 0 : cargv = malloc(sizeof(char *) * cargc);
1047 : 0 : if (!cargv)
1048 : 0 : exit(ENOMEM);
1049 : :
1050 : 0 : cnt = 1;
1051 : 0 : cargv[0] = cmd->name;
1052 : 0 : for (i = 1; i < cargc; i++) {
1053 : 0 : char *arg = argv[i + (argc - cargc)];
1054 : :
1055 : 0 : if (!strcmp(arg, "--debug")) {
1056 : 0 : tap_ctl_debug = 1;
1057 : 0 : continue;
1058 : : }
1059 : :
1060 : 0 : cargv[cnt++] = arg;
1061 : : }
1062 : :
1063 : 0 : ret = cmd->func(cnt, cargv);
1064 : :
1065 : 0 : free(cargv);
1066 : 0 : free(path);
1067 : :
1068 : 0 : if (ret)
1069 : : /* FIXME errors are not always returned as negative numbers */
1070 : 0 : fprintf(stderr, "%s\n", strerror(abs(ret)));
1071 : :
1072 : 0 : return (ret >= 0 ? ret : -ret);
1073 : : }
|