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