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_open_usage(FILE *stream)
709 : : {
710 : : fprintf(stream, "usage: open <-p pid> <-m minor> <-a type:/path/to/file> [-R readonly] "
711 : : "[-e <minor> stack on existing tapdisk for the parent chain] "
712 : : "[-r turn on read caching into leaf node] [-2 <path> "
713 : : "use secondary image (in mirror mode if no -s)] [-s "
714 : : "fail over to the secondary image on ENOSPC] "
715 : : "[-t request timeout in seconds] [-D no O_DIRECT] "
716 : : "[-C </path/to/logfile> insert log layer to track changed blocks] "
717 : : "[-E read encryption key from stdin]\n");
718 : : }
719 : :
720 : : static int
721 : 0 : tap_cli_open(int argc, char **argv)
722 : : {
723 : : const char *args, *secondary, *logpath;
724 : : int c, pid, minor, flags, prt_minor, timeout;
725 : : uint8_t *encryption_key;
726 : 0 : ssize_t key_size = 0;
727 : :
728 : 0 : flags = 0;
729 : 0 : pid = -1;
730 : 0 : minor = -1;
731 : 0 : prt_minor = -1;
732 : 0 : timeout = 0;
733 : 0 : args = NULL;
734 : 0 : secondary = NULL;
735 : 0 : logpath = NULL;
736 : 0 : encryption_key = NULL;
737 : :
738 : 0 : optind = 0;
739 : 0 : while ((c = getopt(argc, argv, "a:RDm:p:e:r2:st:C:Eh")) != -1) {
740 : 0 : switch (c) {
741 : : case 'p':
742 : 0 : pid = atoi(optarg);
743 : 0 : break;
744 : : case 'm':
745 : 0 : minor = atoi(optarg);
746 : 0 : break;
747 : : case 'a':
748 : 0 : args = optarg;
749 : 0 : break;
750 : : case 'R':
751 : 0 : flags |= TAPDISK_MESSAGE_FLAG_RDONLY;
752 : 0 : break;
753 : : case 'D':
754 : 0 : flags |= TAPDISK_MESSAGE_FLAG_NO_O_DIRECT;
755 : 0 : break;
756 : : case 'r':
757 : 0 : flags |= TAPDISK_MESSAGE_FLAG_ADD_LCACHE;
758 : 0 : break;
759 : : case 'e':
760 : 0 : flags |= TAPDISK_MESSAGE_FLAG_REUSE_PRT;
761 : 0 : prt_minor = atoi(optarg);
762 : 0 : break;
763 : : case '2':
764 : 0 : flags |= TAPDISK_MESSAGE_FLAG_SECONDARY;
765 : 0 : secondary = optarg;
766 : 0 : break;
767 : : case 's':
768 : 0 : flags |= TAPDISK_MESSAGE_FLAG_STANDBY;
769 : 0 : break;
770 : : case 't':
771 : 0 : timeout = atoi(optarg);
772 : 0 : break;
773 : : case 'C':
774 : 0 : logpath = optarg;
775 : 0 : flags |= TAPDISK_MESSAGE_FLAG_ADD_LOG;
776 : 0 : break;
777 : : case 'E':
778 : 0 : if (encryption_key) {
779 : 0 : fprintf(stderr, "Only supply -E once\n");
780 : 0 : exit(1);
781 : : }
782 : : /* Allocate the space for the key, */
783 : 0 : encryption_key = malloc(MAX_AES_XTS_PLAIN_KEYSIZE / sizeof(uint8_t));
784 : 0 : if (!encryption_key) {
785 : 0 : fprintf(stderr, "Failed to allocate space for encrpytion key\n");
786 : 0 : exit(1);
787 : : }
788 : 0 : key_size = read(STDIN_FILENO, (void*)encryption_key, MAX_AES_XTS_PLAIN_KEYSIZE / sizeof(uint8_t));
789 : 0 : if (key_size != 32 && key_size != 64){
790 : 0 : fprintf(stderr, "Unsupported keysize, use either 256 bit or 512 bit key\n");
791 : 0 : free(encryption_key);
792 : 0 : exit(1);
793 : : }
794 : 0 : flags |= TAPDISK_MESSAGE_FLAG_OPEN_ENCRYPTED;
795 : 0 : break;
796 : : case '?':
797 : : goto usage;
798 : : case 'h':
799 : 0 : tap_cli_open_usage(stdout);
800 : 0 : if (encryption_key) {
801 : 0 : free(encryption_key);
802 : : }
803 : : return 0;
804 : : }
805 : : }
806 : :
807 : 0 : if (pid == -1 || minor == -1 || !args)
808 : : goto usage;
809 : :
810 : 0 : return tap_ctl_open(pid, minor, args, flags, prt_minor, secondary,
811 : 0 : timeout, logpath, (uint8_t)key_size, encryption_key);
812 : :
813 : : usage:
814 : 0 : tap_cli_open_usage(stderr);
815 : 0 : if (encryption_key) {
816 : 0 : free(encryption_key);
817 : : }
818 : : return EINVAL;
819 : : }
820 : :
821 : : static void
822 : : tap_cli_stats_usage(FILE *stream)
823 : : {
824 : : fprintf(stream, "usage: stats <-p pid> <-m minor>\n"
825 : : "\n"
826 : : "Prints a Python dictionary with the VBD stats. The images are "
827 : : "listed in reverse order (leaf to root)\n");
828 : : }
829 : :
830 : : static int
831 : 0 : tap_cli_stats(int argc, char **argv)
832 : : {
833 : : pid_t pid;
834 : : int c, minor, err;
835 : :
836 : 0 : pid = -1;
837 : 0 : minor = -1;
838 : :
839 : 0 : optind = 0;
840 : 0 : while ((c = getopt(argc, argv, "p:m:h")) != -1) {
841 : 0 : switch (c) {
842 : : case 'p':
843 : 0 : pid = atoi(optarg);
844 : 0 : break;
845 : : case 'm':
846 : 0 : minor = atoi(optarg);
847 : 0 : break;
848 : : case '?':
849 : : goto usage;
850 : : case 'h':
851 : 0 : tap_cli_stats_usage(stdout);
852 : 0 : return 0;
853 : : }
854 : : }
855 : :
856 : 0 : if (pid == -1 || minor == -1)
857 : : goto usage;
858 : :
859 : 0 : err = tap_ctl_stats_fwrite(pid, minor, stdout);
860 : 0 : if (err)
861 : : return err;
862 : :
863 : 0 : fprintf(stdout, "\n");
864 : :
865 : 0 : return 0;
866 : :
867 : : usage:
868 : 0 : tap_cli_stats_usage(stderr);
869 : 0 : return EINVAL;
870 : : }
871 : :
872 : :
873 : : struct command commands[] = {
874 : : { .name = "list", .func = tap_cli_list },
875 : : { .name = "allocate", .func = tap_cli_allocate },
876 : : { .name = "free", .func = tap_cli_free },
877 : : { .name = "create", .func = tap_cli_create },
878 : : { .name = "destroy", .func = tap_cli_destroy },
879 : : { .name = "spawn", .func = tap_cli_spawn },
880 : : { .name = "attach", .func = tap_cli_attach },
881 : : { .name = "detach", .func = tap_cli_detach },
882 : : { .name = "open", .func = tap_cli_open },
883 : : { .name = "close", .func = tap_cli_close },
884 : : { .name = "pause", .func = tap_cli_pause },
885 : : { .name = "unpause", .func = tap_cli_unpause },
886 : : { .name = "stats", .func = tap_cli_stats },
887 : : };
888 : :
889 : : #define print_commands() \
890 : : do { \
891 : : int i, n; \
892 : : n = sizeof(commands) / sizeof(struct command); \
893 : : printf("COMMAND := { "); \
894 : : printf("%s", commands[0].name); \
895 : : for (i = 1; i < n; i++) \
896 : : printf(" | %s", commands[i].name); \
897 : : printf(" }\n"); \
898 : : } while (0)
899 : :
900 : : void
901 : 0 : help(void)
902 : : {
903 : : printf("usage: tap-ctl COMMAND [OPTIONS]\n");
904 : 0 : print_commands();
905 : 0 : exit(0);
906 : : }
907 : :
908 : : struct command *
909 : 0 : get_command(char *command)
910 : : {
911 : : int i, n;
912 : :
913 : 0 : if (strnlen(command, 25) >= 25)
914 : : return NULL;
915 : :
916 : : n = sizeof(commands) / sizeof (struct command);
917 : :
918 : 0 : for (i = 0; i < n; i++)
919 : 0 : if (!strcmp(command, commands[i].name))
920 : 0 : return &commands[i];
921 : :
922 : : return NULL;
923 : : }
924 : :
925 : : int
926 : 0 : main(int argc, char *argv[])
927 : : {
928 : : char **cargv;
929 : : struct command *cmd;
930 : : int cargc, i, cnt, ret;
931 : 0 : char *path = NULL, *prgname = NULL;
932 : :
933 : 0 : path = strdup(argv[0]);
934 : 0 : if (path)
935 : 0 : prgname = basename(path);
936 : : else
937 : : prgname = "tap-ctl";
938 : 0 : openlog(prgname, LOG_PID, LOG_USER);
939 : :
940 : : #ifdef CORE_DUMP
941 : : #include <sys/resource.h>
942 : : struct rlimit rlim;
943 : : rlim.rlim_cur = RLIM_INFINITY;
944 : : rlim.rlim_max = RLIM_INFINITY;
945 : : if (setrlimit(RLIMIT_CORE, &rlim) < 0)
946 : : PERROR("setrlimit failed");
947 : : #endif
948 : :
949 : 0 : signal(SIGPIPE, SIG_IGN);
950 : :
951 : 0 : ret = 0;
952 : :
953 : 0 : if (argc < 2)
954 : 0 : help();
955 : :
956 : 0 : cargc = argc - 1;
957 : 0 : cmd = get_command(argv[1]);
958 : 0 : if (!cmd) {
959 : 0 : EPRINTF("invalid COMMAND %s", argv[1]);
960 : 0 : help();
961 : : }
962 : :
963 : 0 : cargv = malloc(sizeof(char *) * cargc);
964 : 0 : if (!cargv)
965 : 0 : exit(ENOMEM);
966 : :
967 : 0 : cnt = 1;
968 : 0 : cargv[0] = cmd->name;
969 : 0 : for (i = 1; i < cargc; i++) {
970 : 0 : char *arg = argv[i + (argc - cargc)];
971 : :
972 : 0 : if (!strcmp(arg, "--debug")) {
973 : 0 : tap_ctl_debug = 1;
974 : 0 : continue;
975 : : }
976 : :
977 : 0 : cargv[cnt++] = arg;
978 : : }
979 : :
980 : 0 : ret = cmd->func(cnt, cargv);
981 : :
982 : 0 : free(cargv);
983 : 0 : free(path);
984 : :
985 : 0 : if (ret)
986 : : /* FIXME errors are not always returned as negative numbers */
987 : 0 : fprintf(stderr, "%s\n", strerror(abs(ret)));
988 : :
989 : 0 : return (ret >= 0 ? ret : -ret);
990 : : }
|