1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
   4  */
   5 
   6 /*
   7  * BSD 3 Clause License
   8  *
   9  * Copyright (c) 2007, The Storage Networking Industry Association.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  *      - Redistributions of source code must retain the above copyright
  15  *        notice, this list of conditions and the following disclaimer.
  16  *
  17  *      - Redistributions in binary form must reproduce the above copyright
  18  *        notice, this list of conditions and the following disclaimer in
  19  *        the documentation and/or other materials provided with the
  20  *        distribution.
  21  *
  22  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  23  *        nor the names of its contributors may be used to endorse or promote
  24  *        products derived from this software without specific prior written
  25  *        permission.
  26  *
  27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37  * POSSIBILITY OF SUCH DAMAGE.
  38  */
  39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
  40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
  41 #include <sys/types.h>
  42 #include <sys/param.h>
  43 #include <sys/socket.h>
  44 #include <netinet/in.h>
  45 #include <errno.h>
  46 #include <arpa/inet.h>
  47 #include <stdlib.h>
  48 #include <string.h>
  49 #include "ndmpd_common.h"
  50 #include "ndmpd.h"
  51 
  52 static int ndmpd_data_error_send_v4(ndmpd_session_t *session,
  53     ndmp_data_halt_reason reason);
  54 static int ndmpd_data_error_send(ndmpd_session_t *session,
  55     ndmp_data_halt_reason reason);
  56 static void data_accept_connection_v3(void *cookie, int fd, ulong_t mode);
  57 static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
  58     ushort_t *port);
  59 static ndmp_error data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr,
  60     ushort_t port);
  61 static int discard_data_v3(ndmpd_session_t *session, ulong_t length);
  62 static void nlp_release_job_stat(ndmpd_session_t *session);
  63 static u_longlong_t ndmpd_data_get_info(ndmpd_session_t *session);
  64 
  65 static ndmp_error ndmpd_tar_start_backup_v2(ndmpd_session_t *, char *,
  66     ndmp_pval *, ulong_t);
  67 static ndmp_error ndmpd_tar_start_recover_v2(ndmpd_session_t *, char *,
  68     ndmp_pval *, ulong_t, ndmp_name *, ulong_t);
  69 static ndmp_error ndmpd_tar_start_backup_v3(ndmpd_session_t *, char *,
  70     ndmp_pval *, ulong_t);
  71 static ndmp_error ndmpd_tar_start_recover_v3(ndmpd_session_t *,
  72     ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t);
  73 
  74 static ndmp_error ndmpd_zfs_start_op(ndmpd_session_t *,
  75     ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t, enum ndmp_data_operation);
  76 
  77 
  78 /*
  79  * ************************************************************************
  80  * NDMP V2 HANDLERS
  81  * ************************************************************************
  82  */
  83 
  84 /*
  85  * ndmpd_data_get_state_v2
  86  *
  87  * Request handler. Returns current data state.
  88  *
  89  * Parameters:
  90  *   connection (input) - connection handle.
  91  *   body       (input) - request message body.
  92  *
  93  * Returns:
  94  *   void
  95  */
  96 /*ARGSUSED*/
  97 void
 
 
 139 ndmpd_data_start_backup_v2(ndmp_connection_t *connection, void *body)
 140 {
 141         ndmp_data_start_backup_request_v2 *request;
 142         ndmp_data_start_backup_reply_v2 reply;
 143         ndmpd_session_t *session = ndmp_get_client_data(connection);
 144         ndmp_error err;
 145 
 146         request = (ndmp_data_start_backup_request_v2 *)body;
 147 
 148         reply.error = NDMP_NO_ERR;
 149         session->ns_data.dd_mover = request->mover;
 150 
 151         err = ndmpd_tar_start_backup_v2(session, request->bu_type,
 152             request->env.env_val, request->env.env_len);
 153 
 154         /*
 155          * start_backup sends the reply if the backup is successfully started.
 156          * Otherwise, send the reply containing the error here.
 157          */
 158         if (err != NDMP_NO_ERR) {
 159                 NDMP_LOG(LOG_DEBUG, "err: %d", err);
 160                 reply.error = err;
 161                 ndmp_send_reply(connection, &reply,
 162                     "sending data_start_backup reply");
 163                 ndmpd_data_cleanup(session);
 164         }
 165 }
 166 
 167 /*
 168  * ndmpd_data_start_recover_v2
 169  *
 170  * Request handler. Starts a restore.
 171  *
 172  * Parameters:
 173  *   connection (input) - connection handle.
 174  *   body       (input) - request message body.
 175  *
 176  * Returns:
 177  *   void
 178  */
 179 void
 
 209  * Request handler. Returns the environment variable array sent
 210  * with the backup request. This request may only be sent with
 211  * a backup operation is in progress.
 212  *
 213  * Parameters:
 214  *   connection (input) - connection handle.
 215  *   body       (input) - request message body.
 216  *
 217  * Returns:
 218  *   void
 219  */
 220 /*ARGSUSED*/
 221 void
 222 ndmpd_data_get_env_v2(ndmp_connection_t *connection, void *body)
 223 {
 224         ndmp_data_get_env_reply reply;
 225         ndmpd_session_t *session = ndmp_get_client_data(connection);
 226 
 227         (void) memset((void*)&reply, 0, sizeof (reply));
 228         if (session->ns_data.dd_operation != NDMP_DATA_OP_BACKUP) {
 229                 NDMP_LOG(LOG_ERR, "Backup operation not active.");
 230                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 231                 reply.env.env_len = 0;
 232         } else {
 233                 reply.error = NDMP_NO_ERR;
 234                 reply.env.env_len = session->ns_data.dd_env_len;
 235                 reply.env.env_val = session->ns_data.dd_env;
 236         }
 237 
 238         ndmp_send_reply(connection, &reply, "sending data_get_env reply");
 239 }
 240 
 241 
 242 /*
 243  * ndmpd_data_stop_v2
 244  *
 245  * Request handler. Stops the current data operation.
 246  *
 247  * Parameters:
 248  *   connection (input) - connection handle.
 249  *   body       (input) - request message body.
 250  *
 251  * Returns:
 252  *   void
 253  */
 254 /*ARGSUSED*/
 255 void
 256 ndmpd_data_stop_v2(ndmp_connection_t *connection, void *body)
 257 {
 258         ndmp_data_stop_reply reply;
 259         ndmpd_session_t *session = ndmp_get_client_data(connection);
 260 
 261         if (session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
 262                 NDMP_LOG(LOG_ERR, "Invalid state to process stop request.");
 263                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 264                 ndmp_send_reply(connection, &reply,
 265                     "sending data_stop reply");
 266                 return;
 267         }
 268         ndmp_waitfor_op(session);
 269         ndmpd_data_cleanup(session);
 270         ndmpd_file_history_cleanup(session, FALSE);
 271 
 272         nlp_release_job_stat(session);
 273 
 274         /* prepare for another data operation */
 275         (void) ndmpd_data_init(session);
 276         ndmpd_file_history_init(session);
 277 
 278         reply.error = NDMP_NO_ERR;
 279         ndmp_send_reply(connection, &reply, "sending data_stop reply");
 280 }
 281 
 282 
 
 286  * Request handler. Aborts the current backup/restore. The operation
 287  * state is not changed to the halted state until after the operation
 288  * has actually been aborted and the notify_halt request has been sent.
 289  *
 290  * Parameters:
 291  *   connection (input) - connection handle.
 292  *   body       (input) - request message body.
 293  *
 294  * Returns:
 295  *   void
 296  */
 297 /*ARGSUSED*/
 298 void
 299 ndmpd_data_abort_v2(ndmp_connection_t *connection, void *body)
 300 {
 301         ndmp_data_abort_reply reply;
 302         ndmpd_session_t *session = ndmp_get_client_data(connection);
 303 
 304         if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
 305             session->ns_data.dd_state == NDMP_DATA_STATE_HALTED) {
 306                 NDMP_LOG(LOG_ERR, "Invalid state to process abort request.");
 307                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 308                 ndmp_send_reply(connection, &reply,
 309                     "sending data_abort reply");
 310                 return;
 311         }
 312         /*
 313          * Don't go to HALTED state yet. Need to wait for data operation to
 314          * abort. When this happens, ndmpd_done will get called and will
 315          * perform the halt processing.
 316          */
 317         session->ns_data.dd_abort = TRUE;
 318         (*session->ns_data.dd_module.dm_abort_func)(
 319             session->ns_data.dd_module.dm_module_cookie);
 320 
 321         reply.error = NDMP_NO_ERR;
 322         ndmp_send_reply(connection, &reply, "sending data_abort reply");
 323 }
 324 
 325 /*
 326  * ************************************************************************
 
 384  *
 385  * Parameters:
 386  *   connection (input) - connection handle.
 387  *   body       (input) - request message body.
 388  *
 389  * Returns:
 390  *   void
 391  */
 392 void
 393 ndmpd_data_start_backup_v3(ndmp_connection_t *connection, void *body)
 394 {
 395         ndmp_data_start_backup_request_v3 *request;
 396         ndmp_data_start_backup_reply_v3 reply;
 397         ndmpd_session_t *session = ndmp_get_client_data(connection);
 398 
 399         request = (ndmp_data_start_backup_request_v3 *)body;
 400 
 401         (void) memset((void*)&reply, 0, sizeof (reply));
 402 
 403         if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
 404                 NDMP_LOG(LOG_ERR,
 405                     "Can't start new backup in current state.");
 406                 NDMP_LOG(LOG_ERR,
 407                     "Connection to the mover is not established.");
 408                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 409                 goto _error;
 410         }
 411 
 412         if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
 413                 if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
 414                         NDMP_LOG(LOG_ERR, "Write protected device.");
 415                         reply.error = NDMP_WRITE_PROTECT_ERR;
 416                         goto _error;
 417                 }
 418         }
 419 
 420         if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) {
 421                 session->ns_butype = NDMP_BUTYPE_TAR;
 422         } else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) {
 423                 session->ns_butype = NDMP_BUTYPE_DUMP;
 424         } else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) {
 425                 session->ns_butype = NDMP_BUTYPE_ZFS;
 426         } else {
 427                 char msg_invalid[32];
 428                 char msg_types[32];
 429 
 430                 (void) snprintf(msg_invalid, 32, "Invalid backup type: %s.",
 431                     request->bu_type);
 432                 (void) snprintf(msg_types, 32,
 433                     "Supported backup types are tar, dump, and zfs.");
 434 
 435                 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
 436                     msg_invalid);
 437                 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
 438                     msg_types);
 439                 NDMP_LOG(LOG_ERR, msg_invalid);
 440                 NDMP_LOG(LOG_ERR, msg_types);
 441 
 442                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 443                 goto _error;
 444         }
 445 
 446         if (session->ns_butype == NDMP_BUTYPE_ZFS) {
 447                 reply.error = ndmpd_zfs_start_op(session, request->env.env_val,
 448                     request->env.env_len, NULL, 0, NDMP_DATA_OP_BACKUP);
 449         } else {
 450                 reply.error = ndmpd_tar_start_backup_v3(session,
 451                     request->bu_type, request->env.env_val,
 452                     request->env.env_len);
 453         }
 454 
 455         /*
 456          * *_start_backup* sends the reply if the backup is
 457          * successfully started.  Otherwise, send the reply
 458          * containing the error here.
 459          */
 460 
 461 _error:
 462 
 463         if (reply.error != NDMP_NO_ERR) {
 464                 ndmp_send_reply(connection, &reply,
 465                     "sending data_start_backup_v3 reply");
 466                 ndmpd_data_cleanup(session);
 467         }
 468 }
 469 
 470 /*
 471  * ndmpd_data_start_recover_v3
 472  *
 473  * Request handler. Starts a restore.
 474  *
 475  * Parameters:
 476  *   connection (input) - connection handle.
 477  *   body       (input) - request message body.
 478  *
 479  * Returns:
 480  *   void
 481  */
 482 void
 483 ndmpd_data_start_recover_v3(ndmp_connection_t *connection, void *body)
 484 {
 485         ndmp_data_start_recover_request_v3 *request;
 486         ndmp_data_start_recover_reply_v3 reply;
 487         ndmpd_session_t *session = ndmp_get_client_data(connection);
 488 
 489         request = (ndmp_data_start_recover_request_v3 *)body;
 490 
 491         (void) memset((void*)&reply, 0, sizeof (reply));
 492 
 493         if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
 494                 NDMP_LOG(LOG_ERR, "Can't start new recover in current state.");
 495                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 496                 goto _error;
 497         }
 498 
 499         if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) {
 500                 session->ns_butype = NDMP_BUTYPE_TAR;
 501         } else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) {
 502                 session->ns_butype = NDMP_BUTYPE_DUMP;
 503         } else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) {
 504                 session->ns_butype = NDMP_BUTYPE_ZFS;
 505         } else {
 506                 char msg_invalid[32];
 507                 char msg_types[32];
 508 
 509                 (void) snprintf(msg_invalid, 32, "Invalid backup type: %s.",
 510                     request->bu_type);
 511                 (void) snprintf(msg_types, 32,
 512                     "Supported backup types are tar, dump, and zfs.");
 513 
 514                 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
 515                     msg_invalid);
 516                 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
 517                     msg_types);
 518                 NDMP_LOG(LOG_ERR, msg_invalid);
 519                 NDMP_LOG(LOG_ERR, msg_types);
 520 
 521                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 522                 goto _error;
 523         }
 524 
 525         if (session->ns_butype == NDMP_BUTYPE_ZFS) {
 526                 reply.error = ndmpd_zfs_start_op(session, request->env.env_val,
 527                     request->env.env_len, request->nlist.nlist_val,
 528                     request->nlist.nlist_len, NDMP_DATA_OP_RECOVER);
 529         } else {
 530                 reply.error = ndmpd_tar_start_recover_v3(session,
 531                     request->env.env_val, request->env.env_len,
 532                     request->nlist.nlist_val, request->nlist.nlist_len);
 533         }
 534 
 535         /*
 536          * *_start_recover* sends the reply if the recover is
 537          * successfully started.  Otherwise, send the reply
 538          * containing the error here.
 539          */
 540 
 541 _error:
 542 
 543         if (reply.error != NDMP_NO_ERR) {
 544                 ndmp_send_reply(connection, &reply,
 545                     "sending data_start_recover_v3 reply");
 546                 ndmpd_data_error(session, NDMP_DATA_HALT_INTERNAL_ERROR);
 547                 ndmpd_data_cleanup(session);
 548         }
 549 }
 550 
 551 /*
 552  * ndmpd_data_abort_v3
 553  *
 
 555  * state is not changed to the halted state until after the operation
 556  * has actually been aborted and the notify_halt request has been sent.
 557  *
 558  * Parameters:
 559  *   connection (input) - connection handle.
 560  *   body       (input) - request message body.
 561  *
 562  * Returns:
 563  *   void
 564  */
 565 /*ARGSUSED*/
 566 void
 567 ndmpd_data_abort_v3(ndmp_connection_t *connection, void *body)
 568 {
 569         ndmp_data_abort_reply reply;
 570         ndmpd_session_t *session = ndmp_get_client_data(connection);
 571 
 572         switch (session->ns_data.dd_state) {
 573         case NDMP_DATA_STATE_IDLE:
 574                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 575                 NDMP_LOG(LOG_ERR, "Invalid state to process abort request.");
 576                 break;
 577 
 578         case NDMP_DATA_STATE_ACTIVE:
 579                 /*
 580                  * Don't go to HALTED state yet.  Need to wait for data
 581                  * operation to abort.  When this happens, ndmpd_done_v3
 582                  * will get called and will perform the halt processing.
 583                  */
 584                 reply.error = NDMP_NO_ERR;
 585                 session->ns_data.dd_abort = TRUE;
 586                 if (session->ns_data.dd_module.dm_abort_func)
 587                         (*session->ns_data.dd_module.dm_abort_func)(
 588                             session->ns_data.dd_module.dm_module_cookie);
 589                 break;
 590 
 591         case NDMP_DATA_STATE_HALTED:
 592         case NDMP_DATA_STATE_LISTEN:
 593         case NDMP_DATA_STATE_CONNECTED:
 594                 reply.error = NDMP_NO_ERR;
 595                 session->ns_data.dd_abort = TRUE;
 596                 ndmpd_data_error(session, NDMP_DATA_HALT_ABORTED);
 597                 break;
 598         default:
 599                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 600                 NDMP_LOG(LOG_DEBUG, "Unknown data V3 state %d",
 601                     session->ns_data.dd_state);
 602         }
 603 
 604         ndmp_send_reply(connection, &reply,
 605             "sending data_abort_v3 reply");
 606 }
 607 
 608 
 609 /*
 610  * ndmpd_data_stop_v3
 611  *
 612  * Request handler. Stops the current data operation.
 613  *
 614  * Parameters:
 615  *   connection (input) - connection handle.
 616  *   body       (input) - request message body.
 617  *
 618  * Returns:
 619  *   void
 620  */
 621 /*ARGSUSED*/
 622 void
 623 ndmpd_data_stop_v3(ndmp_connection_t *connection, void *body)
 624 {
 625         ndmp_data_stop_reply reply;
 626         ndmpd_session_t *session = ndmp_get_client_data(connection);
 627 
 628         if (session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
 629                 NDMP_LOG(LOG_ERR, "Invalid state to process stop request.");
 630                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 631                 ndmp_send_reply(connection, &reply,
 632                     "sending data_stop_v3 reply");
 633                 return;
 634         }
 635         ndmp_waitfor_op(session);
 636         ndmpd_data_cleanup(session);
 637         ndmpd_file_history_cleanup(session, FALSE);
 638 
 639         /* prepare for another data operation */
 640         (void) ndmpd_data_init(session);
 641         ndmpd_file_history_init(session);
 642 
 643         reply.error = NDMP_NO_ERR;
 644         ndmp_send_reply(connection, &reply,
 645             "sending data_stop_v3 reply");
 646 }
 647 
 648 
 649 /*
 
 657  *   body       (input) - request message body.
 658  *
 659  * Returns:
 660  *   void
 661  */
 662 void
 663 ndmpd_data_listen_v3(ndmp_connection_t *connection, void *body)
 664 {
 665         ndmp_data_listen_request_v3 *request;
 666         ndmp_data_listen_reply_v3 reply;
 667         ndmpd_session_t *session = ndmp_get_client_data(connection);
 668         ulong_t addr;
 669         ushort_t port;
 670 
 671         request = (ndmp_data_listen_request_v3 *)body;
 672 
 673         (void) memset((void*)&reply, 0, sizeof (reply));
 674 
 675         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 676                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 677                 NDMP_LOG(LOG_ERR,
 678                     "Invalid internal data state to process listen request.");
 679         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
 680                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 681                 NDMP_LOG(LOG_ERR,
 682                     "Invalid mover state to process listen request.");
 683         } else {
 684                 reply.error = NDMP_NO_ERR;
 685         }
 686 
 687         if (reply.error != NDMP_NO_ERR) {
 688                 ndmp_send_reply(connection, &reply,
 689                     "ndmp_data_listen_request_v3 reply");
 690                 return;
 691         }
 692 
 693         switch (request->addr_type) {
 694         case NDMP_ADDR_LOCAL:
 695                 reply.data_connection_addr.addr_type = request->addr_type;
 696                 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
 697                 break;
 698         case NDMP_ADDR_TCP:
 699                 if (create_listen_socket_v3(session, &addr, &port) < 0) {
 700                         reply.error = NDMP_IO_ERR;
 701                         break;
 702                 }
 703 
 704                 reply.error = NDMP_NO_ERR;
 705                 reply.data_connection_addr.addr_type = request->addr_type;
 706                 reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
 707                 reply.data_connection_addr.tcp_port_v3 = htons(port);
 708                 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
 709                 session->ns_data.dd_data_addr.tcp_ip_v3 = addr;
 710                 session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(port);
 711                 NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
 712                     session->ns_data.dd_listen_sock);
 713                 break;
 714 
 715         default:
 716                 NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
 717                     request->addr_type);
 718                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 719                 break;
 720         }
 721 
 722         if (reply.error == NDMP_NO_ERR)
 723                 session->ns_data.dd_state = NDMP_DATA_STATE_LISTEN;
 724 
 725         ndmp_send_reply(connection, &reply,
 726             "ndmp_data_listen_request_v3 reply");
 727 }
 728 
 729 
 730 /*
 731  * ndmpd_data_connect_v3
 732  *
 733  * Request handler. Connects the data server to either a local
 734  * or remote mover.
 735  *
 736  * Parameters:
 737  *   connection (input) - connection handle.
 738  *   body       (input) - request message body.
 739  *
 740  * Returns:
 741  *   void
 742  */
 743 void
 744 ndmpd_data_connect_v3(ndmp_connection_t *connection, void *body)
 745 {
 746         ndmp_data_connect_request_v3 *request;
 747         ndmp_data_connect_reply_v3 reply;
 748         ndmpd_session_t *session = ndmp_get_client_data(connection);
 749 
 750         request = (ndmp_data_connect_request_v3 *)body;
 751 
 752         (void) memset((void*)&reply, 0, sizeof (reply));
 753 
 754         if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
 755                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 756                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
 757                     request->addr.addr_type);
 758         } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 759                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 760                 NDMP_LOG(LOG_ERR, "Invalid state to process connect request.");
 761         } else {
 762                 reply.error = NDMP_NO_ERR;
 763         }
 764 
 765         if (reply.error != NDMP_NO_ERR) {
 766                 ndmp_send_reply(connection, &reply,
 767                     "sending ndmp_data_connect_v3 reply");
 768                 return;
 769         }
 770 
 771         switch (request->addr.addr_type) {
 772         case NDMP_ADDR_LOCAL:
 773                 /*
 774                  * Verify that the mover is listening for a
 775                  * local connection
 776                  */
 777                 if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN ||
 778                     session->ns_mover.md_listen_sock != -1) {
 779                         reply.error = NDMP_ILLEGAL_STATE_ERR;
 780                         NDMP_LOG(LOG_ERR,
 781                             "Mover is not in local listen state.");
 782                 } else {
 783                         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
 784                 }
 785                 break;
 786 
 787         case NDMP_ADDR_TCP:
 788                 reply.error = data_connect_sock_v3(session,
 789                     request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
 790                 break;
 791 
 792         default:
 793                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 794                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
 795                     request->addr.addr_type);
 796         }
 797 
 798         if (reply.error == NDMP_NO_ERR)
 799                 session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
 800 
 801         ndmp_send_reply(connection, &reply,
 802             "sending ndmp_data_connect_v3 reply");
 803 }
 804 
 805 
 806 /*
 807  * ************************************************************************
 808  * NDMP V4 HANDLERS
 809  * ************************************************************************
 810  */
 811 
 812 /*
 813  * ndmpd_data_get_env_v4
 814  *
 
 817  * a backup operation is in progress.
 818  *
 819  * Parameters:
 820  *   connection (input) - connection handle.
 821  *   body       (input) - request message body.
 822  *
 823  * Returns:
 824  *   void
 825  */
 826 /*ARGSUSED*/
 827 void
 828 ndmpd_data_get_env_v4(ndmp_connection_t *connection, void *body)
 829 {
 830         ndmp_data_get_env_reply reply;
 831         ndmpd_session_t *session = ndmp_get_client_data(connection);
 832 
 833         (void) memset((void*)&reply, 0, sizeof (reply));
 834 
 835         if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE &&
 836             session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
 837                 NDMP_LOG(LOG_ERR, "Invalid state for the data server.");
 838                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 839                 reply.env.env_len = 0;
 840         } else if (session->ns_data.dd_operation != NDMP_DATA_OP_BACKUP) {
 841                 NDMP_LOG(LOG_ERR, "Backup operation not active.");
 842                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 843                 reply.env.env_len = 0;
 844         } else {
 845                 reply.error = NDMP_NO_ERR;
 846                 reply.env.env_len = session->ns_data.dd_env_len;
 847                 reply.env.env_val = session->ns_data.dd_env;
 848         }
 849 
 850         ndmp_send_reply(connection, &reply, "sending data_get_env reply");
 851 }
 852 
 853 /*
 854  * ndmpd_data_get_state_v4
 855  *
 856  * Request handler. Returns current data state.
 857  *
 858  * Parameters:
 859  *   connection (input) - connection handle.
 860  *   body       (input) - request message body.
 861  *
 
 909  * Parameters:
 910  *   connection (input) - connection handle.
 911  *   body       (input) - request message body.
 912  *
 913  * Returns:
 914  *   void
 915  */
 916 void
 917 ndmpd_data_connect_v4(ndmp_connection_t *connection, void *body)
 918 {
 919         ndmp_data_connect_request_v4 *request;
 920         ndmp_data_connect_reply_v4 reply;
 921         ndmpd_session_t *session = ndmp_get_client_data(connection);
 922 
 923         request = (ndmp_data_connect_request_v4 *)body;
 924 
 925         (void) memset((void*)&reply, 0, sizeof (reply));
 926 
 927         if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
 928                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 929                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
 930                     request->addr.addr_type);
 931         } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 932                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 933                 NDMP_LOG(LOG_ERR, "Invalid state to process connect request.");
 934         } else {
 935                 reply.error = NDMP_NO_ERR;
 936         }
 937 
 938         if (reply.error != NDMP_NO_ERR) {
 939                 ndmp_send_reply(connection, &reply,
 940                     "sending ndmp_data_connect_v4 reply");
 941                 return;
 942         }
 943 
 944         switch (request->addr.addr_type) {
 945         case NDMP_ADDR_LOCAL:
 946                 /*
 947                  * Verify that the mover is listening for a
 948                  * local connection
 949                  */
 950                 if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN ||
 951                     session->ns_mover.md_listen_sock != -1) {
 952                         reply.error = NDMP_ILLEGAL_STATE_ERR;
 953                         NDMP_LOG(LOG_ERR,
 954                             "Mover is not in local listen state.");
 955                 } else {
 956                         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
 957                 }
 958                 break;
 959 
 960         case NDMP_ADDR_TCP:
 961                 reply.error = data_connect_sock_v3(session,
 962                     request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
 963                 break;
 964 
 965         default:
 966                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 967                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
 968                     request->addr.addr_type);
 969         }
 970 
 971         if (reply.error == NDMP_NO_ERR)
 972                 session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
 973 
 974         ndmp_send_reply(connection, &reply,
 975             "sending ndmp_data_connect_v4 reply");
 976 }
 977 
 978 /*
 979  * ndmpd_data_listen_v4
 980  *
 981  * Request handler. Configures the server to listen for a connection
 982  * from a remote mover.
 983  *
 984  * Parameters:
 985  *   connection (input) - connection handle.
 986  *   body       (input) - request message body.
 987  *
 988  * Returns:
 989  *   void
 990  */
 991 void
 992 ndmpd_data_listen_v4(ndmp_connection_t *connection, void *body)
 993 {
 994         ndmp_data_listen_request_v4 *request;
 995         ndmp_data_listen_reply_v4 reply;
 996         ndmpd_session_t *session = ndmp_get_client_data(connection);
 997         ulong_t addr;
 998         ushort_t port;
 999 
1000         request = (ndmp_data_listen_request_v4 *)body;
1001 
1002         (void) memset((void*)&reply, 0, sizeof (reply));
1003 
1004         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1005                 reply.error = NDMP_ILLEGAL_STATE_ERR;
1006                 NDMP_LOG(LOG_ERR,
1007                     "Invalid internal data state to process listen request.");
1008         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1009                 reply.error = NDMP_ILLEGAL_STATE_ERR;
1010                 NDMP_LOG(LOG_ERR,
1011                     "Invalid mover state to process listen request.");
1012         } else {
1013                 reply.error = NDMP_NO_ERR;
1014         }
1015 
1016         if (reply.error != NDMP_NO_ERR) {
1017                 ndmp_send_reply(connection, &reply,
1018                     "ndmp_data_listen_request_v4 reply");
1019                 return;
1020         }
1021 
1022         switch (request->addr_type) {
1023         case NDMP_ADDR_LOCAL:
1024                 reply.connect_addr.addr_type = request->addr_type;
1025                 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
1026                 break;
1027         case NDMP_ADDR_TCP:
1028                 if (create_listen_socket_v3(session, &addr, &port) < 0) {
1029                         reply.error = NDMP_IO_ERR;
1030                         break;
 
1034                 reply.connect_addr.addr_type = request->addr_type;
1035                 reply.connect_addr.tcp_addr_v4 =
1036                     ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1037 
1038                 reply.connect_addr.tcp_ip_v4(0) = htonl(addr);
1039                 reply.connect_addr.tcp_port_v4(0) = htons(port);
1040                 reply.connect_addr.tcp_len_v4 = 1;
1041 
1042                 session->ns_data.dd_data_addr_v4.addr_type = NDMP_ADDR_TCP;
1043                 session->ns_data.dd_data_addr_v4.tcp_addr_v4 =
1044                     ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1045 
1046                 session->ns_data.dd_data_addr_v4.tcp_ip_v4(0) = addr;
1047                 session->ns_data.dd_data_addr_v4.tcp_port_v4(0) = ntohs(port);
1048                 session->ns_data.dd_data_addr_v4.tcp_len_v4 = 1;
1049 
1050                 /* Copy that to data_addr for compatibility */
1051                 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
1052                 session->ns_data.dd_data_addr.tcp_ip_v3 = addr;
1053                 session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(port);
1054                 NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
1055                     session->ns_data.dd_listen_sock);
1056                 break;
1057 
1058         default:
1059                 NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
1060                     request->addr_type);
1061                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1062                 break;
1063         }
1064 
1065         if (reply.error == NDMP_NO_ERR)
1066                 session->ns_data.dd_state = NDMP_DATA_STATE_LISTEN;
1067 
1068         ndmp_send_reply(connection, &reply,
1069             "ndmp_data_listen_request_v4 reply");
1070 }
1071 
1072 
1073 /*
1074  * ndmpd_data_start_recover_filehist_v4
1075  *
1076  * Request handler. Recovers the file history (not supported yet)
1077  * This command has an optional support in V4.
1078  *
1079  * Parameters:
1080  *   connection (input) - connection handle.
1081  *   body       (input) - request message body.
1082  *
1083  * Returns:
1084  *   void
1085  */
1086 /*ARGSUSED*/
1087 void
1088 ndmpd_data_start_recover_filehist_v4(ndmp_connection_t *connection, void *body)
1089 {
1090         ndmp_data_start_recover_filehist_reply_v4 reply;
1091 
1092         NDMP_LOG(LOG_DEBUG, "Request not supported");
1093         reply.error = NDMP_NOT_SUPPORTED_ERR;
1094 
1095         ndmp_send_reply(connection, &reply,
1096             "sending ndmp_data_start_recover_filehist_reply_v4 reply");
1097 }
1098 
1099 /*
1100  * ************************************************************************
1101  * LOCALS
1102  * ************************************************************************
1103  */
1104 
1105 /*
1106  * ndmpd_data_error_send
1107  *
1108  * This function sends the notify message to the client.
1109  *
1110  * Parameters:
1111  *   session (input) - session pointer.
1112  *   reason  (input) - halt reason.
 
1178                 /*
1179                  * Send/discard any buffered file history data.
1180                  */
1181                 ndmpd_file_history_cleanup(session,
1182                     (reason == NDMP_DATA_HALT_SUCCESSFUL ? TRUE : FALSE));
1183 
1184                 /*
1185                  * If mover local and successful backup, write any
1186                  * remaining buffered data to tape.
1187                  */
1188                 if (session->ns_data.dd_data_addr.addr_type
1189                     == NDMP_ADDR_LOCAL && reason == NDMP_DATA_HALT_SUCCESSFUL)
1190                         (void) ndmpd_local_write_v3(session, 0, 0);
1191         }
1192 
1193         session->ns_data.dd_state = NDMP_DATA_STATE_HALTED;
1194         session->ns_data.dd_halt_reason = reason;
1195 
1196         if (session->ns_protocol_version == NDMPV4) {
1197                 if (ndmpd_data_error_send_v4(session, reason) < 0)
1198                         NDMP_LOG(LOG_DEBUG,
1199                             "Error sending notify_data_halted request");
1200         } else {
1201                 if (ndmpd_data_error_send(session, reason) < 0)
1202                         NDMP_LOG(LOG_DEBUG,
1203                             "Error sending notify_data_halted request");
1204         }
1205 
1206         if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP) {
1207                 if (session->ns_data.dd_sock != -1) {
1208                         (void) ndmpd_remove_file_handler(session,
1209                             session->ns_data.dd_sock);
1210                         /*
1211                          * ndmpcopy: we use the same socket for the mover,
1212                          * so expect to close when mover is done!
1213                          */
1214                         if (session->ns_data.dd_sock !=
1215                             session->ns_mover.md_sock)
1216                                 (void) close(session->ns_data.dd_sock);
1217 
1218                         session->ns_data.dd_sock = -1;
1219                 }
1220                 if (session->ns_data.dd_listen_sock != -1) {
1221                         (void) ndmpd_remove_file_handler(session,
1222                             session->ns_data.dd_listen_sock);
 
1240  * Parameters:
1241  *   cookie  (input) - session pointer.
1242  *   fd      (input) - file descriptor.
1243  *   mode    (input) - select mode.
1244  *
1245  * Returns:
1246  *   void
1247  */
1248 /*ARGSUSED*/
1249 static void
1250 data_accept_connection_v3(void *cookie, int fd, ulong_t mode)
1251 {
1252         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1253         int from_len;
1254         struct sockaddr_in from;
1255 
1256         from_len = sizeof (from);
1257         session->ns_data.dd_sock = accept(fd, (struct sockaddr *)&from,
1258             &from_len);
1259 
1260         NDMP_LOG(LOG_DEBUG, "sock fd: %d",
1261             session->ns_data.dd_sock);
1262         NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s",
1263             ntohs(from.sin_port),
1264             inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
1265 
1266         (void) ndmpd_remove_file_handler(session, fd);
1267         (void) close(session->ns_data.dd_listen_sock);
1268         session->ns_data.dd_listen_sock = -1;
1269 
1270         if (session->ns_data.dd_sock < 0) {
1271                 NDMP_LOG(LOG_DEBUG, "Accept error: %m");
1272                 ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1273                 return;
1274         }
1275 
1276         /*
1277          * Save the peer address.
1278          */
1279         session->ns_data.dd_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
1280         session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(from.sin_port);
1281 
1282         /* Set the parameter of the new socket */
1283         set_socket_options(session->ns_data.dd_sock);
1284 
1285         session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1286 }
1287 
1288 
1289 /*
1290  * create_listen_socket_v3
1291  *
 
1294  */
1295 static int
1296 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
1297 {
1298         session->ns_data.dd_listen_sock = ndmp_create_socket(addr, port);
1299         if (session->ns_data.dd_listen_sock < 0)
1300                 return (-1);
1301 
1302         /*
1303          * Add a file handler for the listen socket.
1304          * ndmpd_select will call data_accept_connection when a
1305          * connection is ready to be accepted.
1306          */
1307         if (ndmpd_add_file_handler(session, (void*)session,
1308             session->ns_data.dd_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
1309             data_accept_connection_v3) < 0) {
1310                 (void) close(session->ns_data.dd_listen_sock);
1311                 session->ns_data.dd_listen_sock = -1;
1312                 return (-1);
1313         }
1314         NDMP_LOG(LOG_DEBUG, "addr: %s:%d",
1315             inet_ntoa(IN_ADDR(*addr)), ntohs(*port));
1316 
1317         return (0);
1318 }
1319 
1320 
1321 /*
1322  * data_connect_sock_v3
1323  *
1324  * Connect the data interface socket to the specified ip/port
1325  *
1326  * Parameters:
1327  *   session (input) - session pointer.
1328  *   addr    (input) - IP address
1329  *   port    (input) - port number
1330  *
1331  * Returns:
1332  *   NDMP_NO_ERR - backup successfully started.
1333  *   otherwise - error code of backup start error.
1334  */
 
1356  * Start the backup work
1357  *
1358  * Parameters:
1359  *   session   (input) - session pointer.
1360  *   bu_type   (input) - backup type.
1361  *   env_val   (input) - environment variable array.
1362  *   env_len   (input) - length of env_val.
1363  *
1364  * Returns:
1365  *   NDMP_NO_ERR - backup successfully started.
1366  *   otherwise - error code of backup start error.
1367  */
1368 static ndmp_error
1369 ndmpd_tar_start_backup_v3(ndmpd_session_t *session, char *bu_type,
1370     ndmp_pval *env_val, ulong_t env_len)
1371 {
1372         int err;
1373         ndmp_lbr_params_t *nlp;
1374         ndmpd_module_params_t *params;
1375         ndmp_data_start_backup_reply_v3 reply;
1376 
1377         (void) memset((void*)&reply, 0, sizeof (reply));
1378 
1379         err = ndmpd_save_env(session, env_val, env_len);
1380         if (err != NDMP_NO_ERR)
1381                 return (err);
1382 
1383         nlp = ndmp_get_nlp(session);
1384         NDMP_FREE(nlp->nlp_params);
1385         params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1386         if (!params)
1387                 return (NDMP_NO_MEM_ERR);
1388 
1389         params->mp_daemon_cookie = (void *)session;
1390         params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1391         params->mp_protocol_version = session->ns_protocol_version;
1392         params->mp_operation = NDMP_DATA_OP_BACKUP;
1393         params->mp_get_env_func = ndmpd_api_get_env;
1394         params->mp_add_env_func = ndmpd_api_add_env;
1395         params->mp_set_env_func = ndmpd_api_set_env;
 
1425         } else {
1426                 NLP_UNSET(nlp, NLPF_DUMP);
1427                 NLP_UNSET(nlp, NLPF_TAR);
1428         }
1429 
1430         session->ns_data.dd_module.dm_start_func = ndmpd_tar_backup_starter_v3;
1431         session->ns_data.dd_module.dm_abort_func = ndmpd_tar_backup_abort_v3;
1432 
1433         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1434         session->ns_data.dd_module.dm_stats.ms_est_time_remaining  = 0;
1435         session->ns_data.dd_nlist_v3 = 0;
1436         session->ns_data.dd_nlist_len = 0;
1437         session->ns_data.dd_bytes_left_to_read = 0;
1438         session->ns_data.dd_position = 0;
1439         session->ns_data.dd_discard_length = 0;
1440         session->ns_data.dd_read_offset = 0;
1441         session->ns_data.dd_read_length = 0;
1442 
1443         reply.error = ndmp_backup_get_params_v3(session, params);
1444         if (reply.error != NDMP_NO_ERR) {
1445                 NDMP_LOG(LOG_DEBUG, "err: %d", err);
1446                 NDMP_FREE(nlp->nlp_params);
1447                 return (reply.error);
1448         }
1449 
1450         reply.error = NDMP_NO_ERR;
1451         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1452             &reply) < 0) {
1453                 NDMP_LOG(LOG_DEBUG, "Sending data_start_backup_v3 reply");
1454                 return (NDMP_NO_ERR);
1455         }
1456 
1457         NS_INC(nbk);
1458         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1459         session->ns_data.dd_operation = NDMP_DATA_OP_BACKUP;
1460         session->ns_data.dd_abort = FALSE;
1461 
1462         /*
1463          * perform the backup
1464          *
1465          * Cannot wait for the thread to exit as we are replying to the
1466          * client request here.
1467          */
1468         err = pthread_create(NULL, NULL,
1469             (funct_t)session->ns_data.dd_module.dm_start_func,
1470             params);
1471         if (err != 0) {
1472                 NDMP_LOG(LOG_ERR, "Can't start backup session.");
1473                 return (NDMP_ILLEGAL_ARGS_ERR);
1474         }
1475 
1476         return (NDMP_NO_ERR);
1477 }
1478 
1479 /*
1480  * ndmpd_tar_start_recover_v3
1481  *
1482  * Start the restore work
1483  *
1484  * Parameters:
1485  *   session   (input) - session pointer.
1486  *   bu_type   (input) - backup type.
1487  *   env_val   (input) - environment variable array.
1488  *   env_len   (input) - length of env_val.
1489  *   nlist_val (input) - list of files.
1490  *   nlist_len (input) - length of nlist_val.
1491  *
1492  * Returns:
1493  *   NDMP_NO_ERR - recover successfully started.
1494  *   otherwise   - error code of recover start error.
1495  */
1496 static ndmp_error
1497 ndmpd_tar_start_recover_v3(ndmpd_session_t *session,
1498     ndmp_pval *env_val, ulong_t env_len, ndmp_name_v3 *nlist_val,
1499     ulong_t nlist_len)
1500 {
1501         ndmp_data_start_recover_reply_v3 reply;
1502         ndmpd_module_params_t *params;
1503         ndmp_lbr_params_t *nlp;
1504         int err;
1505 
1506         (void) memset((void*)&reply, 0, sizeof (reply));
1507 
1508         nlp = ndmp_get_nlp(session);
1509         NDMP_FREE(nlp->nlp_params);
1510         params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1511         if (!params) {
1512                 return (NDMP_NO_MEM_ERR);
1513         }
1514 
1515         reply.error = ndmpd_save_env(session, env_val, env_len);
1516         if (reply.error != NDMP_NO_ERR) {
1517                 NDMP_FREE(nlp->nlp_params);
1518                 return (NDMP_NO_MEM_ERR);
1519         }
1520 
1521         reply.error = ndmpd_save_nlist_v3(session, nlist_val, nlist_len);
1522         if (reply.error != NDMP_NO_ERR) {
1523                 NDMP_FREE(nlp->nlp_params);
 
1560         session->ns_data.dd_module.dm_abort_func = ndmpd_tar_restore_abort_v3;
1561         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1562         session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1563         session->ns_data.dd_bytes_left_to_read = 0;
1564         session->ns_data.dd_position = 0;
1565         session->ns_data.dd_discard_length = 0;
1566         session->ns_data.dd_read_offset = 0;
1567         session->ns_data.dd_read_length = 0;
1568 
1569         err = ndmp_restore_get_params_v3(session, params);
1570         if (err != NDMP_NO_ERR) {
1571                 NDMP_FREE(nlp->nlp_params);
1572                 return (err);
1573         }
1574 
1575         reply.error = NDMP_NO_ERR;
1576         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1577             &reply) < 0) {
1578                 NDMP_FREE(nlp->nlp_params);
1579                 ndmpd_free_nlist_v3(session);
1580                 NDMP_LOG(LOG_DEBUG,
1581                     "Error sending ndmp_data_start_recover_reply");
1582                 ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1583                 return (NDMP_NO_ERR);
1584         }
1585 
1586         NS_INC(nrs);
1587         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1588         session->ns_data.dd_operation = NDMP_DATA_OP_RECOVER;
1589         session->ns_data.dd_abort = FALSE;
1590 
1591         /*
1592          * perform the restore
1593          *
1594          * Cannot wait for the thread to exit as we are replying to the
1595          * client request here.
1596          */
1597         err = pthread_create(NULL, NULL,
1598             (funct_t)session->ns_data.dd_module.dm_start_func,
1599             params);
1600 
1601         if (err != 0) {
1602                 NDMP_LOG(LOG_ERR, "Can't start recover session.");
1603                 return (NDMP_ILLEGAL_ARGS_ERR);
1604         }
1605         return (NDMP_NO_ERR);
1606 }
1607 
1608 static ndmp_error
1609 ndmpd_zfs_start_op(ndmpd_session_t *session, ndmp_pval *env_val,
1610     ulong_t env_len, ndmp_name_v3 *nlist_val, ulong_t nlist_len,
1611     enum ndmp_data_operation op)
1612 {
1613         ndmpd_zfs_args_t *ndmpd_zfs_args = &session->ns_ndmpd_zfs_args;
1614         ndmp_data_start_backup_reply_v3 backup_reply;
1615         ndmp_data_start_recover_reply_v3 recover_reply;
1616         pthread_t tid;
1617         void *reply;
1618         char str[8];
1619         int err;
1620 
1621         if (ndmpd_zfs_init(session) != 0)
1622                 return (NDMP_UNDEFINED_ERR);
1623 
1624         err = ndmpd_save_env(session, env_val, env_len);
1625         if (err != NDMP_NO_ERR) {
1626                 ndmpd_zfs_fini(ndmpd_zfs_args);
1627                 return (err);
1628         }
1629 
1630         switch (op) {
1631         case NDMP_DATA_OP_BACKUP:
1632                 if (!ndmpd_zfs_backup_parms_valid(ndmpd_zfs_args)) {
1633                         ndmpd_zfs_fini(ndmpd_zfs_args);
1634                         return (NDMP_ILLEGAL_ARGS_ERR);
1635                 }
1636 
1637                 if (ndmpd_zfs_pre_backup(ndmpd_zfs_args)) {
1638                         NDMP_LOG(LOG_ERR, "pre_backup error");
1639                         return (NDMP_ILLEGAL_ARGS_ERR);
1640                 }
1641 
1642                 session->ns_data.dd_module.dm_start_func =
1643                     ndmpd_zfs_backup_starter;
1644                 (void) strlcpy(str, "backup", 8);
1645                 break;
1646         case NDMP_DATA_OP_RECOVER:
1647                 err = ndmpd_save_nlist_v3(session, nlist_val, nlist_len);
1648                 if (err != NDMP_NO_ERR) {
1649                         ndmpd_zfs_fini(ndmpd_zfs_args);
1650                         return (NDMP_NO_MEM_ERR);
1651                 }
1652 
1653                 if (!ndmpd_zfs_restore_parms_valid(ndmpd_zfs_args)) {
1654                         ndmpd_zfs_fini(ndmpd_zfs_args);
1655                         return (NDMP_ILLEGAL_ARGS_ERR);
1656                 }
1657 
1658                 if (ndmpd_zfs_pre_restore(ndmpd_zfs_args)) {
1659                         NDMP_LOG(LOG_ERR, "pre_restore error");
1660                         (void) ndmpd_zfs_post_restore(ndmpd_zfs_args);
1661                         return (NDMP_ILLEGAL_ARGS_ERR);
1662                 }
1663                 session->ns_data.dd_module.dm_start_func =
1664                     ndmpd_zfs_restore_starter;
1665                 (void) strlcpy(str, "recover", 8);
1666                 break;
1667         }
1668 
1669         ndmpd_zfs_params->mp_operation = op;
1670         session->ns_data.dd_operation = op;
1671         session->ns_data.dd_module.dm_abort_func = ndmpd_zfs_abort;
1672         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1673         session->ns_data.dd_abort = FALSE;
1674 
1675         if (op == NDMP_DATA_OP_BACKUP) {
1676                 (void) memset((void*)&backup_reply, 0, sizeof (backup_reply));
1677                 backup_reply.error = NDMP_NO_ERR;
1678                 reply = &backup_reply;
1679         } else {
1680                 (void) memset((void*)&recover_reply, 0, sizeof (recover_reply));
1681                 recover_reply.error = NDMP_NO_ERR;
1682                 reply = &recover_reply;
1683         }
1684 
1685         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1686             reply) < 0) {
1687                 NDMP_LOG(LOG_DEBUG, "Sending data_start_%s_v3 reply", str);
1688                 if (op == NDMP_DATA_OP_RECOVER)
1689                         ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1690                 ndmpd_zfs_fini(ndmpd_zfs_args);
1691                 return (NDMP_NO_ERR);
1692         }
1693 
1694         err = pthread_create(&tid, NULL,
1695             (funct_t)session->ns_data.dd_module.dm_start_func, ndmpd_zfs_args);
1696 
1697         if (err) {
1698                 NDMP_LOG(LOG_ERR, "Can't start %s session (errno %d)",
1699                     str, err);
1700                 ndmpd_zfs_fini(ndmpd_zfs_args);
1701                 MOD_DONE(ndmpd_zfs_params, -1);
1702                 return (NDMP_NO_ERR);
1703         }
1704 
1705         (void) pthread_detach(tid);
1706 
1707         if (op == NDMP_DATA_OP_BACKUP)
1708                 NS_INC(nbk);
1709         else
1710                 NS_INC(nrs);
1711 
1712         ndmpd_zfs_dma_log(ndmpd_zfs_args, NDMP_LOG_NORMAL,
1713             "'zfs' %s starting\n", str);
1714 
1715         return (NDMP_NO_ERR);
1716 }
1717 
1718 /*
1719  * discard_data_v3
1720  *
1721  * Read and discard data from the data connection.
1722  * Called when a module has called ndmpd_seek() prior to
1723  * reading all of the data from the previous seek.
1724  *
1725  * Parameters:
1726  *   session (input) - session pointer.
1727  *
1728  * Returns:
1729  *   number of bytes read and discarded.
1730  *  -1 - error.
1731  */
1732 static int
1733 discard_data_v3(ndmpd_session_t *session, ulong_t length)
1734 {
1735         static char buf[MAX_RECORD_SIZE];
1736         int n, toread;
1737 
1738         toread = (length < MAX_RECORD_SIZE) ? length :
1739             MAX_RECORD_SIZE;
1740 
1741         /* Read and discard the data. */
1742         n = read(session->ns_data.dd_sock, buf, toread);
1743         if (n < 0) {
1744                 NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1745                 n = -1;
1746         }
1747 
1748         return (n);
1749 }
1750 
1751 
1752 /*
1753  * ndmpd_remote_read_v3
1754  *
1755  * Reads data from the remote mover.
1756  *
1757  * Parameters:
1758  *   session (input) - session pointer.
1759  *   data    (input) - data to be written.
1760  *   length  (input) - data length.
1761  *
1762  * Returns:
1763  *   0 - data successfully read.
1764  *  -1 - error.
1765  */
1766 int
1767 ndmpd_remote_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
1768 {
1769         ulong_t count;
1770         ulong_t len;
1771         ssize_t n;
1772         ndmp_notify_data_read_request request;
1773         tlm_job_stats_t *jstat;
1774         longlong_t fsize;
1775 
1776         NDMP_LOG(LOG_DEBUG, "ns_data.dd_xx: [%llu, %llu, %llu, %llu, %llu]",
1777             session->ns_data.dd_bytes_left_to_read,
1778             session->ns_data.dd_read_offset,
1779             session->ns_data.dd_read_length,
1780             session->ns_data.dd_position,
1781             session->ns_data.dd_discard_length);
1782 
1783         count = 0;
1784         while (count < length) {
1785                 len = length - count;
1786 
1787                 /*
1788                  * If the end of the seek window has been reached then
1789                  * send an ndmp_read request to the client.
1790                  * The NDMP client will then send a mover_data_read request to
1791                  * the remote mover and the mover will send more data.
1792                  * This condition can occur if the module attempts to read past
1793                  * a seek window set via a prior call to ndmpd_seek() or
1794                  * the module has not issued a seek. If no seek was issued then
1795                  * pretend that a seek was issued to read the entire tape.
1796                  */
1797                 if (session->ns_data.dd_bytes_left_to_read == 0) {
1798                         /* ndmpd_seek() never called? */
1799                         if (session->ns_data.dd_read_length == 0) {
1800                                 session->ns_data.dd_bytes_left_to_read = ~0LL;
1801                                 session->ns_data.dd_read_offset = 0LL;
1802                                 session->ns_data.dd_read_length = ~0LL;
1803                         } else {
1804                                 /*
1805                                  * While restoring a file, restoreFile()
1806                                  * records the number of bytes still need to
1807                                  * be restored.  We use this as a guidance
1808                                  * when asking for data from the tape.
1809                                  */
1810                                 jstat = session->ns_ndmp_lbr_params->nlp_jstat;
1811                                 fsize = jstat->js_bytes_in_file;
1812 
1813                                 NDMP_LOG(LOG_DEBUG, "bytes_left [%llu / %u]",
1814                                     fsize, len);
1815 
1816                                 /*
1817                                  * Fall back to the old way if fsize if too
1818                                  * small.
1819                                  */
1820                                 if (fsize < len)
1821                                         fsize = len;
1822 
1823                                 session->ns_data.dd_bytes_left_to_read = fsize;
1824                                 session->ns_data.dd_read_offset =
1825                                     session->ns_data.dd_position;
1826                                 session->ns_data.dd_read_length = fsize;
1827                         }
1828 
1829                         request.offset =
1830                             long_long_to_quad(session->ns_data.dd_read_offset);
1831                         request.length =
1832                             long_long_to_quad(session->ns_data.dd_read_length);
1833 
1834                         NDMP_LOG(LOG_DEBUG, "to NOTIFY_DATA_READ [%llu, %llu]",
1835                             session->ns_data.dd_read_offset,
1836                             session->ns_data.dd_read_length);
1837 
1838                         if (ndmp_send_request_lock(session->ns_connection,
1839                             NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1840                             &request, 0) < 0) {
1841                                 NDMP_LOG(LOG_DEBUG,
1842                                     "Sending notify_data_read request");
1843                                 return (-1);
1844                         }
1845                 }
1846 
1847                 /*
1848                  * If the module called ndmpd_seek() prior to reading all of the
1849                  * data that the remote mover was requested to send, then the
1850                  * excess data from the seek has to be discarded.
1851                  */
1852                 if (session->ns_data.dd_discard_length != 0) {
1853                         n = discard_data_v3(session,
1854                             (ulong_t)session->ns_data.dd_discard_length);
1855                         if (n < 0)
1856                                 return (-1);
1857 
1858                         session->ns_data.dd_discard_length -= n;
1859                         continue;
1860                 }
1861 
1862                 /*
1863                  * Don't attempt to read more data than the remote is sending.
1864                  */
1865                 if (len > session->ns_data.dd_bytes_left_to_read)
1866                         len = session->ns_data.dd_bytes_left_to_read;
1867 
1868                 if ((n = read(session->ns_data.dd_sock, &data[count],
1869                     len)) < 0) {
1870                         NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1871                         return (-1);
1872                 }
1873 
1874                 /* read returns 0 if the connection was closed */
1875                 if (n == 0) {
1876                         NDMP_LOG(LOG_DEBUG, "n 0 errno %d",
1877                             errno);
1878                         return (-1);
1879                 }
1880 
1881                 count += n;
1882                 session->ns_data.dd_bytes_left_to_read -= n;
1883                 session->ns_data.dd_position += n;
1884         }
1885         return (0);
1886 }
1887 
1888 /*
1889  * nlp_release_job_stat
1890  *
1891  * Unreference the job statistics
1892  *
1893  * Parameters:
1894  *   session (input) - session pointer.
1895  *
1896  * Returns:
1897  *   void
1898  */
1899 static void
1900 nlp_release_job_stat(ndmpd_session_t *session)
1901 {
1902         ndmp_lbr_params_t *nlp;
1903 
1904         if ((nlp = ndmp_get_nlp(session)) == NULL) {
1905                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1906                 return;
1907         }
1908         if (nlp->nlp_jstat != NULL) {
1909                 nlp->nlp_bytes_total =
1910                     (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
1911                 tlm_un_ref_job_stats(nlp->nlp_jstat->js_job_name);
1912                 nlp->nlp_jstat = NULL;
1913         } else
1914                 NDMP_LOG(LOG_DEBUG, "JSTAT == NULL");
1915 }
1916 
1917 
1918 /* *** ndmpd global internal functions *********************************** */
1919 
1920 /*
1921  * ndmpd_data_init
1922  *
1923  * Initializes data specific session variables.
1924  *
1925  * Parameters:
1926  *   session (input) - session pointer.
1927  *
1928  * Returns:
1929  *   void
1930  */
1931 int
1932 ndmpd_data_init(ndmpd_session_t *session)
1933 {
1934         session->ns_data.dd_operation = NDMP_DATA_OP_NOACTION;
 
1958         return (0);
1959 }
1960 
1961 
1962 
1963 /*
1964  * ndmpd_data_cleanup
1965  *
1966  * Releases resources allocated during a data operation.
1967  *
1968  * Parameters:
1969  *   session (input) - session pointer.
1970  *
1971  * Returns:
1972  *   void
1973  */
1974 void
1975 ndmpd_data_cleanup(ndmpd_session_t *session)
1976 {
1977         if (session->ns_data.dd_listen_sock != -1) {
1978                 NDMP_LOG(LOG_DEBUG, "data.listen_sock: %d",
1979                     session->ns_data.dd_listen_sock);
1980                 (void) ndmpd_remove_file_handler(session,
1981                     session->ns_data.dd_listen_sock);
1982                 (void) close(session->ns_data.dd_listen_sock);
1983                 session->ns_data.dd_listen_sock = -1;
1984         }
1985         if (session->ns_data.dd_sock != -1) {
1986                 NDMP_LOG(LOG_DEBUG, "data.sock: %d",
1987                     session->ns_data.dd_sock);
1988 
1989                 /*
1990                  * ndmpcopy: we use the same socket for the mover,
1991                  * so expect to close when mover is done!
1992                  */
1993                 if (session->ns_data.dd_sock != session->ns_mover.md_sock)
1994                         (void) close(session->ns_data.dd_sock);
1995 
1996                 session->ns_data.dd_sock = -1;
1997         }
1998 
1999         ndmpd_free_env(session);
2000         ndmpd_free_nlist(session);
2001 }
2002 
2003 
2004 /*
2005  * ndmp_data_get_mover_mode
2006  *
 
2018 {
2019         char *rv;
2020 
2021         switch (session->ns_protocol_version) {
2022         case NDMPV2:
2023                 rv = ((session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP)
2024                     ? "remote" : "local");
2025                 break;
2026         case NDMPV3:
2027                 rv = ((session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP)
2028                     ? "remote" : "local");
2029                 break;
2030         case NDMPV4:
2031                 rv = ((session->ns_data.dd_data_addr.addr_type ==
2032                     NDMP_ADDR_TCP ||
2033                     (session->ns_data.dd_data_addr_v4.addr_type ==
2034                     NDMP_ADDR_TCP)) ? "remote" : "local");
2035                 break;
2036         default:
2037                 rv = "Unknown";
2038                 NDMP_LOG(LOG_ERR, "Invalid protocol version %d.",
2039                     session->ns_protocol_version);
2040         }
2041 
2042         return (rv);
2043 }
2044 
2045 /* *** static functions ******************************************** */
2046 
2047 /*
2048  * ndmpd_tar_start_backup_v2
2049  *
2050  * Request handling code common to version 1 and
2051  * version 2 data_start_backup request handlers.
2052  *
2053  * Parameters:
2054  *   session   (input) - session pointer.
2055  *   bu_type   (input) - backup type.
2056  *   env_val   (input) - environment variable array.
2057  *   env_len   (input) - length of env_val.
2058  *
2059  * Returns:
2060  *   NDMP_NO_ERR - backup successfully started.
2061  *   otherwise - error code of backup start error.
2062  */
2063 static ndmp_error
2064 ndmpd_tar_start_backup_v2(ndmpd_session_t *session, char *bu_type,
2065     ndmp_pval *env_val, ulong_t env_len)
2066 {
2067         ndmp_data_start_backup_reply reply;
2068         ndmpd_module_params_t *params;
2069         ndmp_lbr_params_t *nlp;
2070         int err;
2071 
2072         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
2073                 NDMP_LOG(LOG_ERR, "Can't start new backup in current state.");
2074                 return (NDMP_ILLEGAL_STATE_ERR);
2075         }
2076         if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
2077             strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
2078                 NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type);
2079                 NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump.");
2080                 return (NDMP_ILLEGAL_ARGS_ERR);
2081         }
2082         if ((err = ndmpd_save_env(session, env_val, env_len)) != NDMP_NO_ERR)
2083                 return (err);
2084 
2085         nlp = ndmp_get_nlp(session);
2086         NDMP_FREE(nlp->nlp_params);
2087         params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
2088         if (params == NULL)
2089                 return (NDMP_NO_MEM_ERR);
2090 
2091         params->mp_daemon_cookie = (void *)session;
2092         params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
2093         params->mp_protocol_version = session->ns_protocol_version;
2094         params->mp_operation = NDMP_DATA_OP_BACKUP;
2095         params->mp_get_env_func = ndmpd_api_get_env;
2096         params->mp_add_env_func = ndmpd_api_add_env;
2097         params->mp_get_name_func = ndmpd_api_get_name;
2098         params->mp_dispatch_func = ndmpd_api_dispatch;
2099         params->mp_done_func = ndmpd_api_done_v2;
 
2120                     ndmpd_api_file_history_path_v2;
2121                 params->mp_file_history_dir_func = 0;
2122                 params->mp_file_history_node_func = 0;
2123         } else {
2124                 NLP_UNSET(nlp, NLPF_DUMP);
2125                 NLP_UNSET(nlp, NLPF_TAR);
2126         }
2127 
2128         session->ns_data.dd_module.dm_start_func = ndmpd_tar_backup_starter;
2129         session->ns_data.dd_module.dm_abort_func = ndmpd_tar_backup_abort;
2130 
2131         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
2132         session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
2133         session->ns_data.dd_nlist = 0;
2134         session->ns_data.dd_nlist_len = 0;
2135         session->ns_data.dd_read_offset = 0;
2136         session->ns_data.dd_read_length = 0;
2137 
2138         if ((err = ndmp_backup_extract_params(session,
2139             params)) != NDMP_NO_ERR) {
2140                 NDMP_LOG(LOG_DEBUG, "err: %d", err);
2141                 NDMP_FREE(nlp->nlp_params);
2142                 return (err);
2143         }
2144 
2145         err = ndmpd_mover_connect(session, NDMP_MOVER_MODE_READ);
2146         if (err != NDMP_NO_ERR) {
2147                 NDMP_LOG(LOG_DEBUG,
2148                     "mover connect err: %d", err);
2149                 NDMP_FREE(nlp->nlp_params);
2150                 return (err);
2151         }
2152 
2153         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
2154 
2155         session->ns_data.dd_operation = NDMP_DATA_OP_BACKUP;
2156         session->ns_data.dd_abort = FALSE;
2157 
2158         NDMP_LOG(LOG_DEBUG, "starting backup");
2159 
2160         reply.error = NDMP_NO_ERR;
2161         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
2162             &reply) < 0) {
2163                 NDMP_LOG(LOG_DEBUG, "Sending data_start_backup reply");
2164                 NDMP_FREE(nlp->nlp_params);
2165                 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
2166                         /*
2167                          * ndmpcopy: we use the same socket for the mover,
2168                          * so expect to close when mover is done!
2169                          */
2170                         if (session->ns_data.dd_sock !=
2171                             session->ns_mover.md_sock)
2172                                 (void) close(session->ns_data.dd_sock);
2173 
2174                         session->ns_data.dd_sock = -1;
2175                 } else
2176                         ndmpd_mover_error(session,
2177                             NDMP_MOVER_HALT_CONNECT_CLOSED);
2178                 return (NDMP_NO_ERR);
2179         }
2180 
2181         /*
2182          * perform the backup
2183          *
2184          * Cannot wait for the thread to exit as we are replying to the
2185          * client request here.
2186          */
2187         (void) pthread_create(NULL, NULL,
2188             (funct_t)session->ns_data.dd_module.dm_start_func,
2189             params);
2190 
2191         return (NDMP_NO_ERR);
2192 }
2193 
2194 /*
2195  * ndmpd_tar_start_recover_v2
2196  *
2197  * The main recover/restore function
2198  *
2199  * Parameters:
2200  *   session   (input) - session pointer.
2201  *   bu_type   (input) - backup type.
2202  *   env_val   (input) - environment variable array.
2203  *   env_len   (input) - length of env_val.
2204  *   nlist_val (input) - list of files.
2205  *   nlist_len (input) - length of nlist_val.
2206  *
2207  * Returns:
2208  *   NDMP_NO_ERR - recover successfully started.
2209  *   otherwise - error code of backup start error.
2210  */
2211 static ndmp_error
2212 ndmpd_tar_start_recover_v2(ndmpd_session_t *session, char *bu_type,
2213     ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val,
2214     ulong_t nlist_len)
2215 {
2216         ndmp_data_start_recover_reply_v2 reply;
2217         ndmpd_module_params_t *params;
2218         ndmp_lbr_params_t *nlp;
2219         int err;
2220 
2221         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
2222                 NDMP_LOG(LOG_ERR, "Can't start new recover in current state.");
2223                 return (NDMP_ILLEGAL_STATE_ERR);
2224         }
2225 
2226         if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
2227             strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
2228                 NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", bu_type);
2229                 NDMP_LOG(LOG_ERR, "Supported backup types are tar and dump.");
2230                 return (NDMP_ILLEGAL_ARGS_ERR);
2231         }
2232 
2233         reply.error = ndmpd_save_env(session, env_val, env_len);
2234         if (reply.error != NDMP_NO_ERR)
2235                 return (NDMP_NO_MEM_ERR);
2236 
2237         reply.error = ndmpd_save_nlist_v2(session, nlist_val, nlist_len);
2238         if (reply.error != NDMP_NO_ERR)
2239                 return (NDMP_NO_MEM_ERR);
2240 
2241         nlp = ndmp_get_nlp(session);
2242         NDMP_FREE(nlp->nlp_params);
2243         params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
2244         if (params == NULL)
2245                 return (NDMP_NO_MEM_ERR);
2246 
2247         /*
2248          * Setup restore parameters.
2249          */
 
2278 
2279         if ((err = ndmp_restore_extract_params(session,
2280             params)) != NDMP_NO_ERR) {
2281                 NDMP_FREE(nlp->nlp_params);
2282                 return (err);
2283         }
2284 
2285         err = ndmpd_mover_connect(session, NDMP_MOVER_MODE_WRITE);
2286         if (err != NDMP_NO_ERR) {
2287                 NDMP_FREE(nlp->nlp_params);
2288                 return (err);
2289         }
2290 
2291         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
2292         session->ns_data.dd_operation = NDMP_DATA_OP_RECOVER;
2293         session->ns_data.dd_abort = FALSE;
2294 
2295         reply.error = NDMP_NO_ERR;
2296         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
2297             &reply) < 0) {
2298                 NDMP_LOG(LOG_DEBUG, "Sending data_start_recover reply");
2299                 NDMP_FREE(nlp->nlp_params);
2300                 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
2301                         /*
2302                          * ndmpcopy: we use the same socket for the mover,
2303                          * so expect to close when mover is done!
2304                          */
2305                         if (session->ns_data.dd_sock !=
2306                             session->ns_mover.md_sock)
2307                                 (void) close(session->ns_data.dd_sock);
2308 
2309                         session->ns_data.dd_sock = -1;
2310                 } else {
2311                         ndmpd_mover_error(session,
2312                             NDMP_MOVER_HALT_CONNECT_CLOSED);
2313                 }
2314                 return (NDMP_NO_ERR);
2315         }
2316 
2317 
2318         /*
2319          * perform the restore
2320          *
2321          * Cannot wait for the thread to exit as we are replying to the
2322          * client request here.
2323          */
2324         (void) pthread_create(NULL, NULL,
2325             (funct_t)session->ns_data.dd_module.dm_start_func,
2326             params);
2327 
2328         return (NDMP_NO_ERR);
2329 }
2330 
2331 /*
2332  * ndmpd_data_get_info
2333  *
2334  * Return the total number of bytes processed
2335  *
2336  * Parameters:
2337  *   session   (input) - session pointer.
2338  *
2339  * Returns:
2340  *   the number of bytes processed
2341  */
2342 static u_longlong_t
2343 ndmpd_data_get_info(ndmpd_session_t *session)
2344 {
2345         ndmp_lbr_params_t *nlp;
2346 
2347         nlp = ndmp_get_nlp(session);
 | 
   1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
   4  */
   5 
   6 /*
   7  * BSD 3 Clause License
   8  *
   9  * Copyright (c) 2007, The Storage Networking Industry Association.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  *      - Redistributions of source code must retain the above copyright
  15  *        notice, this list of conditions and the following disclaimer.
  16  *
  17  *      - Redistributions in binary form must reproduce the above copyright
  18  *        notice, this list of conditions and the following disclaimer in
  19  *        the documentation and/or other materials provided with the
  20  *        distribution.
  21  *
  22  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  23  *        nor the names of its contributors may be used to endorse or promote
  24  *        products derived from this software without specific prior written
  25  *        permission.
  26  *
  27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37  * POSSIBILITY OF SUCH DAMAGE.
  38  */
  39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
  40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
  41 #include <sys/types.h>
  42 #include <sys/param.h>
  43 #include <sys/socket.h>
  44 #include <syslog.h>
  45 #include <netinet/in.h>
  46 #include <errno.h>
  47 #include <arpa/inet.h>
  48 #include <stdlib.h>
  49 #include <string.h>
  50 #include "ndmpd_common.h"
  51 #include "ndmpd.h"
  52 
  53 static int ndmpd_data_error_send_v4(ndmpd_session_t *session,
  54     ndmp_data_halt_reason reason);
  55 static int ndmpd_data_error_send(ndmpd_session_t *session,
  56     ndmp_data_halt_reason reason);
  57 static void data_accept_connection_v3(void *cookie, int fd, ulong_t mode);
  58 static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
  59     ushort_t *port);
  60 static ndmp_error data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr,
  61     ushort_t port);
  62 static int discard_data_v3(ndmpd_session_t *session, ulong_t length);
  63 static void nlp_release_job_stat(ndmpd_session_t *session);
  64 static u_longlong_t ndmpd_data_get_info(ndmpd_session_t *session);
  65 
  66 static ndmp_error ndmpd_tar_start_backup_v2(ndmpd_session_t *, char *,
  67     ndmp_pval *, ulong_t);
  68 static ndmp_error ndmpd_tar_start_recover_v2(ndmpd_session_t *, char *,
  69     ndmp_pval *, ulong_t, ndmp_name *, ulong_t);
  70 static ndmp_error ndmpd_tar_start_backup_v3(ndmpd_session_t *, char *,
  71     ndmp_pval *, ulong_t);
  72 static ndmp_error ndmpd_tar_start_recover_v3(ndmpd_session_t *,
  73     ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t);
  74 
  75 /*
  76  * ************************************************************************
  77  * NDMP V2 HANDLERS
  78  * ************************************************************************
  79  */
  80 
  81 /*
  82  * ndmpd_data_get_state_v2
  83  *
  84  * Request handler. Returns current data state.
  85  *
  86  * Parameters:
  87  *   connection (input) - connection handle.
  88  *   body       (input) - request message body.
  89  *
  90  * Returns:
  91  *   void
  92  */
  93 /*ARGSUSED*/
  94 void
 
 
 136 ndmpd_data_start_backup_v2(ndmp_connection_t *connection, void *body)
 137 {
 138         ndmp_data_start_backup_request_v2 *request;
 139         ndmp_data_start_backup_reply_v2 reply;
 140         ndmpd_session_t *session = ndmp_get_client_data(connection);
 141         ndmp_error err;
 142 
 143         request = (ndmp_data_start_backup_request_v2 *)body;
 144 
 145         reply.error = NDMP_NO_ERR;
 146         session->ns_data.dd_mover = request->mover;
 147 
 148         err = ndmpd_tar_start_backup_v2(session, request->bu_type,
 149             request->env.env_val, request->env.env_len);
 150 
 151         /*
 152          * start_backup sends the reply if the backup is successfully started.
 153          * Otherwise, send the reply containing the error here.
 154          */
 155         if (err != NDMP_NO_ERR) {
 156                 syslog(LOG_ERR, "err: %d", err);
 157                 reply.error = err;
 158                 ndmp_send_reply(connection, &reply,
 159                     "sending data_start_backup reply");
 160                 ndmpd_data_cleanup(session);
 161         }
 162 }
 163 
 164 /*
 165  * ndmpd_data_start_recover_v2
 166  *
 167  * Request handler. Starts a restore.
 168  *
 169  * Parameters:
 170  *   connection (input) - connection handle.
 171  *   body       (input) - request message body.
 172  *
 173  * Returns:
 174  *   void
 175  */
 176 void
 
 206  * Request handler. Returns the environment variable array sent
 207  * with the backup request. This request may only be sent with
 208  * a backup operation is in progress.
 209  *
 210  * Parameters:
 211  *   connection (input) - connection handle.
 212  *   body       (input) - request message body.
 213  *
 214  * Returns:
 215  *   void
 216  */
 217 /*ARGSUSED*/
 218 void
 219 ndmpd_data_get_env_v2(ndmp_connection_t *connection, void *body)
 220 {
 221         ndmp_data_get_env_reply reply;
 222         ndmpd_session_t *session = ndmp_get_client_data(connection);
 223 
 224         (void) memset((void*)&reply, 0, sizeof (reply));
 225         if (session->ns_data.dd_operation != NDMP_DATA_OP_BACKUP) {
 226                 syslog(LOG_ERR, "Backup operation not active.");
 227                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 228                 reply.env.env_len = 0;
 229         } else {
 230                 reply.error = NDMP_NO_ERR;
 231                 reply.env.env_len = session->ns_data.dd_env_len;
 232                 reply.env.env_val = session->ns_data.dd_env;
 233         }
 234 
 235         ndmp_send_reply(connection, &reply, "sending data_get_env reply");
 236 }
 237 
 238 
 239 /*
 240  * ndmpd_data_stop_v2
 241  *
 242  * Request handler. Stops the current data operation.
 243  *
 244  * Parameters:
 245  *   connection (input) - connection handle.
 246  *   body       (input) - request message body.
 247  *
 248  * Returns:
 249  *   void
 250  */
 251 /*ARGSUSED*/
 252 void
 253 ndmpd_data_stop_v2(ndmp_connection_t *connection, void *body)
 254 {
 255         ndmp_data_stop_reply reply;
 256         ndmpd_session_t *session = ndmp_get_client_data(connection);
 257 
 258         if (session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
 259                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 260                 ndmp_send_reply(connection, &reply,
 261                     "sending data_stop reply");
 262                 return;
 263         }
 264         ndmp_waitfor_op(session);
 265         ndmpd_data_cleanup(session);
 266         ndmpd_file_history_cleanup(session, FALSE);
 267 
 268         nlp_release_job_stat(session);
 269 
 270         /* prepare for another data operation */
 271         (void) ndmpd_data_init(session);
 272         ndmpd_file_history_init(session);
 273 
 274         reply.error = NDMP_NO_ERR;
 275         ndmp_send_reply(connection, &reply, "sending data_stop reply");
 276 }
 277 
 278 
 
 282  * Request handler. Aborts the current backup/restore. The operation
 283  * state is not changed to the halted state until after the operation
 284  * has actually been aborted and the notify_halt request has been sent.
 285  *
 286  * Parameters:
 287  *   connection (input) - connection handle.
 288  *   body       (input) - request message body.
 289  *
 290  * Returns:
 291  *   void
 292  */
 293 /*ARGSUSED*/
 294 void
 295 ndmpd_data_abort_v2(ndmp_connection_t *connection, void *body)
 296 {
 297         ndmp_data_abort_reply reply;
 298         ndmpd_session_t *session = ndmp_get_client_data(connection);
 299 
 300         if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
 301             session->ns_data.dd_state == NDMP_DATA_STATE_HALTED) {
 302                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 303                 ndmp_send_reply(connection, &reply,
 304                     "sending data_abort reply");
 305                 return;
 306         }
 307         /*
 308          * Don't go to HALTED state yet. Need to wait for data operation to
 309          * abort. When this happens, ndmpd_done will get called and will
 310          * perform the halt processing.
 311          */
 312         session->ns_data.dd_abort = TRUE;
 313         (*session->ns_data.dd_module.dm_abort_func)(
 314             session->ns_data.dd_module.dm_module_cookie);
 315 
 316         reply.error = NDMP_NO_ERR;
 317         ndmp_send_reply(connection, &reply, "sending data_abort reply");
 318 }
 319 
 320 /*
 321  * ************************************************************************
 
 379  *
 380  * Parameters:
 381  *   connection (input) - connection handle.
 382  *   body       (input) - request message body.
 383  *
 384  * Returns:
 385  *   void
 386  */
 387 void
 388 ndmpd_data_start_backup_v3(ndmp_connection_t *connection, void *body)
 389 {
 390         ndmp_data_start_backup_request_v3 *request;
 391         ndmp_data_start_backup_reply_v3 reply;
 392         ndmpd_session_t *session = ndmp_get_client_data(connection);
 393 
 394         request = (ndmp_data_start_backup_request_v3 *)body;
 395 
 396         (void) memset((void*)&reply, 0, sizeof (reply));
 397 
 398         if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
 399                 syslog(LOG_ERR,
 400                     "Can't start new backup in NOT CONNECTED state.");
 401                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 402                 goto _error;
 403         }
 404 
 405         if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
 406                 if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
 407                         syslog(LOG_ERR, "Write protected device.");
 408                         reply.error = NDMP_WRITE_PROTECT_ERR;
 409                         goto _error;
 410                 }
 411         }
 412 
 413         if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) {
 414                 session->ns_butype = NDMP_BUTYPE_TAR;
 415         } else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) {
 416                 session->ns_butype = NDMP_BUTYPE_DUMP;
 417         } else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) {
 418                 session->ns_butype = NDMP_BUTYPE_ZFS;
 419         } else {
 420                 char msg_invalid[32];
 421                 char msg_types[32];
 422 
 423                 (void) snprintf(msg_invalid, 32, "Invalid backup type: %s.",
 424                     request->bu_type);
 425                 (void) snprintf(msg_types, 32,
 426                     "Supported backup types are tar, dump.");
 427 
 428                 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
 429                     msg_invalid);
 430                 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
 431                     msg_types);
 432                 syslog(LOG_ERR, "Invalid backup type: %s.",
 433                     request->bu_type);
 434                 syslog(LOG_ERR,
 435                     "Supported backup types are tar, dump.");
 436 
 437                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 438                 goto _error;
 439         }
 440 
 441         reply.error = ndmpd_tar_start_backup_v3(session,
 442             request->bu_type, request->env.env_val,
 443             request->env.env_len);
 444 
 445         /*
 446          * *_start_backup* sends the reply if the backup is
 447          * successfully started.  Otherwise, send the reply
 448          * containing the error here.
 449          */
 450 
 451 _error:
 452 
 453         if (reply.error != NDMP_NO_ERR) {
 454                 ndmp_send_reply(connection, &reply,
 455                     "sending data_start_backup_v3 reply");
 456                 ndmpd_data_cleanup(session);
 457         }
 458 }
 459 
 460 /*
 461  * ndmpd_data_start_recover_v3
 462  *
 463  * Request handler. Starts a restore.
 464  *
 465  * Parameters:
 466  *   connection (input) - connection handle.
 467  *   body       (input) - request message body.
 468  *
 469  * Returns:
 470  *   void
 471  */
 472 void
 473 ndmpd_data_start_recover_v3(ndmp_connection_t *connection, void *body)
 474 {
 475         ndmp_data_start_recover_request_v3 *request;
 476         ndmp_data_start_recover_reply_v3 reply;
 477         ndmpd_session_t *session = ndmp_get_client_data(connection);
 478 
 479         request = (ndmp_data_start_recover_request_v3 *)body;
 480 
 481         (void) memset((void*)&reply, 0, sizeof (reply));
 482 
 483         if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
 484                 syslog(LOG_ERR, "Can't start new recover in current state.");
 485                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 486                 goto _error;
 487         }
 488 
 489         if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) {
 490                 session->ns_butype = NDMP_BUTYPE_TAR;
 491         } else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) {
 492                 session->ns_butype = NDMP_BUTYPE_DUMP;
 493         } else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) {
 494                 session->ns_butype = NDMP_BUTYPE_ZFS;
 495         } else {
 496                 char msg_invalid[32];
 497                 char msg_types[32];
 498 
 499                 (void) snprintf(msg_invalid, 32, "Invalid backup type: %s.",
 500                     request->bu_type);
 501                 (void) snprintf(msg_types, 32,
 502                     "Supported backup types are tar, dump.");
 503 
 504                 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
 505                     msg_invalid);
 506                 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
 507                     msg_types);
 508                 syslog(LOG_ERR, "Invalid backup type: %s.",
 509                     request->bu_type);
 510                 syslog(LOG_ERR,
 511                     "Supported backup types are tar, dump.");
 512 
 513                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 514                 goto _error;
 515         }
 516 
 517         reply.error = ndmpd_tar_start_recover_v3(session,
 518             request->env.env_val, request->env.env_len,
 519             request->nlist.nlist_val, request->nlist.nlist_len);
 520 
 521         /*
 522          * *_start_recover* sends the reply if the recover is
 523          * successfully started.  Otherwise, send the reply
 524          * containing the error here.
 525          */
 526 
 527 _error:
 528 
 529         if (reply.error != NDMP_NO_ERR) {
 530                 ndmp_send_reply(connection, &reply,
 531                     "sending data_start_recover_v3 reply");
 532                 ndmpd_data_error(session, NDMP_DATA_HALT_INTERNAL_ERROR);
 533                 ndmpd_data_cleanup(session);
 534         }
 535 }
 536 
 537 /*
 538  * ndmpd_data_abort_v3
 539  *
 
 541  * state is not changed to the halted state until after the operation
 542  * has actually been aborted and the notify_halt request has been sent.
 543  *
 544  * Parameters:
 545  *   connection (input) - connection handle.
 546  *   body       (input) - request message body.
 547  *
 548  * Returns:
 549  *   void
 550  */
 551 /*ARGSUSED*/
 552 void
 553 ndmpd_data_abort_v3(ndmp_connection_t *connection, void *body)
 554 {
 555         ndmp_data_abort_reply reply;
 556         ndmpd_session_t *session = ndmp_get_client_data(connection);
 557 
 558         switch (session->ns_data.dd_state) {
 559         case NDMP_DATA_STATE_IDLE:
 560                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 561                 break;
 562 
 563         case NDMP_DATA_STATE_ACTIVE:
 564                 /*
 565                  * Don't go to HALTED state yet.  Need to wait for data
 566                  * operation to abort.  When this happens, ndmpd_done_v3
 567                  * will get called and will perform the halt processing.
 568                  */
 569                 reply.error = NDMP_NO_ERR;
 570                 session->ns_data.dd_abort = TRUE;
 571                 if (session->ns_data.dd_module.dm_abort_func)
 572                         (*session->ns_data.dd_module.dm_abort_func)(
 573                             session->ns_data.dd_module.dm_module_cookie);
 574                 break;
 575 
 576         case NDMP_DATA_STATE_HALTED:
 577         case NDMP_DATA_STATE_LISTEN:
 578         case NDMP_DATA_STATE_CONNECTED:
 579                 reply.error = NDMP_NO_ERR;
 580                 session->ns_data.dd_abort = TRUE;
 581                 ndmpd_data_error(session, NDMP_DATA_HALT_ABORTED);
 582                 break;
 583         default:
 584                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 585                 syslog(LOG_ERR, "Unknown data V3 state %d",
 586                     session->ns_data.dd_state);
 587         }
 588 
 589         ndmp_send_reply(connection, &reply,
 590             "sending data_abort_v3 reply");
 591 }
 592 
 593 
 594 /*
 595  * ndmpd_data_stop_v3
 596  *
 597  * Request handler. Stops the current data operation.
 598  *
 599  * Parameters:
 600  *   connection (input) - connection handle.
 601  *   body       (input) - request message body.
 602  *
 603  * Returns:
 604  *   void
 605  */
 606 /*ARGSUSED*/
 607 void
 608 ndmpd_data_stop_v3(ndmp_connection_t *connection, void *body)
 609 {
 610         ndmp_data_stop_reply reply;
 611         ndmpd_session_t *session = ndmp_get_client_data(connection);
 612 
 613         if (session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
 614                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 615                 ndmp_send_reply(connection, &reply,
 616                     "sending data_stop_v3 reply");
 617                 return;
 618         }
 619         ndmp_waitfor_op(session);
 620         ndmpd_data_cleanup(session);
 621         ndmpd_file_history_cleanup(session, FALSE);
 622 
 623         /* prepare for another data operation */
 624         (void) ndmpd_data_init(session);
 625         ndmpd_file_history_init(session);
 626 
 627         reply.error = NDMP_NO_ERR;
 628         ndmp_send_reply(connection, &reply,
 629             "sending data_stop_v3 reply");
 630 }
 631 
 632 
 633 /*
 
 641  *   body       (input) - request message body.
 642  *
 643  * Returns:
 644  *   void
 645  */
 646 void
 647 ndmpd_data_listen_v3(ndmp_connection_t *connection, void *body)
 648 {
 649         ndmp_data_listen_request_v3 *request;
 650         ndmp_data_listen_reply_v3 reply;
 651         ndmpd_session_t *session = ndmp_get_client_data(connection);
 652         ulong_t addr;
 653         ushort_t port;
 654 
 655         request = (ndmp_data_listen_request_v3 *)body;
 656 
 657         (void) memset((void*)&reply, 0, sizeof (reply));
 658 
 659         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 660                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 661                 syslog(LOG_ERR,
 662                     "Invalid internal data state to process listen request.");
 663         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
 664                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 665                 syslog(LOG_ERR,
 666                     "Invalid mover state to process listen request.");
 667         } else {
 668                 reply.error = NDMP_NO_ERR;
 669         }
 670 
 671         if (reply.error != NDMP_NO_ERR) {
 672                 ndmp_send_reply(connection, &reply,
 673                     "ndmp_data_listen_request_v3 reply");
 674                 return;
 675         }
 676 
 677         switch (request->addr_type) {
 678         case NDMP_ADDR_LOCAL:
 679                 reply.data_connection_addr.addr_type = request->addr_type;
 680                 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
 681                 break;
 682         case NDMP_ADDR_TCP:
 683                 if (create_listen_socket_v3(session, &addr, &port) < 0) {
 684                         reply.error = NDMP_IO_ERR;
 685                         break;
 686                 }
 687 
 688                 reply.error = NDMP_NO_ERR;
 689                 reply.data_connection_addr.addr_type = request->addr_type;
 690                 reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
 691                 reply.data_connection_addr.tcp_port_v3 = htons(port);
 692                 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
 693                 session->ns_data.dd_data_addr.tcp_ip_v3 = addr;
 694                 session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(port);
 695                 syslog(LOG_DEBUG, "listen_socket: %d",
 696                     session->ns_data.dd_listen_sock);
 697                 break;
 698 
 699         default:
 700                 syslog(LOG_ERR, "Invalid address type: %d",
 701                     request->addr_type);
 702                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 703                 break;
 704         }
 705 
 706         if (reply.error == NDMP_NO_ERR)
 707                 session->ns_data.dd_state = NDMP_DATA_STATE_LISTEN;
 708 
 709         ndmp_send_reply(connection, &reply,
 710             "ndmp_data_listen_request_v3 reply");
 711 }
 712 
 713 
 714 /*
 715  * ndmpd_data_connect_v3
 716  *
 717  * Request handler. Connects the data server to either a local
 718  * or remote mover.
 719  *
 720  * Parameters:
 721  *   connection (input) - connection handle.
 722  *   body       (input) - request message body.
 723  *
 724  * Returns:
 725  *   void
 726  */
 727 void
 728 ndmpd_data_connect_v3(ndmp_connection_t *connection, void *body)
 729 {
 730         ndmp_data_connect_request_v3 *request;
 731         ndmp_data_connect_reply_v3 reply;
 732         ndmpd_session_t *session = ndmp_get_client_data(connection);
 733 
 734         request = (ndmp_data_connect_request_v3 *)body;
 735 
 736         (void) memset((void*)&reply, 0, sizeof (reply));
 737 
 738         if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
 739                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 740                 syslog(LOG_ERR, "Invalid address type %d",
 741                     request->addr.addr_type);
 742         } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 743                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 744         } else {
 745                 reply.error = NDMP_NO_ERR;
 746         }
 747 
 748         if (reply.error != NDMP_NO_ERR) {
 749                 ndmp_send_reply(connection, &reply,
 750                     "sending ndmp_data_connect_v3 reply");
 751                 return;
 752         }
 753 
 754         switch (request->addr.addr_type) {
 755         case NDMP_ADDR_LOCAL:
 756                 /*
 757                  * Verify that the mover is listening for a
 758                  * local connection
 759                  */
 760                 if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN ||
 761                     session->ns_mover.md_listen_sock != -1) {
 762                         reply.error = NDMP_ILLEGAL_STATE_ERR;
 763                         syslog(LOG_ERR,
 764                             "Mover is not in local listen state.");
 765                 } else {
 766                         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
 767                 }
 768                 break;
 769 
 770         case NDMP_ADDR_TCP:
 771                 reply.error = data_connect_sock_v3(session,
 772                     request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
 773                 break;
 774 
 775         default:
 776                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 777                 syslog(LOG_ERR, "Invalid address type %d",
 778                     request->addr.addr_type);
 779         }
 780 
 781         if (reply.error == NDMP_NO_ERR)
 782                 session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
 783 
 784         ndmp_send_reply(connection, &reply,
 785             "sending ndmp_data_connect_v3 reply");
 786 }
 787 
 788 
 789 /*
 790  * ************************************************************************
 791  * NDMP V4 HANDLERS
 792  * ************************************************************************
 793  */
 794 
 795 /*
 796  * ndmpd_data_get_env_v4
 797  *
 
 800  * a backup operation is in progress.
 801  *
 802  * Parameters:
 803  *   connection (input) - connection handle.
 804  *   body       (input) - request message body.
 805  *
 806  * Returns:
 807  *   void
 808  */
 809 /*ARGSUSED*/
 810 void
 811 ndmpd_data_get_env_v4(ndmp_connection_t *connection, void *body)
 812 {
 813         ndmp_data_get_env_reply reply;
 814         ndmpd_session_t *session = ndmp_get_client_data(connection);
 815 
 816         (void) memset((void*)&reply, 0, sizeof (reply));
 817 
 818         if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE &&
 819             session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
 820                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 821                 reply.env.env_len = 0;
 822         } else if (session->ns_data.dd_operation != NDMP_DATA_OP_BACKUP) {
 823                 syslog(LOG_ERR, "Backup operation not active.");
 824                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 825                 reply.env.env_len = 0;
 826         } else {
 827                 reply.error = NDMP_NO_ERR;
 828                 reply.env.env_len = session->ns_data.dd_env_len;
 829                 reply.env.env_val = session->ns_data.dd_env;
 830         }
 831 
 832         ndmp_send_reply(connection, &reply, "sending data_get_env reply");
 833 }
 834 
 835 /*
 836  * ndmpd_data_get_state_v4
 837  *
 838  * Request handler. Returns current data state.
 839  *
 840  * Parameters:
 841  *   connection (input) - connection handle.
 842  *   body       (input) - request message body.
 843  *
 
 891  * Parameters:
 892  *   connection (input) - connection handle.
 893  *   body       (input) - request message body.
 894  *
 895  * Returns:
 896  *   void
 897  */
 898 void
 899 ndmpd_data_connect_v4(ndmp_connection_t *connection, void *body)
 900 {
 901         ndmp_data_connect_request_v4 *request;
 902         ndmp_data_connect_reply_v4 reply;
 903         ndmpd_session_t *session = ndmp_get_client_data(connection);
 904 
 905         request = (ndmp_data_connect_request_v4 *)body;
 906 
 907         (void) memset((void*)&reply, 0, sizeof (reply));
 908 
 909         if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
 910                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 911                 syslog(LOG_ERR, "Invalid address type %d",
 912                     request->addr.addr_type);
 913         } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 914                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 915         } else {
 916                 reply.error = NDMP_NO_ERR;
 917         }
 918 
 919         if (reply.error != NDMP_NO_ERR) {
 920                 ndmp_send_reply(connection, &reply,
 921                     "sending ndmp_data_connect_v4 reply");
 922                 return;
 923         }
 924 
 925         switch (request->addr.addr_type) {
 926         case NDMP_ADDR_LOCAL:
 927                 /*
 928                  * Verify that the mover is listening for a
 929                  * local connection
 930                  */
 931                 if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN ||
 932                     session->ns_mover.md_listen_sock != -1) {
 933                         reply.error = NDMP_ILLEGAL_STATE_ERR;
 934                         syslog(LOG_ERR,
 935                             "Mover is not in local listen state.");
 936                 } else {
 937                         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
 938                 }
 939                 break;
 940 
 941         case NDMP_ADDR_TCP:
 942                 reply.error = data_connect_sock_v3(session,
 943                     request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
 944                 break;
 945 
 946         default:
 947                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 948                 syslog(LOG_ERR, "Invalid address type %d",
 949                     request->addr.addr_type);
 950         }
 951 
 952         if (reply.error == NDMP_NO_ERR)
 953                 session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
 954 
 955         ndmp_send_reply(connection, &reply,
 956             "sending ndmp_data_connect_v4 reply");
 957 }
 958 
 959 /*
 960  * ndmpd_data_listen_v4
 961  *
 962  * Request handler. Configures the server to listen for a connection
 963  * from a remote mover.
 964  *
 965  * Parameters:
 966  *   connection (input) - connection handle.
 967  *   body       (input) - request message body.
 968  *
 969  * Returns:
 970  *   void
 971  */
 972 void
 973 ndmpd_data_listen_v4(ndmp_connection_t *connection, void *body)
 974 {
 975         ndmp_data_listen_request_v4 *request;
 976         ndmp_data_listen_reply_v4 reply;
 977         ndmpd_session_t *session = ndmp_get_client_data(connection);
 978         ulong_t addr;
 979         ushort_t port;
 980 
 981         request = (ndmp_data_listen_request_v4 *)body;
 982 
 983         (void) memset((void*)&reply, 0, sizeof (reply));
 984 
 985         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 986                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 987                 syslog(LOG_ERR,
 988                     "Invalid internal data state to process listen request.");
 989         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
 990                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 991                 syslog(LOG_ERR,
 992                     "Invalid mover state to process listen request.");
 993         } else {
 994                 reply.error = NDMP_NO_ERR;
 995         }
 996 
 997         if (reply.error != NDMP_NO_ERR) {
 998                 ndmp_send_reply(connection, &reply,
 999                     "ndmp_data_listen_request_v4 reply");
1000                 return;
1001         }
1002 
1003         switch (request->addr_type) {
1004         case NDMP_ADDR_LOCAL:
1005                 reply.connect_addr.addr_type = request->addr_type;
1006                 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
1007                 break;
1008         case NDMP_ADDR_TCP:
1009                 if (create_listen_socket_v3(session, &addr, &port) < 0) {
1010                         reply.error = NDMP_IO_ERR;
1011                         break;
 
1015                 reply.connect_addr.addr_type = request->addr_type;
1016                 reply.connect_addr.tcp_addr_v4 =
1017                     ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1018 
1019                 reply.connect_addr.tcp_ip_v4(0) = htonl(addr);
1020                 reply.connect_addr.tcp_port_v4(0) = htons(port);
1021                 reply.connect_addr.tcp_len_v4 = 1;
1022 
1023                 session->ns_data.dd_data_addr_v4.addr_type = NDMP_ADDR_TCP;
1024                 session->ns_data.dd_data_addr_v4.tcp_addr_v4 =
1025                     ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1026 
1027                 session->ns_data.dd_data_addr_v4.tcp_ip_v4(0) = addr;
1028                 session->ns_data.dd_data_addr_v4.tcp_port_v4(0) = ntohs(port);
1029                 session->ns_data.dd_data_addr_v4.tcp_len_v4 = 1;
1030 
1031                 /* Copy that to data_addr for compatibility */
1032                 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
1033                 session->ns_data.dd_data_addr.tcp_ip_v3 = addr;
1034                 session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(port);
1035                 syslog(LOG_DEBUG, "listen_socket: %d",
1036                     session->ns_data.dd_listen_sock);
1037                 break;
1038 
1039         default:
1040                 syslog(LOG_ERR, "Invalid address type: %d",
1041                     request->addr_type);
1042                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1043                 break;
1044         }
1045 
1046         if (reply.error == NDMP_NO_ERR)
1047                 session->ns_data.dd_state = NDMP_DATA_STATE_LISTEN;
1048 
1049         ndmp_send_reply(connection, &reply,
1050             "ndmp_data_listen_request_v4 reply");
1051 }
1052 
1053 
1054 /*
1055  * ndmpd_data_start_recover_filehist_v4
1056  *
1057  * Request handler. Recovers the file history (not supported yet)
1058  * This command has an optional support in V4.
1059  *
1060  * Parameters:
1061  *   connection (input) - connection handle.
1062  *   body       (input) - request message body.
1063  *
1064  * Returns:
1065  *   void
1066  */
1067 /*ARGSUSED*/
1068 void
1069 ndmpd_data_start_recover_filehist_v4(ndmp_connection_t *connection, void *body)
1070 {
1071         ndmp_data_start_recover_filehist_reply_v4 reply;
1072 
1073         syslog(LOG_DEBUG, "Request not supported");
1074         reply.error = NDMP_NOT_SUPPORTED_ERR;
1075 
1076         ndmp_send_reply(connection, &reply,
1077             "sending ndmp_data_start_recover_filehist_reply_v4 reply");
1078 }
1079 
1080 /*
1081  * ************************************************************************
1082  * LOCALS
1083  * ************************************************************************
1084  */
1085 
1086 /*
1087  * ndmpd_data_error_send
1088  *
1089  * This function sends the notify message to the client.
1090  *
1091  * Parameters:
1092  *   session (input) - session pointer.
1093  *   reason  (input) - halt reason.
 
1159                 /*
1160                  * Send/discard any buffered file history data.
1161                  */
1162                 ndmpd_file_history_cleanup(session,
1163                     (reason == NDMP_DATA_HALT_SUCCESSFUL ? TRUE : FALSE));
1164 
1165                 /*
1166                  * If mover local and successful backup, write any
1167                  * remaining buffered data to tape.
1168                  */
1169                 if (session->ns_data.dd_data_addr.addr_type
1170                     == NDMP_ADDR_LOCAL && reason == NDMP_DATA_HALT_SUCCESSFUL)
1171                         (void) ndmpd_local_write_v3(session, 0, 0);
1172         }
1173 
1174         session->ns_data.dd_state = NDMP_DATA_STATE_HALTED;
1175         session->ns_data.dd_halt_reason = reason;
1176 
1177         if (session->ns_protocol_version == NDMPV4) {
1178                 if (ndmpd_data_error_send_v4(session, reason) < 0)
1179                         syslog(LOG_ERR,
1180                             "Error sending notify_data_halted request");
1181         } else {
1182                 if (ndmpd_data_error_send(session, reason) < 0)
1183                         syslog(LOG_ERR,
1184                             "Error sending notify_data_halted request");
1185         }
1186 
1187         if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP) {
1188                 if (session->ns_data.dd_sock != -1) {
1189                         (void) ndmpd_remove_file_handler(session,
1190                             session->ns_data.dd_sock);
1191                         /*
1192                          * ndmpcopy: we use the same socket for the mover,
1193                          * so expect to close when mover is done!
1194                          */
1195                         if (session->ns_data.dd_sock !=
1196                             session->ns_mover.md_sock)
1197                                 (void) close(session->ns_data.dd_sock);
1198 
1199                         session->ns_data.dd_sock = -1;
1200                 }
1201                 if (session->ns_data.dd_listen_sock != -1) {
1202                         (void) ndmpd_remove_file_handler(session,
1203                             session->ns_data.dd_listen_sock);
 
1221  * Parameters:
1222  *   cookie  (input) - session pointer.
1223  *   fd      (input) - file descriptor.
1224  *   mode    (input) - select mode.
1225  *
1226  * Returns:
1227  *   void
1228  */
1229 /*ARGSUSED*/
1230 static void
1231 data_accept_connection_v3(void *cookie, int fd, ulong_t mode)
1232 {
1233         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1234         int from_len;
1235         struct sockaddr_in from;
1236 
1237         from_len = sizeof (from);
1238         session->ns_data.dd_sock = accept(fd, (struct sockaddr *)&from,
1239             &from_len);
1240 
1241         syslog(LOG_DEBUG, "sock fd: %d",
1242             session->ns_data.dd_sock);
1243         syslog(LOG_DEBUG, "sin: port %d addr %s",
1244             ntohs(from.sin_port),
1245             inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
1246 
1247         (void) ndmpd_remove_file_handler(session, fd);
1248         (void) close(session->ns_data.dd_listen_sock);
1249         session->ns_data.dd_listen_sock = -1;
1250 
1251         if (session->ns_data.dd_sock < 0) {
1252                 syslog(LOG_ERR, "Accept error: %m");
1253                 ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1254                 return;
1255         }
1256 
1257         /*
1258          * Save the peer address.
1259          */
1260         session->ns_data.dd_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
1261         session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(from.sin_port);
1262 
1263         /* Set the parameter of the new socket */
1264         set_socket_options(session->ns_data.dd_sock);
1265 
1266         session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1267 }
1268 
1269 
1270 /*
1271  * create_listen_socket_v3
1272  *
 
1275  */
1276 static int
1277 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
1278 {
1279         session->ns_data.dd_listen_sock = ndmp_create_socket(addr, port);
1280         if (session->ns_data.dd_listen_sock < 0)
1281                 return (-1);
1282 
1283         /*
1284          * Add a file handler for the listen socket.
1285          * ndmpd_select will call data_accept_connection when a
1286          * connection is ready to be accepted.
1287          */
1288         if (ndmpd_add_file_handler(session, (void*)session,
1289             session->ns_data.dd_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
1290             data_accept_connection_v3) < 0) {
1291                 (void) close(session->ns_data.dd_listen_sock);
1292                 session->ns_data.dd_listen_sock = -1;
1293                 return (-1);
1294         }
1295         syslog(LOG_DEBUG, "addr: %s:%d",
1296             inet_ntoa(IN_ADDR(*addr)), ntohs(*port));
1297 
1298         return (0);
1299 }
1300 
1301 
1302 /*
1303  * data_connect_sock_v3
1304  *
1305  * Connect the data interface socket to the specified ip/port
1306  *
1307  * Parameters:
1308  *   session (input) - session pointer.
1309  *   addr    (input) - IP address
1310  *   port    (input) - port number
1311  *
1312  * Returns:
1313  *   NDMP_NO_ERR - backup successfully started.
1314  *   otherwise - error code of backup start error.
1315  */
 
1337  * Start the backup work
1338  *
1339  * Parameters:
1340  *   session   (input) - session pointer.
1341  *   bu_type   (input) - backup type.
1342  *   env_val   (input) - environment variable array.
1343  *   env_len   (input) - length of env_val.
1344  *
1345  * Returns:
1346  *   NDMP_NO_ERR - backup successfully started.
1347  *   otherwise - error code of backup start error.
1348  */
1349 static ndmp_error
1350 ndmpd_tar_start_backup_v3(ndmpd_session_t *session, char *bu_type,
1351     ndmp_pval *env_val, ulong_t env_len)
1352 {
1353         int err;
1354         ndmp_lbr_params_t *nlp;
1355         ndmpd_module_params_t *params;
1356         ndmp_data_start_backup_reply_v3 reply;
1357         pthread_t tid;
1358 
1359         (void) memset((void*)&reply, 0, sizeof (reply));
1360 
1361         err = ndmpd_save_env(session, env_val, env_len);
1362         if (err != NDMP_NO_ERR)
1363                 return (err);
1364 
1365         nlp = ndmp_get_nlp(session);
1366         NDMP_FREE(nlp->nlp_params);
1367         params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1368         if (!params)
1369                 return (NDMP_NO_MEM_ERR);
1370 
1371         params->mp_daemon_cookie = (void *)session;
1372         params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1373         params->mp_protocol_version = session->ns_protocol_version;
1374         params->mp_operation = NDMP_DATA_OP_BACKUP;
1375         params->mp_get_env_func = ndmpd_api_get_env;
1376         params->mp_add_env_func = ndmpd_api_add_env;
1377         params->mp_set_env_func = ndmpd_api_set_env;
 
1407         } else {
1408                 NLP_UNSET(nlp, NLPF_DUMP);
1409                 NLP_UNSET(nlp, NLPF_TAR);
1410         }
1411 
1412         session->ns_data.dd_module.dm_start_func = ndmpd_tar_backup_starter_v3;
1413         session->ns_data.dd_module.dm_abort_func = ndmpd_tar_backup_abort_v3;
1414 
1415         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1416         session->ns_data.dd_module.dm_stats.ms_est_time_remaining  = 0;
1417         session->ns_data.dd_nlist_v3 = 0;
1418         session->ns_data.dd_nlist_len = 0;
1419         session->ns_data.dd_bytes_left_to_read = 0;
1420         session->ns_data.dd_position = 0;
1421         session->ns_data.dd_discard_length = 0;
1422         session->ns_data.dd_read_offset = 0;
1423         session->ns_data.dd_read_length = 0;
1424 
1425         reply.error = ndmp_backup_get_params_v3(session, params);
1426         if (reply.error != NDMP_NO_ERR) {
1427                 syslog(LOG_ERR, "err: %d", err);
1428                 NDMP_FREE(nlp->nlp_params);
1429                 return (reply.error);
1430         }
1431 
1432         reply.error = NDMP_NO_ERR;
1433         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1434             &reply) < 0) {
1435                 syslog(LOG_DEBUG, "Sending data_start_backup_v3 reply");
1436                 return (NDMP_NO_ERR);
1437         }
1438 
1439         NS_INC(nbk);
1440         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1441         session->ns_data.dd_operation = NDMP_DATA_OP_BACKUP;
1442         session->ns_data.dd_abort = FALSE;
1443 
1444         /*
1445          * perform the backup
1446          *
1447          * Cannot wait for the thread to exit as we are replying to the
1448          * client request here.
1449          */
1450         err = pthread_create(&tid, NULL,
1451             (funct_t)session->ns_data.dd_module.dm_start_func,
1452             params);
1453 
1454         if (err != 0) {
1455                 syslog(LOG_ERR, "Can't start V3 backup session.");
1456                 return (NDMP_ILLEGAL_ARGS_ERR);
1457         }
1458 
1459         (void) pthread_detach(tid);
1460 
1461         return (NDMP_NO_ERR);
1462 }
1463 
1464 /*
1465  * ndmpd_tar_start_recover_v3
1466  *
1467  * Start the restore work
1468  *
1469  * Parameters:
1470  *   session   (input) - session pointer.
1471  *   bu_type   (input) - backup type.
1472  *   env_val   (input) - environment variable array.
1473  *   env_len   (input) - length of env_val.
1474  *   nlist_val (input) - list of files.
1475  *   nlist_len (input) - length of nlist_val.
1476  *
1477  * Returns:
1478  *   NDMP_NO_ERR - recover successfully started.
1479  *   otherwise   - error code of recover start error.
1480  */
1481 static ndmp_error
1482 ndmpd_tar_start_recover_v3(ndmpd_session_t *session,
1483     ndmp_pval *env_val, ulong_t env_len, ndmp_name_v3 *nlist_val,
1484     ulong_t nlist_len)
1485 {
1486         ndmp_data_start_recover_reply_v3 reply;
1487         ndmpd_module_params_t *params;
1488         ndmp_lbr_params_t *nlp;
1489         pthread_t tid;
1490         int err;
1491 
1492         (void) memset((void*)&reply, 0, sizeof (reply));
1493 
1494         nlp = ndmp_get_nlp(session);
1495         NDMP_FREE(nlp->nlp_params);
1496         params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1497         if (!params) {
1498                 return (NDMP_NO_MEM_ERR);
1499         }
1500 
1501         reply.error = ndmpd_save_env(session, env_val, env_len);
1502         if (reply.error != NDMP_NO_ERR) {
1503                 NDMP_FREE(nlp->nlp_params);
1504                 return (NDMP_NO_MEM_ERR);
1505         }
1506 
1507         reply.error = ndmpd_save_nlist_v3(session, nlist_val, nlist_len);
1508         if (reply.error != NDMP_NO_ERR) {
1509                 NDMP_FREE(nlp->nlp_params);
 
1546         session->ns_data.dd_module.dm_abort_func = ndmpd_tar_restore_abort_v3;
1547         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1548         session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1549         session->ns_data.dd_bytes_left_to_read = 0;
1550         session->ns_data.dd_position = 0;
1551         session->ns_data.dd_discard_length = 0;
1552         session->ns_data.dd_read_offset = 0;
1553         session->ns_data.dd_read_length = 0;
1554 
1555         err = ndmp_restore_get_params_v3(session, params);
1556         if (err != NDMP_NO_ERR) {
1557                 NDMP_FREE(nlp->nlp_params);
1558                 return (err);
1559         }
1560 
1561         reply.error = NDMP_NO_ERR;
1562         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1563             &reply) < 0) {
1564                 NDMP_FREE(nlp->nlp_params);
1565                 ndmpd_free_nlist_v3(session);
1566                 syslog(LOG_ERR,
1567                     "Error sending ndmp_data_start_recover_reply");
1568                 ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1569                 return (NDMP_NO_ERR);
1570         }
1571 
1572         NS_INC(nrs);
1573         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1574         session->ns_data.dd_operation = NDMP_DATA_OP_RECOVER;
1575         session->ns_data.dd_abort = FALSE;
1576 
1577         /*
1578          * perform the restore
1579          *
1580          * Cannot wait for the thread to exit as we are replying to the
1581          * client request here.
1582          */
1583         err = pthread_create(&tid, NULL,
1584             (funct_t)session->ns_data.dd_module.dm_start_func,
1585             params);
1586 
1587         if (err != 0) {
1588                 syslog(LOG_ERR, "Can't start V3 recover session.");
1589                 return (NDMP_ILLEGAL_ARGS_ERR);
1590         }
1591 
1592         (void) pthread_detach(tid);
1593 
1594         return (NDMP_NO_ERR);
1595 }
1596 
1597 /*
1598  * discard_data_v3
1599  *
1600  * Read and discard data from the data connection.
1601  * Called when a module has called ndmpd_seek() prior to
1602  * reading all of the data from the previous seek.
1603  *
1604  * Parameters:
1605  *   session (input) - session pointer.
1606  *
1607  * Returns:
1608  *   number of bytes read and discarded.
1609  *  -1 - error.
1610  */
1611 static int
1612 discard_data_v3(ndmpd_session_t *session, ulong_t length)
1613 {
1614         static char buf[MAX_RECORD_SIZE];
1615         int n, toread;
1616 
1617         toread = (length < MAX_RECORD_SIZE) ? length :
1618             MAX_RECORD_SIZE;
1619 
1620         /* Read and discard the data. */
1621         n = read(session->ns_data.dd_sock, buf, toread);
1622         if (n < 0) {
1623                 syslog(LOG_ERR, "Socket read error: %m.");
1624                 n = -1;
1625         }
1626 
1627         return (n);
1628 }
1629 
1630 
1631 /*
1632  * ndmpd_remote_read_v3
1633  *
1634  * Reads data from the remote mover.
1635  *
1636  * Parameters:
1637  *   session (input) - session pointer.
1638  *   data    (input) - data to be written.
1639  *   length  (input) - data length.
1640  *
1641  * Returns:
1642  *   0 - data successfully read.
1643  *  -1 - error.
1644  */
1645 int
1646 ndmpd_remote_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
1647 {
1648         ulong_t count;
1649         ulong_t len;
1650         ssize_t n;
1651         ndmp_notify_data_read_request request;
1652         tlm_job_stats_t *jstat;
1653         longlong_t fsize;
1654 
1655         count = 0;
1656         while (count < length) {
1657                 len = length - count;
1658 
1659                 /*
1660                  * If the end of the seek window has been reached then
1661                  * send an ndmp_read request to the client.
1662                  * The NDMP client will then send a mover_data_read request to
1663                  * the remote mover and the mover will send more data.
1664                  * This condition can occur if the module attempts to read past
1665                  * a seek window set via a prior call to ndmpd_seek() or
1666                  * the module has not issued a seek. If no seek was issued then
1667                  * pretend that a seek was issued to read the entire tape.
1668                  */
1669                 if (session->ns_data.dd_bytes_left_to_read == 0) {
1670                         /* ndmpd_seek() never called? */
1671                         if (session->ns_data.dd_read_length == 0) {
1672                                 session->ns_data.dd_bytes_left_to_read = ~0LL;
1673                                 session->ns_data.dd_read_offset = 0LL;
1674                                 session->ns_data.dd_read_length = ~0LL;
1675                         } else {
1676                                 /*
1677                                  * While restoring a file, restoreFile()
1678                                  * records the number of bytes still need to
1679                                  * be restored.  We use this as a guidance
1680                                  * when asking for data from the tape.
1681                                  */
1682                                 jstat = session->ns_ndmp_lbr_params->nlp_jstat;
1683                                 fsize = jstat->js_bytes_in_file;
1684 
1685                                 /*
1686                                  * Fall back to the old way if fsize if too
1687                                  * small.
1688                                  */
1689                                 if (fsize < len)
1690                                         fsize = len;
1691 
1692                                 session->ns_data.dd_bytes_left_to_read = fsize;
1693                                 session->ns_data.dd_read_offset =
1694                                     session->ns_data.dd_position;
1695                                 session->ns_data.dd_read_length = fsize;
1696                         }
1697 
1698                         request.offset =
1699                             long_long_to_quad(session->ns_data.dd_read_offset);
1700                         request.length =
1701                             long_long_to_quad(session->ns_data.dd_read_length);
1702 
1703                         syslog(LOG_DEBUG, "to NOTIFY_DATA_READ [%lu, %lu]",
1704                             session->ns_data.dd_read_offset,
1705                             session->ns_data.dd_read_length);
1706 
1707                         if (ndmp_send_request_lock(session->ns_connection,
1708                             NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1709                             &request, 0) < 0) {
1710                                 syslog(LOG_ERR,
1711                                     "Sending notify_data_read request");
1712                                 return (-1);
1713                         }
1714                 }
1715 
1716                 /*
1717                  * If the module called ndmpd_seek() prior to reading all of the
1718                  * data that the remote mover was requested to send, then the
1719                  * excess data from the seek has to be discarded.
1720                  */
1721                 if (session->ns_data.dd_discard_length != 0) {
1722                         n = discard_data_v3(session,
1723                             (ulong_t)session->ns_data.dd_discard_length);
1724                         if (n < 0)
1725                                 return (-1);
1726 
1727                         session->ns_data.dd_discard_length -= n;
1728                         continue;
1729                 }
1730 
1731                 /*
1732                  * Don't attempt to read more data than the remote is sending.
1733                  */
1734                 if (len > session->ns_data.dd_bytes_left_to_read)
1735                         len = session->ns_data.dd_bytes_left_to_read;
1736 
1737                 if ((n = read(session->ns_data.dd_sock, &data[count],
1738                     len)) < 0) {
1739                         syslog(LOG_ERR, "Socket read error: %m.");
1740                         return (-1);
1741                 }
1742 
1743                 /* read returns 0 if the connection was closed */
1744                 if (n == 0) {
1745                         syslog(LOG_ERR, "n 0 errno %d",
1746                             errno);
1747                         return (-1);
1748                 }
1749 
1750                 count += n;
1751                 session->ns_data.dd_bytes_left_to_read -= n;
1752                 session->ns_data.dd_position += n;
1753         }
1754         return (0);
1755 }
1756 
1757 /*
1758  * nlp_release_job_stat
1759  *
1760  * Unreference the job statistics
1761  *
1762  * Parameters:
1763  *   session (input) - session pointer.
1764  *
1765  * Returns:
1766  *   void
1767  */
1768 static void
1769 nlp_release_job_stat(ndmpd_session_t *session)
1770 {
1771         ndmp_lbr_params_t *nlp;
1772 
1773         if ((nlp = ndmp_get_nlp(session)) == NULL) {
1774                 return;
1775         }
1776         if (nlp->nlp_jstat != NULL) {
1777                 nlp->nlp_bytes_total =
1778                     (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
1779                 tlm_un_ref_job_stats(nlp->nlp_jstat->js_job_name);
1780                 nlp->nlp_jstat = NULL;
1781         }
1782 }
1783 
1784 
1785 /* *** ndmpd global internal functions *********************************** */
1786 
1787 /*
1788  * ndmpd_data_init
1789  *
1790  * Initializes data specific session variables.
1791  *
1792  * Parameters:
1793  *   session (input) - session pointer.
1794  *
1795  * Returns:
1796  *   void
1797  */
1798 int
1799 ndmpd_data_init(ndmpd_session_t *session)
1800 {
1801         session->ns_data.dd_operation = NDMP_DATA_OP_NOACTION;
 
1825         return (0);
1826 }
1827 
1828 
1829 
1830 /*
1831  * ndmpd_data_cleanup
1832  *
1833  * Releases resources allocated during a data operation.
1834  *
1835  * Parameters:
1836  *   session (input) - session pointer.
1837  *
1838  * Returns:
1839  *   void
1840  */
1841 void
1842 ndmpd_data_cleanup(ndmpd_session_t *session)
1843 {
1844         if (session->ns_data.dd_listen_sock != -1) {
1845                 syslog(LOG_DEBUG, "data.listen_sock: %d",
1846                     session->ns_data.dd_listen_sock);
1847                 (void) ndmpd_remove_file_handler(session,
1848                     session->ns_data.dd_listen_sock);
1849                 (void) close(session->ns_data.dd_listen_sock);
1850                 session->ns_data.dd_listen_sock = -1;
1851         }
1852         if (session->ns_data.dd_sock != -1) {
1853                 syslog(LOG_ERR, "data.sock: %d",
1854                     session->ns_data.dd_sock);
1855 
1856                 /*
1857                  * ndmpcopy: we use the same socket for the mover,
1858                  * so expect to close when mover is done!
1859                  */
1860                 if (session->ns_data.dd_sock != session->ns_mover.md_sock)
1861                         (void) close(session->ns_data.dd_sock);
1862 
1863                 session->ns_data.dd_sock = -1;
1864         }
1865 
1866         ndmpd_free_env(session);
1867         ndmpd_free_nlist(session);
1868 }
1869 
1870 
1871 /*
1872  * ndmp_data_get_mover_mode
1873  *
 
1885 {
1886         char *rv;
1887 
1888         switch (session->ns_protocol_version) {
1889         case NDMPV2:
1890                 rv = ((session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP)
1891                     ? "remote" : "local");
1892                 break;
1893         case NDMPV3:
1894                 rv = ((session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP)
1895                     ? "remote" : "local");
1896                 break;
1897         case NDMPV4:
1898                 rv = ((session->ns_data.dd_data_addr.addr_type ==
1899                     NDMP_ADDR_TCP ||
1900                     (session->ns_data.dd_data_addr_v4.addr_type ==
1901                     NDMP_ADDR_TCP)) ? "remote" : "local");
1902                 break;
1903         default:
1904                 rv = "Unknown";
1905                 syslog(LOG_ERR, "Invalid protocol version %d.",
1906                     session->ns_protocol_version);
1907         }
1908 
1909         return (rv);
1910 }
1911 
1912 /* *** static functions ******************************************** */
1913 
1914 /*
1915  * ndmpd_tar_start_backup_v2
1916  *
1917  * Request handling code common to version 1 and
1918  * version 2 data_start_backup request handlers.
1919  *
1920  * Parameters:
1921  *   session   (input) - session pointer.
1922  *   bu_type   (input) - backup type.
1923  *   env_val   (input) - environment variable array.
1924  *   env_len   (input) - length of env_val.
1925  *
1926  * Returns:
1927  *   NDMP_NO_ERR - backup successfully started.
1928  *   otherwise - error code of backup start error.
1929  */
1930 static ndmp_error
1931 ndmpd_tar_start_backup_v2(ndmpd_session_t *session, char *bu_type,
1932     ndmp_pval *env_val, ulong_t env_len)
1933 {
1934         ndmp_data_start_backup_reply reply;
1935         ndmpd_module_params_t *params;
1936         ndmp_lbr_params_t *nlp;
1937         pthread_t tid;
1938         int err;
1939 
1940         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1941                 syslog(LOG_ERR, "Can't start new backup in current state.");
1942                 return (NDMP_ILLEGAL_STATE_ERR);
1943         }
1944         if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
1945             strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
1946                 syslog(LOG_ERR, "Invalid backup type: %s.", bu_type);
1947                 syslog(LOG_ERR, "Supported backup types are tar and dump.");
1948                 return (NDMP_ILLEGAL_ARGS_ERR);
1949         }
1950         if ((err = ndmpd_save_env(session, env_val, env_len)) != NDMP_NO_ERR)
1951                 return (err);
1952 
1953         nlp = ndmp_get_nlp(session);
1954         NDMP_FREE(nlp->nlp_params);
1955         params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1956         if (params == NULL)
1957                 return (NDMP_NO_MEM_ERR);
1958 
1959         params->mp_daemon_cookie = (void *)session;
1960         params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1961         params->mp_protocol_version = session->ns_protocol_version;
1962         params->mp_operation = NDMP_DATA_OP_BACKUP;
1963         params->mp_get_env_func = ndmpd_api_get_env;
1964         params->mp_add_env_func = ndmpd_api_add_env;
1965         params->mp_get_name_func = ndmpd_api_get_name;
1966         params->mp_dispatch_func = ndmpd_api_dispatch;
1967         params->mp_done_func = ndmpd_api_done_v2;
 
1988                     ndmpd_api_file_history_path_v2;
1989                 params->mp_file_history_dir_func = 0;
1990                 params->mp_file_history_node_func = 0;
1991         } else {
1992                 NLP_UNSET(nlp, NLPF_DUMP);
1993                 NLP_UNSET(nlp, NLPF_TAR);
1994         }
1995 
1996         session->ns_data.dd_module.dm_start_func = ndmpd_tar_backup_starter;
1997         session->ns_data.dd_module.dm_abort_func = ndmpd_tar_backup_abort;
1998 
1999         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
2000         session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
2001         session->ns_data.dd_nlist = 0;
2002         session->ns_data.dd_nlist_len = 0;
2003         session->ns_data.dd_read_offset = 0;
2004         session->ns_data.dd_read_length = 0;
2005 
2006         if ((err = ndmp_backup_extract_params(session,
2007             params)) != NDMP_NO_ERR) {
2008                 syslog(LOG_ERR, "err: %d", err);
2009                 NDMP_FREE(nlp->nlp_params);
2010                 return (err);
2011         }
2012 
2013         err = ndmpd_mover_connect(session, NDMP_MOVER_MODE_READ);
2014         if (err != NDMP_NO_ERR) {
2015                 syslog(LOG_ERR,
2016                     "mover connect err: %d", err);
2017                 NDMP_FREE(nlp->nlp_params);
2018                 return (err);
2019         }
2020 
2021         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
2022 
2023         session->ns_data.dd_operation = NDMP_DATA_OP_BACKUP;
2024         session->ns_data.dd_abort = FALSE;
2025 
2026         syslog(LOG_DEBUG, "starting backup");
2027 
2028         reply.error = NDMP_NO_ERR;
2029         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
2030             &reply) < 0) {
2031                 syslog(LOG_DEBUG, "Sending data_start_backup reply");
2032                 NDMP_FREE(nlp->nlp_params);
2033                 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
2034                         /*
2035                          * ndmpcopy: we use the same socket for the mover,
2036                          * so expect to close when mover is done!
2037                          */
2038                         if (session->ns_data.dd_sock !=
2039                             session->ns_mover.md_sock)
2040                                 (void) close(session->ns_data.dd_sock);
2041 
2042                         session->ns_data.dd_sock = -1;
2043                 } else
2044                         ndmpd_mover_error(session,
2045                             NDMP_MOVER_HALT_CONNECT_CLOSED);
2046                 return (NDMP_NO_ERR);
2047         }
2048 
2049         /*
2050          * perform the backup
2051          *
2052          * Cannot wait for the thread to exit as we are replying to the
2053          * client request here.
2054          */
2055         (void) pthread_create(&tid, NULL,
2056             (funct_t)session->ns_data.dd_module.dm_start_func,
2057             params);
2058 
2059         if (err) {
2060                 syslog(LOG_ERR, "Can't start V2 backup session.");
2061                 return (NDMP_ILLEGAL_ARGS_ERR);
2062         }
2063 
2064         (void) pthread_detach(tid);
2065 
2066         return (NDMP_NO_ERR);
2067 }
2068 
2069 /*
2070  * ndmpd_tar_start_recover_v2
2071  *
2072  * The main recover/restore function
2073  *
2074  * Parameters:
2075  *   session   (input) - session pointer.
2076  *   bu_type   (input) - backup type.
2077  *   env_val   (input) - environment variable array.
2078  *   env_len   (input) - length of env_val.
2079  *   nlist_val (input) - list of files.
2080  *   nlist_len (input) - length of nlist_val.
2081  *
2082  * Returns:
2083  *   NDMP_NO_ERR - recover successfully started.
2084  *   otherwise - error code of backup start error.
2085  */
2086 static ndmp_error
2087 ndmpd_tar_start_recover_v2(ndmpd_session_t *session, char *bu_type,
2088     ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val,
2089     ulong_t nlist_len)
2090 {
2091         ndmp_data_start_recover_reply_v2 reply;
2092         ndmpd_module_params_t *params;
2093         ndmp_lbr_params_t *nlp;
2094         pthread_t tid;
2095         int err;
2096 
2097         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
2098                 syslog(LOG_ERR, "Can't start new recover in current state.");
2099                 return (NDMP_ILLEGAL_STATE_ERR);
2100         }
2101 
2102         if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
2103             strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
2104                 syslog(LOG_ERR, "Invalid backup type: %s.", bu_type);
2105                 syslog(LOG_ERR, "Supported backup types are tar and dump.");
2106                 return (NDMP_ILLEGAL_ARGS_ERR);
2107         }
2108 
2109         reply.error = ndmpd_save_env(session, env_val, env_len);
2110         if (reply.error != NDMP_NO_ERR)
2111                 return (NDMP_NO_MEM_ERR);
2112 
2113         reply.error = ndmpd_save_nlist_v2(session, nlist_val, nlist_len);
2114         if (reply.error != NDMP_NO_ERR)
2115                 return (NDMP_NO_MEM_ERR);
2116 
2117         nlp = ndmp_get_nlp(session);
2118         NDMP_FREE(nlp->nlp_params);
2119         params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
2120         if (params == NULL)
2121                 return (NDMP_NO_MEM_ERR);
2122 
2123         /*
2124          * Setup restore parameters.
2125          */
 
2154 
2155         if ((err = ndmp_restore_extract_params(session,
2156             params)) != NDMP_NO_ERR) {
2157                 NDMP_FREE(nlp->nlp_params);
2158                 return (err);
2159         }
2160 
2161         err = ndmpd_mover_connect(session, NDMP_MOVER_MODE_WRITE);
2162         if (err != NDMP_NO_ERR) {
2163                 NDMP_FREE(nlp->nlp_params);
2164                 return (err);
2165         }
2166 
2167         session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
2168         session->ns_data.dd_operation = NDMP_DATA_OP_RECOVER;
2169         session->ns_data.dd_abort = FALSE;
2170 
2171         reply.error = NDMP_NO_ERR;
2172         if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
2173             &reply) < 0) {
2174                 syslog(LOG_DEBUG, "Sending data_start_recover reply");
2175                 NDMP_FREE(nlp->nlp_params);
2176                 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
2177                         /*
2178                          * ndmpcopy: we use the same socket for the mover,
2179                          * so expect to close when mover is done!
2180                          */
2181                         if (session->ns_data.dd_sock !=
2182                             session->ns_mover.md_sock)
2183                                 (void) close(session->ns_data.dd_sock);
2184 
2185                         session->ns_data.dd_sock = -1;
2186                 } else {
2187                         ndmpd_mover_error(session,
2188                             NDMP_MOVER_HALT_CONNECT_CLOSED);
2189                 }
2190                 return (NDMP_NO_ERR);
2191         }
2192 
2193 
2194         /*
2195          * perform the restore
2196          *
2197          * Cannot wait for the thread to exit as we are replying to the
2198          * client request here.
2199          */
2200         (void) pthread_create(&tid, NULL,
2201             (funct_t)session->ns_data.dd_module.dm_start_func,
2202             params);
2203 
2204         if (err != 0) {
2205                 syslog(LOG_ERR, "Can't start V2 recover session.");
2206                 return (NDMP_ILLEGAL_ARGS_ERR);
2207         }
2208 
2209         (void) pthread_detach(tid);
2210 
2211         return (NDMP_NO_ERR);
2212 }
2213 
2214 /*
2215  * ndmpd_data_get_info
2216  *
2217  * Return the total number of bytes processed
2218  *
2219  * Parameters:
2220  *   session   (input) - session pointer.
2221  *
2222  * Returns:
2223  *   the number of bytes processed
2224  */
2225 static u_longlong_t
2226 ndmpd_data_get_info(ndmpd_session_t *session)
2227 {
2228         ndmp_lbr_params_t *nlp;
2229 
2230         nlp = ndmp_get_nlp(session);
 |