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

Generated by: LCOV version 1.13