LCOV - code coverage report
Current view: top level - control - tap-ctl.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 574 0
Test Date: 2026-06-26 00:00:00 Functions: 0.0 % 20 0
Branches: 0.0 % 235 0

             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                 :             : }
        

Generated by: LCOV version 2.0-1