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 : 0 : 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 : 0 : 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 : 0 : int c, minor, tty, err;
118 : 0 : const char *type, *file;
119 : 0 : tap_list_t *entry;
120 : 0 : 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 : 0 : case 'm':
130 : 0 : minor = atoi(optarg);
131 : 0 : break;
132 : 0 : case 'p':
133 : 0 : pid = atoi(optarg);
134 : 0 : break;
135 : 0 : case 't':
136 : 0 : type = optarg;
137 : 0 : break;
138 : 0 : case 'f':
139 : 0 : file = optarg;
140 : 0 : break;
141 : 0 : case '?':
142 : 0 : goto usage;
143 : 0 : 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 : 0 : usage:
192 : 0 : tap_cli_list_usage(stderr);
193 : : return EINVAL;
194 : : }
195 : :
196 : : static void
197 : 0 : tap_cli_allocate_usage(FILE *stream)
198 : : {
199 : 0 : fprintf(stream, "usage: allocate\n");
200 : 0 : }
201 : :
202 : : static int
203 : 0 : tap_cli_allocate(int argc, char **argv)
204 : : {
205 : 0 : char *devname;
206 : 0 : int c, minor, err;
207 : :
208 : 0 : devname = NULL;
209 : :
210 : 0 : optind = 0;
211 [ # # ]: 0 : while ((c = getopt(argc, argv, "h")) != -1) {
212 [ # # # ]: 0 : switch (c) {
213 : 0 : case '?':
214 : 0 : goto usage;
215 : 0 : case 'h':
216 : 0 : tap_cli_allocate_usage(stdout);
217 : 0 : return 0;
218 : : }
219 : : }
220 : :
221 : 0 : err = tap_ctl_allocate(&minor, &devname);
222 [ # # ]: 0 : if (!err)
223 : 0 : printf("%s\n", devname);
224 : :
225 : 0 : free(devname);
226 : :
227 : 0 : return err;
228 : :
229 : 0 : usage:
230 : 0 : tap_cli_allocate_usage(stderr);
231 : : return EINVAL;
232 : : }
233 : :
234 : : static void
235 : 0 : tap_cli_free_usage(FILE *stream)
236 : : {
237 : 0 : fprintf(stream, "usage: free <-m minor>\n");
238 : : }
239 : :
240 : : static int
241 : 0 : tap_cli_free(int argc, char **argv)
242 : : {
243 : 0 : int c, minor;
244 : :
245 : 0 : minor = -1;
246 : :
247 : 0 : optind = 0;
248 [ # # ]: 0 : while ((c = getopt(argc, argv, "m:h")) != -1) {
249 [ # # # # ]: 0 : switch (c) {
250 : 0 : case 'm':
251 : 0 : minor = atoi(optarg);
252 : 0 : break;
253 : 0 : case '?':
254 : 0 : goto usage;
255 : 0 : case 'h':
256 : 0 : tap_cli_free_usage(stdout);
257 : 0 : return 0;
258 : : }
259 : : }
260 : :
261 [ # # ]: 0 : if (minor == -1)
262 : 0 : goto usage;
263 : :
264 : 0 : return tap_ctl_free(minor);
265 : :
266 : 0 : usage:
267 : 0 : tap_cli_free_usage(stderr);
268 : 0 : return EINVAL;
269 : : }
270 : :
271 : : static void
272 : 0 : tap_cli_create_usage(FILE *stream)
273 : : {
274 : 0 : fprintf(stream, "usage: create <-a type:/path/to/file> [-d device name] [-R readonly] "
275 : : "[-e <minor> stack on existing tapdisk for the parent chain] "
276 : : "[-r turn on read caching into leaf node] [-2 <path> "
277 : : "use secondary image (in mirror mode if no -s)] [-s "
278 : : "fail over to the secondary image on ENOSPC] "
279 : : "[-t request timeout in seconds] [-D no O_DIRECT] "
280 : : "[-C <path/to/logfile> insert log layer to track changed blocks]\n");
281 : 0 : }
282 : :
283 : : static int
284 : 0 : tap_cli_create(int argc, char **argv)
285 : : {
286 : 0 : int c, err, flags, prt_minor, timeout;
287 : 0 : char *args, *devname, *secondary;
288 : 0 : char d_flag = 0;
289 : 0 : char *logpath = NULL;
290 : :
291 : 0 : args = NULL;
292 : 0 : devname = NULL;
293 : 0 : secondary = NULL;
294 : 0 : prt_minor = -1;
295 : 0 : flags = 0;
296 : 0 : timeout = 0;
297 : :
298 : 0 : optind = 0;
299 [ # # ]: 0 : while ((c = getopt(argc, argv, "a:RDd:e:r2:st:C:h")) != -1) {
300 [ # # # # : 0 : switch (c) {
# # # # #
# # # # ]
301 : 0 : case 'a':
302 : 0 : args = optarg;
303 : 0 : break;
304 : 0 : case 'd':
305 : 0 : devname = optarg;
306 : 0 : d_flag = 1;
307 : 0 : break;
308 : 0 : case 'R':
309 : 0 : flags |= TAPDISK_MESSAGE_FLAG_RDONLY;
310 : 0 : break;
311 : 0 : case 'D':
312 : 0 : flags |= TAPDISK_MESSAGE_FLAG_NO_O_DIRECT;
313 : 0 : break;
314 : 0 : case 'r':
315 : 0 : flags |= TAPDISK_MESSAGE_FLAG_ADD_LCACHE;
316 : 0 : break;
317 : 0 : case 'e':
318 : 0 : flags |= TAPDISK_MESSAGE_FLAG_REUSE_PRT;
319 : 0 : prt_minor = atoi(optarg);
320 : 0 : break;
321 : 0 : case '2':
322 : 0 : flags |= TAPDISK_MESSAGE_FLAG_SECONDARY;
323 : 0 : secondary = optarg;
324 : 0 : break;
325 : 0 : case 's':
326 : 0 : flags |= TAPDISK_MESSAGE_FLAG_STANDBY;
327 : 0 : break;
328 : 0 : case 't':
329 : 0 : timeout = atoi(optarg);
330 : 0 : break;
331 : 0 : case 'C':
332 : 0 : logpath = optarg;
333 : 0 : flags |= TAPDISK_MESSAGE_FLAG_ADD_LOG;
334 : 0 : break;
335 : 0 : case '?':
336 : 0 : goto usage;
337 : 0 : case 'h':
338 : 0 : tap_cli_create_usage(stdout);
339 : 0 : return 0;
340 : : }
341 : : }
342 : :
343 [ # # ]: 0 : if (!args)
344 : 0 : goto usage;
345 : :
346 : 0 : err = tap_ctl_create(args, &devname, flags, prt_minor, secondary,
347 : : timeout, logpath);
348 [ # # ]: 0 : if (!err)
349 : 0 : printf("%s\n", devname);
350 : :
351 [ # # ]: 0 : if (!d_flag)
352 : 0 : free(devname);
353 : :
354 : : return err;
355 : :
356 : 0 : usage:
357 : 0 : tap_cli_create_usage(stderr);
358 : : return EINVAL;
359 : : }
360 : :
361 : : static void
362 : 0 : tap_cli_destroy_usage(FILE *stream)
363 : : {
364 : 0 : fprintf(stream, "usage: destroy <-p pid> <-m minor> [-t timeout secs]\n");
365 : : }
366 : :
367 : : static struct timeval*
368 : 0 : tap_cli_timeout(const char *optarg)
369 : : {
370 : 0 : static struct timeval tv;
371 : :
372 : 0 : tv.tv_sec = atoi(optarg);
373 : 0 : tv.tv_usec = 0;
374 : :
375 : 0 : return &tv;
376 : : }
377 : :
378 : : static int
379 : 0 : tap_cli_destroy(int argc, char **argv)
380 : : {
381 : 0 : int c, pid, minor;
382 : 0 : struct timeval *timeout;
383 : :
384 : 0 : pid = -1;
385 : 0 : minor = -1;
386 : 0 : timeout = NULL;
387 : :
388 : 0 : optind = 0;
389 [ # # ]: 0 : while ((c = getopt(argc, argv, "p:m:t:h")) != -1) {
390 [ # # # # : 0 : switch (c) {
# # ]
391 : 0 : case 'p':
392 : 0 : pid = atoi(optarg);
393 : 0 : break;
394 : 0 : case 'm':
395 : 0 : minor = atoi(optarg);
396 : 0 : break;
397 : 0 : case 't':
398 : 0 : timeout = tap_cli_timeout(optarg);
399 : 0 : if (!timeout)
400 : : goto usage;
401 : : break;
402 : 0 : case '?':
403 : 0 : goto usage;
404 : 0 : case 'h':
405 : 0 : tap_cli_destroy_usage(stdout);
406 : 0 : return 0;
407 : : }
408 : : }
409 : :
410 [ # # ]: 0 : if (pid == -1 || minor == -1)
411 : 0 : goto usage;
412 : :
413 : 0 : return tap_ctl_destroy(pid, minor, 0, timeout);
414 : :
415 : 0 : usage:
416 : 0 : tap_cli_destroy_usage(stderr);
417 : 0 : return EINVAL;
418 : : }
419 : :
420 : : static void
421 : 0 : tap_cli_spawn_usage(FILE *stream)
422 : : {
423 : 0 : fprintf(stream, "usage: spawn\n");
424 : : }
425 : :
426 : : static int
427 : 0 : tap_cli_spawn(int argc, char **argv)
428 : : {
429 : 0 : int c, tty;
430 : 0 : pid_t pid;
431 : :
432 : 0 : optind = 0;
433 [ # # ]: 0 : while ((c = getopt(argc, argv, "h")) != -1) {
434 [ # # # ]: 0 : switch (c) {
435 : 0 : case '?':
436 : 0 : goto usage;
437 : 0 : case 'h':
438 : 0 : tap_cli_spawn_usage(stdout);
439 : 0 : return 0;
440 : : }
441 : : }
442 : :
443 : 0 : pid = tap_ctl_spawn();
444 [ # # ]: 0 : if (pid < 0)
445 : : return pid;
446 : :
447 : 0 : tty = isatty(STDOUT_FILENO);
448 [ # # ]: 0 : if (tty)
449 : 0 : printf("tapdisk spawned with pid %d\n", pid);
450 : : else
451 : 0 : printf("%d\n", pid);
452 : :
453 : : return 0;
454 : :
455 : 0 : usage:
456 : 0 : tap_cli_spawn_usage(stderr);
457 : 0 : return EINVAL;
458 : : }
459 : :
460 : : static void
461 : 0 : tap_cli_attach_usage(FILE *stream)
462 : : {
463 : 0 : fprintf(stream, "usage: attach <-p pid> <-m minor>\n");
464 : : }
465 : :
466 : : static int
467 : 0 : tap_cli_attach(int argc, char **argv)
468 : : {
469 : 0 : int c, pid, minor;
470 : :
471 : 0 : pid = -1;
472 : 0 : minor = -1;
473 : :
474 : 0 : optind = 0;
475 [ # # ]: 0 : while ((c = getopt(argc, argv, "p:m:h")) != -1) {
476 [ # # # # : 0 : switch (c) {
# ]
477 : 0 : case 'p':
478 : 0 : pid = atoi(optarg);
479 : 0 : break;
480 : 0 : case 'm':
481 : 0 : minor = atoi(optarg);
482 : 0 : break;
483 : 0 : case '?':
484 : 0 : goto usage;
485 : 0 : case 'h':
486 : 0 : tap_cli_attach_usage(stderr);
487 : 0 : return 0;
488 : : }
489 : : }
490 : :
491 [ # # ]: 0 : if (pid == -1 || minor == -1)
492 : 0 : goto usage;
493 : :
494 : 0 : return tap_ctl_attach(pid, minor);
495 : :
496 : 0 : usage:
497 : 0 : tap_cli_attach_usage(stderr);
498 : 0 : return EINVAL;
499 : : }
500 : :
501 : : static void
502 : 0 : tap_cli_detach_usage(FILE *stream)
503 : : {
504 : 0 : fprintf(stream, "usage: detach <-p pid> <-m minor>\n");
505 : : }
506 : :
507 : : static int
508 : 0 : tap_cli_detach(int argc, char **argv)
509 : : {
510 : 0 : int c, pid, minor;
511 : :
512 : 0 : pid = -1;
513 : 0 : minor = -1;
514 : :
515 : 0 : optind = 0;
516 [ # # ]: 0 : while ((c = getopt(argc, argv, "p:m:h")) != -1) {
517 [ # # # # : 0 : switch (c) {
# ]
518 : 0 : case 'p':
519 : 0 : pid = atoi(optarg);
520 : 0 : break;
521 : 0 : case 'm':
522 : 0 : minor = atoi(optarg);
523 : 0 : break;
524 : 0 : case '?':
525 : 0 : goto usage;
526 : 0 : case 'h':
527 : 0 : tap_cli_detach_usage(stdout);
528 : 0 : return 0;
529 : : }
530 : : }
531 : :
532 [ # # ]: 0 : if (pid == -1 || minor == -1)
533 : 0 : goto usage;
534 : :
535 : 0 : return tap_ctl_detach(pid, minor);
536 : :
537 : 0 : usage:
538 : 0 : tap_cli_detach_usage(stderr);
539 : 0 : return EINVAL;
540 : : }
541 : :
542 : : static void
543 : 0 : tap_cli_close_usage(FILE *stream)
544 : : {
545 : 0 : fprintf(stream, "usage: close <-p pid> <-m minor> [-f force] [-t timeout secs]\n");
546 : : }
547 : :
548 : : static int
549 : 0 : tap_cli_close(int argc, char **argv)
550 : : {
551 : 0 : int c, pid, minor, force;
552 : 0 : struct timeval *timeout;
553 : :
554 : 0 : pid = -1;
555 : 0 : minor = -1;
556 : 0 : force = 0;
557 : 0 : timeout = NULL;
558 : :
559 : 0 : optind = 0;
560 [ # # ]: 0 : while ((c = getopt(argc, argv, "p:m:ft:h")) != -1) {
561 [ # # # # : 0 : switch (c) {
# # # ]
562 : 0 : case 'p':
563 : 0 : pid = atoi(optarg);
564 : 0 : break;
565 : 0 : case 'm':
566 : 0 : minor = atoi(optarg);
567 : 0 : break;
568 : 0 : case 'f':
569 : 0 : force = -1;
570 : 0 : break;
571 : 0 : case 't':
572 : 0 : timeout = tap_cli_timeout(optarg);
573 : 0 : if (!timeout)
574 : : goto usage;
575 : : break;
576 : 0 : case '?':
577 : 0 : goto usage;
578 : 0 : case 'h':
579 : 0 : tap_cli_close_usage(stdout);
580 : 0 : return 0;
581 : : }
582 : : }
583 : :
584 [ # # ]: 0 : if (pid == -1 || minor == -1)
585 : 0 : goto usage;
586 : :
587 : 0 : return tap_ctl_close(pid, minor, force, timeout);
588 : :
589 : 0 : usage:
590 : 0 : tap_cli_close_usage(stderr);
591 : 0 : return EINVAL;
592 : : }
593 : :
594 : : static void
595 : 0 : tap_cli_pause_usage(FILE *stream)
596 : : {
597 : 0 : fprintf(stream, "usage: pause <-p pid> <-m minor> [-t timeout secs]\n");
598 : : }
599 : :
600 : : static int
601 : 0 : tap_cli_pause(int argc, char **argv)
602 : : {
603 : 0 : int c, pid, minor;
604 : 0 : struct timeval *timeout;
605 : :
606 : 0 : pid = -1;
607 : 0 : minor = -1;
608 : 0 : timeout = NULL;
609 : :
610 : 0 : optind = 0;
611 [ # # ]: 0 : while ((c = getopt(argc, argv, "p:m:t:h")) != -1) {
612 [ # # # # : 0 : switch (c) {
# # ]
613 : 0 : case 'p':
614 : 0 : pid = atoi(optarg);
615 : 0 : break;
616 : 0 : case 'm':
617 : 0 : minor = atoi(optarg);
618 : 0 : break;
619 : 0 : case 't':
620 : 0 : timeout = tap_cli_timeout(optarg);
621 : 0 : if (!timeout)
622 : : goto usage;
623 : : case '?':
624 : 0 : goto usage;
625 : 0 : case 'h':
626 : 0 : tap_cli_pause_usage(stdout);
627 : 0 : return 0;
628 : : }
629 : : }
630 : :
631 [ # # ]: 0 : if (pid == -1 || minor == -1)
632 : 0 : goto usage;
633 : :
634 : 0 : return tap_ctl_pause(pid, minor, timeout);
635 : :
636 : 0 : usage:
637 : 0 : tap_cli_pause_usage(stderr);
638 : 0 : return EINVAL;
639 : : }
640 : :
641 : : static void
642 : 0 : tap_cli_unpause_usage(FILE *stream)
643 : : {
644 : 0 : fprintf(stream, "usage: unpause <-p pid> <-m minor> [-a type:/path/to/file] "
645 : : "[-2 secondary] "
646 : : "[-c </path/to/logfile> insert log layer to track changed blocks]\n");
647 : : }
648 : :
649 : : int
650 : 0 : tap_cli_unpause(int argc, char **argv)
651 : : {
652 : 0 : const char *args, *logpath;
653 : 0 : char *secondary;
654 : 0 : int c, pid, minor, flags;
655 : :
656 : 0 : pid = -1;
657 : 0 : minor = -1;
658 : 0 : args = NULL;
659 : 0 : secondary = NULL;
660 : 0 : flags = 0;
661 : 0 : logpath = NULL;
662 : :
663 : 0 : optind = 0;
664 [ # # ]: 0 : while ((c = getopt(argc, argv, "p:m:a:2:c:h")) != -1) {
665 [ # # # # : 0 : switch (c) {
# # # # ]
666 : 0 : case 'p':
667 : 0 : pid = atoi(optarg);
668 : 0 : break;
669 : 0 : case 'm':
670 : 0 : minor = atoi(optarg);
671 : 0 : break;
672 : 0 : case 'a':
673 : 0 : args = optarg;
674 : 0 : break;
675 : 0 : case '2':
676 : 0 : flags |= TAPDISK_MESSAGE_FLAG_SECONDARY;
677 : 0 : secondary = optarg;
678 : 0 : break;
679 : 0 : case 'c':
680 : 0 : logpath = optarg;
681 : 0 : flags |= TAPDISK_MESSAGE_FLAG_ADD_LOG;
682 : 0 : break;
683 : 0 : case '?':
684 : 0 : goto usage;
685 : 0 : case 'h':
686 : 0 : tap_cli_unpause_usage(stdout);
687 : 0 : return 0;
688 : : }
689 : : }
690 : :
691 [ # # ]: 0 : if (pid == -1 || minor == -1)
692 : 0 : goto usage;
693 : :
694 : 0 : return tap_ctl_unpause(pid, minor, args, flags, secondary, logpath);
695 : :
696 : 0 : usage:
697 : 0 : tap_cli_unpause_usage(stderr);
698 : 0 : return EINVAL;
699 : : }
700 : :
701 : : static void
702 : 0 : tap_cli_open_usage(FILE *stream)
703 : : {
704 : 0 : fprintf(stream, "usage: open <-p pid> <-m minor> <-a type:/path/to/file> [-R readonly] "
705 : : "[-e <minor> stack on existing tapdisk for the parent chain] "
706 : : "[-r turn on read caching into leaf node] [-2 <path> "
707 : : "use secondary image (in mirror mode if no -s)] [-s "
708 : : "fail over to the secondary image on ENOSPC] "
709 : : "[-t request timeout in seconds] [-D no O_DIRECT] "
710 : : "[-C </path/to/logfile> insert log layer to track changed blocks] "
711 : : "[-E read encryption key from stdin]\n");
712 : : }
713 : :
714 : : static int
715 : 0 : tap_cli_open(int argc, char **argv)
716 : : {
717 : 0 : const char *args, *secondary, *logpath;
718 : 0 : int c, pid, minor, flags, prt_minor, timeout;
719 : 0 : uint8_t *encryption_key;
720 : 0 : ssize_t key_size = 0;
721 : :
722 : 0 : flags = 0;
723 : 0 : pid = -1;
724 : 0 : minor = -1;
725 : 0 : prt_minor = -1;
726 : 0 : timeout = 0;
727 : 0 : args = NULL;
728 : 0 : secondary = NULL;
729 : 0 : logpath = NULL;
730 : 0 : encryption_key = NULL;
731 : :
732 : 0 : optind = 0;
733 [ # # ]: 0 : while ((c = getopt(argc, argv, "a:RDm:p:e:r2:st:C:Eh")) != -1) {
734 [ # # # # : 0 : switch (c) {
# # # # #
# # # # #
# ]
735 : 0 : case 'p':
736 : 0 : pid = atoi(optarg);
737 : 0 : break;
738 : 0 : case 'm':
739 : 0 : minor = atoi(optarg);
740 : 0 : break;
741 : 0 : case 'a':
742 : 0 : args = optarg;
743 : 0 : break;
744 : 0 : case 'R':
745 : 0 : flags |= TAPDISK_MESSAGE_FLAG_RDONLY;
746 : 0 : break;
747 : 0 : case 'D':
748 : 0 : flags |= TAPDISK_MESSAGE_FLAG_NO_O_DIRECT;
749 : 0 : break;
750 : 0 : case 'r':
751 : 0 : flags |= TAPDISK_MESSAGE_FLAG_ADD_LCACHE;
752 : 0 : break;
753 : 0 : case 'e':
754 : 0 : flags |= TAPDISK_MESSAGE_FLAG_REUSE_PRT;
755 : 0 : prt_minor = atoi(optarg);
756 : 0 : break;
757 : 0 : case '2':
758 : 0 : flags |= TAPDISK_MESSAGE_FLAG_SECONDARY;
759 : 0 : secondary = optarg;
760 : 0 : break;
761 : 0 : case 's':
762 : 0 : flags |= TAPDISK_MESSAGE_FLAG_STANDBY;
763 : 0 : break;
764 : 0 : case 't':
765 : 0 : timeout = atoi(optarg);
766 : 0 : break;
767 : 0 : case 'C':
768 : 0 : logpath = optarg;
769 : 0 : flags |= TAPDISK_MESSAGE_FLAG_ADD_LOG;
770 : 0 : break;
771 : 0 : case 'E':
772 [ # # ]: 0 : if (encryption_key) {
773 : 0 : fprintf(stderr, "Only supply -E once\n");
774 : 0 : exit(1);
775 : : }
776 : : /* Allocate the space for the key, */
777 : 0 : encryption_key = malloc(MAX_AES_XTS_PLAIN_KEYSIZE / sizeof(uint8_t));
778 [ # # ]: 0 : if (!encryption_key) {
779 : 0 : fprintf(stderr, "Failed to allocate space for encrpytion key\n");
780 : 0 : exit(1);
781 : : }
782 [ # # ]: 0 : key_size = read(STDIN_FILENO, (void*)encryption_key, MAX_AES_XTS_PLAIN_KEYSIZE / sizeof(uint8_t));
783 [ # # ]: 0 : if (key_size != 32 && key_size != 64){
784 : 0 : fprintf(stderr, "Unsupported keysize, use either 256 bit or 512 bit key\n");
785 : 0 : free(encryption_key);
786 : 0 : exit(1);
787 : : }
788 : 0 : flags |= TAPDISK_MESSAGE_FLAG_OPEN_ENCRYPTED;
789 : 0 : break;
790 : 0 : case '?':
791 : 0 : goto usage;
792 : 0 : case 'h':
793 : 0 : tap_cli_open_usage(stdout);
794 [ # # ]: 0 : if (encryption_key) {
795 : 0 : free(encryption_key);
796 : : }
797 : : return 0;
798 : : }
799 : : }
800 : :
801 [ # # # # ]: 0 : if (pid == -1 || minor == -1 || !args)
802 : 0 : goto usage;
803 : :
804 : 0 : return tap_ctl_open(pid, minor, args, flags, prt_minor, secondary,
805 : 0 : timeout, logpath, (uint8_t)key_size, encryption_key);
806 : :
807 : 0 : usage:
808 : 0 : tap_cli_open_usage(stderr);
809 [ # # ]: 0 : if (encryption_key) {
810 : 0 : free(encryption_key);
811 : : }
812 : : return EINVAL;
813 : : }
814 : :
815 : : static void
816 : 0 : tap_cli_stats_usage(FILE *stream)
817 : : {
818 : 0 : fprintf(stream, "usage: stats <-p pid> <-m minor>\n"
819 : : "\n"
820 : : "Prints a Python dictionary with the VBD stats. The images are "
821 : : "listed in reverse order (leaf to root)\n");
822 : : }
823 : :
824 : : static int
825 : 0 : tap_cli_stats(int argc, char **argv)
826 : : {
827 : 0 : pid_t pid;
828 : 0 : int c, minor, err;
829 : :
830 : 0 : pid = -1;
831 : 0 : minor = -1;
832 : :
833 : 0 : optind = 0;
834 [ # # ]: 0 : while ((c = getopt(argc, argv, "p:m:h")) != -1) {
835 [ # # # # : 0 : switch (c) {
# ]
836 : 0 : case 'p':
837 : 0 : pid = atoi(optarg);
838 : 0 : break;
839 : 0 : case 'm':
840 : 0 : minor = atoi(optarg);
841 : 0 : break;
842 : 0 : case '?':
843 : 0 : goto usage;
844 : 0 : case 'h':
845 : 0 : tap_cli_stats_usage(stdout);
846 : 0 : return 0;
847 : : }
848 : : }
849 : :
850 [ # # ]: 0 : if (pid == -1 || minor == -1)
851 : 0 : goto usage;
852 : :
853 : 0 : err = tap_ctl_stats_fwrite(pid, minor, stdout);
854 [ # # ]: 0 : if (err)
855 : : return err;
856 : :
857 : 0 : fprintf(stdout, "\n");
858 : :
859 : 0 : return 0;
860 : :
861 : 0 : usage:
862 : 0 : tap_cli_stats_usage(stderr);
863 : 0 : return EINVAL;
864 : : }
865 : :
866 : :
867 : : struct command commands[] = {
868 : : { .name = "list", .func = tap_cli_list },
869 : : { .name = "allocate", .func = tap_cli_allocate },
870 : : { .name = "free", .func = tap_cli_free },
871 : : { .name = "create", .func = tap_cli_create },
872 : : { .name = "destroy", .func = tap_cli_destroy },
873 : : { .name = "spawn", .func = tap_cli_spawn },
874 : : { .name = "attach", .func = tap_cli_attach },
875 : : { .name = "detach", .func = tap_cli_detach },
876 : : { .name = "open", .func = tap_cli_open },
877 : : { .name = "close", .func = tap_cli_close },
878 : : { .name = "pause", .func = tap_cli_pause },
879 : : { .name = "unpause", .func = tap_cli_unpause },
880 : : { .name = "stats", .func = tap_cli_stats },
881 : : };
882 : :
883 : : #define print_commands() \
884 : : do { \
885 : : int i, n; \
886 : : n = sizeof(commands) / sizeof(struct command); \
887 : : printf("COMMAND := { "); \
888 : : printf("%s", commands[0].name); \
889 : : for (i = 1; i < n; i++) \
890 : : printf(" | %s", commands[i].name); \
891 : : printf(" }\n"); \
892 : : } while (0)
893 : :
894 : : void
895 : 0 : help(void)
896 : : {
897 : 0 : printf("usage: tap-ctl COMMAND [OPTIONS]\n");
898 [ # # ]: 0 : print_commands();
899 : 0 : exit(0);
900 : : }
901 : :
902 : : struct command *
903 : 0 : get_command(char *command)
904 : : {
905 : 0 : int i, n;
906 : :
907 [ # # ]: 0 : if (strnlen(command, 25) >= 25)
908 : : return NULL;
909 : :
910 : : n = sizeof(commands) / sizeof (struct command);
911 : :
912 [ # # ]: 0 : for (i = 0; i < n; i++)
913 [ # # ]: 0 : if (!strcmp(command, commands[i].name))
914 : 0 : return &commands[i];
915 : :
916 : : return NULL;
917 : : }
918 : :
919 : : int
920 : 0 : main(int argc, char *argv[])
921 : : {
922 : 0 : char **cargv;
923 : 0 : struct command *cmd;
924 : 0 : int cargc, i, cnt, ret;
925 : 0 : char *path = NULL, *prgname = NULL;
926 : :
927 : 0 : path = strdup(argv[0]);
928 [ # # ]: 0 : if (path)
929 : 0 : prgname = basename(path);
930 : : else
931 : : prgname = "tap-ctl";
932 : 0 : openlog(prgname, LOG_PID, LOG_USER);
933 : :
934 : : #ifdef CORE_DUMP
935 : : #include <sys/resource.h>
936 : : struct rlimit rlim;
937 : : rlim.rlim_cur = RLIM_INFINITY;
938 : : rlim.rlim_max = RLIM_INFINITY;
939 : : if (setrlimit(RLIMIT_CORE, &rlim) < 0)
940 : : PERROR("setrlimit failed");
941 : : #endif
942 : :
943 : 0 : signal(SIGPIPE, SIG_IGN);
944 : :
945 : 0 : ret = 0;
946 : :
947 [ # # ]: 0 : if (argc < 2)
948 : 0 : help();
949 : :
950 : 0 : cargc = argc - 1;
951 : 0 : cmd = get_command(argv[1]);
952 [ # # ]: 0 : if (!cmd) {
953 : 0 : EPRINTF("invalid COMMAND %s", argv[1]);
954 : 0 : help();
955 : : }
956 : :
957 : 0 : cargv = malloc(sizeof(char *) * cargc);
958 [ # # ]: 0 : if (!cargv)
959 : 0 : exit(ENOMEM);
960 : :
961 : 0 : cnt = 1;
962 : 0 : cargv[0] = cmd->name;
963 [ # # ]: 0 : for (i = 1; i < cargc; i++) {
964 : 0 : char *arg = argv[i + (argc - cargc)];
965 : :
966 [ # # ]: 0 : if (!strcmp(arg, "--debug")) {
967 : 0 : tap_ctl_debug = 1;
968 : 0 : continue;
969 : : }
970 : :
971 : 0 : cargv[cnt++] = arg;
972 : : }
973 : :
974 : 0 : ret = cmd->func(cnt, cargv);
975 : :
976 : 0 : free(cargv);
977 : 0 : free(path);
978 : :
979 [ # # ]: 0 : if (ret)
980 : : /* FIXME errors are not always returned as negative numbers */
981 : 0 : fprintf(stderr, "%s\n", strerror(abs(ret)));
982 : :
983 : 0 : return (ret >= 0 ? ret : -ret);
984 : : }
|