Statistics
| Branch: | Revision:

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
}