1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 #include <sys/types.h>
  17 #include <stdio.h>
  18 #include <stdlib.h>
  19 #include <string.h>
  20 #include <stdarg.h>
  21 #include <unistd.h>
  22 #include <stropts.h>
  23 #include <fcntl.h>
  24 #include <errno.h>
  25 #include <sys/debug.h>
  26 #include <inttypes.h>
  27 #include <ctype.h>
  28 #include <umem.h>
  29 #include <libnvpair.h>
  30 #include <uuid/uuid.h>
  31 
  32 #include <libsysevent.h>
  33 #include <sys/sysevent/krrp.h>
  34 
  35 #include <assert.h>
  36 
  37 #include <sys/krrp.h>
  38 #include <libkrrp.h>
  39 
  40 
  41 #define KRRP_CMD_MAP(X) \
  42         X(read-event, krrp_do_read_event, \
  43             krrp_usage_event, READ_EVENT) \
  44         X(sess-list, krrp_do_sess_list, \
  45             krrp_usage_sess, SESS_LIST) \
  46         X(sess-create, krrp_do_sess_create, \
  47             krrp_usage_sess, SESS_CREATE) \
  48         X(sess-destroy, krrp_do_sess_action, \
  49             krrp_usage_sess, SESS_DESTROY) \
  50         X(sess-run, krrp_do_sess_action, \
  51             krrp_usage_sess, SESS_RUN) \
  52         X(sess-send-stop, krrp_do_sess_action, \
  53             krrp_usage_sess, SESS_SEND_STOP) \
  54         X(sess-status, krrp_do_sess_status, \
  55             krrp_usage_sess, SESS_STATUS) \
  56         X(sess-create-conn, krrp_do_sess_create_conn, \
  57             krrp_usage_sess, SESS_CREATE_CONN) \
  58         X(sess-create-read-stream, krrp_do_sess_create_read_stream, \
  59             krrp_usage_sess, SESS_CREATE_READ_STREAM) \
  60         X(sess-create-write-stream, krrp_do_sess_create_write_stream, \
  61             krrp_usage_sess, SESS_CREATE_WRITE_STREAM) \
  62         X(sess-create-pdu-engine, krrp_do_sess_create_pdu_engine, \
  63             krrp_usage_sess, SESS_CREATE_PDU_ENGINE) \
  64         X(sess-conn-throttle, krrp_do_sess_action, \
  65             krrp_usage_sess, SESS_CONN_THROTTLE) \
  66         X(sess-get-conn-info, krrp_do_sess_get_conn_info, \
  67             krrp_usage_sess, SESS_GET_CONN_INFO) \
  68         X(ksvc-enable, krrp_do_ksvc_action, \
  69             krrp_usage_ksvc, KSVC_ENABLE) \
  70         X(ksvc-disable, krrp_do_ksvc_action, \
  71             krrp_usage_ksvc, KSVC_DISABLE) \
  72         X(ksvc-state, krrp_do_svc_get_state, \
  73             krrp_usage_ksvc, KSVC_STATE) \
  74         X(ksvc-configure, krrp_do_ksvc_configure, \
  75             krrp_usage_ksvc, KSVC_CONFIGURE) \
  76 
  77 typedef enum {
  78 #define KRRP_CMD_EXPAND(cmd_name, action_func, usage_func, enum_name) \
  79     KRRP_CMD_##enum_name,
  80         KRRP_CMD_MAP(KRRP_CMD_EXPAND)
  81 #undef KRRP_CMD_EXPAND
  82         KRRP_CMD_LAST
  83 } krrp_cmd_item_t;
  84 
  85 typedef struct krrp_cmd_s krrp_cmd_t;
  86 
  87 typedef void (krrp_usage_func)(int, krrp_cmd_t *, boolean_t);
  88 typedef int (krrp_handler_func)(int argc, char **argv, krrp_cmd_t *);
  89 
  90 struct krrp_cmd_s {
  91         const char                      *name;
  92         krrp_handler_func       *handler_func;
  93         krrp_usage_func         *usage_func;
  94         krrp_cmd_item_t         item;
  95 };
  96 
  97 static void common_usage(int);
  98 static int krrp_lookup_cmd(const char *, krrp_cmd_t **);
  99 
 100 static krrp_usage_func krrp_usage_ksvc, krrp_usage_sess, krrp_usage_event;
 101 
 102 static krrp_handler_func krrp_do_ksvc_action, krrp_do_ksvc_configure,
 103     krrp_do_sess_list, krrp_do_sess_action, krrp_do_sess_create_conn,
 104     krrp_do_sess_create_read_stream, krrp_do_sess_create_write_stream,
 105     krrp_do_sess_create_pdu_engine, krrp_do_sess_status, krrp_do_read_event,
 106     krrp_do_svc_get_state, krrp_do_sess_create, krrp_do_sess_get_conn_info;
 107 
 108 static int krrp_parse_and_check_sess_id(char *sess_id_str,
 109     uuid_t sess_id);
 110 
 111 static int krrp_sysevent_cb(libkrrp_event_t *ev, void *cookie);
 112 static void krrp_print_err_already_defined(const char *param);
 113 static void krrp_print_err_unknown_param(const char *param);
 114 static void krrp_print_err_no_sess_id(void);
 115 static void krrp_print_libkrrp_error(void);
 116 
 117 static void fprintf_err(const char *fmt, ...);
 118 static void fprintf_msg(const char *fmt, ...);
 119 
 120 static krrp_cmd_t cmds[] = {
 121 #define KRRP_CMD_EXPAND(cmd_name, action_func, usage_func, enum_name) \
 122         {#cmd_name, action_func, usage_func, KRRP_CMD_##enum_name},
 123         KRRP_CMD_MAP(KRRP_CMD_EXPAND)
 124 #undef KRRP_CMD_EXPAND
 125 };
 126 static size_t cmds_sz = sizeof (cmds) / sizeof (cmds[0]);
 127 
 128 const char *tool_name;
 129 libkrrp_handle_t *libkrrp_hdl = NULL;
 130 
 131 int
 132 main(int argc, char **argv)
 133 {
 134         int rc = 0;
 135         krrp_cmd_t *cmd;
 136 
 137         opterr = 0;
 138 
 139         tool_name = argv[0];
 140 
 141         if (argc < 2) {
 142                 fprintf_err("missing command\n\n\n");
 143                 common_usage(1);
 144         }
 145 
 146         rc = krrp_lookup_cmd(argv[1], &cmd);
 147         if (rc != 0) {
 148                 fprintf_err("unknown command\n");
 149                 common_usage(1);
 150         }
 151 
 152         libkrrp_hdl = libkrrp_init();
 153         if (libkrrp_hdl == NULL) {
 154                 fprintf_err("Failed to init libkrrp\n");
 155                 exit(1);
 156         }
 157 
 158         rc = cmd->handler_func(argc - 1, argv + 1, cmd);
 159 
 160         return (rc);
 161 }
 162 
 163 static void
 164 common_usage(int rc)
 165 {
 166         size_t i;
 167 
 168         for (i = 0; i < cmds_sz; i++)
 169                 cmds[i].usage_func(0, &cmds[i], B_TRUE);
 170 
 171         exit(rc);
 172 }
 173 
 174 static void
 175 krrp_usage_event(int rc, krrp_cmd_t *cmd, boolean_t use_return)
 176 {
 177         assert(cmd->item == KRRP_CMD_READ_EVENT);
 178 
 179         fprintf_msg("Usage: %s read-event\n\n\n", tool_name);
 180 
 181         if (use_return)
 182                 return;
 183 
 184         exit(rc);
 185 }
 186 
 187 static void
 188 krrp_usage_ksvc(int rc, krrp_cmd_t *cmd, boolean_t use_return)
 189 {
 190         switch (cmd->item) {
 191         case KRRP_CMD_KSVC_ENABLE:
 192                 fprintf_msg("Usage: %s ksvc-enable\n", tool_name);
 193                 break;
 194         case KRRP_CMD_KSVC_DISABLE:
 195                 fprintf_msg("Usage: %s ksvc-disable\n", tool_name);
 196                 break;
 197         case KRRP_CMD_KSVC_STATE:
 198                 fprintf_msg("Usage: %s ksvc-state\n", tool_name);
 199                 break;
 200         case KRRP_CMD_KSVC_CONFIGURE:
 201                 fprintf_msg("Usage: %s ksvc-configure "
 202                     "<-p listning port>\n", tool_name);
 203                 break;
 204         default:
 205                 assert(0);
 206         }
 207 
 208         fprintf_msg("\n\n");
 209 
 210         if (use_return)
 211                 return;
 212 
 213         exit(rc);
 214 }
 215 
 216 static void
 217 krrp_usage_sess(int rc, krrp_cmd_t *cmd, boolean_t use_return)
 218 {
 219         switch (cmd->item) {
 220         case KRRP_CMD_SESS_LIST:
 221                 fprintf_msg("Usage: %s sess-list\n", tool_name);
 222                 break;
 223         case KRRP_CMD_SESS_CREATE:
 224                 fprintf_msg("Usage: %s sess-create -s <sess_id> "
 225                     "<-k kstat_id (16 symbols)> "
 226                     "[-a <auth digest (max 255 symbols)>] "
 227                     "[-z] [-f] [-c]\n", tool_name);
 228                 break;
 229         case KRRP_CMD_SESS_DESTROY:
 230                 fprintf_msg("Usage: %s sess-destroy "
 231                     "-s <sess_id>\n", tool_name);
 232                 break;
 233         case KRRP_CMD_SESS_STATUS:
 234                 fprintf_msg("Usage: %s sess-status "
 235                     "-s <sess_id>\n", tool_name);
 236                 break;
 237         case KRRP_CMD_SESS_RUN:
 238                 fprintf_msg("Usage: %s sess-run "
 239                     "-s <sess_id>\n", tool_name);
 240                 break;
 241         case KRRP_CMD_SESS_SEND_STOP:
 242                 fprintf_msg("Usage: %s sess-send-stop "
 243                     "-s <sess_id>\n", tool_name);
 244                 break;
 245         case KRRP_CMD_SESS_CREATE_CONN:
 246                 fprintf_msg("Usage: %s sess-create-conn "
 247                     "-s <sess_id> -a <remote IP> -p <remote port> "
 248                     "-t <timeout>\n", tool_name);
 249                 break;
 250         case KRRP_CMD_SESS_CONN_THROTTLE:
 251                 fprintf_msg("Usage: %s sess-conn-throttle "
 252                     "-s <sess_id> -l <limit>\n",
 253                     tool_name);
 254                 break;
 255         case KRRP_CMD_SESS_GET_CONN_INFO:
 256                 fprintf_msg("Usage: %s sess-get-conn-info "
 257                     "-s <sess_id>\n", tool_name);
 258                 break;
 259         case KRRP_CMD_SESS_CREATE_READ_STREAM:
 260                 fprintf_msg("Usage: %s sess-create-read-stream "
 261                     "-s <sess_id> -d <src dataset> [-z <src snapshot>] "
 262                     "[-c <common snapshot>] [-I] [-r] [-p] [-e] [-k] "
 263                     "[-j] [-b] [-f <fake_data_sz>] [-t <resume_token>] "
 264                     "[-n <keep snaps>] [-m <user_prop_name>=<val>]\n",
 265                     tool_name);
 266                 break;
 267         case KRRP_CMD_SESS_CREATE_WRITE_STREAM:
 268                 fprintf_msg("Usage: %s sess-create-write-stream "
 269                     "-s <sess_id> -d <dst dataset> [-c <common snapshot>] "
 270                     "[-F] [-k] [-l | -x] [-i <prop_name>] "
 271                     "[-o <prop_name=value>] [-t <resume_token>] "
 272                     "[-n <keep snaps>]\n", tool_name);
 273                 break;
 274         case KRRP_CMD_SESS_CREATE_PDU_ENGINE:
 275                 fprintf_msg("Usage: %s sess-create-pdu-engine "
 276                     "-s <sess_id> -b <data block size> [-a] "
 277                     "-m <max memory in MB>\n", tool_name);
 278                 break;
 279         default:
 280                 assert(0);
 281         }
 282 
 283         fprintf_msg("\n\n");
 284 
 285         if (use_return)
 286                 return;
 287 
 288         exit(rc);
 289 }
 290 
 291 static int
 292 krrp_lookup_cmd(const char *cmd_name, krrp_cmd_t **cmd)
 293 {
 294         size_t i;
 295         int rc = -1;
 296 
 297         for (i = 0; i < cmds_sz; i++) {
 298                 if (strcmp(cmds[i].name, cmd_name) == 0) {
 299                         *cmd = &cmds[i];
 300                         rc = 0;
 301                         break;
 302                 }
 303         }
 304 
 305         return (rc);
 306 }
 307 
 308 /* ARGSUSED */
 309 static int
 310 krrp_do_read_event(int argc, char **argv, krrp_cmd_t *cmd)
 311 {
 312         int rc;
 313         libkrrp_evc_handle_t *libkrrp_evc_hdl = NULL;
 314 
 315 
 316         rc = libkrrp_evc_subscribe(&libkrrp_evc_hdl, krrp_sysevent_cb, NULL);
 317         if (rc != 0) {
 318                 fprintf_err("Failed to subscribe to KRRP events\n");
 319                 exit(1);
 320         }
 321 
 322         for (;;)
 323                 (void) sleep(1);
 324 
 325         /* NOTREACHED */
 326         return (0);
 327 }
 328 
 329 /* ARGSUSED */
 330 static int
 331 krrp_sysevent_cb(libkrrp_event_t *ev, void *cookie)
 332 {
 333         libkrrp_ev_type_t ev_type;
 334         libkrrp_ev_data_t *ev_data;
 335         char sess_id_str[UUID_PRINTABLE_STRING_LENGTH];
 336         libkrrp_error_descr_t err_desc;
 337 
 338         ev_type = libkrrp_ev_type(ev);
 339         ev_data = libkrrp_ev_data(ev);
 340 
 341         switch (ev_type) {
 342         case LIBKRRP_EV_TYPE_SESS_SEND_DONE:
 343                 uuid_unparse(ev_data->sess_send_done.sess_id, sess_id_str);
 344                 fprintf_msg("Session '%s' has done send\n", sess_id_str);
 345                 break;
 346         case LIBKRRP_EV_TYPE_SESS_ERROR:
 347                 uuid_unparse(ev_data->sess_error.sess_id, sess_id_str);
 348                 libkrrp_ev_data_error_description(ev_type,
 349                     &ev_data->sess_error.libkrrp_error, err_desc);
 350                 fprintf_msg("Session '%s' has interrupted by error:\n"
 351                     "    %s\n", sess_id_str, err_desc);
 352                 break;
 353         case LIBKRRP_EV_TYPE_SERVER_ERROR:
 354                 libkrrp_ev_data_error_description(ev_type,
 355                     &ev_data->sess_error.libkrrp_error, err_desc);
 356                 fprintf_msg("An error occured in kernel-server:\n"
 357                     "    %s\n", err_desc);
 358                 break;
 359         default:
 360                 fprintf_err("Unknow event type\n");
 361                 assert(0);
 362         }
 363 
 364         return (0);
 365 }
 366 
 367 static int
 368 krrp_do_sess_create(int argc, char **argv, krrp_cmd_t *cmd)
 369 {
 370         int c, rc = 0;
 371         uuid_t sess_id;
 372         boolean_t sender = B_FALSE, compound = B_FALSE,
 373             fake_mode = B_FALSE;
 374         char *auth_digest = NULL, *kstat_id = NULL;
 375 
 376         assert(cmd->item == KRRP_CMD_SESS_CREATE);
 377 
 378         uuid_clear(sess_id);
 379 
 380         while ((c = getopt(argc, argv, "hs:zfck:a:")) != -1) {
 381                 switch (c) {
 382                 case 's':
 383                         if (krrp_parse_and_check_sess_id(optarg, sess_id) != 0)
 384                                 exit(1);
 385 
 386                         break;
 387                 case 'a':
 388                         if (auth_digest != NULL) {
 389                                 krrp_print_err_already_defined("a");
 390                                 exit(1);
 391                         }
 392 
 393                         auth_digest = optarg;
 394                         break;
 395                 case 'k':
 396                         if (kstat_id != NULL) {
 397                                 krrp_print_err_already_defined("k");
 398                                 exit(1);
 399                         }
 400 
 401                         kstat_id = optarg;
 402                         break;
 403                 case 'z':
 404                         if (sender) {
 405                                 krrp_print_err_already_defined("z");
 406                                 exit(1);
 407                         }
 408 
 409                         sender = B_TRUE;
 410                         break;
 411                 case 'f':
 412                         if (fake_mode) {
 413                                 krrp_print_err_already_defined("f");
 414                                 exit(1);
 415                         }
 416 
 417                         fake_mode = B_TRUE;
 418                         break;
 419                 case 'c':
 420                         if (compound) {
 421                                 krrp_print_err_already_defined("c");
 422                                 exit(1);
 423                         }
 424 
 425                         compound = B_TRUE;
 426                         break;
 427                 case '?':
 428                         krrp_print_err_unknown_param(argv[optind - 1]);
 429                         cmd->usage_func(1, cmd, B_FALSE);
 430                         break;
 431                 case 'h':
 432                         cmd->usage_func(0, cmd, B_FALSE);
 433                         break;
 434                 }
 435         }
 436 
 437         if (uuid_is_null(sess_id) == 1) {
 438                 krrp_print_err_no_sess_id();
 439                 cmd->usage_func(1, cmd, B_FALSE);
 440         }
 441 
 442         if (kstat_id == NULL) {
 443                 fprintf_err("Session Kstat ID is not defined\n");
 444                 cmd->usage_func(1, cmd, B_FALSE);
 445         }
 446 
 447         if (sender && compound) {
 448                 fprintf_err("'c' and 'z' parameters cannot "
 449                     "be used together\n");
 450                 exit(1);
 451         }
 452 
 453         if (compound) {
 454                 rc = krrp_sess_create_compound(libkrrp_hdl, sess_id,
 455                     kstat_id, fake_mode);
 456         } else if (sender) {
 457                 rc = krrp_sess_create_sender(libkrrp_hdl, sess_id,
 458                     kstat_id, auth_digest, fake_mode);
 459         } else {
 460                 rc = krrp_sess_create_receiver(libkrrp_hdl, sess_id,
 461                     kstat_id, auth_digest, fake_mode);
 462         }
 463 
 464         if (rc != 0) {
 465                 fprintf_err("Failed to create session\n");
 466                 krrp_print_libkrrp_error();
 467                 exit(1);
 468         }
 469 
 470         return (0);
 471 }
 472 
 473 static int
 474 krrp_do_sess_action(int argc, char **argv, krrp_cmd_t *cmd)
 475 {
 476         int c, rc = 0;
 477         uuid_t sess_id;
 478         uint32_t limit = UINT32_MAX;
 479         boolean_t run_once = B_FALSE;
 480         const char *opts = "hs:";
 481 
 482         uuid_clear(sess_id);
 483 
 484         switch (cmd->item) {
 485         case KRRP_CMD_SESS_RUN:
 486                 opts = "hs:o";
 487                 break;
 488         case KRRP_CMD_SESS_CONN_THROTTLE:
 489                 opts = "hs:l:";
 490                 break;
 491         case KRRP_CMD_SESS_SEND_STOP:
 492                 break;
 493         case KRRP_CMD_SESS_DESTROY:
 494                 break;
 495         default:
 496                 fprintf_err("Unknown cmd_item: [%d]\n", cmd->item);
 497                 assert(0);
 498         }
 499 
 500         while ((c = getopt(argc, argv, opts)) != -1) {
 501                 switch (c) {
 502                 case 's':
 503                         if (krrp_parse_and_check_sess_id(optarg, sess_id) != 0)
 504                                 exit(1);
 505 
 506                         break;
 507                 case 'l':
 508                         if (limit != UINT32_MAX) {
 509                                 krrp_print_err_already_defined("l");
 510                                 exit(1);
 511                         }
 512 
 513                         limit = strtoul(optarg, NULL, 0);
 514                         if (limit < KRRP_MIN_CONN_THROTTLE && limit != 0) {
 515                                 fprintf_err("Limit must be 0 or > %d\n",
 516                                     KRRP_MIN_CONN_THROTTLE);
 517                                 exit(1);
 518                         }
 519 
 520                         break;
 521                 case 'o':
 522                         if (run_once) {
 523                                 krrp_print_err_already_defined("o");
 524                                 exit(1);
 525                         }
 526 
 527                         run_once = B_TRUE;
 528                         break;
 529                 case '?':
 530                         krrp_print_err_unknown_param(argv[optind - 1]);
 531                         cmd->usage_func(1, cmd, B_FALSE);
 532                         break;
 533                 case 'h':
 534                         cmd->usage_func(0, cmd, B_FALSE);
 535                         break;
 536                 }
 537         }
 538 
 539         if (uuid_is_null(sess_id) == 1) {
 540                 krrp_print_err_no_sess_id();
 541                 cmd->usage_func(1, cmd, B_FALSE);
 542         }
 543 
 544         switch (cmd->item) {
 545         case KRRP_CMD_SESS_RUN:
 546                 rc = krrp_sess_run(libkrrp_hdl, sess_id, run_once);
 547                 if (rc != 0)
 548                         fprintf_err("Failed to run session\n");
 549 
 550                 break;
 551         case KRRP_CMD_SESS_CONN_THROTTLE:
 552                 if (limit == UINT32_MAX) {
 553                         fprintf_err("The throughput limit is not defined\n");
 554                         cmd->usage_func(1, cmd, B_FALSE);
 555                 }
 556 
 557                 rc = krrp_sess_conn_throttle(libkrrp_hdl, sess_id, limit);
 558                 if (rc != 0) {
 559                         fprintf_err("Failed to throttle "
 560                             "session's connection\n");
 561                 }
 562 
 563                 break;
 564         case KRRP_CMD_SESS_SEND_STOP:
 565                 rc = krrp_sess_send_stop(libkrrp_hdl, sess_id);
 566                 if (rc != 0)
 567                         fprintf_err("Failed to stop sending\n");
 568 
 569                 break;
 570         case KRRP_CMD_SESS_DESTROY:
 571                 rc = krrp_sess_destroy(libkrrp_hdl, sess_id);
 572                 if (rc != 0)
 573                         fprintf_err("Failed to destroy session\n");
 574 
 575                 break;
 576         default:
 577                 break;
 578         }
 579 
 580         if (rc != 0) {
 581                 krrp_print_libkrrp_error();
 582                 exit(1);
 583         }
 584 
 585         return (0);
 586 }
 587 
 588 static int
 589 krrp_do_sess_get_conn_info(int argc, char **argv, krrp_cmd_t *cmd)
 590 {
 591         int c, rc = 0;
 592         uuid_t sess_id;
 593         libkrrp_sess_conn_info_t sess_conn_info;
 594         char *sess_id_str = NULL;
 595 
 596         assert(cmd->item == KRRP_CMD_SESS_GET_CONN_INFO);
 597 
 598         uuid_clear(sess_id);
 599 
 600         while ((c = getopt(argc, argv, "hs:")) != -1) {
 601                 switch (c) {
 602                 case 's':
 603                         if (krrp_parse_and_check_sess_id(optarg, sess_id) != 0)
 604                                 exit(1);
 605 
 606                         sess_id_str = optarg;
 607                         break;
 608                 case '?':
 609                         krrp_print_err_unknown_param(argv[optind - 1]);
 610                         cmd->usage_func(1, cmd, B_FALSE);
 611                         break;
 612                 case 'h':
 613                         cmd->usage_func(0, cmd, B_FALSE);
 614                         break;
 615                 }
 616         }
 617 
 618         if (uuid_is_null(sess_id) == 1) {
 619                 krrp_print_err_no_sess_id();
 620                 cmd->usage_func(1, cmd, B_FALSE);
 621         }
 622 
 623         rc = krrp_sess_get_conn_info(libkrrp_hdl, sess_id, &sess_conn_info);
 624         if (rc != 0) {
 625                 fprintf_err("Failed to get information about connection\n");
 626                 krrp_print_libkrrp_error();
 627                 exit(1);
 628         }
 629 
 630         fprintf_msg("Session: [%s]\n"
 631             "    block size: %u\n",
 632             sess_id_str,
 633             sess_conn_info.blk_sz);
 634 
 635         fprintf_msg("\n");
 636 
 637         return (0);
 638 }
 639 
 640 static int
 641 krrp_do_sess_status(int argc, char **argv, krrp_cmd_t *cmd)
 642 {
 643         int c, rc = 0;
 644         uuid_t sess_id;
 645         libkrrp_sess_status_t sess_status;
 646         libkrrp_error_descr_t err_desc;
 647         char *sess_id_str = NULL;
 648 
 649         assert(cmd->item == KRRP_CMD_SESS_STATUS);
 650 
 651         uuid_clear(sess_id);
 652 
 653         while ((c = getopt(argc, argv, "hs:")) != -1) {
 654                 switch (c) {
 655                 case 's':
 656                         if (krrp_parse_and_check_sess_id(optarg, sess_id) != 0)
 657                                 exit(1);
 658 
 659                         sess_id_str = optarg;
 660                         break;
 661                 case '?':
 662                         krrp_print_err_unknown_param(argv[optind - 1]);
 663                         cmd->usage_func(1, cmd, B_FALSE);
 664                         break;
 665                 case 'h':
 666                         cmd->usage_func(0, cmd, B_FALSE);
 667                         break;
 668                 }
 669         }
 670 
 671         if (uuid_is_null(sess_id) == 1) {
 672                 krrp_print_err_no_sess_id();
 673                 cmd->usage_func(1, cmd, B_FALSE);
 674         }
 675 
 676         rc = krrp_sess_status(libkrrp_hdl, sess_id, &sess_status);
 677         if (rc != 0) {
 678                 fprintf_err("Failed to get session status\n");
 679                 krrp_print_libkrrp_error();
 680                 exit(1);
 681         }
 682 
 683         fprintf_msg("Session: [%s]\n"
 684             "    kstat ID: %s\n"
 685             "    type: %s\n"
 686             "    started: %s\n"
 687             "    running: %s\n",
 688             sess_id_str,
 689             sess_status.sess_kstat_id,
 690             sess_status.sess_type == LIBKRRP_SESS_TYPE_SENDER ? "sender" :
 691             sess_status.sess_type == LIBKRRP_SESS_TYPE_RECEIVER ? "receiver" :
 692             "compound",
 693             sess_status.sess_started ? "YES" : "NO",
 694             sess_status.sess_running ? "YES" : "NO",
 695             err_desc);
 696 
 697         if (sess_status.libkrrp_error.libkrrp_errno != LIBKRRP_ERRNO_OK) {
 698                 libkrrp_sess_error_description(&sess_status.libkrrp_error,
 699                     err_desc);
 700 
 701                 fprintf_msg("    error: %s\n", err_desc);
 702         }
 703 
 704         fprintf_msg("\n");
 705 
 706         return (0);
 707 }
 708 
 709 static int
 710 krrp_do_sess_list(int argc, char **argv, krrp_cmd_t *cmd)
 711 {
 712         int c, rc = 0;
 713         libkrrp_sess_list_t *sess_list = NULL, *sess_list_head = NULL;
 714 
 715         while ((c = getopt(argc, argv, "h")) != -1) {
 716                 switch (c) {
 717                 case '?':
 718                         krrp_print_err_unknown_param(argv[optind - 1]);
 719                         cmd->usage_func(1, cmd, B_FALSE);
 720                         break;
 721                 case 'h':
 722                         cmd->usage_func(0, cmd, B_FALSE);
 723                         break;
 724                 }
 725         }
 726 
 727         rc = krrp_sess_list(libkrrp_hdl, &sess_list_head);
 728         if (rc != 0) {
 729                 fprintf_err("Failed to get list of sessions\n");
 730                 krrp_print_libkrrp_error();
 731                 exit(1);
 732         }
 733 
 734         sess_list = sess_list_head;
 735         while (sess_list != NULL) {
 736                 char sess_id_str[UUID_PRINTABLE_STRING_LENGTH];
 737 
 738                 uuid_unparse(sess_list->sess_id, sess_id_str);
 739 
 740                 fprintf_msg("Session: [%s]\n"
 741                     "    kstat ID: %s\n"
 742                     "    started: %s\n"
 743                     "    running: %s\n\n",
 744                     sess_id_str,
 745                     sess_list->sess_kstat_id,
 746                     sess_list->sess_started ? "YES" : "NO",
 747                     sess_list->sess_running ? "YES" : "NO");
 748 
 749                 sess_list = sess_list->sl_next;
 750         }
 751 
 752         krrp_sess_list_free(sess_list_head);
 753         return (0);
 754 }
 755 
 756 static int
 757 krrp_do_sess_create_conn(int argc, char **argv, krrp_cmd_t *cmd)
 758 {
 759         int c, i, rc = 0;
 760         uuid_t sess_id;
 761         const char *remote_addr = NULL;
 762         uint16_t remote_port = 0;
 763         uint32_t timeout = 0;
 764 
 765         uuid_clear(sess_id);
 766 
 767         while ((c = getopt(argc, argv, "hs:a:p:t:")) != -1) {
 768                 switch (c) {
 769                 case 's':
 770                         if (krrp_parse_and_check_sess_id(optarg, sess_id) != 0)
 771                                 exit(1);
 772 
 773                         break;
 774                 case 'a':
 775                         if (remote_addr != NULL) {
 776                                 krrp_print_err_already_defined("a");
 777                                 exit(1);
 778                         }
 779 
 780                         remote_addr = optarg;
 781                         break;
 782                 case 'p':
 783                         if (remote_port != 0) {
 784                                 krrp_print_err_already_defined("p");
 785                                 exit(1);
 786                         }
 787 
 788                         i = strtol(optarg, NULL, 0);
 789                         if (i < KRRP_MIN_PORT || i > KRRP_MAX_PORT) {
 790                                 fprintf_err("Port number must be an "
 791                                     "integer in range from %d to %d\n",
 792                                     KRRP_MIN_PORT, KRRP_MAX_PORT);
 793                                 exit(1);
 794                         }
 795 
 796                         remote_port = i;
 797                         break;
 798                 case 't':
 799                         if (timeout != 0) {
 800                                 krrp_print_err_already_defined("t");
 801                                 exit(1);
 802                         }
 803 
 804                         i = strtol(optarg, NULL, 0);
 805                         if (i < KRRP_MIN_CONN_TIMEOUT ||
 806                             i > KRRP_MAX_CONN_TIMEOUT) {
 807                                 fprintf_err("Connection timeout "
 808                                     "must be an integer in range from "
 809                                     "%d to %d\n", KRRP_MIN_CONN_TIMEOUT,
 810                                     KRRP_MAX_CONN_TIMEOUT);
 811                                 exit(1);
 812                         }
 813 
 814                         timeout = i;
 815                         break;
 816                 case '?':
 817                         krrp_print_err_unknown_param(argv[optind - 1]);
 818                         cmd->usage_func(1, cmd, B_FALSE);
 819                         break;
 820                 case 'h':
 821                         cmd->usage_func(0, cmd, B_FALSE);
 822                         break;
 823                 }
 824         }
 825 
 826         if (uuid_is_null(sess_id) == 1) {
 827                 krrp_print_err_no_sess_id();
 828                 cmd->usage_func(1, cmd, B_FALSE);
 829         }
 830 
 831         if (remote_addr == NULL) {
 832                 fprintf_err("Remote host is not defined\n");
 833                 cmd->usage_func(1, cmd, B_FALSE);
 834         }
 835 
 836         if (remote_port == 0) {
 837                 fprintf_err("Remote port is not defined\n");
 838                 cmd->usage_func(1, cmd, B_FALSE);
 839         }
 840 
 841         rc = krrp_sess_create_conn(libkrrp_hdl, sess_id,
 842             remote_addr, remote_port, timeout);
 843         if (rc != 0) {
 844                 fprintf_err("Failed to create connection\n");
 845                 krrp_print_libkrrp_error();
 846                 exit(1);
 847         }
 848 
 849         return (0);
 850 }
 851 
 852 static int
 853 krrp_do_sess_create_read_stream(int argc, char **argv, krrp_cmd_t *cmd)
 854 {
 855         int c, i, rc = 0;
 856         uuid_t sess_id;
 857         uint64_t fake_data_sz = 0;
 858         char *dataset = NULL, *common_snap = NULL, *src_snap = NULL,
 859             *resume_token = NULL, *skip_snaps_mask = NULL;
 860         krrp_sess_stream_flags_t flags = 0;
 861         uint32_t keep_snaps = 0;
 862 
 863         uuid_clear(sess_id);
 864 
 865         while ((c = getopt(argc, argv, "hs:d:c:z:Irpejbkf:t:n:m:")) != -1) {
 866                 switch (c) {
 867                 case 's':
 868                         if (krrp_parse_and_check_sess_id(optarg, sess_id) != 0)
 869                                 exit(1);
 870 
 871                         break;
 872                 case 'd':
 873                         if (dataset != NULL) {
 874                                 krrp_print_err_already_defined("d");
 875                                 exit(1);
 876                         }
 877 
 878                         dataset = optarg;
 879                         break;
 880                 case 'z':
 881                         if (src_snap != NULL) {
 882                                 krrp_print_err_already_defined("z");
 883                                 exit(1);
 884                         }
 885 
 886                         src_snap = optarg;
 887                         break;
 888                 case 'c':
 889                         if (common_snap != NULL) {
 890                                 krrp_print_err_already_defined("c");
 891                                 exit(1);
 892                         }
 893 
 894                         common_snap = optarg;
 895                         break;
 896                 case 'I':
 897                         if ((flags & KRRP_STREAM_INCLUDE_ALL_SNAPS) != 0) {
 898                                 krrp_print_err_already_defined("I");
 899                                 exit(1);
 900                         }
 901 
 902                         flags |= KRRP_STREAM_INCLUDE_ALL_SNAPS;
 903                         break;
 904                 case 'r':
 905                         if ((flags & KRRP_STREAM_SEND_RECURSIVE) != 0) {
 906                                 krrp_print_err_already_defined("r");
 907                                 exit(1);
 908                         }
 909 
 910                         flags |= KRRP_STREAM_SEND_RECURSIVE;
 911                         break;
 912                 case 'p':
 913                         if ((flags & KRRP_STREAM_SEND_PROPERTIES) != 0) {
 914                                 krrp_print_err_already_defined("p");
 915                                 exit(1);
 916                         }
 917 
 918                         flags |= KRRP_STREAM_SEND_PROPERTIES;
 919                         break;
 920                 case 'e':
 921                         if ((flags & KRRP_STREAM_ZFS_EMBEDDED) != 0) {
 922                                 krrp_print_err_already_defined("e");
 923                                 exit(1);
 924                         }
 925 
 926                         flags |= KRRP_STREAM_ZFS_EMBEDDED;
 927                         break;
 928                 case 'j':
 929                         if ((flags & KRRP_STREAM_ZFS_COMPRESSED) != 0) {
 930                                 krrp_print_err_already_defined("j");
 931                                 exit(1);
 932                         }
 933 
 934                         flags |= KRRP_STREAM_ZFS_COMPRESSED;
 935                         break;
 936                 case 'b':
 937                         if ((flags & KRRP_STREAM_ZFS_LARGE_BLOCKS) != 0) {
 938                                 krrp_print_err_already_defined("b");
 939                                 exit(1);
 940                         }
 941 
 942                         flags |= KRRP_STREAM_ZFS_LARGE_BLOCKS;
 943                         break;
 944                 case 'k':
 945                         if ((flags & KRRP_STREAM_ZFS_CHKSUM) != 0) {
 946                                 krrp_print_err_already_defined("k");
 947                                 exit(1);
 948                         }
 949 
 950                         flags |= KRRP_STREAM_ZFS_CHKSUM;
 951                         break;
 952                 case 'f':
 953                         if (fake_data_sz != 0) {
 954                                 krrp_print_err_already_defined("f");
 955                                 exit(1);
 956                         }
 957 
 958                         fake_data_sz = strtoull(optarg, NULL, 0);
 959                         if (fake_data_sz == 0) {
 960                                 fprintf_err("Fake data size must >0\n");
 961                                 exit(1);
 962                         }
 963 
 964                         break;
 965                 case 't':
 966                         if (resume_token != NULL) {
 967                                 krrp_print_err_already_defined("t");
 968                                 exit(1);
 969                         }
 970 
 971                         resume_token = optarg;
 972                         break;
 973                 case 'n':
 974                         if (keep_snaps != 0) {
 975                                 krrp_print_err_already_defined("n");
 976                                 exit(1);
 977                         }
 978 
 979                         i = strtol(optarg, NULL, 0);
 980                         if (i < KRRP_MIN_KEEP_SNAPS ||
 981                             i > KRRP_MAX_KEEP_SNAPS) {
 982                                 fprintf_err("Maximum number of snapshots that "
 983                                     "will be kept must be an integer in range "
 984                                     "from %d to %d\n", KRRP_MIN_KEEP_SNAPS,
 985                                     KRRP_MAX_KEEP_SNAPS);
 986                                 exit(1);
 987                         }
 988 
 989                         keep_snaps = i;
 990                         break;
 991                 case 'm':
 992                         if (skip_snaps_mask != NULL) {
 993                                 krrp_print_err_already_defined("m");
 994                                 exit(1);
 995                         }
 996 
 997                         skip_snaps_mask = optarg;
 998                         break;
 999                 case '?':
1000                         krrp_print_err_unknown_param(argv[optind - 1]);
1001                         cmd->usage_func(1, cmd, B_FALSE);
1002                         break;
1003                 case 'h':
1004                         cmd->usage_func(0, cmd, B_FALSE);
1005                         break;
1006                 }
1007         }
1008 
1009         if (uuid_is_null(sess_id) == 1) {
1010                 krrp_print_err_no_sess_id();
1011                 cmd->usage_func(1, cmd, B_FALSE);
1012         }
1013 
1014         if (dataset == NULL) {
1015                 fprintf_err("Source dataset must be specified\n");
1016                 cmd->usage_func(1, cmd, B_FALSE);
1017         }
1018 
1019         if (keep_snaps == 0)
1020                 keep_snaps = UINT32_MAX;
1021 
1022         rc = krrp_sess_create_read_stream(libkrrp_hdl, sess_id,
1023             dataset, common_snap, src_snap, fake_data_sz, flags,
1024             resume_token, keep_snaps, skip_snaps_mask);
1025         if (rc != 0) {
1026                 fprintf_err("Failed to create read-stream\n");
1027                 krrp_print_libkrrp_error();
1028                 exit(1);
1029         }
1030 
1031         return (0);
1032 }
1033 
1034 static int
1035 krrp_do_sess_create_write_stream(int argc, char **argv, krrp_cmd_t *cmd)
1036 {
1037         int c, i, rc = 0;
1038         uuid_t sess_id;
1039         nvlist_t *ignore_props_list, *replace_props_list;
1040         char *dataset = NULL, *common_snap = NULL, *resume_token = NULL;
1041         krrp_sess_stream_flags_t flags = 0;
1042         uint32_t keep_snaps = 0;
1043 
1044         ignore_props_list = fnvlist_alloc();
1045         replace_props_list = fnvlist_alloc();
1046 
1047         uuid_clear(sess_id);
1048 
1049         while ((c = getopt(argc, argv, "hs:d:c:Fki:o:t:n:lx")) != -1) {
1050                 switch (c) {
1051                 case 's':
1052                         if (krrp_parse_and_check_sess_id(optarg, sess_id) != 0)
1053                                 exit(1);
1054 
1055                         break;
1056                 case 'd':
1057                         if (dataset != NULL) {
1058                                 krrp_print_err_already_defined("d");
1059                                 exit(1);
1060                         }
1061 
1062                         dataset = optarg;
1063                         break;
1064                 case 'c':
1065                         if (common_snap != NULL) {
1066                                 krrp_print_err_already_defined("c");
1067                                 exit(1);
1068                         }
1069 
1070                         common_snap = optarg;
1071                         break;
1072                 case 'i':
1073                         if (nvlist_exists(ignore_props_list, optarg)) {
1074                                 (void) fprintf(stderr, "The property '%s' "
1075                                     "already defined\n", optarg);
1076                                 exit(1);
1077                         }
1078 
1079                         fnvlist_add_boolean_value(ignore_props_list,
1080                             optarg, B_TRUE);
1081                         break;
1082                 case 'o':
1083                         {
1084                                 char *p;
1085 
1086                                 p = strchr(optarg, '=');
1087                                 if (p == NULL || *(p + 1) == '\0') {
1088                                         (void) fprintf(stderr, "Incorrect "
1089                                             "argument of '-o' parameter\n");
1090                                         exit(1);
1091                                 }
1092 
1093                                 *p = '\0'; p++;
1094 
1095                                 if (nvlist_exists(replace_props_list, optarg)) {
1096                                         (void) fprintf(stderr, "The property "
1097                                             "'%s' already defined\n", optarg);
1098                                         exit(1);
1099                                 }
1100 
1101                                 fnvlist_add_string(replace_props_list,
1102                                     optarg, p);
1103                                 p--; *p = '=';
1104                         }
1105                         break;
1106                 case 'F':
1107                         if ((flags & KRRP_STREAM_FORCE_RECEIVE) != 0) {
1108                                 krrp_print_err_already_defined("F");
1109                                 exit(1);
1110                         }
1111 
1112                         flags |= KRRP_STREAM_FORCE_RECEIVE;
1113                         break;
1114                 case 'k':
1115                         if ((flags & KRRP_STREAM_ZFS_CHKSUM) != 0) {
1116                                 krrp_print_err_already_defined("k");
1117                                 exit(1);
1118                         }
1119 
1120                         flags |= KRRP_STREAM_ZFS_CHKSUM;
1121                         break;
1122                 case 't':
1123                         if (resume_token != NULL) {
1124                                 krrp_print_err_already_defined("t");
1125                                 exit(1);
1126                         }
1127 
1128                         resume_token = optarg;
1129                         break;
1130                 case 'n':
1131                         if (keep_snaps != 0) {
1132                                 krrp_print_err_already_defined("n");
1133                                 exit(1);
1134                         }
1135 
1136                         i = strtol(optarg, NULL, 0);
1137                         if (i < KRRP_MIN_KEEP_SNAPS ||
1138                             i > KRRP_MAX_KEEP_SNAPS) {
1139                                 fprintf_err("Maximum number of snapshots that "
1140                                     "will be kept must be an integer in range "
1141                                     "from %d to %d\n", KRRP_MIN_KEEP_SNAPS,
1142                                     KRRP_MAX_KEEP_SNAPS);
1143                                 exit(1);
1144                         }
1145 
1146                         keep_snaps = i;
1147                         break;
1148                 case 'l':
1149                         if ((flags & KRRP_STREAM_LEAVE_TAIL) != 0) {
1150                                 krrp_print_err_already_defined("l");
1151                                 exit(1);
1152                         }
1153 
1154                         flags |= KRRP_STREAM_LEAVE_TAIL;
1155                         break;
1156                 case 'x':
1157                         if ((flags & KRRP_STREAM_DISCARD_HEAD) != 0) {
1158                                 krrp_print_err_already_defined("x");
1159                                 exit(1);
1160                         }
1161 
1162                         flags |= KRRP_STREAM_DISCARD_HEAD;
1163                         break;
1164                 case '?':
1165                         krrp_print_err_unknown_param(argv[optind - 1]);
1166                         cmd->usage_func(1, cmd, B_FALSE);
1167                         break;
1168                 case 'h':
1169                         cmd->usage_func(0, cmd, B_FALSE);
1170                         break;
1171                 }
1172         }
1173 
1174         if (((flags & KRRP_STREAM_DISCARD_HEAD) != 0) &&
1175             ((flags & KRRP_STREAM_LEAVE_TAIL) != 0)) {
1176                 fprintf_err("Parameters 'x' and 'l' cannot "
1177                     "be used together\n");
1178                 exit(1);
1179         }
1180 
1181 
1182         if (uuid_is_null(sess_id) == 1) {
1183                 krrp_print_err_no_sess_id();
1184                 cmd->usage_func(1, cmd, B_FALSE);
1185         }
1186 
1187         if (dataset == NULL) {
1188                 fprintf_err("Destination dataset must be specified\n");
1189                 cmd->usage_func(1, cmd, B_FALSE);
1190         }
1191 
1192         if (nvlist_empty(ignore_props_list)) {
1193                 fnvlist_free(ignore_props_list);
1194                 ignore_props_list = NULL;
1195         }
1196 
1197         if (nvlist_empty(replace_props_list)) {
1198                 fnvlist_free(replace_props_list);
1199                 replace_props_list = NULL;
1200         }
1201 
1202         if (keep_snaps == 0)
1203                 keep_snaps = UINT32_MAX;
1204 
1205         rc = krrp_sess_create_write_stream(libkrrp_hdl, sess_id,
1206             dataset, common_snap, flags, ignore_props_list,
1207             replace_props_list, resume_token, keep_snaps);
1208         if (rc != 0) {
1209                 fprintf_err("Failed to create write stream\n");
1210                 krrp_print_libkrrp_error();
1211                 exit(1);
1212         }
1213 
1214         return (0);
1215 }
1216 
1217 static int
1218 krrp_do_sess_create_pdu_engine(int argc, char **argv, krrp_cmd_t *cmd)
1219 {
1220         int c, i, rc = 0;
1221         uuid_t sess_id;
1222         int mem_limit = 0, dblk_sz = 0;
1223         boolean_t use_prealloc = B_FALSE;
1224 
1225         uuid_clear(sess_id);
1226 
1227         while ((c = getopt(argc, argv, "hs:m:b:a")) != -1) {
1228                 switch (c) {
1229                 case 's':
1230                         if (krrp_parse_and_check_sess_id(optarg, sess_id) != 0)
1231                                 exit(1);
1232 
1233                         break;
1234                 case 'm':
1235                         if (mem_limit != 0) {
1236                                 krrp_print_err_already_defined("m");
1237                                 exit(1);
1238                         }
1239 
1240                         i = strtol(optarg, NULL, 0);
1241                         if (i < KRRP_MIN_MAXMEM || i > 16384) {
1242                                 fprintf_err("Maximum memory size "
1243                                     "must be an integer in range from "
1244                                     "%d to 16384\n", KRRP_MIN_MAXMEM);
1245                                 exit(1);
1246                         }
1247 
1248                         mem_limit = i;
1249                         break;
1250                 case 'b':
1251                         if (dblk_sz != 0) {
1252                                 krrp_print_err_already_defined("b");
1253                                 exit(1);
1254                         }
1255 
1256                         i = strtol(optarg, NULL, 0);
1257                         if (i < KRRP_MIN_SESS_PDU_DBLK_DATA_SZ ||
1258                             i > KRRP_MAX_SESS_PDU_DBLK_DATA_SZ) {
1259                                 fprintf_err("DBLK data size must "
1260                                     "be an integer in range from "
1261                                     "%d to %d\n",
1262                                     KRRP_MIN_SESS_PDU_DBLK_DATA_SZ,
1263                                     KRRP_MAX_SESS_PDU_DBLK_DATA_SZ);
1264                                 exit(1);
1265                         }
1266 
1267                         dblk_sz = i;
1268                         break;
1269                 case 'a':
1270                         if (use_prealloc) {
1271                                 krrp_print_err_already_defined("a");
1272                                 exit(1);
1273                         }
1274 
1275                         use_prealloc = B_TRUE;
1276                         break;
1277                 case '?':
1278                         krrp_print_err_unknown_param(argv[optind - 1]);
1279                         cmd->usage_func(1, cmd, B_FALSE);
1280                         break;
1281                 case 'h':
1282                         cmd->usage_func(0, cmd, B_FALSE);
1283                         break;
1284                 }
1285         }
1286 
1287         if (uuid_is_null(sess_id) == 1) {
1288                 krrp_print_err_no_sess_id();
1289                 cmd->usage_func(1, cmd, B_FALSE);
1290         }
1291 
1292         if (dblk_sz == 0) {
1293                 fprintf_err("DBLK Data size is not defined\n");
1294                 cmd->usage_func(1, cmd, B_FALSE);
1295         }
1296 
1297         if (mem_limit == 0) {
1298                 fprintf_err("Maximum memory is not defined\n");
1299                 cmd->usage_func(1, cmd, B_FALSE);
1300         }
1301 
1302         rc = krrp_sess_create_pdu_engine(libkrrp_hdl, sess_id,
1303             mem_limit, dblk_sz, use_prealloc);
1304         if (rc != 0) {
1305                 fprintf_err("Failed to create pdu engine\n");
1306                 krrp_print_libkrrp_error();
1307                 exit(1);
1308         }
1309 
1310         return (0);
1311 }
1312 
1313 static int
1314 krrp_do_ksvc_action(int argc, char **argv, krrp_cmd_t *cmd)
1315 {
1316         int rc = 0;
1317         const char *action;
1318 
1319         assert(cmd->item == KRRP_CMD_KSVC_ENABLE ||
1320             cmd->item == KRRP_CMD_KSVC_DISABLE);
1321 
1322         if (argc > 1) {
1323                 if (strcmp(argv[1], "-h") == 0) {
1324                         cmd->usage_func(0, cmd, B_FALSE);
1325                 } else {
1326                         fprintf_err("Unknown params\n");
1327                         cmd->usage_func(1, cmd, B_FALSE);
1328                 }
1329         }
1330 
1331         if (cmd->item == KRRP_CMD_KSVC_ENABLE) {
1332                 rc = krrp_svc_enable(libkrrp_hdl);
1333                 action = "enable";
1334         } else {
1335                 rc = krrp_svc_disable(libkrrp_hdl);
1336                 action = "disable";
1337         }
1338 
1339         if (rc != 0) {
1340                 fprintf_err("Failed to %s in kernel service\n", action);
1341                 krrp_print_libkrrp_error();
1342                 exit(1);
1343         }
1344 
1345         return (0);
1346 }
1347 
1348 /* ARGSUSED */
1349 static int
1350 krrp_do_svc_get_state(int argc, char **argv, krrp_cmd_t *cmd)
1351 {
1352         int rc;
1353         libkrrp_svc_state_t svc_state;
1354 
1355         assert(cmd->item == KRRP_CMD_KSVC_STATE);
1356 
1357         rc = krrp_svc_state(libkrrp_hdl, &svc_state);
1358         if (rc != 0) {
1359                 fprintf_err("Failed to get state of in-kernel service\n");
1360                 krrp_print_libkrrp_error();
1361                 exit(1);
1362         }
1363 
1364         fprintf_msg("KSVC-ENABLED: %s, KSRV-RUNNING: %s\n",
1365             (svc_state.enabled ? "YES" : "NO"),
1366             (svc_state.running ? "YES" : "NO"));
1367 
1368         return (0);
1369 }
1370 
1371 static int
1372 krrp_do_ksvc_configure(int argc, char **argv, krrp_cmd_t *cmd)
1373 {
1374         int c, rc, port = -1;
1375         const char *addr = NULL;
1376 
1377         assert(cmd->item == KRRP_CMD_KSVC_CONFIGURE);
1378 
1379         while ((c = getopt(argc, argv, "hp:a:")) != -1) {
1380                 switch (c) {
1381                 case 'p':
1382                         if (port != -1) {
1383                                 krrp_print_err_already_defined("p");
1384                                 exit(1);
1385                         }
1386 
1387                         port = strtol(optarg, NULL, 0);
1388                         if (port < KRRP_MIN_PORT || port > KRRP_MAX_PORT) {
1389                                 fprintf_err("Port number must be "
1390                                     "an integer in range from %d to %d\n",
1391                                     KRRP_MIN_PORT, KRRP_MAX_PORT);
1392                                 exit(1);
1393                         }
1394 
1395                         break;
1396                 case 'a':
1397                         if (addr != NULL) {
1398                                 krrp_print_err_already_defined("a");
1399                                 exit(1);
1400                         }
1401 
1402                         addr = optarg;
1403                         break;
1404                 case '?':
1405                         krrp_print_err_unknown_param(argv[optind - 1]);
1406                         cmd->usage_func(1, cmd, B_FALSE);
1407                         break;
1408                 case 'h':
1409                         cmd->usage_func(0, cmd, B_FALSE);
1410                         break;
1411                 }
1412         }
1413 
1414         if (port == -1) {
1415                 fprintf_err("Listening port number is not defined\n");
1416                 exit(1);
1417         }
1418 
1419         rc = krrp_set_srv_config(libkrrp_hdl, addr, port);
1420         if (rc != 0) {
1421                 fprintf_err("Failed to configure in-kernel service\n");
1422                 krrp_print_libkrrp_error();
1423                 exit(1);
1424         }
1425 
1426         return (0);
1427 }
1428 
1429 static int
1430 krrp_parse_and_check_sess_id(char *sess_id_str, uuid_t sess_id)
1431 {
1432         if (uuid_is_null(sess_id) != 1) {
1433                 fprintf_err("Session ID already defined\n");
1434                 return (-1);
1435         }
1436 
1437         if (uuid_parse(sess_id_str, sess_id) != 0) {
1438                 fprintf_err("Failed to parse Session ID\n");
1439                 return (-1);
1440         }
1441 
1442         return (0);
1443 }
1444 
1445 static void
1446 krrp_print_err_already_defined(const char *param)
1447 {
1448         fprintf_err("The parameter '%s' already defined\n", param);
1449 }
1450 
1451 static void
1452 krrp_print_err_unknown_param(const char *param)
1453 {
1454         fprintf_err("Unknown parameter '%s'\n", param);
1455 }
1456 
1457 static void
1458 krrp_print_err_no_sess_id(void)
1459 {
1460         fprintf_err("Session ID is not defined\n");
1461 }
1462 
1463 static void
1464 krrp_print_libkrrp_error(void)
1465 {
1466         fprintf_err("%s\n", libkrrp_error_description(libkrrp_hdl));
1467 }
1468 
1469 static void
1470 fprintf_err(const char *fmt, ...)
1471 {
1472         va_list ap;
1473 
1474         va_start(ap, fmt);
1475         (void) vfprintf(stderr, fmt, ap);
1476         va_end(ap);
1477 }
1478 
1479 static void
1480 fprintf_msg(const char *fmt, ...)
1481 {
1482         va_list ap;
1483 
1484         va_start(ap, fmt);
1485         (void) vfprintf(stdout, fmt, ap);
1486         va_end(ap);
1487 }