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
  95 ndmpd_data_get_state_v2(ndmp_connection_t *connection, void *body)
  96 {
  97         ndmp_data_get_state_reply_v2 reply;
  98         ndmpd_session_t *session = ndmp_get_client_data(connection);
  99 
 100         reply.error = NDMP_NO_ERR;
 101         reply.operation = session->ns_data.dd_operation;
 102         reply.state = session->ns_data.dd_state;
 103         reply.halt_reason = session->ns_data.dd_halt_reason;
 104 
 105         reply.est_time_remain =
 106             session->ns_data.dd_module.dm_stats.ms_est_time_remaining;
 107         reply.est_bytes_remain =
 108             long_long_to_quad(
 109             session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining);
 110 
 111         reply.bytes_processed =
 112             long_long_to_quad(ndmpd_data_get_info(session));
 113 
 114         reply.mover = session->ns_data.dd_mover;
 115         reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
 116         reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
 117 
 118         ndmp_send_reply(connection, &reply,
 119             "sending data_get_state reply");
 120 }
 121 
 122 
 123 /*
 124  * ndmpd_data_start_backup_v2
 125  *
 126  * Request handler. Starts a backup.
 127  *
 128  * Parameters:
 129  *   connection (input) - connection handle.
 130  *   body       (input) - request message body.
 131  *
 132  * Returns:
 133  *   void
 134  */
 135 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
 177 ndmpd_data_start_recover_v2(ndmp_connection_t *connection, void *body)
 178 {
 179         ndmp_data_start_recover_request_v2 *request;
 180         ndmp_data_start_recover_reply_v2 reply;
 181         ndmpd_session_t *session = ndmp_get_client_data(connection);
 182         ndmp_error err;
 183 
 184         request = (ndmp_data_start_recover_request_v2 *) body;
 185         session->ns_data.dd_mover = request->mover;
 186 
 187         err = ndmpd_tar_start_recover_v2(session, request->bu_type,
 188             request->env.env_val, request->env.env_len,
 189             request->nlist.nlist_val, request->nlist.nlist_len);
 190 
 191         /*
 192          * start_recover sends the reply if the recover is successfully started.
 193          * Otherwise, send the reply containing the error here.
 194          */
 195         if (err != NDMP_NO_ERR) {
 196                 reply.error = err;
 197                 ndmp_send_reply(connection, &reply,
 198                     "sending ndmp_data_start_recover_request_v2 reply");
 199                 ndmpd_data_cleanup(session);
 200         }
 201 }
 202 
 203 /*
 204  * ndmpd_data_get_env_v2
 205  *
 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 
 279 /*
 280  * ndmpd_data_abort_v2
 281  *
 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  * ************************************************************************
 322  * NDMP V3 HANDLERS
 323  * ************************************************************************
 324  */
 325 
 326 /*
 327  * ndmpd_data_get_state_v3
 328  *
 329  * Request handler. Returns current data state.
 330  *
 331  * Parameters:
 332  *   connection (input) - connection handle.
 333  *   body       (input) - request message body.
 334  *
 335  * Returns:
 336  *   void
 337  */
 338 /*ARGSUSED*/
 339 void
 340 ndmpd_data_get_state_v3(ndmp_connection_t *connection, void *body)
 341 {
 342         ndmp_data_get_state_reply_v3 reply;
 343         ndmpd_session_t *session = ndmp_get_client_data(connection);
 344 
 345         (void) memset((void*)&reply, 0, sizeof (reply));
 346 
 347         reply.error = NDMP_NO_ERR;
 348         reply.invalid = NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID
 349             | NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID;
 350         reply.operation = session->ns_data.dd_operation;
 351         reply.state = session->ns_data.dd_state;
 352         reply.halt_reason = session->ns_data.dd_halt_reason;
 353 
 354         if (reply.operation == NDMP_DATA_OP_BACKUP)
 355                 reply.bytes_processed =
 356                     long_long_to_quad(
 357                     session->ns_data.dd_module.dm_stats.ms_bytes_processed);
 358         else
 359                 reply.bytes_processed =
 360                     long_long_to_quad(ndmpd_data_get_info(session));
 361 
 362         reply.est_bytes_remain = long_long_to_quad(0LL);
 363         reply.est_time_remain = 0;
 364         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE)
 365                 ndmp_copy_addr_v3(&reply.data_connection_addr,
 366                     &session->ns_data.dd_data_addr);
 367         reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
 368         reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
 369 
 370         ndmp_send_reply(connection, &reply,
 371             "sending ndmp_data_get_state_v3 reply");
 372 }
 373 
 374 
 375 /*
 376  * ndmpd_data_start_backup_v3
 377  *
 378  * Request handler. Starts a backup.
 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  *
 540  * Request handler. Aborts the current backup/restore. The operation
 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 /*
 634  * ndmpd_data_listen_v3
 635  *
 636  * Request handler. Configures the server to listen for a connection
 637  * from a remote mover.
 638  *
 639  * Parameters:
 640  *   connection (input) - connection handle.
 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  *
 798  * Request handler. Returns the environment variable array sent
 799  * with the backup request. This request may only be sent with
 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  *
 844  * Returns:
 845  *   void
 846  */
 847 /*ARGSUSED*/
 848 void
 849 ndmpd_data_get_state_v4(ndmp_connection_t *connection, void *body)
 850 {
 851         ndmp_data_get_state_reply_v4 reply;
 852         ndmpd_session_t *session = ndmp_get_client_data(connection);
 853 
 854         (void) memset((void*)&reply, 0, sizeof (reply));
 855 
 856         reply.error = NDMP_NO_ERR;
 857         reply.unsupported = NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID
 858             | NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID;
 859         reply.operation = session->ns_data.dd_operation;
 860         reply.state = session->ns_data.dd_state;
 861         reply.halt_reason = session->ns_data.dd_halt_reason;
 862 
 863         if (reply.operation == NDMP_DATA_OP_BACKUP)
 864                 reply.bytes_processed = long_long_to_quad(
 865                     session->ns_data.dd_module.dm_stats.ms_bytes_processed);
 866         else
 867                 reply.bytes_processed =
 868                     long_long_to_quad(ndmpd_data_get_info(session));
 869 
 870         reply.est_bytes_remain = long_long_to_quad(0LL);
 871         reply.est_time_remain = 0;
 872         if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE)
 873                 ndmp_copy_addr_v4(&reply.data_connection_addr,
 874                     &session->ns_data.dd_data_addr_v4);
 875 
 876         reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
 877         reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
 878 
 879         ndmp_send_reply(connection, &reply,
 880             "sending ndmp_data_get_state_v4 reply");
 881         free(reply.data_connection_addr.tcp_addr_v4);
 882 }
 883 
 884 
 885 /*
 886  * ndmpd_data_connect_v4
 887  *
 888  * Request handler. Connects the data server to either a local
 889  * or remote mover.
 890  *
 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;
1012                 }
1013 
1014                 reply.error = NDMP_NO_ERR;
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.
1094  *
1095  * Returns:
1096  *   Error code
1097  */
1098 /*ARGSUSED*/
1099 static int
1100 ndmpd_data_error_send(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1101 {
1102         ndmp_notify_data_halted_request req;
1103 
1104         req.reason = session->ns_data.dd_halt_reason;
1105         req.text_reason = "";
1106 
1107         return (ndmp_send_request(session->ns_connection,
1108             NDMP_NOTIFY_DATA_HALTED, NDMP_NO_ERR, &req, 0));
1109 }
1110 
1111 
1112 /*
1113  * ndmpd_data_error_send_v4
1114  *
1115  * This function sends the notify message to the client.
1116  *
1117  * Parameters:
1118  *   session (input) - session pointer.
1119  *   reason  (input) - halt reason.
1120  *
1121  * Returns:
1122  *   Error code
1123  */
1124 /*ARGSUSED*/
1125 static int
1126 ndmpd_data_error_send_v4(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1127 {
1128         ndmp_notify_data_halted_request_v4 req;
1129 
1130         req.reason = session->ns_data.dd_halt_reason;
1131 
1132         return ndmp_send_request(session->ns_connection,
1133             NDMP_NOTIFY_DATA_HALTED, NDMP_NO_ERR, &req, 0);
1134 }
1135 
1136 
1137 /*
1138  * ndmpd_data_error
1139  *
1140  * This function is called when a data error has been detected.
1141  * A notify message is sent to the client and the data server is
1142  * placed into the halted state.
1143  *
1144  * Parameters:
1145  *   session (input) - session pointer.
1146  *   reason  (input) - halt reason.
1147  *
1148  * Returns:
1149  *   void
1150  */
1151 void
1152 ndmpd_data_error(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1153 {
1154         if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
1155             session->ns_data.dd_state == NDMP_DATA_STATE_HALTED)
1156                 return;
1157 
1158         if (session->ns_data.dd_operation == NDMP_DATA_OP_BACKUP) {
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);
1204 
1205                         (void) close(session->ns_data.dd_listen_sock);
1206                         session->ns_data.dd_listen_sock = -1;
1207                 }
1208         } else {
1209                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
1210         }
1211 }
1212 
1213 
1214 /*
1215  * data_accept_connection_v3
1216  *
1217  * Accept a data connection from a remote mover.
1218  * Called by ndmpd_select when a connection is pending on
1219  * the data listen socket.
1220  *
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  *
1273  * Creates the data sockets for listening for a remote mover/data
1274  * incoming connections.
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  */
1316 static ndmp_error
1317 data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr, ushort_t port)
1318 {
1319         int sock;
1320 
1321         sock = ndmp_connect_sock_v3(addr, port);
1322         if (sock < 0)
1323                 return (NDMP_CONNECT_ERR);
1324 
1325         session->ns_data.dd_sock = sock;
1326         session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
1327         session->ns_data.dd_data_addr.tcp_ip_v3 = ntohl(addr);
1328         session->ns_data.dd_data_addr.tcp_port_v3 = port;
1329 
1330         return (NDMP_NO_ERR);
1331 }
1332 
1333 
1334 /*
1335  * ndmpd_tar_start_backup_v3
1336  *
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;
1378         params->mp_get_name_func = 0;
1379         params->mp_dispatch_func = ndmpd_api_dispatch;
1380         params->mp_done_func = ndmpd_api_done_v3;
1381         if (session->ns_protocol_version == NDMPV4)
1382                 params->mp_log_func_v3 = ndmpd_api_log_v4;
1383         else
1384                 params->mp_log_func_v3 = ndmpd_api_log_v3;
1385 
1386         params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1387         params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1388         params->mp_write_func = ndmpd_api_write_v3;
1389         params->mp_read_func = 0;
1390         params->mp_file_recovered_func = 0;
1391         params->mp_stats = &session->ns_data.dd_module.dm_stats;
1392         session->ns_data.dd_module.dm_module_cookie = 0;
1393 
1394         if (strcmp(bu_type, NDMP_DUMP_TYPE) == 0) {
1395                 NLP_SET(nlp, NLPF_DUMP);
1396                 params->mp_file_history_path_func = 0;
1397                 params->mp_file_history_dir_func =
1398                     ndmpd_api_file_history_dir_v3;
1399                 params->mp_file_history_node_func =
1400                     ndmpd_api_file_history_node_v3;
1401         } else if (strcmp(bu_type, NDMP_TAR_TYPE) == 0) {
1402                 NLP_SET(nlp, NLPF_TAR);
1403                 params->mp_file_history_path_func =
1404                     ndmpd_api_file_history_file_v3;
1405                 params->mp_file_history_dir_func = 0;
1406                 params->mp_file_history_node_func = 0;
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);
1510                 return (NDMP_NO_MEM_ERR);
1511         }
1512 
1513         /*
1514          * Setup restore parameters.
1515          */
1516         params->mp_daemon_cookie = (void *)session;
1517         params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1518         params->mp_protocol_version = session->ns_protocol_version;
1519         params->mp_operation = NDMP_DATA_OP_RECOVER;
1520         params->mp_get_env_func = ndmpd_api_get_env;
1521         params->mp_add_env_func = ndmpd_api_add_env;
1522         params->mp_set_env_func = ndmpd_api_set_env;
1523         params->mp_get_name_func = ndmpd_api_get_name_v3;
1524         params->mp_dispatch_func = ndmpd_api_dispatch;
1525         params->mp_done_func = ndmpd_api_done_v3;
1526         if (session->ns_protocol_version == NDMPV4) {
1527                 params->mp_log_func_v3 = ndmpd_api_log_v4;
1528                 params->mp_file_recovered_func = ndmpd_api_file_recovered_v4;
1529         } else {
1530                 params->mp_log_func_v3 = ndmpd_api_log_v3;
1531                 params->mp_file_recovered_func = ndmpd_api_file_recovered_v3;
1532         }
1533 
1534         params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1535         params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1536         params->mp_write_func = 0;
1537         params->mp_file_history_path_func = 0;
1538         params->mp_file_history_dir_func = 0;
1539         params->mp_file_history_node_func = 0;
1540         params->mp_read_func = ndmpd_api_read_v3;
1541         params->mp_seek_func = ndmpd_api_seek_v3;
1542         params->mp_stats = &session->ns_data.dd_module.dm_stats;
1543 
1544         session->ns_data.dd_module.dm_module_cookie = 0;
1545         session->ns_data.dd_module.dm_start_func = ndmpd_tar_restore_starter_v3;
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;
1802         session->ns_data.dd_state = NDMP_DATA_STATE_IDLE;
1803         session->ns_data.dd_halt_reason = NDMP_DATA_HALT_NA;
1804         session->ns_data.dd_abort = FALSE;
1805         session->ns_data.dd_env = 0;
1806         session->ns_data.dd_env_len = 0;
1807         session->ns_data.dd_nlist = 0;
1808         session->ns_data.dd_nlist_len = 0;
1809         session->ns_data.dd_mover.addr_type = NDMP_ADDR_LOCAL;
1810         session->ns_data.dd_sock = -1;
1811         session->ns_data.dd_read_offset = 0;
1812         session->ns_data.dd_read_length = 0;
1813         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1814         session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1815         /*
1816          * NDMP V3
1817          */
1818         session->ns_data.dd_state = NDMP_DATA_STATE_IDLE;
1819         session->ns_data.dd_nlist_v3 = 0;
1820         session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
1821         session->ns_data.dd_listen_sock = -1;
1822         session->ns_data.dd_bytes_left_to_read = 0LL;
1823         session->ns_data.dd_position = 0LL;
1824         session->ns_data.dd_discard_length = 0LL;
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  *
1874  * Return the mover mode
1875  *
1876  * Parameters:
1877  *   session (input) - session pointer.
1878  *
1879  * Returns:
1880  *   remote - remote backup
1881  *   local  - local backup
1882  */
1883 char *
1884 ndmp_data_get_mover_mode(ndmpd_session_t *session)
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;
1968         params->mp_log_func = ndmpd_api_log_v2;
1969         params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1970         params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1971         params->mp_write_func = ndmpd_api_write_v2;
1972         params->mp_read_func = 0;
1973         params->mp_file_recovered_func = 0;
1974         params->mp_stats = &session->ns_data.dd_module.dm_stats;
1975 
1976         session->ns_data.dd_module.dm_module_cookie = 0;
1977         if (strcmp(bu_type, NDMP_DUMP_TYPE) == 0) {
1978                 NLP_SET(nlp, NLPF_DUMP);
1979                 params->mp_file_history_path_func = 0;
1980                 params->mp_file_history_dir_func =
1981                     ndmpd_api_file_history_dir_v2;
1982                 params->mp_file_history_node_func =
1983                     ndmpd_api_file_history_node_v2;
1984         } else if (strcmp(bu_type, NDMP_TAR_TYPE) == 0) {
1985                 /* backup type == NDMP_TAR_TYPE */
1986                 NLP_SET(nlp, NLPF_TAR);
1987                 params->mp_file_history_path_func =
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          */
2126         params->mp_daemon_cookie = (void *)session;
2127         params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
2128         params->mp_protocol_version = session->ns_protocol_version;
2129         params->mp_operation = NDMP_DATA_OP_RECOVER;
2130         params->mp_get_env_func = ndmpd_api_get_env;
2131         params->mp_add_env_func = ndmpd_api_add_env;
2132         params->mp_get_name_func = ndmpd_api_get_name;
2133         params->mp_dispatch_func = ndmpd_api_dispatch;
2134         params->mp_done_func = ndmpd_api_done_v2;
2135         params->mp_log_func = ndmpd_api_log_v2;
2136         params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
2137         params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
2138         params->mp_write_func = 0;
2139         params->mp_file_history_path_func = 0;
2140         params->mp_file_history_dir_func = 0;
2141         params->mp_file_history_node_func = 0;
2142         params->mp_read_func = ndmpd_api_read_v2;
2143         params->mp_seek_func = ndmpd_api_seek_v2;
2144         params->mp_file_recovered_func = ndmpd_api_file_recovered_v2;
2145         params->mp_stats = &session->ns_data.dd_module.dm_stats;
2146 
2147         session->ns_data.dd_module.dm_module_cookie = 0;
2148         session->ns_data.dd_module.dm_start_func = ndmpd_tar_restore_starter;
2149         session->ns_data.dd_module.dm_abort_func = ndmpd_tar_restore_abort;
2150         session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
2151         session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
2152         session->ns_data.dd_read_offset = 0;
2153         session->ns_data.dd_read_length = 0;
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);
2231         if (nlp == NULL)
2232                 return ((u_longlong_t)0);
2233 
2234         if (nlp->nlp_jstat == NULL)
2235                 return (nlp->nlp_bytes_total);
2236 
2237         return ((u_longlong_t)nlp->nlp_jstat->js_bytes_total);
2238 }