1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 
   5 /*
   6  * BSD 3 Clause License
   7  *
   8  * Copyright (c) 2007, The Storage Networking Industry Association.
   9  *
  10  * Redistribution and use in source and binary forms, with or without
  11  * modification, are permitted provided that the following conditions
  12  * are met:
  13  *      - Redistributions of source code must retain the above copyright
  14  *        notice, this list of conditions and the following disclaimer.
  15  *
  16  *      - Redistributions in binary form must reproduce the above copyright
  17  *        notice, this list of conditions and the following disclaimer in
  18  *        the documentation and/or other materials provided with the
  19  *        distribution.
  20  *
  21  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  22  *        nor the names of its contributors may be used to endorse or promote
  23  *        products derived from this software without specific prior written
  24  *        permission.
  25  *
  26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36  * POSSIBILITY OF SUCH DAMAGE.
  37  */
  38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
  39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
  40 /* Copyright 2014 Nexenta Systems, Inc.  All rights reserved. */
  41 
  42 #include <sys/ioctl.h>
  43 #include <sys/types.h>
  44 #include <sys/socket.h>
  45 #include <sys/socketvar.h>
  46 #include <netinet/in.h>
  47 #include <arpa/inet.h>
  48 #include <net/if.h>
  49 #include <errno.h>
  50 #include <fcntl.h>
  51 #include <netdb.h>
  52 #include <stdlib.h>
  53 #include <unistd.h>
  54 #include <string.h>
  55 #include "ndmpd_common.h"
  56 #include "ndmpd.h"
  57 #include <sys/mtio.h>
  58 
  59 /*
  60  * Maximum mover record size
  61  */
  62 #define MAX_MOVER_RECSIZE       (512*KILOBYTE)
  63 
  64 static int create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr,
  65     ushort_t *port);
  66 static int tape_read(ndmpd_session_t *session, char *data);
  67 static int change_tape(ndmpd_session_t *session);
  68 static int discard_data(ndmpd_session_t *session, ulong_t length);
  69 static int mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf);
  70 static int mover_socket_write_one_buf(ndmpd_session_t *session,
  71     tlm_buffer_t *buf);
  72 static int start_mover_for_restore(ndmpd_session_t *session);
  73 static int mover_socket_read_one_buf(ndmpd_session_t *session,
  74     tlm_buffer_t *buf, long read_size);
  75 static int mover_tape_write_one_buf(ndmpd_session_t *session,
  76     tlm_buffer_t *buf);
  77 static int start_mover_for_backup(ndmpd_session_t *session);
  78 static boolean_t is_writer_running_v3(ndmpd_session_t *session);
  79 static int mover_pause_v3(ndmpd_session_t *session,
  80     ndmp_mover_pause_reason reason);
  81 static int mover_tape_write_v3(ndmpd_session_t *session, char *data,
  82     ssize_t length);
  83 static int mover_tape_flush_v3(ndmpd_session_t *session);
  84 static int mover_tape_read_v3(ndmpd_session_t *session, char *data);
  85 static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
  86     ushort_t *port);
  87 static void mover_data_read_v3(void *cookie, int fd, ulong_t mode);
  88 static void accept_connection(void *cookie, int fd, ulong_t mode);
  89 static void mover_data_write_v3(void *cookie, int fd, ulong_t mode);
  90 static void accept_connection_v3(void *cookie, int fd, ulong_t mode);
  91 static ndmp_error mover_connect_sock(ndmpd_session_t *session,
  92     ndmp_mover_mode mode, ulong_t addr, ushort_t port);
  93 static boolean_t is_writer_running(ndmpd_session_t *session);
  94 static int set_socket_nonblock(int sock);
  95 
  96 
  97 int ndmp_max_mover_recsize = MAX_MOVER_RECSIZE; /* patchable */
  98 
  99 #define TAPE_READ_ERR           -1
 100 #define TAPE_NO_WRITER_ERR      -2
 101 
 102 /*
 103  * Set non-blocking mode for socket.
 104  */
 105 static int
 106 set_socket_nonblock(int sock)
 107 {
 108         int flags;
 109 
 110         flags = fcntl(sock, F_GETFL, 0);
 111         if (flags < 0)
 112                 return (0);
 113         return (fcntl(sock, F_SETFL, flags|O_NONBLOCK) == 0);
 114 }
 115 
 116 /*
 117  * ************************************************************************
 118  * NDMP V2 HANDLERS
 119  * ************************************************************************
 120  */
 121 
 122 /*
 123  * ndmpd_mover_get_state_v2
 124  *
 125  * This handler handles the mover_get_state request.
 126  * Status information for the mover state machine is returned.
 127  *
 128  * Parameters:
 129  *   connection (input) - connection handle.
 130  *   body       (input) - request message body.
 131  *
 132  * Returns:
 133  *   void
 134  */
 135 /*ARGSUSED*/
 136 void
 137 ndmpd_mover_get_state_v2(ndmp_connection_t *connection, void *body)
 138 {
 139         ndmp_mover_get_state_reply_v2 reply;
 140         ndmpd_session_t *session = ndmp_get_client_data(connection);
 141 
 142         reply.error = NDMP_NO_ERR;
 143         reply.state = session->ns_mover.md_state;
 144         reply.pause_reason = session->ns_mover.md_pause_reason;
 145         reply.halt_reason = session->ns_mover.md_halt_reason;
 146         reply.record_size = session->ns_mover.md_record_size;
 147         reply.record_num = session->ns_mover.md_record_num;
 148         reply.data_written =
 149             long_long_to_quad(session->ns_mover.md_data_written);
 150         reply.seek_position =
 151             long_long_to_quad(session->ns_mover.md_seek_position);
 152         reply.bytes_left_to_read =
 153             long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
 154         reply.window_offset =
 155             long_long_to_quad(session->ns_mover.md_window_offset);
 156         reply.window_length =
 157             long_long_to_quad(session->ns_mover.md_window_length);
 158 
 159         ndmp_send_reply(connection, (void *) &reply,
 160             "sending tape_get_state reply");
 161 }
 162 
 163 
 164 /*
 165  * ndmpd_mover_listen_v2
 166  *
 167  * This handler handles mover_listen requests.
 168  *
 169  * Parameters:
 170  *   connection (input) - connection handle.
 171  *   body       (input) - request message body.
 172  *
 173  * Returns:
 174  *   void
 175  */
 176 void
 177 ndmpd_mover_listen_v2(ndmp_connection_t *connection, void *body)
 178 {
 179         ndmp_mover_listen_request_v2 *request;
 180         ndmp_mover_listen_reply_v2 reply;
 181         ndmpd_session_t *session = ndmp_get_client_data(connection);
 182         ulong_t addr;
 183         ushort_t port;
 184 
 185         request = (ndmp_mover_listen_request_v2 *)body;
 186 
 187         if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE ||
 188             session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 189                 NDMP_LOG(LOG_DEBUG, "Invalid state");
 190                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 191                 ndmp_send_reply(connection, (void *) &reply,
 192                     "sending mover_listen reply");
 193                 return;
 194         }
 195         session->ns_mover.md_mode = request->mode;
 196 
 197         if (request->addr_type == NDMP_ADDR_LOCAL) {
 198                 reply.mover.addr_type = NDMP_ADDR_LOCAL;
 199         } else {
 200                 if (create_listen_socket_v2(session, &addr, &port) < 0) {
 201                         reply.error = NDMP_IO_ERR;
 202                         ndmp_send_reply(connection, (void *) &reply,
 203                             "sending mover_listen reply");
 204                         return;
 205                 }
 206                 reply.mover.addr_type = NDMP_ADDR_TCP;
 207                 reply.mover.ndmp_mover_addr_u.addr.ip_addr = htonl(addr);
 208                 reply.mover.ndmp_mover_addr_u.addr.port = htons(port);
 209         }
 210 
 211         session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
 212 
 213         /*
 214          * ndmp window should always set by client during restore
 215          */
 216 
 217         /* Set the default window. */
 218         session->ns_mover.md_window_offset = 0;
 219         session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
 220         session->ns_mover.md_position = 0;
 221 
 222         reply.error = NDMP_NO_ERR;
 223         ndmp_send_reply(connection, (void *) &reply,
 224             "sending mover_listen reply");
 225 }
 226 
 227 
 228 /*
 229  * ndmpd_mover_continue_v2
 230  *
 231  * This handler handles mover_continue requests.
 232  *
 233  * Parameters:
 234  *   connection (input) - connection handle.
 235  *   body       (input) - request message body.
 236  *
 237  * Returns:
 238  *   void
 239  */
 240 /*ARGSUSED*/
 241 void
 242 ndmpd_mover_continue_v2(ndmp_connection_t *connection, void *body)
 243 {
 244         ndmp_mover_continue_reply reply;
 245         ndmpd_session_t *session = ndmp_get_client_data(connection);
 246 
 247         if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
 248                 NDMP_LOG(LOG_DEBUG, "Invalid state");
 249 
 250                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 251                 ndmp_send_reply(connection, (void *) &reply,
 252                     "sending mover_continue reply");
 253                 return;
 254         }
 255         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
 256         reply.error = NDMP_NO_ERR;
 257         ndmp_send_reply(connection, (void *) &reply,
 258             "sending mover_continue reply");
 259 }
 260 
 261 
 262 /*
 263  * ndmpd_mover_abort_v2
 264  *
 265  * This handler handles mover_abort requests.
 266  *
 267  * Parameters:
 268  *   connection (input) - connection handle.
 269  *   body       (input) - request message body.
 270  *
 271  * Returns:
 272  *   void
 273  */
 274 /*ARGSUSED*/
 275 void
 276 ndmpd_mover_abort_v2(ndmp_connection_t *connection, void *body)
 277 {
 278         ndmp_mover_abort_reply reply;
 279         ndmpd_session_t *session = ndmp_get_client_data(connection);
 280 
 281         if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
 282             session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
 283                 NDMP_LOG(LOG_DEBUG, "Invalid state");
 284 
 285                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 286                 ndmp_send_reply(connection, (void *) &reply,
 287                     "sending mover_abort reply");
 288                 return;
 289         }
 290 
 291         reply.error = NDMP_NO_ERR;
 292         ndmp_send_reply(connection, (void *) &reply,
 293             "sending mover_abort reply");
 294 
 295         ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
 296         ndmp_stop_buffer_worker(session);
 297 }
 298 
 299 
 300 /*
 301  * ndmpd_mover_stop_v2
 302  *
 303  * This handler handles mover_stop requests.
 304  *
 305  * Parameters:
 306  *   connection (input) - connection handle.
 307  *   body       (input) - request message body.
 308  *
 309  * Returns:
 310  *   void
 311  */
 312 /*ARGSUSED*/
 313 void
 314 ndmpd_mover_stop_v2(ndmp_connection_t *connection, void *body)
 315 {
 316         ndmp_mover_stop_reply reply;
 317         ndmpd_session_t *session = ndmp_get_client_data(connection);
 318 
 319         if (session->ns_mover.md_state != NDMP_MOVER_STATE_HALTED) {
 320                 NDMP_LOG(LOG_DEBUG, "Invalid state");
 321 
 322                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 323                 ndmp_send_reply(connection, (void *) &reply,
 324                     "sending mover_stop reply");
 325                 return;
 326         }
 327 
 328         ndmp_waitfor_op(session);
 329         reply.error = NDMP_NO_ERR;
 330         ndmp_send_reply(connection, (void *) &reply,
 331             "sending mover_stop reply");
 332 
 333         ndmp_lbr_cleanup(session);
 334         ndmpd_mover_cleanup(session);
 335         (void) ndmpd_mover_init(session);
 336         (void) ndmp_lbr_init(session);
 337 }
 338 
 339 
 340 /*
 341  * ndmpd_mover_set_window_v2
 342  *
 343  * This handler handles mover_set_window requests.
 344  *
 345  *
 346  * Parameters:
 347  *   connection (input) - connection handle.
 348  *   body       (input) - request message body.
 349  *
 350  * Returns:
 351  *   void
 352  */
 353 void
 354 ndmpd_mover_set_window_v2(ndmp_connection_t *connection, void *body)
 355 {
 356         ndmp_mover_set_window_request *request;
 357         ndmp_mover_set_window_reply reply;
 358         ndmpd_session_t *session = ndmp_get_client_data(connection);
 359 
 360         request = (ndmp_mover_set_window_request *) body;
 361 
 362         /*
 363          * The NDMPv2 specification states that "a window can be set only
 364          * when in the listen or paused state."
 365          *
 366          * See the comment in ndmpd_mover_set_window_v3 regarding the reason for
 367          * allowing it in the idle state as well.
 368          */
 369         if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
 370             session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED &&
 371             session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
 372                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 373                 NDMP_LOG(LOG_DEBUG, "Invalid state %d",
 374                     session->ns_mover.md_state);
 375         } else {
 376                 if (quad_to_long_long(request->length) == 0) {
 377                         reply.error = NDMP_ILLEGAL_ARGS_ERR;
 378                         NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
 379                             quad_to_long_long(request->length));
 380                 } else {
 381                         reply.error = NDMP_NO_ERR;
 382                         session->ns_mover.md_window_offset =
 383                             quad_to_long_long(request->offset);
 384                         session->ns_mover.md_window_length =
 385                             quad_to_long_long(request->length);
 386                         session->ns_mover.md_position =
 387                             session->ns_mover.md_window_offset;
 388                 }
 389         }
 390 
 391         ndmp_send_reply(connection, (void *) &reply,
 392             "sending mover_set_window reply");
 393 }
 394 
 395 
 396 /*
 397  * ndmpd_mover_read_v2
 398  *
 399  * This handler handles mover_read requests. If the requested offset is
 400  * outside of the current window, the mover is paused and a notify_mover_paused
 401  * request is sent notifying the client that a seek is required. If the
 402  * requested offest is within the window but not within the current record,
 403  * then the tape is positioned to the record containing the requested offest.
 404  * The requested amount of data is then read from the tape device and written
 405  * to the data connection.
 406  *
 407  * Parameters:
 408  *   connection (input) - connection handle.
 409  *   body       (input) - request message body.
 410  *
 411  * Returns:
 412  *   void
 413  */
 414 void
 415 ndmpd_mover_read_v2(ndmp_connection_t *connection, void *body)
 416 {
 417         ndmp_mover_read_request *request = (ndmp_mover_read_request *) body;
 418         ndmp_mover_read_reply reply;
 419         ndmpd_session_t *session = ndmp_get_client_data(connection);
 420         int err;
 421 
 422         if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
 423             session->ns_mover.md_bytes_left_to_read != 0 ||
 424             session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
 425                 NDMP_LOG(LOG_DEBUG, "Invalid state");
 426                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 427                 ndmp_send_reply(connection, &reply,
 428                     "sending mover_read reply");
 429                 return;
 430         }
 431         if (session->ns_tape.td_fd == -1) {
 432                 NDMP_LOG(LOG_DEBUG, "Tape device is not open");
 433                 reply.error = NDMP_DEV_NOT_OPEN_ERR;
 434                 ndmp_send_reply(connection, &reply,
 435                     "sending mover_read reply");
 436                 return;
 437         }
 438 
 439         reply.error = NDMP_NO_ERR;
 440         ndmp_send_reply(connection, &reply, "sending mover_read reply");
 441 
 442         err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
 443             quad_to_long_long(request->length));
 444         if (err < 0) {
 445                 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
 446                 return;
 447         }
 448         /*
 449          * Just return if we are waiting for the NDMP client to
 450          * complete the seek.
 451          */
 452         if (err == 1)
 453                 return;
 454 
 455         /*
 456          * Start the mover for restore in the 3-way backups.
 457          */
 458         if (start_mover_for_restore(session) < 0)
 459                 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
 460 }
 461 
 462 
 463 /*
 464  * ndmpd_mover_close_v2
 465  *
 466  * This handler handles mover_close requests.
 467  *
 468  * Parameters:
 469  *   connection (input) - connection handle.
 470  *   body       (input) - request message body.
 471  *
 472  * Returns:
 473  *   void
 474  */
 475 /*ARGSUSED*/
 476 void
 477 ndmpd_mover_close_v2(ndmp_connection_t *connection, void *body)
 478 {
 479         ndmp_mover_close_reply reply;
 480         ndmpd_session_t *session = ndmp_get_client_data(connection);
 481 
 482         if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
 483                 NDMP_LOG(LOG_DEBUG, "Invalid state");
 484 
 485                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 486                 ndmp_send_reply(connection, &reply,
 487                     "sending mover_close reply");
 488                 return;
 489         }
 490         free(session->ns_mover.md_data_addr_v4.tcp_addr_v4);
 491 
 492         reply.error = NDMP_NO_ERR;
 493         ndmp_send_reply(connection, &reply, "sending mover_close reply");
 494 
 495         ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
 496 }
 497 
 498 
 499 /*
 500  * ndmpd_mover_set_record_size_v2
 501  *
 502  * This handler handles mover_set_record_size requests.
 503  *
 504  * Parameters:
 505  *   connection (input) - connection handle.
 506  *   body       (input) - request message body.
 507  *
 508  * Returns:
 509  *   void
 510  */
 511 void
 512 ndmpd_mover_set_record_size_v2(ndmp_connection_t *connection, void *body)
 513 {
 514         ndmp_mover_set_record_size_request *request;
 515         ndmp_mover_set_record_size_reply reply;
 516         ndmpd_session_t *session = ndmp_get_client_data(connection);
 517 
 518         request = (ndmp_mover_set_record_size_request *) body;
 519 
 520         session->ns_mover.md_record_size = request->len;
 521         session->ns_mover.md_buf = realloc(session->ns_mover.md_buf,
 522             request->len);
 523 
 524         reply.error = NDMP_NO_ERR;
 525         ndmp_send_reply(connection, &reply,
 526             "sending mover_set_record_size reply");
 527 }
 528 
 529 
 530 /*
 531  * ************************************************************************
 532  * NDMP V3 HANDLERS
 533  * ************************************************************************
 534  */
 535 
 536 /*
 537  * ndmpd_mover_get_state_v3
 538  *
 539  * This handler handles the ndmp_mover_get_state_request.
 540  * Status information for the mover state machine is returned.
 541  *
 542  * Parameters:
 543  *   connection (input) - connection handle.
 544  *   body       (input) - request message body.
 545  *
 546  * Returns:
 547  *   void
 548  */
 549 /*ARGSUSED*/
 550 void
 551 ndmpd_mover_get_state_v3(ndmp_connection_t *connection, void *body)
 552 {
 553         ndmp_mover_get_state_reply_v3 reply;
 554         ndmpd_session_t *session = ndmp_get_client_data(connection);
 555 
 556         (void) memset((void*)&reply, 0, sizeof (reply));
 557 
 558         reply.error = NDMP_NO_ERR;
 559         reply.state = session->ns_mover.md_state;
 560         reply.pause_reason = session->ns_mover.md_pause_reason;
 561         reply.halt_reason = session->ns_mover.md_halt_reason;
 562         reply.record_size = session->ns_mover.md_record_size;
 563         reply.record_num = session->ns_mover.md_record_num;
 564         reply.data_written =
 565             long_long_to_quad(session->ns_mover.md_data_written);
 566         reply.seek_position =
 567             long_long_to_quad(session->ns_mover.md_seek_position);
 568         reply.bytes_left_to_read =
 569             long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
 570         reply.window_offset =
 571             long_long_to_quad(session->ns_mover.md_window_offset);
 572         reply.window_length =
 573             long_long_to_quad(session->ns_mover.md_window_length);
 574         if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
 575                 ndmp_copy_addr_v3(&reply.data_connection_addr,
 576                     &session->ns_mover.md_data_addr);
 577 
 578         ndmp_send_reply(connection, &reply,
 579             "sending ndmp_mover_get_state reply");
 580 }
 581 
 582 
 583 /*
 584  * ndmpd_mover_listen_v3
 585  *
 586  * This handler handles ndmp_mover_listen_requests.
 587  * A TCP/IP socket is created that is used to listen for
 588  * and accept data connections initiated by a remote
 589  * data server.
 590  *
 591  * Parameters:
 592  *   connection (input) - connection handle.
 593  *   body       (input) - request message body.
 594  *
 595  * Returns:
 596  *   void
 597  */
 598 void
 599 ndmpd_mover_listen_v3(ndmp_connection_t *connection, void *body)
 600 {
 601         ndmp_mover_listen_request_v3 *request;
 602         ndmp_mover_listen_reply_v3 reply;
 603         ndmpd_session_t *session = ndmp_get_client_data(connection);
 604         ulong_t addr;
 605         ushort_t port;
 606 
 607         request = (ndmp_mover_listen_request_v3 *)body;
 608 
 609         (void) memset((void*)&reply, 0, sizeof (reply));
 610         reply.error = NDMP_NO_ERR;
 611 
 612         if (request->mode != NDMP_MOVER_MODE_READ &&
 613             request->mode != NDMP_MOVER_MODE_WRITE) {
 614                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 615                 NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
 616         } else if (!ndmp_valid_v3addr_type(request->addr_type)) {
 617                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 618                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
 619                     request->addr_type);
 620         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
 621                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 622                 NDMP_LOG(LOG_DEBUG,
 623                     "Invalid mover state to process listen request");
 624         } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 625                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 626                 NDMP_LOG(LOG_DEBUG,
 627                     "Invalid data state to process listen request");
 628         } else if (session->ns_tape.td_fd == -1) {
 629                 reply.error = NDMP_DEV_NOT_OPEN_ERR;
 630                 NDMP_LOG(LOG_DEBUG, "No tape device open");
 631         } else if (request->mode == NDMP_MOVER_MODE_READ &&
 632             session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
 633                 reply.error = NDMP_PERMISSION_ERR;
 634                 NDMP_LOG(LOG_ERR, "Write protected device.");
 635         }
 636 
 637         if (reply.error != NDMP_NO_ERR) {
 638                 ndmp_send_reply(connection, &reply,
 639                     "error sending ndmp_mover_listen reply");
 640                 return;
 641         }
 642 
 643         switch (request->addr_type) {
 644         case NDMP_ADDR_LOCAL:
 645                 reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL;
 646                 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
 647                 reply.error = NDMP_NO_ERR;
 648                 break;
 649         case NDMP_ADDR_TCP:
 650                 if (create_listen_socket_v3(session, &addr, &port) < 0) {
 651                         reply.error = NDMP_IO_ERR;
 652                         break;
 653                 }
 654                 reply.error = NDMP_NO_ERR;
 655                 reply.data_connection_addr.addr_type = NDMP_ADDR_TCP;
 656                 reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
 657                 reply.data_connection_addr.tcp_port_v3 = htons(port);
 658                 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
 659                 session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
 660                 session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
 661                 NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
 662                     session->ns_mover.md_listen_sock);
 663                 break;
 664         default:
 665                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 666                 NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
 667                     request->addr_type);
 668         }
 669 
 670         if (reply.error == NDMP_NO_ERR) {
 671                 session->ns_mover.md_mode = request->mode;
 672                 session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
 673         }
 674 
 675         ndmp_send_reply(connection, &reply,
 676             "error sending ndmp_mover_listen reply");
 677 }
 678 
 679 
 680 /*
 681  * ndmpd_mover_continue_v3
 682  *
 683  * This handler handles ndmp_mover_continue_requests.
 684  *
 685  * Parameters:
 686  *   connection (input) - connection handle.
 687  *   body       (input) - request message body.
 688  *
 689  * Returns:
 690  *   void
 691  */
 692 /*ARGSUSED*/
 693 void
 694 ndmpd_mover_continue_v3(ndmp_connection_t *connection, void *body)
 695 {
 696         ndmp_mover_continue_reply reply;
 697         ndmpd_session_t *session = ndmp_get_client_data(connection);
 698         ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
 699         int ret;
 700 
 701         (void) memset((void*)&reply, 0, sizeof (reply));
 702 
 703         if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
 704                 NDMP_LOG(LOG_DEBUG, "Invalid state");
 705                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 706                 ndmp_send_reply(connection, (void *) &reply,
 707                     "sending mover_continue reply");
 708                 return;
 709         }
 710 
 711         if (session->ns_protocol_version == NDMPV4 &&
 712             !session->ns_mover.md_pre_cond) {
 713                 NDMP_LOG(LOG_DEBUG, "Precondition check");
 714                 reply.error = NDMP_PRECONDITION_ERR;
 715                 ndmp_send_reply(connection, (void *) &reply,
 716                     "sending mover_continue reply");
 717                 return;
 718         }
 719         /*
 720          * Restore the file handler if the mover is remote to the data
 721          * server and the handler was removed pending the continuation of a
 722          * seek request. The handler is removed in mover_data_write().
 723          */
 724         if (session->ns_mover.md_pause_reason == NDMP_MOVER_PAUSE_SEEK &&
 725             session->ns_mover.md_sock != -1) {
 726                 /*
 727                  * If we are here, it means that we needed DMA interference
 728                  * for seek. We should be on the right window, so we do not
 729                  * need the DMA interference anymore.
 730                  * We do another seek inside the Window to move to the
 731                  * exact position on the tape.
 732                  * If the resore is running without DAR the pause reason should
 733                  * not be seek.
 734                  */
 735                 ret = ndmpd_mover_seek(session,
 736                     session->ns_mover.md_seek_position,
 737                     session->ns_mover.md_bytes_left_to_read);
 738                 if (ret < 0) {
 739                         ndmpd_mover_error(session,
 740                             NDMP_MOVER_HALT_INTERNAL_ERROR);
 741                         return;
 742                 }
 743 
 744                 if (!ret) {
 745                         if (ndmpd_add_file_handler(session, (void*) session,
 746                             session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE,
 747                             HC_MOVER, mover_data_write_v3) < 0)
 748                                 ndmpd_mover_error(session,
 749                                     NDMP_MOVER_HALT_INTERNAL_ERROR);
 750                 } else {
 751                         /*
 752                          * This should not happen because we should be in the
 753                          * right window. This means that DMA does not follow
 754                          * the V3 spec.
 755                          */
 756                         NDMP_LOG(LOG_DEBUG, "DMA Error.");
 757                         ndmpd_mover_error(session,
 758                             NDMP_MOVER_HALT_INTERNAL_ERROR);
 759                         return;
 760                 }
 761         }
 762 
 763         (void) mutex_lock(&nlp->nlp_mtx);
 764         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
 765         session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
 766         (void) cond_broadcast(&nlp->nlp_cv);
 767         (void) mutex_unlock(&nlp->nlp_mtx);
 768 
 769         reply.error = NDMP_NO_ERR;
 770         ndmp_send_reply(connection, (void *) &reply,
 771             "sending mover_continue reply");
 772 }
 773 
 774 
 775 /*
 776  * ndmpd_mover_abort_v3
 777  *
 778  * This handler handles mover_abort requests.
 779  *
 780  * Parameters:
 781  *   connection (input) - connection handle.
 782  *   body       (input) - request message body.
 783  *
 784  * Returns:
 785  *   void
 786  */
 787 /*ARGSUSED*/
 788 void
 789 ndmpd_mover_abort_v3(ndmp_connection_t *connection, void *body)
 790 {
 791         ndmp_mover_abort_reply reply;
 792         ndmpd_session_t *session = ndmp_get_client_data(connection);
 793 
 794         if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
 795             session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
 796                 NDMP_LOG(LOG_DEBUG, "Invalid state");
 797 
 798                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 799                 ndmp_send_reply(connection, (void *) &reply,
 800                     "sending mover_abort reply");
 801                 return;
 802         }
 803 
 804         reply.error = NDMP_NO_ERR;
 805         ndmp_send_reply(connection, (void *) &reply,
 806             "sending mover_abort reply");
 807 
 808         ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
 809 }
 810 
 811 
 812 /*
 813  * ndmpd_mover_set_window_v3
 814  *
 815  * This handler handles mover_set_window requests.
 816  *
 817  *
 818  * Parameters:
 819  *   connection (input) - connection handle.
 820  *   body       (input) - request message body.
 821  *
 822  * Returns:
 823  *   void
 824  */
 825 void
 826 ndmpd_mover_set_window_v3(ndmp_connection_t *connection, void *body)
 827 {
 828         ndmp_mover_set_window_request *request;
 829         ndmp_mover_set_window_reply reply;
 830         ndmpd_session_t *session = ndmp_get_client_data(connection);
 831 
 832         request = (ndmp_mover_set_window_request *) body;
 833 
 834         /*
 835          * Note: The spec says that the window can be set only in the listen
 836          * and paused states.  We let this happen when mover is in the idle
 837          * state as well.  I can't rememebr which NDMP client (net_backup 4.5
 838          * or net_worker 6.1.1) forced us to do this!
 839          */
 840         if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
 841             session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN &&
 842             session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
 843                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 844                 NDMP_LOG(LOG_DEBUG, "Invalid state %d",
 845                     session->ns_mover.md_state);
 846         } else if (session->ns_mover.md_record_size == 0) {
 847                 if (session->ns_protocol_version == NDMPV4)
 848                         reply.error = NDMP_PRECONDITION_ERR;
 849                 else
 850                         reply.error = NDMP_ILLEGAL_ARGS_ERR;
 851                 NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
 852         } else
 853                 reply.error = NDMP_NO_ERR;
 854 
 855         if (quad_to_long_long(request->length) == 0) {
 856                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 857                 NDMP_LOG(LOG_DEBUG, "Invalid window size %d",
 858                     quad_to_long_long(request->length));
 859         }
 860 
 861         if (reply.error != NDMP_NO_ERR) {
 862                 ndmp_send_reply(connection, (void *) &reply,
 863                     "sending mover_set_window_v3 reply");
 864                 return;
 865         }
 866 
 867         session->ns_mover.md_pre_cond = TRUE;
 868         session->ns_mover.md_window_offset = quad_to_long_long(request->offset);
 869         session->ns_mover.md_window_length = quad_to_long_long(request->length);
 870 
 871         /*
 872          * We have to update the position for DAR. DAR needs this
 873          * information to position to the right index on tape,
 874          * especially when we span the tapes.
 875          */
 876 #ifdef  NO_POSITION_CHANGE
 877         /*
 878          * Do not change the mover position if we are reading from
 879          * the tape.  In this way, we can use the position+window_length
 880          * to know how much we can write to a tape before pausing with
 881          * EOW reason.
 882          */
 883         if (session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE)
 884 #endif  /* NO_POSITION_CHANGE */
 885                 session->ns_mover.md_position =
 886                     session->ns_mover.md_window_offset;
 887 
 888         ndmp_send_reply(connection, (void *) &reply,
 889             "sending mover_set_window_v3 reply");
 890 }
 891 
 892 
 893 /*
 894  * ndmpd_mover_read_v3
 895  *
 896  * This handler handles ndmp_mover_read_requests.
 897  * If the requested offset is outside of the current window, the mover
 898  * is paused and a notify_mover_paused request is sent notifying the
 899  * client that a seek is required. If the requested offest is within
 900  * the window but not within the current record, then the tape is
 901  * positioned to the record containing the requested offest. The requested
 902  * amount of data is then read from the tape device and written to the
 903  * data connection.
 904  *
 905  * Parameters:
 906  *   connection (input) - connection handle.
 907  *   body       (input) - request message body.
 908  *
 909  * Returns:
 910  *   void
 911  */
 912 void
 913 ndmpd_mover_read_v3(ndmp_connection_t *connection, void *body)
 914 {
 915         ndmp_mover_read_request *request = (ndmp_mover_read_request *)body;
 916         ndmp_mover_read_reply reply;
 917         ndmpd_session_t *session = ndmp_get_client_data(connection);
 918         int err;
 919 
 920         (void) memset((void*)&reply, 0, sizeof (reply));
 921 
 922         if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
 923             session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
 924                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 925                 NDMP_LOG(LOG_DEBUG, "Invalid state");
 926         } else if (session->ns_mover.md_bytes_left_to_read != 0) {
 927                 reply.error = NDMP_READ_IN_PROGRESS_ERR;
 928                 NDMP_LOG(LOG_DEBUG, "In progress");
 929         } else if (session->ns_tape.td_fd == -1) {
 930                 reply.error = NDMP_DEV_NOT_OPEN_ERR;
 931                 NDMP_LOG(LOG_DEBUG, "Tape device is not open");
 932         } else if (quad_to_long_long(request->length) == 0 ||
 933             (quad_to_long_long(request->length) == MAX_WINDOW_SIZE &&
 934             quad_to_long_long(request->offset) != 0)) {
 935                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 936                 NDMP_LOG(LOG_DEBUG, "Illegal args");
 937         } else {
 938                 reply.error = NDMP_NO_ERR;
 939         }
 940 
 941         ndmp_send_reply(connection, (void *) &reply,
 942             "sending ndmp_mover_read_reply");
 943         if (reply.error != NDMP_NO_ERR)
 944                 return;
 945 
 946         err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
 947             quad_to_long_long(request->length));
 948         if (err < 0) {
 949                 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
 950                 return;
 951         }
 952 
 953         /*
 954          * Just return if we are waiting for the DMA to complete the seek.
 955          */
 956         if (err == 1)
 957                 return;
 958 
 959         /*
 960          * Setup a handler function that will be called when
 961          * data can be written to the data connection without blocking.
 962          */
 963         if (ndmpd_add_file_handler(session, (void*)session,
 964             session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE, HC_MOVER,
 965             mover_data_write_v3) < 0) {
 966                 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
 967                 return;
 968         }
 969 }
 970 
 971 
 972 /*
 973  * ndmpd_mover_set_record_size_v3
 974  *
 975  * This handler handles mover_set_record_size requests.
 976  *
 977  * Parameters:
 978  *   connection (input) - connection handle.
 979  *   body       (input) - request message body.
 980  *
 981  * Returns:
 982  *   void
 983  */
 984 void
 985 ndmpd_mover_set_record_size_v3(ndmp_connection_t *connection, void *body)
 986 {
 987         ndmp_mover_set_record_size_request *request;
 988         ndmp_mover_set_record_size_reply reply;
 989         ndmpd_session_t *session = ndmp_get_client_data(connection);
 990         char *cp;
 991 
 992         request = (ndmp_mover_set_record_size_request *) body;
 993 
 994         if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
 995                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 996                 NDMP_LOG(LOG_DEBUG, "Invalid mover state %d",
 997                     session->ns_mover.md_state);
 998         } else if (request->len > (unsigned int)ndmp_max_mover_recsize) {
 999                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1000                 NDMP_LOG(LOG_DEBUG,
1001                     "Invalid argument %d, should be > 0 and <= %d",
1002                     request->len, ndmp_max_mover_recsize);
1003         } else if (request->len == session->ns_mover.md_record_size)
1004                 reply.error = NDMP_NO_ERR;
1005         else if (!(cp = realloc(session->ns_mover.md_buf, request->len))) {
1006                 reply.error = NDMP_NO_MEM_ERR;
1007         } else {
1008                 reply.error = NDMP_NO_ERR;
1009                 session->ns_mover.md_buf = cp;
1010                 session->ns_mover.md_record_size = request->len;
1011                 session->ns_mover.md_window_offset = 0;
1012                 session->ns_mover.md_window_length = 0;
1013         }
1014 
1015         ndmp_send_reply(connection, (void *) &reply,
1016             "sending mover_set_record_size reply");
1017 }
1018 
1019 
1020 /*
1021  * ndmpd_mover_connect_v3
1022  *   Request handler. Connects the mover to either a local
1023  *   or remote data server.
1024  *
1025  * Parameters:
1026  *   connection (input) - connection handle.
1027  *   body       (input) - request message body.
1028  *
1029  * Returns:
1030  *   void
1031  */
1032 void
1033 ndmpd_mover_connect_v3(ndmp_connection_t *connection, void *body)
1034 {
1035         ndmp_mover_connect_request_v3 *request;
1036         ndmp_mover_connect_reply_v3 reply;
1037         ndmpd_session_t *session = ndmp_get_client_data(connection);
1038 
1039         request = (ndmp_mover_connect_request_v3*)body;
1040 
1041         (void) memset((void*)&reply, 0, sizeof (reply));
1042 
1043         if (request->mode != NDMP_MOVER_MODE_READ &&
1044             request->mode != NDMP_MOVER_MODE_WRITE) {
1045                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1046                 NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1047         } else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
1048                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1049                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1050                     request->addr.addr_type);
1051         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1052                 reply.error = NDMP_ILLEGAL_STATE_ERR;
1053                 NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
1054                     session->ns_mover.md_state);
1055         } else if (session->ns_tape.td_fd == -1) {
1056                 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1057                 NDMP_LOG(LOG_DEBUG, "No tape device open");
1058         } else if (request->mode == NDMP_MOVER_MODE_READ &&
1059             session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1060                 reply.error = NDMP_WRITE_PROTECT_ERR;
1061                 NDMP_LOG(LOG_ERR, "Write protected device.");
1062         } else
1063                 reply.error = NDMP_NO_ERR;
1064 
1065         if (reply.error != NDMP_NO_ERR) {
1066                 ndmp_send_reply(connection, (void *) &reply,
1067                     "sending ndmp_mover_connect reply");
1068                 return;
1069         }
1070 
1071         switch (request->addr.addr_type) {
1072         case NDMP_ADDR_LOCAL:
1073                 /*
1074                  * Verify that the data server is listening for a
1075                  * local connection.
1076                  */
1077                 if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
1078                     session->ns_data.dd_listen_sock != -1) {
1079                         NDMP_LOG(LOG_DEBUG,
1080                             "Data server is not in local listen state");
1081                         reply.error = NDMP_ILLEGAL_STATE_ERR;
1082                 } else
1083                         session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1084                 break;
1085 
1086         case NDMP_ADDR_TCP:
1087                 reply.error = mover_connect_sock(session, request->mode,
1088                     request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
1089                 break;
1090 
1091         default:
1092                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1093                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1094                     request->addr.addr_type);
1095         }
1096 
1097         if (reply.error == NDMP_NO_ERR) {
1098                 session->ns_mover.md_data_addr.addr_type =
1099                     request->addr.addr_type;
1100                 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1101                 session->ns_mover.md_mode = request->mode;
1102         }
1103 
1104         ndmp_send_reply(connection, (void *) &reply,
1105             "sending ndmp_mover_connect reply");
1106 }
1107 
1108 
1109 /*
1110  * ************************************************************************
1111  * NDMP V4 HANDLERS
1112  * ************************************************************************
1113  */
1114 
1115 /*
1116  * ndmpd_mover_get_state_v4
1117  *
1118  * This handler handles the ndmp_mover_get_state_request.
1119  * Status information for the mover state machine is returned.
1120  *
1121  * Parameters:
1122  *   connection (input) - connection handle.
1123  *   body       (input) - request message body.
1124  *
1125  * Returns:
1126  *   void
1127  */
1128 /*ARGSUSED*/
1129 void
1130 ndmpd_mover_get_state_v4(ndmp_connection_t *connection, void *body)
1131 {
1132         ndmp_mover_get_state_reply_v4 reply;
1133         ndmpd_session_t *session = ndmp_get_client_data(connection);
1134 
1135         (void) memset((void*)&reply, 0, sizeof (reply));
1136 
1137         reply.error = NDMP_NO_ERR;
1138         reply.state = session->ns_mover.md_state;
1139         reply.mode = session->ns_mover.md_mode;
1140         reply.pause_reason = session->ns_mover.md_pause_reason;
1141         reply.halt_reason = session->ns_mover.md_halt_reason;
1142         reply.record_size = session->ns_mover.md_record_size;
1143         reply.record_num = session->ns_mover.md_record_num;
1144         reply.bytes_moved =
1145             long_long_to_quad(session->ns_mover.md_data_written);
1146         reply.seek_position =
1147             long_long_to_quad(session->ns_mover.md_seek_position);
1148         reply.bytes_left_to_read =
1149             long_long_to_quad(session->ns_mover.md_bytes_left_to_read);
1150         reply.window_offset =
1151             long_long_to_quad(session->ns_mover.md_window_offset);
1152         reply.window_length =
1153             long_long_to_quad(session->ns_mover.md_window_length);
1154         if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE)
1155                 ndmp_copy_addr_v4(&reply.data_connection_addr,
1156                     &session->ns_mover.md_data_addr_v4);
1157 
1158         ndmp_send_reply(connection, (void *) &reply,
1159             "sending ndmp_mover_get_state reply");
1160         free(reply.data_connection_addr.tcp_addr_v4);
1161 }
1162 
1163 
1164 /*
1165  * ndmpd_mover_listen_v4
1166  *
1167  * This handler handles ndmp_mover_listen_requests.
1168  * A TCP/IP socket is created that is used to listen for
1169  * and accept data connections initiated by a remote
1170  * data server.
1171  *
1172  * Parameters:
1173  *   connection (input) - connection handle.
1174  *   body       (input) - request message body.
1175  *
1176  * Returns:
1177  *   void
1178  */
1179 void
1180 ndmpd_mover_listen_v4(ndmp_connection_t *connection, void *body)
1181 {
1182         ndmp_mover_listen_request_v4 *request;
1183 
1184         ndmp_mover_listen_reply_v4 reply;
1185         ndmpd_session_t *session = ndmp_get_client_data(connection);
1186         ulong_t addr;
1187         ushort_t port;
1188 
1189         request = (ndmp_mover_listen_request_v4 *)body;
1190 
1191         (void) memset((void*)&reply, 0, sizeof (reply));
1192         reply.error = NDMP_NO_ERR;
1193 
1194         if (request->mode != NDMP_MOVER_MODE_READ &&
1195             request->mode != NDMP_MOVER_MODE_WRITE) {
1196                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1197                 NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1198         } else if (!ndmp_valid_v3addr_type(request->addr_type)) {
1199                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1200                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1201                     request->addr_type);
1202         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1203                 reply.error = NDMP_ILLEGAL_STATE_ERR;
1204                 NDMP_LOG(LOG_DEBUG,
1205                     "Invalid mover state to process listen request");
1206         } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1207                 reply.error = NDMP_ILLEGAL_STATE_ERR;
1208                 NDMP_LOG(LOG_DEBUG,
1209                     "Invalid data state to process listen request");
1210         } else if (session->ns_tape.td_fd == -1) {
1211                 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1212                 NDMP_LOG(LOG_DEBUG, "No tape device open");
1213         } else if (session->ns_mover.md_record_size == 0) {
1214                 reply.error = NDMP_PRECONDITION_ERR;
1215                 NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
1216         } else if (request->mode == NDMP_MOVER_MODE_READ &&
1217             session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1218                 reply.error = NDMP_PERMISSION_ERR;
1219                 NDMP_LOG(LOG_ERR, "Write protected device.");
1220         }
1221 
1222         if (reply.error != NDMP_NO_ERR) {
1223                 ndmp_send_reply(connection, (void *) &reply,
1224                     "error sending ndmp_mover_listen reply");
1225                 return;
1226         }
1227 
1228         switch (request->addr_type) {
1229         case NDMP_ADDR_LOCAL:
1230                 reply.connect_addr.addr_type = NDMP_ADDR_LOCAL;
1231                 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
1232                 reply.error = NDMP_NO_ERR;
1233                 break;
1234         case NDMP_ADDR_TCP:
1235                 if (create_listen_socket_v3(session, &addr, &port) < 0) {
1236                         reply.error = NDMP_IO_ERR;
1237                         break;
1238                 }
1239                 reply.error = NDMP_NO_ERR;
1240 
1241                 session->ns_mover.md_data_addr_v4.addr_type = NDMP_ADDR_TCP;
1242                 session->ns_mover.md_data_addr_v4.tcp_len_v4 = 1;
1243                 session->ns_mover.md_data_addr_v4.tcp_addr_v4 =
1244                     ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1245 
1246                 session->ns_mover.md_data_addr_v4.tcp_ip_v4(0) = addr;
1247                 session->ns_mover.md_data_addr_v4.tcp_port_v4(0) = ntohs(port);
1248 
1249                 ndmp_copy_addr_v4(&reply.connect_addr,
1250                     &session->ns_mover.md_data_addr_v4);
1251 
1252                 /* For compatibility with V3 */
1253                 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
1254                 session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
1255                 session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
1256                 NDMP_LOG(LOG_DEBUG, "listen_socket: %d",
1257                     session->ns_mover.md_listen_sock);
1258                 break;
1259         default:
1260                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1261                 NDMP_LOG(LOG_DEBUG, "Invalid address type: %d",
1262                     request->addr_type);
1263         }
1264 
1265         if (reply.error == NDMP_NO_ERR) {
1266                 session->ns_mover.md_mode = request->mode;
1267                 session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
1268         }
1269 
1270         ndmp_send_reply(connection, (void *) &reply,
1271             "error sending ndmp_mover_listen reply");
1272         free(reply.connect_addr.tcp_addr_v4);
1273 }
1274 
1275 /*
1276  * ndmpd_mover_connect_v4
1277  *   Request handler. Connects the mover to either a local
1278  *   or remote data server.
1279  *
1280  * Parameters:
1281  *   connection (input) - connection handle.
1282  *   body       (input) - request message body.
1283  *
1284  * Returns:
1285  *   void
1286  */
1287 void
1288 ndmpd_mover_connect_v4(ndmp_connection_t *connection, void *body)
1289 {
1290         ndmp_mover_connect_request_v4 *request;
1291         ndmp_mover_connect_reply_v4 reply;
1292         ndmpd_session_t *session = ndmp_get_client_data(connection);
1293 
1294         request = (ndmp_mover_connect_request_v4 *)body;
1295         (void) memset((void*)&reply, 0, sizeof (reply));
1296 
1297         if (request->mode != NDMP_MOVER_MODE_READ &&
1298             request->mode != NDMP_MOVER_MODE_WRITE) {
1299                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1300                 NDMP_LOG(LOG_DEBUG, "Invalid mode %d", request->mode);
1301         } else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
1302                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1303                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1304                     request->addr.addr_type);
1305         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1306                 reply.error = NDMP_ILLEGAL_STATE_ERR;
1307                 NDMP_LOG(LOG_DEBUG, "Invalid state %d: mover is not idle",
1308                     session->ns_mover.md_state);
1309         } else if (session->ns_tape.td_fd == -1) {
1310                 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1311                 NDMP_LOG(LOG_DEBUG, "No tape device open");
1312         } else if (request->mode == NDMP_MOVER_MODE_READ &&
1313             session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1314                 reply.error = NDMP_PERMISSION_ERR;
1315                 NDMP_LOG(LOG_ERR, "Write protected device.");
1316         } else if (session->ns_mover.md_record_size == 0) {
1317                 reply.error = NDMP_PRECONDITION_ERR;
1318                 NDMP_LOG(LOG_DEBUG, "Invalid record size 0");
1319         } else
1320                 reply.error = NDMP_NO_ERR;
1321 
1322         if (reply.error != NDMP_NO_ERR) {
1323                 ndmp_send_reply(connection, (void *) &reply,
1324                     "sending ndmp_mover_connect reply");
1325                 return;
1326         }
1327 
1328         switch (request->addr.addr_type) {
1329         case NDMP_ADDR_LOCAL:
1330                 /*
1331                  * Verify that the data server is listening for a
1332                  * local connection.
1333                  */
1334                 if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
1335                     session->ns_data.dd_listen_sock != -1) {
1336                         NDMP_LOG(LOG_DEBUG,
1337                             "Data server is not in local listen state");
1338                         reply.error = NDMP_ILLEGAL_STATE_ERR;
1339                 } else
1340                         session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1341                 break;
1342 
1343         case NDMP_ADDR_TCP:
1344                 reply.error = mover_connect_sock(session, request->mode,
1345                     request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
1346                 break;
1347 
1348         default:
1349                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1350                 NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
1351                     request->addr.addr_type);
1352         }
1353 
1354         if (reply.error == NDMP_NO_ERR) {
1355                 session->ns_mover.md_data_addr.addr_type =
1356                     request->addr.addr_type;
1357                 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1358                 session->ns_mover.md_mode = request->mode;
1359         }
1360 
1361         ndmp_send_reply(connection, (void *) &reply,
1362             "sending ndmp_mover_connect reply");
1363 }
1364 
1365 
1366 
1367 /*
1368  * ************************************************************************
1369  * LOCALS
1370  * ************************************************************************
1371  */
1372 
1373 /*
1374  * ndmpd_local_write
1375  *
1376  * Writes data to the mover.
1377  * Buffers and write data to the tape device.
1378  * A full tape record is buffered before being written.
1379  *
1380  * Parameters:
1381  *   session    (input) - session pointer.
1382  *   data       (input) - data to be written.
1383  *   length     (input) - data length.
1384  *
1385  * Returns:
1386  *   0 - data successfully written.
1387  *  -1 - error.
1388  */
1389 int
1390 ndmpd_local_write(ndmpd_session_t *session, char *data, ulong_t length)
1391 {
1392         ulong_t count = 0;
1393         ssize_t n;
1394         ulong_t len;
1395 
1396         /*
1397          * A length of 0 indicates that any buffered data should be
1398          * flushed to tape.
1399          */
1400         if (length == 0) {
1401                 if (session->ns_mover.md_w_index == 0)
1402                         return (0);
1403 
1404                 (void) memset(
1405                     &session->ns_mover.md_buf[session->ns_mover.md_w_index],
1406                     0, session->ns_mover.md_record_size -
1407                     session->ns_mover.md_w_index);
1408 
1409                 n = mover_tape_write_v3(session, session->ns_mover.md_buf,
1410                     session->ns_mover.md_record_size);
1411                 if (n <= 0) {
1412                         ndmpd_mover_error(session,
1413                             (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1414                             NDMP_MOVER_HALT_INTERNAL_ERROR));
1415                         return (-1);
1416                 }
1417                 session->ns_mover.md_position += n;
1418                 session->ns_mover.md_data_written +=
1419                     session->ns_mover.md_w_index;
1420                 session->ns_mover.md_record_num++;
1421                 session->ns_mover.md_w_index = 0;
1422                 return (0);
1423         }
1424         /* Break the data into records. */
1425         while (count < length) {
1426                 /*
1427                  * Determine if data needs to be buffered or
1428                  * can be written directly from user supplied location.
1429                  * We can fast path the write if there is no pending
1430                  * buffered data and there is at least a full record's worth
1431                  * of data to be written.
1432                  */
1433                 if (session->ns_mover.md_w_index == 0 &&
1434                     length - count >= session->ns_mover.md_record_size) {
1435                         n = mover_tape_write_v3(session, &data[count],
1436                             session->ns_mover.md_record_size);
1437                         if (n <= 0) {
1438                                 ndmpd_mover_error(session,
1439                                     (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1440                                     NDMP_MOVER_HALT_INTERNAL_ERROR));
1441                                 return (-1);
1442                         }
1443                         session->ns_mover.md_position += n;
1444                         session->ns_mover.md_data_written += n;
1445                         session->ns_mover.md_record_num++;
1446                         count += n;
1447                         continue;
1448                 }
1449                 /* Buffer the data */
1450                 len = length - count;
1451                 if (len > session->ns_mover.md_record_size -
1452                     session->ns_mover.md_w_index)
1453                         len = session->ns_mover.md_record_size -
1454                             session->ns_mover.md_w_index;
1455 
1456                 (void) memcpy(
1457                     &session->ns_mover.md_buf[session->ns_mover.md_w_index],
1458                     &data[count], len);
1459                 session->ns_mover.md_w_index += len;
1460                 count += len;
1461 
1462                 /* Write the buffer if its full */
1463                 if (session->ns_mover.md_w_index ==
1464                     session->ns_mover.md_record_size) {
1465                         n = mover_tape_write_v3(session,
1466                             session->ns_mover.md_buf,
1467                             session->ns_mover.md_record_size);
1468                         if (n <= 0) {
1469                                 ndmpd_mover_error(session,
1470                                     (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1471                                     NDMP_MOVER_HALT_INTERNAL_ERROR));
1472                                 return (-1);
1473                         }
1474                         session->ns_mover.md_position += n;
1475                         session->ns_mover.md_data_written += n;
1476                         session->ns_mover.md_record_num++;
1477                         session->ns_mover.md_w_index = 0;
1478                 }
1479         }
1480 
1481         return (0);
1482 }
1483 
1484 
1485 /*
1486  * ndmpd_remote_write
1487  *
1488  * Writes data to the remote mover.
1489  *
1490  * Parameters:
1491  *   session    (input) - session pointer.
1492  *   data       (input) - data to be written.
1493  *   length     (input) - data length.
1494  *
1495  * Returns:
1496  *   0 - data successfully written.
1497  *  -1 - error.
1498  */
1499 int
1500 ndmpd_remote_write(ndmpd_session_t *session, char *data, ulong_t length)
1501 {
1502         ssize_t n;
1503         ulong_t count = 0;
1504 
1505         while (count < length) {
1506                 if (session->ns_eof == TRUE ||
1507                     session->ns_data.dd_abort == TRUE)
1508                         return (-1);
1509 
1510                 if ((n = write(session->ns_data.dd_sock, &data[count],
1511                     length - count)) < 0) {
1512                         NDMP_LOG(LOG_ERR, "Socket write error: %m.");
1513                         return (-1);
1514                 }
1515                 count += n;
1516         }
1517 
1518         return (0);
1519 }
1520 
1521 /*
1522  * ndmpd_local_read
1523  *
1524  * Reads data from the local tape device.
1525  * Full tape records are read and buffered.
1526  *
1527  * Parameters:
1528  *   session (input) - session pointer.
1529  *   data    (input) - location to store data.
1530  *   length  (input) - data length.
1531  *
1532  * Returns:
1533  *   0 - data successfully read.
1534  *  -1 - error.
1535  *   1 - session terminated or operation aborted.
1536  */
1537 int
1538 ndmpd_local_read(ndmpd_session_t *session, char *data, ulong_t length)
1539 {
1540         ulong_t count = 0;
1541         ssize_t n;
1542         ulong_t len;
1543         ndmp_notify_mover_paused_request pause_request;
1544 
1545         /*
1546          * Automatically increase the seek window if necessary.
1547          * This is needed in the event the module attempts to read
1548          * past a seek window set via a prior call to ndmpd_seek() or
1549          * the module has not issued a seek. If no seek was issued then
1550          * pretend that a seek was issued to read the entire tape.
1551          */
1552         if (length > session->ns_mover.md_bytes_left_to_read) {
1553                 /* ndmpd_seek() never called? */
1554                 if (session->ns_data.dd_read_length == 0) {
1555                         session->ns_mover.md_bytes_left_to_read = ~0LL;
1556                         session->ns_data.dd_read_offset = 0LL;
1557                         session->ns_data.dd_read_length = ~0LL;
1558                 } else {
1559                         session->ns_mover.md_bytes_left_to_read = length;
1560                         session->ns_data.dd_read_offset =
1561                             session->ns_mover.md_position;
1562                         session->ns_data.dd_read_length = length;
1563                 }
1564         }
1565         /*
1566          * Read as many records as necessary to satisfy the request.
1567          */
1568         while (count < length) {
1569                 /*
1570                  * If the end of the mover window has been reached,
1571                  * then notify the client that a new data window is needed.
1572                  */
1573                 if (session->ns_mover.md_position >=
1574                     session->ns_mover.md_window_offset +
1575                     session->ns_mover.md_window_length) {
1576 
1577                         session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
1578                         session->ns_mover.md_pause_reason =
1579                             NDMP_MOVER_PAUSE_SEEK;
1580                         pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
1581                         pause_request.seek_position =
1582                             long_long_to_quad(session->ns_mover.md_position);
1583 
1584                         if (ndmp_send_request(session->ns_connection,
1585                             NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
1586                             (void *) &pause_request, 0) < 0) {
1587                                 NDMP_LOG(LOG_DEBUG,
1588                                     "Sending notify_mover_paused request");
1589                                 ndmpd_mover_error(session,
1590                                     NDMP_MOVER_HALT_INTERNAL_ERROR);
1591                                 return (-1);
1592                         }
1593                         /*
1594                          * Wait until the state is changed by
1595                          * an abort or continue request.
1596                          */
1597                         if (ndmp_wait_for_mover(session) != 0)
1598                                 return (1);
1599                 }
1600                 len = length - count;
1601 
1602                 /*
1603                  * Prevent reading past the end of the window.
1604                  */
1605                 if (len >
1606                     session->ns_mover.md_window_offset +
1607                     session->ns_mover.md_window_length -
1608                     session->ns_mover.md_position)
1609                         len = session->ns_mover.md_window_offset +
1610                             session->ns_mover.md_window_length -
1611                             session->ns_mover.md_position;
1612 
1613                 /*
1614                  * Copy from the data buffer first.
1615                  */
1616                 if (session->ns_mover.md_w_index -
1617                     session->ns_mover.md_r_index != 0) {
1618                         /*
1619                          * Limit the copy to the amount of data in the buffer.
1620                          */
1621                         if (len > session->ns_mover.md_w_index -
1622                             session->ns_mover.md_r_index)
1623                                 len = session->ns_mover.md_w_index
1624                                     - session->ns_mover.md_r_index;
1625 
1626                         (void) memcpy((void *) &data[count],
1627                             &session->ns_mover.md_buf[session->
1628                             ns_mover.md_r_index], len);
1629                         count += len;
1630                         session->ns_mover.md_r_index += len;
1631                         session->ns_mover.md_bytes_left_to_read -= len;
1632                         session->ns_mover.md_position += len;
1633                         continue;
1634                 }
1635                 /*
1636                  * Determine if data needs to be buffered or
1637                  * can be read directly to user supplied location.
1638                  * We can fast path the read if at least a full record
1639                  * needs to be read and there is no seek pending.
1640                  * This is done to eliminate a buffer copy.
1641                  */
1642                 if (len >= session->ns_mover.md_record_size &&
1643                     session->ns_mover.md_position >=
1644                     session->ns_mover.md_seek_position) {
1645                         n = tape_read(session, &data[count]);
1646                         if (n <= 0) {
1647                                 if (n == TAPE_NO_WRITER_ERR)
1648                                         return (1);
1649 
1650                                 ndmpd_mover_error(session,
1651                                     (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1652                                     NDMP_MOVER_HALT_INTERNAL_ERROR));
1653                                 return (n == 0) ? (1) : (-1);
1654                         }
1655                         count += n;
1656                         session->ns_mover.md_bytes_left_to_read -= n;
1657                         session->ns_mover.md_position += n;
1658                         continue;
1659                 }
1660                 /* Read the next record into the buffer. */
1661                 n = tape_read(session, session->ns_mover.md_buf);
1662                 if (n <= 0) {
1663                         if (n == TAPE_NO_WRITER_ERR)
1664                                 return (1);
1665 
1666                         ndmpd_mover_error(session,
1667                             (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1668                             NDMP_MOVER_HALT_INTERNAL_ERROR));
1669                         return (n == 0) ? (1) : (-1);
1670                 }
1671                 session->ns_mover.md_w_index = n;
1672                 session->ns_mover.md_r_index = 0;
1673 
1674                 NDMP_LOG(LOG_DEBUG, "n: %d", n);
1675 
1676                 /*
1677                  * Discard data if the current data stream position is
1678                  * prior to the seek position. This is necessary if a seek
1679                  * request set the seek pointer to a position that is not a
1680                  * record boundary. The seek request handler can only position
1681                  * to the start of a record.
1682                  */
1683                 if (session->ns_mover.md_position <
1684                     session->ns_mover.md_seek_position) {
1685                         session->ns_mover.md_r_index =
1686                             session->ns_mover.md_seek_position -
1687                             session->ns_mover.md_position;
1688                         session->ns_mover.md_position =
1689                             session->ns_mover.md_seek_position;
1690                 }
1691         }
1692 
1693         return (0);
1694 }
1695 
1696 
1697 /*
1698  * ndmpd_remote_read
1699  *
1700  * Reads data from the remote mover.
1701  *
1702  * Parameters:
1703  *   session (input) - session pointer.
1704  *   data    (input) - data to be written.
1705  *   length  (input) - data length.
1706  *
1707  * Returns:
1708  *   0 - data successfully read.
1709  *  -1 - error.
1710  *   1 - session terminated or operation aborted.
1711  */
1712 int
1713 ndmpd_remote_read(ndmpd_session_t *session, char *data, ulong_t length)
1714 {
1715         ulong_t count = 0;
1716         ssize_t n;
1717         ulong_t len;
1718         ndmp_notify_data_read_request request;
1719 
1720         while (count < length) {
1721                 len = length - count;
1722 
1723                 /*
1724                  * If the end of the seek window has been reached then
1725                  * send an ndmp_read request to the client.
1726                  * The NDMP client will then send a mover_data_read request to
1727                  * the remote mover and the mover will send more data.
1728                  * This condition can occur if the module attempts to read past
1729                  * a seek window set via a prior call to ndmpd_seek() or
1730                  * the module has not issued a seek. If no seek was issued then
1731                  * pretend that a seek was issued to read the entire tape.
1732                  */
1733                 if (session->ns_mover.md_bytes_left_to_read == 0) {
1734                         /* ndmpd_seek() never called? */
1735                         if (session->ns_data.dd_read_length == 0) {
1736                                 session->ns_mover.md_bytes_left_to_read = ~0LL;
1737                                 session->ns_data.dd_read_offset = 0LL;
1738                                 session->ns_data.dd_read_length = ~0LL;
1739                         } else {
1740                                 session->ns_mover.md_bytes_left_to_read = len;
1741                                 session->ns_data.dd_read_offset =
1742                                     session->ns_mover.md_position;
1743                                 session->ns_data.dd_read_length = len;
1744                         }
1745 
1746                         request.offset =
1747                             long_long_to_quad(session->ns_data.dd_read_offset);
1748                         request.length =
1749                             long_long_to_quad(session->ns_data.dd_read_length);
1750 
1751                         if (ndmp_send_request_lock(session->ns_connection,
1752                             NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1753                             (void *) &request, 0) < 0) {
1754                                 NDMP_LOG(LOG_DEBUG,
1755                                     "Sending notify_data_read request");
1756                                 return (-1);
1757                         }
1758                 }
1759                 if (session->ns_eof == TRUE ||
1760                     session->ns_data.dd_abort == TRUE)
1761                         return (1);
1762 
1763                 /*
1764                  * If the module called ndmpd_seek() prior to reading all of the
1765                  * data that the remote mover was requested to send, then the
1766                  * excess data from the seek has to be discardd.
1767                  */
1768                 if (session->ns_mover.md_discard_length != 0) {
1769                         n = discard_data(session,
1770                             (ulong_t)session->ns_mover.md_discard_length);
1771                         if (n < 0)
1772                                 return (-1);
1773                         session->ns_mover.md_discard_length -= n;
1774                         continue;
1775                 }
1776                 /*
1777                  * Don't attempt to read more data than the remote is sending.
1778                  */
1779                 if (len > session->ns_mover.md_bytes_left_to_read)
1780                         len = session->ns_mover.md_bytes_left_to_read;
1781 
1782                 NDMP_LOG(LOG_DEBUG, "len: %u", len);
1783 
1784                 if ((n = read(session->ns_data.dd_sock, &data[count],
1785                     len)) < 0) {
1786                         NDMP_LOG(LOG_ERR, "Socket read error: %m.");
1787                         return (-1);
1788                 }
1789                 /* read returns 0 if the connection was closed */
1790                 if (n == 0)
1791                         return (-1);
1792 
1793                 count += n;
1794                 session->ns_mover.md_bytes_left_to_read -= n;
1795                 session->ns_mover.md_position += n;
1796         }
1797 
1798         return (0);
1799 }
1800 
1801 /* *** ndmpd internal functions ***************************************** */
1802 
1803 /*
1804  * ndmpd_mover_init
1805  *
1806  * Initialize mover specific session variables.
1807  * Don't initialize variables such as record_size that need to
1808  * persist across data operations. A client may open a connection and
1809  * do multiple backups after setting the record_size.
1810  *
1811  * Parameters:
1812  *   session (input) - session pointer.
1813  *
1814  * Returns:
1815  *   0 - success.
1816  *  -1 - error.
1817  */
1818 int
1819 ndmpd_mover_init(ndmpd_session_t *session)
1820 {
1821         session->ns_mover.md_state = NDMP_MOVER_STATE_IDLE;
1822         session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
1823         session->ns_mover.md_halt_reason = NDMP_MOVER_HALT_NA;
1824         session->ns_mover.md_data_written = 0LL;
1825         session->ns_mover.md_seek_position = 0LL;
1826         session->ns_mover.md_bytes_left_to_read = 0LL;
1827         session->ns_mover.md_window_offset = 0LL;
1828         session->ns_mover.md_window_length = MAX_WINDOW_SIZE;
1829         session->ns_mover.md_position = 0LL;
1830         session->ns_mover.md_discard_length = 0;
1831         session->ns_mover.md_record_num = 0;
1832         session->ns_mover.md_record_size = 0;
1833         session->ns_mover.md_listen_sock = -1;
1834         session->ns_mover.md_pre_cond = FALSE;
1835         session->ns_mover.md_sock = -1;
1836         session->ns_mover.md_r_index = 0;
1837         session->ns_mover.md_w_index = 0;
1838         session->ns_mover.md_buf = ndmp_malloc(MAX_RECORD_SIZE);
1839         if (!session->ns_mover.md_buf)
1840                 return (-1);
1841 
1842         if (ndmp_get_version(session->ns_connection) == NDMPV3) {
1843                 session->ns_mover.md_mode = NDMP_MOVER_MODE_READ;
1844                 (void) memset(&session->ns_mover.md_data_addr, 0,
1845                     sizeof (ndmp_addr_v3));
1846         }
1847         return (0);
1848 }
1849 
1850 
1851 /*
1852  * ndmpd_mover_shut_down
1853  *
1854  * Shutdown the mover. It closes all the sockets.
1855  *
1856  * Parameters:
1857  *   session (input) - session pointer.
1858  *
1859  * Returns:
1860  *   void
1861  */
1862 void
1863 ndmpd_mover_shut_down(ndmpd_session_t *session)
1864 {
1865         ndmp_lbr_params_t *nlp;
1866 
1867         if ((nlp = ndmp_get_nlp(session)) == NULL)
1868                 return;
1869 
1870         (void) mutex_lock(&nlp->nlp_mtx);
1871         if (session->ns_mover.md_listen_sock != -1) {
1872                 NDMP_LOG(LOG_DEBUG, "mover.listen_sock: %d",
1873                     session->ns_mover.md_listen_sock);
1874                 (void) ndmpd_remove_file_handler(session,
1875                     session->ns_mover.md_listen_sock);
1876                 (void) close(session->ns_mover.md_listen_sock);
1877                 session->ns_mover.md_listen_sock = -1;
1878         }
1879         if (session->ns_mover.md_sock != -1) {
1880                 NDMP_LOG(LOG_DEBUG, "mover.sock: %d",
1881                     session->ns_mover.md_sock);
1882                 (void) ndmpd_remove_file_handler(session,
1883                     session->ns_mover.md_sock);
1884                 (void) close(session->ns_mover.md_sock);
1885                 session->ns_mover.md_sock = -1;
1886         }
1887         (void) cond_broadcast(&nlp->nlp_cv);
1888         (void) mutex_unlock(&nlp->nlp_mtx);
1889 }
1890 
1891 
1892 /*
1893  * ndmpd_mover_cleanup
1894  *
1895  * Parameters:
1896  *   session (input) - session pointer.
1897  *
1898  * Returns:
1899  *   void
1900  */
1901 void
1902 ndmpd_mover_cleanup(ndmpd_session_t *session)
1903 {
1904         NDMP_FREE(session->ns_mover.md_buf);
1905 }
1906 
1907 
1908 /*
1909  * ndmpd_mover_connect
1910  *   Create a connection to the specified mover.
1911  *
1912  * Parameters:
1913  *   session (input) - session pointer
1914  *
1915  * Returns:
1916  *   error code.
1917  */
1918 ndmp_error
1919 ndmpd_mover_connect(ndmpd_session_t *session, ndmp_mover_mode mover_mode)
1920 {
1921         ndmp_mover_addr *mover = &session->ns_data.dd_mover;
1922         struct sockaddr_in sin;
1923         int sock = -1;
1924 
1925         if (mover->addr_type == NDMP_ADDR_TCP) {
1926                 if (mover->ndmp_mover_addr_u.addr.ip_addr) {
1927                         (void) memset((void *) &sin, 0, sizeof (sin));
1928                         sin.sin_family = AF_INET;
1929                         sin.sin_addr.s_addr =
1930                             htonl(mover->ndmp_mover_addr_u.addr.ip_addr);
1931                         sin.sin_port =
1932                             htons(mover->ndmp_mover_addr_u.addr.port);
1933 
1934                         /*
1935                          * If the address type is TCP but both the address and
1936                          * the port number are zero, we have to use a different
1937                          * socket than the mover socket. This can happen when
1938                          * using NDMP disk to disk copy (AKA D2D copy).
1939                          * The NDMPCopy client will send a zero address to
1940                          * direct the server to use the mover socket as the
1941                          * data socket to receive the recovery data.
1942                          */
1943                         if (sin.sin_addr.s_addr == 0 && sin.sin_port == 0) {
1944                                 session->ns_data.dd_sock =
1945                                     session->ns_mover.md_sock;
1946                                 return (NDMP_NO_ERR);
1947                         }
1948 
1949                         NDMP_LOG(LOG_DEBUG, "addr: %u port: %u",
1950                             mover->ndmp_mover_addr_u.addr.ip_addr,
1951                             (ulong_t)sin.sin_port);
1952 
1953                         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1954                                 NDMP_LOG(LOG_DEBUG, "Socket error: %m");
1955                                 return (NDMP_IO_ERR);
1956                         }
1957                         if (connect(sock, (struct sockaddr *)&sin,
1958                             sizeof (sin)) < 0) {
1959                                 NDMP_LOG(LOG_DEBUG, "Connect error: %m");
1960                                 (void) close(sock);
1961                                 return (NDMP_IO_ERR);
1962                         }
1963                         set_socket_options(sock);
1964                 } else {
1965                         if ((session->ns_mover.md_state !=
1966                             NDMP_MOVER_STATE_ACTIVE) ||
1967                             (session->ns_mover.md_sock == -1)) {
1968 
1969                                 NDMP_LOG(LOG_DEBUG,
1970                                     "Not in active  state mover"
1971                                     "  state = %d or Invalid mover sock=%d",
1972                                     session->ns_mover.md_state,
1973                                     session->ns_mover.md_sock);
1974                                 return (NDMP_ILLEGAL_STATE_ERR);
1975                         }
1976 
1977                         sock = session->ns_mover.md_sock;
1978                         NDMP_LOG(LOG_DEBUG,
1979                             "session: 0x%x setting data sock fd: %d to be"
1980                             " same as listen_sock", session, sock);
1981                 }
1982 
1983                 NDMP_LOG(LOG_DEBUG, "sock fd: %d", sock);
1984 
1985                 session->ns_data.dd_sock = sock;
1986 
1987                 NDMP_LOG(LOG_DEBUG, "data.mover_sock: %u", sock);
1988 
1989                 return (NDMP_NO_ERR);
1990         }
1991         /* Local mover connection. */
1992 
1993         if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
1994                 NDMP_LOG(LOG_DEBUG, "Mover is not in listen state");
1995                 return (NDMP_ILLEGAL_STATE_ERR);
1996         }
1997         if (session->ns_tape.td_fd == -1) {
1998                 NDMP_LOG(LOG_DEBUG, "Tape device not open");
1999                 return (NDMP_DEV_NOT_OPEN_ERR);
2000         }
2001         if (mover_mode == NDMP_MOVER_MODE_READ &&
2002             session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
2003                 NDMP_LOG(LOG_ERR, "Write protected device.");
2004                 return (NDMP_WRITE_PROTECT_ERR);
2005         }
2006         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2007         session->ns_mover.md_mode = mover_mode;
2008 
2009         return (NDMP_NO_ERR);
2010 }
2011 
2012 
2013 
2014 /*
2015  * ndmpd_mover_seek
2016  *
2017  * Seek to the requested data stream position.
2018  * If the requested offset is outside of the current window,
2019  * the mover is paused and a notify_mover_paused request is sent
2020  * notifying the client that a seek is required.
2021  * If the requested offest is within the window but not within the
2022  * current record, then the tape is positioned to the record containing
2023  * the requested offest.
2024  * The requested amount of data is then read from the tape device and
2025  * written to the data connection.
2026  *
2027  * Parameters:
2028  *   session (input) - session pointer.
2029  *   offset  (input) - data stream position to seek to.
2030  *   length  (input) - amount of data that will be read.
2031  *
2032  * Returns:
2033  *   1 - seek pending completion by the NDMP client.
2034  *   0 - seek successfully completed.
2035  *  -1 - error.
2036  */
2037 int
2038 ndmpd_mover_seek(ndmpd_session_t *session, u_longlong_t offset,
2039     u_longlong_t length)
2040 {
2041         int ctlcmd;
2042         int ctlcnt;
2043         u_longlong_t tape_position;
2044         u_longlong_t buf_position;
2045         ndmp_notify_mover_paused_request pause_request;
2046 
2047         session->ns_mover.md_seek_position = offset;
2048         session->ns_mover.md_bytes_left_to_read = length;
2049 
2050         /*
2051          * If the requested position is outside of the window,
2052          * notify the client that a seek is required.
2053          */
2054         if (session->ns_mover.md_seek_position <
2055             session->ns_mover.md_window_offset ||
2056             session->ns_mover.md_seek_position >=
2057             session->ns_mover.md_window_offset +
2058             session->ns_mover.md_window_length) {
2059                 NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_SEEK(%llu)",
2060                     session->ns_mover.md_seek_position);
2061 
2062                 session->ns_mover.md_w_index = 0;
2063                 session->ns_mover.md_r_index = 0;
2064 
2065                 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2066                 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2067                 pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2068                 pause_request.seek_position = long_long_to_quad(offset);
2069 
2070                 if (ndmp_send_request(session->ns_connection,
2071                     NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2072                     (void *) &pause_request, 0) < 0) {
2073                         NDMP_LOG(LOG_DEBUG,
2074                             "Sending notify_mover_paused request");
2075                         return (-1);
2076                 }
2077                 return (1);
2078         }
2079         /*
2080          * Determine the data stream position of the first byte in the
2081          * data buffer.
2082          */
2083         buf_position = session->ns_mover.md_position -
2084             (session->ns_mover.md_position % session->ns_mover.md_record_size);
2085 
2086         /*
2087          * Determine the data stream position of the next byte that
2088          * will be read from tape.
2089          */
2090         tape_position = buf_position;
2091         if (session->ns_mover.md_w_index != 0)
2092                 tape_position += session->ns_mover.md_record_size;
2093 
2094         /*
2095          * Check if requested position is for data that has been read and is
2096          * in the buffer.
2097          */
2098         if (offset >= buf_position && offset < tape_position) {
2099                 session->ns_mover.md_position = offset;
2100                 session->ns_mover.md_r_index = session->ns_mover.md_position -
2101                     buf_position;
2102 
2103                 NDMP_LOG(LOG_DEBUG, "pos %llu r_index %u",
2104                     session->ns_mover.md_position,
2105                     session->ns_mover.md_r_index);
2106 
2107                 return (0);
2108         }
2109 
2110         ctlcmd = 0;
2111         if (tape_position > session->ns_mover.md_seek_position) {
2112                 /* Need to seek backward. */
2113                 ctlcmd = MTBSR;
2114                 ctlcnt = (int)((tape_position - offset - 1)
2115                     / session->ns_mover.md_record_size) + 1;
2116                 tape_position -= ((u_longlong_t)(((tape_position - offset - 1) /
2117                     session->ns_mover.md_record_size) + 1) *
2118                     (u_longlong_t)session->ns_mover.md_record_size);
2119 
2120         } else if (offset >= tape_position + session->ns_mover.md_record_size) {
2121                 /* Need to seek forward. */
2122                 ctlcmd = MTFSR;
2123                 ctlcnt = (int)((offset - tape_position)
2124                     / session->ns_mover.md_record_size);
2125                 tape_position += ((u_longlong_t)(((offset - tape_position) /
2126                     session->ns_mover.md_record_size)) *
2127                     (u_longlong_t)session->ns_mover.md_record_size);
2128         }
2129         /* Reposition the tape if necessary. */
2130         if (ctlcmd) {
2131                 NDMP_LOG(LOG_DEBUG, "cmd %d count %d",
2132                     ctlcmd, ctlcnt);
2133                 (void) ndmp_mtioctl(session->ns_tape.td_fd, ctlcmd, ctlcnt);
2134         }
2135 
2136         session->ns_mover.md_position = tape_position;
2137         session->ns_mover.md_r_index = 0;
2138         session->ns_mover.md_w_index = 0;
2139 
2140         NDMP_LOG(LOG_DEBUG, "pos %llu", session->ns_mover.md_position);
2141 
2142         return (0);
2143 }
2144 
2145 
2146 /* ** static functions ************************************************** */
2147 
2148 /*
2149  * create_listen_socket_v2
2150  *
2151  * Creates a socket for listening for accepting data connections.
2152  *
2153  * Parameters:
2154  *   session (input)  - session pointer.
2155  *   addr    (output) - location to store address of socket.
2156  *   port    (output) - location to store port of socket.
2157  *
2158  * Returns:
2159  *   0 - success.
2160  *  -1 - error.
2161  */
2162 static int
2163 create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
2164 {
2165         session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
2166         if (session->ns_mover.md_listen_sock < 0)
2167                 return (-1);
2168 
2169         /*
2170          * Add a file handler for the listen socket.
2171          * ndmpd_select will call accept_connection when a
2172          * connection is ready to be accepted.
2173          */
2174         if (ndmpd_add_file_handler(session, (void *) session,
2175             session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
2176             accept_connection) < 0) {
2177                 (void) close(session->ns_mover.md_listen_sock);
2178                 session->ns_mover.md_listen_sock = -1;
2179                 return (-1);
2180         }
2181 
2182         NDMP_LOG(LOG_DEBUG, "addr: 0x%x, port: %d", *addr, *port);
2183         return (0);
2184 }
2185 
2186 /*
2187  * accept_connection
2188  *
2189  * Accept a data connection from a data server.
2190  * Called by ndmpd_select when a connection is pending on
2191  * the mover listen socket.
2192  *
2193  * Parameters:
2194  *   cookie  (input) - session pointer.
2195  *   fd      (input) - file descriptor.
2196  *   mode    (input) - select mode.
2197  *
2198  * Returns:
2199  *   void.
2200  */
2201 /*ARGSUSED*/
2202 static void
2203 accept_connection(void *cookie, int fd, ulong_t mode)
2204 {
2205         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
2206         struct sockaddr_in from;
2207         int from_len;
2208 
2209         from_len = sizeof (from);
2210         session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
2211             &from_len);
2212 
2213         (void) ndmpd_remove_file_handler(session, fd);
2214         (void) close(session->ns_mover.md_listen_sock);
2215         session->ns_mover.md_listen_sock = -1;
2216 
2217         if (session->ns_mover.md_sock < 0) {
2218                 NDMP_LOG(LOG_DEBUG, "Accept error: %m");
2219                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
2220                 return;
2221         }
2222         set_socket_options(session->ns_mover.md_sock);
2223 
2224         NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
2225 
2226         if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
2227                 if (start_mover_for_backup(session) < 0) {
2228                         ndmpd_mover_error(session,
2229                             NDMP_MOVER_HALT_INTERNAL_ERROR);
2230                         return;
2231                 }
2232                 NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
2233                     inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2234                     ntohs(from.sin_port));
2235         } else {
2236                 NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
2237                     inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2238                     ntohs(from.sin_port));
2239         }
2240 
2241         NDMP_LOG(LOG_DEBUG, "Received connection");
2242 
2243         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2244 }
2245 
2246 /*
2247  * tape_read
2248  *
2249  * Reads a data record from tape. Detects and handles EOT conditions.
2250  *
2251  * Parameters:
2252  *   session (input) - session pointer.
2253  *   data    (input) - location to read data to.
2254  *
2255  * Returns:
2256  *    0 - operation aborted.
2257  *   -1 - tape read error.
2258  *   otherwise - number of bytes read.
2259  */
2260 static int
2261 tape_read(ndmpd_session_t *session, char *data)
2262 {
2263         ssize_t n;
2264         int err;
2265         int count = session->ns_mover.md_record_size;
2266 
2267         for (; ; ) {
2268                 n = read(session->ns_tape.td_fd, data, count);
2269                 if (n < 0) {
2270                         NDMP_LOG(LOG_ERR, "Tape read error: %m.");
2271                         return (TAPE_READ_ERR);
2272                 }
2273                 NS_ADD(rtape, n);
2274 
2275                 if (n == 0) {
2276                         if (!is_writer_running(session))
2277                                 return (TAPE_NO_WRITER_ERR);
2278 
2279                         /*
2280                          * End of media reached.
2281                          * Notify client and wait for the client to
2282                          * either abort the data operation or continue the
2283                          * operation after changing the tape.
2284                          */
2285                         NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
2286                             ++ndmp_log_msg_id,
2287                             "End of tape reached. Load next tape");
2288 
2289                         NDMP_LOG(LOG_DEBUG,
2290                             "End of tape reached. Load next tape");
2291 
2292                         err = change_tape(session);
2293 
2294                         /* Operation aborted or connection terminated? */
2295                         if (err < 0) {
2296                                 /*
2297                                  * K.L. Go back one record if it is read
2298                                  * but not used.
2299                                  */
2300 
2301                                 if (count != session->ns_mover.md_record_size) {
2302                                         (void) ndmp_mtioctl(
2303                                             session->ns_tape.td_fd, MTBSR, 1);
2304                                 }
2305                                 return (0);
2306                         }
2307                         /* Retry the read from the new tape. */
2308                         continue;
2309                 }
2310 
2311                 /* Change to pass Veritas Netbackup prequal test. */
2312                 data += n;
2313                 count -= n;
2314                 if (count <= 0) {
2315                         session->ns_mover.md_record_num++;
2316                         session->ns_tape.td_record_count++;
2317                         return (n);
2318                 }
2319         }
2320 }
2321 
2322 /*
2323  * change_tape
2324  *
2325  * Send a notify_pause request (protocol version 1) or
2326  * notify_mover_pause request (protocol version 2) to the
2327  * NDMP client to inform
2328  * the client that a tape volume change is required.
2329  * Process messages until the data/mover operation is either aborted
2330  * or continued.
2331  *
2332  * Parameters:
2333  *   client_data (input) - session pointer.
2334  *
2335  * Returns:
2336  *   0 - operation has been continued.
2337  *  -1 - operation has been aborted.
2338  */
2339 static int
2340 change_tape(ndmpd_session_t *session)
2341 {
2342         ndmp_notify_mover_paused_request request;
2343 
2344         session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2345 
2346         if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ)
2347                 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOM;
2348         else
2349                 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOF;
2350 
2351         request.reason = session->ns_mover.md_pause_reason;
2352         request.seek_position = long_long_to_quad(0LL);
2353 
2354         NDMP_LOG(LOG_DEBUG, "ndmp_send_request: MOVER_PAUSED, reason: %d",
2355             session->ns_mover.md_pause_reason);
2356 
2357         if (ndmp_send_request(session->ns_connection,
2358             NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2359             (void *) &request, 0) < 0) {
2360                 NDMP_LOG(LOG_DEBUG,
2361                     "Sending notify_mover_paused request");
2362                 return (-1);
2363         }
2364         /*
2365          * Wait for until the state is changed by
2366          * an abort or continue request.
2367          */
2368         return (ndmp_wait_for_mover(session));
2369 }
2370 
2371 
2372 /*
2373  * discard_data
2374  *
2375  * Read and discard data from the data connection.
2376  * Called when a module has called ndmpd_seek() prior to
2377  * reading all of the data from the previous seek.
2378  *
2379  * Parameters:
2380  *   session (input) - session pointer.
2381  *
2382  * Returns:
2383  *   number of bytes read and discarded.
2384  *  -1 - error.
2385  */
2386 static int
2387 discard_data(ndmpd_session_t *session, ulong_t length)
2388 {
2389         int n;
2390         char *addr;
2391 
2392         if ((addr = ndmp_malloc(length)) == NULL)
2393                 return (-1);
2394 
2395         /* Read and discard the data. */
2396         n = read(session->ns_mover.md_sock, addr, length);
2397         if (n < 0) {
2398                 NDMP_LOG(LOG_ERR, "Socket read error: %m.");
2399                 free(addr);
2400                 return (-1);
2401         }
2402 
2403         free(addr);
2404         return (n);
2405 }
2406 
2407 
2408 /*
2409  * mover_tape_read_one_buf
2410  *
2411  * Read one buffer from the tape. This is used by mover_tape_reader
2412  *
2413  * Parameters:
2414  *   session (input) - session pointer.
2415  *   buf (input) - buffer read
2416  *
2417  * Returns:
2418  *   0: on success
2419  *  -1: otherwise
2420  */
2421 static int
2422 mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2423 {
2424         int n;
2425 
2426         tlm_buffer_mark_empty(buf);
2427 
2428         /*
2429          * If the end of the mover window has been reached,
2430          * then notify the client that a seek is needed.
2431          * Remove the file handler to prevent this function from
2432          * being called. The handler will be reinstalled in
2433          * ndmpd_mover_continue.
2434          */
2435 
2436         if (session->ns_mover.md_position >=
2437             session->ns_mover.md_window_offset +
2438             session->ns_mover.md_window_length) {
2439                 ndmp_notify_mover_paused_request pause_request;
2440 
2441                 NDMP_LOG(LOG_DEBUG, "end of mover window");
2442 
2443                 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2444                 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2445                 pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2446                 pause_request.seek_position =
2447                     long_long_to_quad(session->ns_mover.md_position);
2448 
2449                 if (ndmp_send_request(session->ns_connection,
2450                     NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2451                     (void *) &pause_request, 0) < 0) {
2452                         NDMP_LOG(LOG_DEBUG,
2453                             "Sending notify_mover_paused request");
2454                         ndmpd_mover_error(session,
2455                             NDMP_MOVER_HALT_INTERNAL_ERROR);
2456                 }
2457                 buf->tb_errno = EIO;
2458                 return (TAPE_READ_ERR);
2459         }
2460 
2461         n = tape_read(session, buf->tb_buffer_data);
2462 
2463         NDMP_LOG(LOG_DEBUG, "read %d bytes from tape", n);
2464 
2465         if (n <= 0) {
2466                 if (n < 0)
2467                         ndmpd_mover_error(session,
2468                             (n == 0 ? NDMP_MOVER_HALT_ABORTED :
2469                             NDMP_MOVER_HALT_INTERNAL_ERROR));
2470                 return (TAPE_READ_ERR);
2471         }
2472 
2473         buf->tb_full = TRUE;
2474         buf->tb_buffer_size = session->ns_mover.md_record_size;
2475 
2476         /*
2477          * Discard data if the current data stream position is
2478          * prior to the seek position. This is necessary if a seek
2479          * request set the seek pointer to a position that is not a
2480          * record boundary. The seek request handler can only position
2481          * to the start of a record.
2482          */
2483         if (session->ns_mover.md_position < session->ns_mover.md_seek_position)
2484                 session->ns_mover.md_position =
2485                     session->ns_mover.md_seek_position;
2486 
2487         return (0);
2488 }
2489 
2490 
2491 /*
2492  * mover_tape_reader
2493  *
2494  * Mover tape reader thread. It is launched when the mover is started
2495  * for restore.
2496  *
2497  * Parameters:
2498  *   session (input) - session pointer.
2499  *
2500  * Returns:
2501  *   0: on success
2502  *  -1: otherwise
2503  */
2504 int
2505 mover_tape_reader(ndmpd_session_t *session)
2506 {
2507         int bidx;       /* buffer index */
2508         int rv;
2509         ndmp_lbr_params_t *nlp;
2510         tlm_buffer_t *buf;
2511         tlm_buffers_t *bufs;
2512         tlm_cmd_t *lcmd;        /* Local command */
2513         tlm_commands_t *cmds;   /* Commands structure */
2514 
2515         if ((nlp = ndmp_get_nlp(session)) == NULL) {
2516                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2517                 return (-1);
2518         }
2519 
2520         cmds = &nlp->nlp_cmds;
2521         lcmd = cmds->tcs_command;
2522         bufs = lcmd->tc_buffers;
2523 
2524         lcmd->tc_ref++;
2525         cmds->tcs_reader_count++;
2526 
2527         /*
2528          * Let our parent thread know that we are running.
2529          */
2530         tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_READER);
2531 
2532         buf = tlm_buffer_in_buf(bufs, &bidx);
2533         while (cmds->tcs_reader == TLM_RESTORE_RUN &&
2534             lcmd->tc_reader == TLM_RESTORE_RUN) {
2535                 buf = tlm_buffer_in_buf(bufs, NULL);
2536 
2537                 if (buf->tb_full) {
2538                         NDMP_LOG(LOG_DEBUG, "R%d", bidx);
2539                         /*
2540                          * The buffer is still full, wait for the consumer
2541                          * thread to use it.
2542                          */
2543                         tlm_buffer_out_buf_timed_wait(bufs, 100);
2544 
2545                 } else {
2546                         NDMP_LOG(LOG_DEBUG, "r%d", bidx);
2547 
2548                         rv = mover_tape_read_one_buf(session, buf);
2549                         /*
2550                          * If there was an error while reading, such as
2551                          * end of stream.
2552                          */
2553                         if (rv < 0) {
2554                                 NDMP_LOG(LOG_DEBUG, "Exiting, rv: %d", rv);
2555                                 break;
2556                         }
2557 
2558                         /*
2559                          * Can we do more buffering?
2560                          */
2561                         if (is_buffer_erroneous(buf)) {
2562                                 NDMP_LOG(LOG_DEBUG,
2563                                     "Exiting, errno: %d, eot: %d, eof: %d",
2564                                     buf->tb_errno, buf->tb_eot, buf->tb_eof);
2565                                 break;
2566                         }
2567 
2568                         (void) tlm_buffer_advance_in_idx(bufs);
2569                         tlm_buffer_release_in_buf(bufs);
2570                         bidx = bufs->tbs_buffer_in;
2571                 }
2572         }
2573 
2574         /* If the consumer is waiting for us, wake it up. */
2575         tlm_buffer_release_in_buf(bufs);
2576 
2577         /*
2578          * Clean up.
2579          */
2580         cmds->tcs_reader_count--;
2581         lcmd->tc_ref--;
2582         lcmd->tc_writer = TLM_STOP;
2583         return (0);
2584 }
2585 
2586 
2587 /*
2588  * mover_socket_write_one_buf
2589  *
2590  * Write one buffer to the network socket. This is used by mover_socket_writer
2591  *
2592  * Parameters:
2593  *   session (input) - session pointer.
2594  *   buf (input) - buffer read
2595  *
2596  * Returns:
2597  *   0: on success
2598  *  -1: otherwise
2599  */
2600 static int
2601 mover_socket_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2602 {
2603         int n;
2604 
2605         /* Write the data to the data connection. */
2606         errno = 0;
2607         n = write(session->ns_mover.md_sock, buf->tb_buffer_data,
2608             buf->tb_buffer_size);
2609 
2610         NDMP_LOG(LOG_DEBUG, "n: %d, len: %d", n, buf->tb_buffer_size);
2611 
2612         if (n < 0) {
2613                 NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
2614                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
2615                 return (-1);
2616         }
2617 
2618         session->ns_mover.md_position += n;
2619         session->ns_mover.md_bytes_left_to_read -= n;
2620         tlm_buffer_mark_empty(buf);
2621 
2622         /*
2623          * If the read limit has been reached,
2624          * then remove the file handler to prevent this
2625          * function from getting called. The next mover_read request
2626          * will reinstall the handler.
2627          */
2628         if (session->ns_mover.md_bytes_left_to_read == 0) {
2629                 NDMP_LOG(LOG_DEBUG, "bytes_left_to_read == 0");
2630                 (void) ndmpd_remove_file_handler(session,
2631                     session->ns_mover.md_sock);
2632                 return (-1);
2633         }
2634 
2635         return (0);
2636 }
2637 
2638 
2639 
2640 /*
2641  * mover_socket_writer
2642  *
2643  * Mover's socket writer thread. This thread sends the read buffer
2644  * from the tape to the data server through the network socket.
2645  *
2646  * Parameters:
2647  *   session (input) - session pointer.
2648  *
2649  * Returns:
2650  *   0: on success
2651  *  -1: otherwise
2652  */
2653 int
2654 mover_socket_writer(ndmpd_session_t *session)
2655 {
2656         int bidx;       /* buffer index */
2657         ndmp_lbr_params_t *nlp;
2658         tlm_buffer_t *buf;
2659         tlm_buffers_t *bufs;
2660         tlm_cmd_t *lcmd;        /* Local command */
2661         tlm_commands_t *cmds;   /* Commands structure */
2662 
2663         if ((nlp = ndmp_get_nlp(session)) == NULL) {
2664                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2665                 return (-1);
2666         }
2667 
2668         cmds = &nlp->nlp_cmds;
2669         lcmd = cmds->tcs_command;
2670         bufs = lcmd->tc_buffers;
2671 
2672         lcmd->tc_ref++;
2673         cmds->tcs_writer_count++;
2674 
2675         /*
2676          * Let our parent thread know that we are running.
2677          */
2678         tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_WRITER);
2679 
2680         bidx = bufs->tbs_buffer_out;
2681         while (cmds->tcs_writer != (int)TLM_ABORT &&
2682             lcmd->tc_writer != (int)TLM_ABORT) {
2683                 buf = &bufs->tbs_buffer[bidx];
2684 
2685                 if (buf->tb_full) {
2686                         NDMP_LOG(LOG_DEBUG, "w%d", bidx);
2687 
2688                         if (mover_socket_write_one_buf(session, buf) < 0) {
2689                                 NDMP_LOG(LOG_DEBUG,
2690                                     "mover_socket_write_one_buf() < 0");
2691                                 break;
2692                         }
2693 
2694                         (void) tlm_buffer_advance_out_idx(bufs);
2695                         tlm_buffer_release_out_buf(bufs);
2696                         bidx = bufs->tbs_buffer_out;
2697                 } else {
2698                         if (lcmd->tc_writer != TLM_RESTORE_RUN) {
2699                                 /* No more data is coming, time to exit */
2700                                 NDMP_LOG(LOG_DEBUG, "Time to exit");
2701                                 break;
2702                         }
2703                         NDMP_LOG(LOG_DEBUG, "W%d", bidx);
2704                         /*
2705                          * The buffer is not full, wait for the producer
2706                          * thread to fill it.
2707                          */
2708                         tlm_buffer_in_buf_timed_wait(bufs, 100);
2709                 }
2710         }
2711 
2712         if (cmds->tcs_writer == (int)TLM_ABORT)
2713                 NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == (int)TLM_ABORT");
2714         if (lcmd->tc_writer == (int)TLM_ABORT)
2715                 NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
2716 
2717         /* If the producer is waiting for us, wake it up. */
2718         tlm_buffer_release_out_buf(bufs);
2719 
2720         /*
2721          * Clean up.
2722          */
2723         cmds->tcs_writer_count--;
2724         lcmd->tc_ref--;
2725         lcmd->tc_reader = TLM_STOP;
2726         return (0);
2727 }
2728 
2729 
2730 /*
2731  * start_mover_for_restore
2732  *
2733  * Creates the mover tape reader and network writer threads for
2734  * the mover to perform the 3-way restore.
2735  *
2736  * Parameters:
2737  *   session (input) - session pointer.
2738  *
2739  * Returns:
2740  *   0: on success
2741  *  -1: otherwise
2742  */
2743 static int
2744 start_mover_for_restore(ndmpd_session_t *session)
2745 {
2746         ndmp_lbr_params_t *nlp;
2747         tlm_commands_t *cmds;
2748         long xfer_size;
2749         int rc;
2750 
2751         if ((nlp = ndmp_get_nlp(session)) == NULL) {
2752                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2753                 return (-1);
2754         }
2755 
2756         cmds = &nlp->nlp_cmds;
2757         (void) memset(cmds, 0, sizeof (*cmds));
2758         cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
2759         xfer_size = ndmp_buffer_get_size(session);
2760         cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2761         if (cmds->tcs_command == NULL)
2762                 return (-1);
2763 
2764         cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
2765         cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
2766 
2767         /*
2768          * We intentionnally don't wait for the threads to start since the
2769          * reply of the request (which resulted in calling this function)
2770          * must be sent to the client before probable errors are sent
2771          * to the client.
2772          */
2773         rc = pthread_create(NULL, NULL, (funct_t)mover_tape_reader, session);
2774         if (rc == 0) {
2775                 tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_READER);
2776         } else {
2777                 NDMP_LOG(LOG_DEBUG, "Launch mover_tape_reader: %s",
2778                     strerror(rc));
2779                 return (-1);
2780         }
2781 
2782         rc = pthread_create(NULL, NULL, (funct_t)mover_socket_writer, session);
2783         if (rc == 0) {
2784                 tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_WRITER);
2785         } else {
2786                 NDMP_LOG(LOG_DEBUG, "Launch mover_socket_writer: %s",
2787                     strerror(rc));
2788                 return (-1);
2789         }
2790 
2791         tlm_release_reader_writer_ipc(cmds->tcs_command);
2792         return (0);
2793 }
2794 
2795 
2796 /*
2797  * mover_socket_read_one_buf
2798  *
2799  * Read one buffer from the network socket for the mover. This is used
2800  * by mover_socket_reader
2801  *
2802  * Parameters:
2803  *   session (input) - session pointer.
2804  *   buf (input) - buffer read
2805  *   read_size (input) - size to be read
2806  *
2807  * Returns:
2808  *   0: on success
2809  *  -1: otherwise
2810  */
2811 static int
2812 mover_socket_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf,
2813     long read_size)
2814 {
2815         int n, index;
2816         long toread;
2817 
2818         tlm_buffer_mark_empty(buf);
2819         for (index = 0, toread = read_size; toread > 0; ) {
2820                 errno = 0;
2821                 NDMP_LOG(LOG_DEBUG, "index: %d, toread: %d", index, toread);
2822 
2823                 n = read(session->ns_mover.md_sock, &buf->tb_buffer_data[index],
2824                     toread);
2825                 if (n == 0) {
2826                         NDMP_LOG(LOG_DEBUG, "n: %d", n);
2827                         break;
2828                 } else if (n > 0) {
2829                         NDMP_LOG(LOG_DEBUG, "n: %d", n);
2830                         index += n;
2831                         toread -= n;
2832                 } else {
2833                         buf->tb_eof = TRUE;
2834                         buf->tb_errno = errno;
2835                         buf->tb_buffer_size = 0;
2836                         NDMP_LOG(LOG_DEBUG, "n: %d, errno: %m", n);
2837                         return (-1);
2838                 }
2839         }
2840 
2841         if (index > 0) {
2842                 buf->tb_full = TRUE;
2843                 buf->tb_buffer_size = read_size;
2844                 if (read_size > 0)
2845                         (void) memset(&buf->tb_buffer_data[index], 0,
2846                             read_size - index);
2847         } else {
2848                 buf->tb_eof = TRUE;
2849                 buf->tb_buffer_size = 0;
2850         }
2851 
2852         NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
2853             " errno: %d, size: %d, data: 0x%x",
2854             buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
2855             buf->tb_buffer_size, buf->tb_buffer_data);
2856 
2857         return (0);
2858 }
2859 
2860 
2861 
2862 /*
2863  * mover_socket_reader
2864  *
2865  * Mover socket reader thread. This is used when reading data from the
2866  * network socket for performing remote backups.
2867  *
2868  * Parameters:
2869  *   session (input) - session pointer.
2870  *
2871  * Returns:
2872  *   0: on success
2873  *  -1: otherwise
2874  */
2875 int
2876 mover_socket_reader(ndmpd_session_t *session)
2877 {
2878         int bidx;       /* buffer index */
2879         ndmp_lbr_params_t *nlp;
2880         tlm_buffer_t *buf;
2881         tlm_buffers_t *bufs;
2882         tlm_cmd_t *lcmd;        /* Local command */
2883         tlm_commands_t *cmds;   /* Commands structure */
2884         static int nr = 0;
2885 
2886         if ((nlp = ndmp_get_nlp(session)) == NULL) {
2887                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2888                 return (-1);
2889         }
2890 
2891         cmds = &nlp->nlp_cmds;
2892         lcmd = cmds->tcs_command;
2893         bufs = lcmd->tc_buffers;
2894 
2895         lcmd->tc_ref++;
2896         cmds->tcs_reader_count++;
2897 
2898         /*
2899          * Let our parent thread know that we are running.
2900          */
2901         tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_READER);
2902 
2903         bidx = bufs->tbs_buffer_in;
2904         while (cmds->tcs_reader == TLM_BACKUP_RUN &&
2905             lcmd->tc_reader == TLM_BACKUP_RUN) {
2906                 buf = &bufs->tbs_buffer[bidx];
2907 
2908                 if (buf->tb_full) {
2909                         NDMP_LOG(LOG_DEBUG, "R%d", bidx);
2910                         /*
2911                          * The buffer is still full, wait for the consumer
2912                          * thread to use it.
2913                          */
2914                         tlm_buffer_out_buf_timed_wait(bufs, 100);
2915                 } else {
2916                         NDMP_LOG(LOG_DEBUG, "r%d, nr: %d", bidx, ++nr);
2917 
2918                         (void) mover_socket_read_one_buf(session, buf,
2919                             bufs->tbs_data_transfer_size);
2920 
2921                         /*
2922                          * Can we do more buffering?
2923                          */
2924                         if (is_buffer_erroneous(buf)) {
2925                                 NDMP_LOG(LOG_DEBUG,
2926                                     "Exiting, errno: %d, eot: %d, eof: %d",
2927                                     buf->tb_errno, buf->tb_eot, buf->tb_eof);
2928                                 break;
2929                         }
2930 
2931                         (void) tlm_buffer_advance_in_idx(bufs);
2932                         tlm_buffer_release_in_buf(bufs);
2933                         bidx = bufs->tbs_buffer_in;
2934                 }
2935         }
2936 
2937         if (cmds->tcs_reader != TLM_BACKUP_RUN)
2938                 NDMP_LOG(LOG_DEBUG, "cmds->tcs_reader != TLM_BACKUP_RUN");
2939         if (lcmd->tc_reader != TLM_BACKUP_RUN)
2940                 NDMP_LOG(LOG_DEBUG, "lcmd->tc_reader != TLM_BACKUP_RUN");
2941         NDMP_LOG(LOG_DEBUG, "nr: %d", nr);
2942 
2943         /* If the consumer is waiting for us, wake it up. */
2944         tlm_buffer_release_in_buf(bufs);
2945 
2946         /*
2947          * Clean up.
2948          */
2949         cmds->tcs_reader_count--;
2950         lcmd->tc_ref--;
2951         lcmd->tc_writer = TLM_STOP;
2952         return (0);
2953 }
2954 
2955 
2956 /*
2957  * mover_tape_writer_one_buf
2958  *
2959  * Write one buffer for the mover to the local tape device. This is
2960  * used by mover_tape_writer thread.
2961  *
2962  * Parameters:
2963  *   session (input) - session pointer.
2964  *   buf (input) - buffer read
2965  *
2966  * Returns:
2967  *   0: on success
2968  *  -1: otherwise
2969  */
2970 static int
2971 mover_tape_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2972 {
2973         int n;
2974 
2975         NDMP_LOG(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
2976             " errno: %d, size: %d, data: 0x%x",
2977             buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
2978             buf->tb_buffer_size, buf->tb_buffer_data);
2979 
2980         n = mover_tape_write_v3(session, buf->tb_buffer_data,
2981             buf->tb_buffer_size);
2982 
2983         NDMP_LOG(LOG_DEBUG, "n: %d", n);
2984 
2985         if (n <= 0) {
2986                 ndmpd_mover_error(session, (n == 0 ? NDMP_MOVER_HALT_ABORTED
2987                     : NDMP_MOVER_HALT_INTERNAL_ERROR));
2988                 return (-1);
2989         }
2990         session->ns_mover.md_position += n;
2991         session->ns_mover.md_data_written += n;
2992         session->ns_mover.md_record_num++;
2993 
2994         NDMP_LOG(LOG_DEBUG, "Calling tlm_buffer_mark_empty(buf)");
2995         tlm_buffer_mark_empty(buf);
2996 
2997         return (0);
2998 }
2999 
3000 
3001 /*
3002  * mover_tape_writer
3003  *
3004  * Mover tape writer thread. This is used for performing remote backups
3005  * in a 3-way configuration. It writes the data from network socket to
3006  * the locally attached tape device.
3007  *
3008  * Parameters:
3009  *   session (input) - session pointer.
3010  *
3011  * Returns:
3012  *   0: on success
3013  *  -1: otherwise
3014  */
3015 int
3016 mover_tape_writer(ndmpd_session_t *session)
3017 {
3018         int bidx;
3019         ndmp_lbr_params_t *nlp;
3020         tlm_buffer_t *buf;
3021         tlm_buffers_t *bufs;
3022         tlm_cmd_t *lcmd;
3023         tlm_commands_t *cmds;
3024         static int nw = 0;
3025 
3026         if ((nlp = ndmp_get_nlp(session)) == NULL) {
3027                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3028                 return (-1);
3029         }
3030 
3031         cmds = &nlp->nlp_cmds;
3032         lcmd = cmds->tcs_command;
3033         bufs = lcmd->tc_buffers;
3034 
3035         lcmd->tc_ref++;
3036         cmds->tcs_writer_count++;
3037 
3038         /*
3039          * Let our parent thread know that we are running.
3040          */
3041         tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_WRITER);
3042 
3043         bidx = bufs->tbs_buffer_out;
3044         buf = &bufs->tbs_buffer[bidx];
3045         while (cmds->tcs_writer != (int)TLM_ABORT &&
3046             lcmd->tc_writer != (int)TLM_ABORT) {
3047                 if (buf->tb_full) {
3048                         NDMP_LOG(LOG_DEBUG, "w%d, nw: %d", bidx, ++nw);
3049 
3050                         if (mover_tape_write_one_buf(session, buf) < 0) {
3051                                 NDMP_LOG(LOG_DEBUG,
3052                                     "mover_tape_write_one_buf() failed");
3053                                 break;
3054                         }
3055 
3056                         (void) tlm_buffer_advance_out_idx(bufs);
3057                         tlm_buffer_release_out_buf(bufs);
3058                         bidx = bufs->tbs_buffer_out;
3059                         buf = &bufs->tbs_buffer[bidx];
3060                 } else {
3061                         if (lcmd->tc_writer != TLM_BACKUP_RUN) {
3062                                 /* No more data is coming, time to exit */
3063                                 NDMP_LOG(LOG_DEBUG, "Time to exit");
3064                                 break;
3065                         }
3066                         NDMP_LOG(LOG_DEBUG, "W%d", bidx);
3067                         /*
3068                          * The buffer is not full, wait for the producer
3069                          * thread to fill it.
3070                          */
3071                         tlm_buffer_in_buf_timed_wait(bufs, 100);
3072                 }
3073         }
3074 
3075         if (cmds->tcs_writer == (int)TLM_ABORT)
3076                 NDMP_LOG(LOG_DEBUG, "cmds->tcs_writer == TLM_ABORT");
3077         if (lcmd->tc_writer == (int)TLM_ABORT)
3078                 NDMP_LOG(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
3079         NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
3080 
3081         if (buf->tb_errno == 0) {
3082                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
3083         } else {
3084                 NDMP_LOG(LOG_DEBUG, "buf->tb_errno: %d", buf->tb_errno);
3085                 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
3086         }
3087 
3088         /* If the producer is waiting for us, wake it up. */
3089         tlm_buffer_release_out_buf(bufs);
3090 
3091         /*
3092          * Clean up.
3093          */
3094         cmds->tcs_writer_count--;
3095         lcmd->tc_ref--;
3096         lcmd->tc_reader = TLM_STOP;
3097         return (0);
3098 }
3099 
3100 
3101 /*
3102  * start_mover_for_backup
3103  *
3104  * Starts a remote backup by running socket reader and tape
3105  * writer threads. The mover runs a remote backup in a 3-way backup
3106  * configuration.
3107  *
3108  * Parameters:
3109  *   session (input) - session pointer.
3110  *
3111  * Returns:
3112  *   0: on success
3113  *  -1: otherwise
3114  */
3115 static int
3116 start_mover_for_backup(ndmpd_session_t *session)
3117 {
3118         ndmp_lbr_params_t *nlp;
3119         tlm_commands_t *cmds;
3120         int rc;
3121 
3122         if ((nlp = ndmp_get_nlp(session)) == NULL) {
3123                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3124                 return (-1);
3125         }
3126 
3127         cmds = &nlp->nlp_cmds;
3128         (void) memset(cmds, 0, sizeof (*cmds));
3129         cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
3130         cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE,
3131             session->ns_mover.md_record_size);
3132         if (cmds->tcs_command == NULL)
3133                 return (-1);
3134 
3135         cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
3136         cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
3137 
3138         /*
3139          * We intentionally don't wait for the threads to start since the
3140          * reply of the request (which resulted in calling this function)
3141          * must be sent to the client before probable errors are sent
3142          * to the client.
3143          */
3144         rc = pthread_create(NULL, NULL, (funct_t)mover_socket_reader, session);
3145         if (rc == 0) {
3146                 tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_READER);
3147         } else {
3148                 NDMP_LOG(LOG_DEBUG, "Launch mover_socket_reader: %s",
3149                     strerror(rc));
3150                 return (-1);
3151         }
3152 
3153         rc = pthread_create(NULL, NULL, (funct_t)mover_tape_writer, session);
3154         if (rc == 0) {
3155                 tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_WRITER);
3156         } else {
3157                 NDMP_LOG(LOG_DEBUG, "Launch mover_tape_writer: %s",
3158                     strerror(rc));
3159                 return (-1);
3160         }
3161 
3162         tlm_release_reader_writer_ipc(cmds->tcs_command);
3163         return (0);
3164 }
3165 
3166 
3167 /*
3168  * is_writer_running
3169  *
3170  * Find out if the writer thread has started or not.
3171  *
3172  * Parameters:
3173  *   session (input) - session pointer.
3174  *
3175  * Returns:
3176  *   0: not started
3177  *   non-zero: started
3178  *      Note: non-zero is also returned if the backup type is
3179  *              neither TAR nor DUMP.  I.e. the is_writer_running()
3180  *              check does not apply in this case and things should
3181  *              appear successful.
3182  */
3183 static boolean_t
3184 is_writer_running(ndmpd_session_t *session)
3185 {
3186         boolean_t rv;
3187         ndmp_lbr_params_t *nlp;
3188 
3189         if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
3190                 return (1);
3191 
3192         if (session == NULL)
3193                 rv = 0;
3194         else if ((nlp = ndmp_get_nlp(session)) == NULL)
3195                 rv = 0;
3196         else
3197                 rv = (nlp->nlp_cmds.tcs_writer_count > 0);
3198 
3199         return (rv);
3200 }
3201 
3202 
3203 /*
3204  * is_writer_running_v3
3205  *
3206  * Find out if the writer thread has started or not.
3207  *
3208  * Parameters:
3209  *   session (input) - session pointer.
3210  *
3211  * Returns:
3212  *   0: not started
3213  *   non-zero: started
3214  *      Note: non-zero is also returned if the backup type is
3215  *              neither TAR nor DUMP.  I.e. the is_writer_running()
3216  *              check does not apply in this case and things should
3217  *              appear successful.
3218  */
3219 static boolean_t
3220 is_writer_running_v3(ndmpd_session_t *session)
3221 {
3222         boolean_t rv;
3223         ndmp_lbr_params_t *nlp;
3224 
3225         if (session && (session->ns_butype > NDMP_BUTYPE_DUMP))
3226                 return (1);
3227 
3228         if (session == NULL)
3229                 rv = 0;
3230         else if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP)
3231                 rv = 1;
3232         else if ((nlp = ndmp_get_nlp(session)) == NULL)
3233                 rv = 0;
3234         else
3235                 rv = (nlp->nlp_cmds.tcs_writer_count > 0);
3236 
3237         return (rv);
3238 }
3239 
3240 
3241 /*
3242  * ndmpd_mover_error_send
3243  *
3244  * This function sends the notify message to the client.
3245  *
3246  * Parameters:
3247  *   session (input) - session pointer.
3248  *   reason  (input) - halt reason.
3249  *
3250  * Returns:
3251  *   Error code
3252  */
3253 int
3254 ndmpd_mover_error_send(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3255 {
3256         ndmp_notify_mover_halted_request req;
3257 
3258         req.reason = reason;
3259         req.text_reason = "";
3260 
3261         return (ndmp_send_request(session->ns_connection,
3262             NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
3263 }
3264 
3265 
3266 /*
3267  * ndmpd_mover_error_send_v4
3268  *
3269  * This function sends the notify message to the client.
3270  *
3271  * Parameters:
3272  *   session (input) - session pointer.
3273  *   reason  (input) - halt reason.
3274  *
3275  * Returns:
3276  *   Error code
3277  */
3278 int
3279 ndmpd_mover_error_send_v4(ndmpd_session_t *session,
3280     ndmp_mover_halt_reason reason)
3281 {
3282         ndmp_notify_mover_halted_request_v4 req;
3283 
3284         req.reason = reason;
3285 
3286         return (ndmp_send_request(session->ns_connection,
3287             NDMP_NOTIFY_MOVER_HALTED, NDMP_NO_ERR, (void *)&req, 0));
3288 }
3289 
3290 
3291 /*
3292  * ndmpd_mover_error
3293  *
3294  * This function is called when an unrecoverable mover error
3295  * has been detected. A notify message is sent to the client and the
3296  * mover is placed into the halted state.
3297  *
3298  * Parameters:
3299  *   session (input) - session pointer.
3300  *   reason  (input) - halt reason.
3301  *
3302  * Returns:
3303  *   void.
3304  */
3305 void
3306 ndmpd_mover_error(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3307 {
3308         ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
3309 
3310         if (session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED ||
3311             (session->ns_protocol_version > NDMPV2 &&
3312             session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE))
3313                 return;
3314 
3315         if (session->ns_protocol_version == NDMPV4) {
3316                 if (ndmpd_mover_error_send_v4(session, reason) < 0)
3317                         NDMP_LOG(LOG_DEBUG,
3318                             "Error sending notify_mover_halted request");
3319         } else {
3320                 /* No media error in V3 */
3321                 if (reason == NDMP_MOVER_HALT_MEDIA_ERROR)
3322                         reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
3323                 if (ndmpd_mover_error_send(session, reason) < 0)
3324                         NDMP_LOG(LOG_DEBUG,
3325                             "Error sending notify_mover_halted request");
3326         }
3327 
3328         (void) mutex_lock(&nlp->nlp_mtx);
3329         if (session->ns_mover.md_listen_sock != -1) {
3330                 (void) ndmpd_remove_file_handler(session,
3331                     session->ns_mover.md_listen_sock);
3332                 (void) close(session->ns_mover.md_listen_sock);
3333                 session->ns_mover.md_listen_sock = -1;
3334         }
3335         if (session->ns_mover.md_sock != -1) {
3336                 (void) ndmpd_remove_file_handler(session,
3337                     session->ns_mover.md_sock);
3338                 (void) close(session->ns_mover.md_sock);
3339                 session->ns_mover.md_sock = -1;
3340         }
3341 
3342         session->ns_mover.md_state = NDMP_MOVER_STATE_HALTED;
3343         session->ns_mover.md_halt_reason = reason;
3344         (void) cond_broadcast(&nlp->nlp_cv);
3345         (void) mutex_unlock(&nlp->nlp_mtx);
3346 }
3347 
3348 
3349 /*
3350  * mover_pause_v3
3351  *
3352  * Send an ndmp_notify_mover_paused request to the
3353  * NDMP client to inform the client that its attention is required.
3354  * Process messages until the data/mover operation is either aborted
3355  * or continued.
3356  *
3357  * Parameters:
3358  *   client_data (input) - session pointer.
3359  *   reason (input) - pause reason.
3360  *
3361  * Returns:
3362  *   0 - operation has been continued.
3363  *  -1 - operation has been aborted.
3364  */
3365 static int
3366 mover_pause_v3(ndmpd_session_t *session, ndmp_mover_pause_reason reason)
3367 {
3368         int rv;
3369         ndmp_notify_mover_paused_request request;
3370 
3371         rv = 0;
3372         session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3373         session->ns_mover.md_pause_reason = reason;
3374         session->ns_mover.md_pre_cond = FALSE;
3375 
3376         request.reason = session->ns_mover.md_pause_reason;
3377         request.seek_position =
3378             long_long_to_quad(session->ns_mover.md_position);
3379 
3380         if (ndmp_send_request(session->ns_connection, NDMP_NOTIFY_MOVER_PAUSED,
3381             NDMP_NO_ERR, (void *)&request, 0) < 0) {
3382                 NDMP_LOG(LOG_DEBUG,
3383                     "Error sending notify_mover_paused_request");
3384                 return (-1);
3385         }
3386 
3387         /*
3388          * 3-way operations are single-thread.  The same thread
3389          * should process the messages.
3390          *
3391          * 2-way operations are multi-thread.  The main thread
3392          * processes the messages.  We just need to wait and
3393          * see if the mover state changes or the operation aborts.
3394          */
3395         if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) {
3396                 /*
3397                  * Process messages until the state is changed by
3398                  * an abort, continue, or close request .
3399                  */
3400                 for (; ; ) {
3401                         if (ndmpd_select(session, TRUE, HC_CLIENT) < 0)
3402                                 return (-1);
3403 
3404                         if (session->ns_eof == TRUE)
3405                                 return (-1);
3406 
3407                         switch (session->ns_mover.md_state) {
3408                         case NDMP_MOVER_STATE_ACTIVE:
3409                                 session->ns_tape.td_record_count = 0;
3410                                 return (0);
3411 
3412                         case NDMP_MOVER_STATE_PAUSED:
3413                                 continue;
3414 
3415                         default:
3416                                 return (-1);
3417                         }
3418                 }
3419 
3420         } else {
3421                 if (session->ns_mover.md_data_addr.addr_type ==
3422                     NDMP_ADDR_LOCAL) {
3423                         rv = ndmp_wait_for_mover(session);
3424                 } else {
3425                         NDMP_LOG(LOG_DEBUG, "Invalid address type %d",
3426                             session->ns_mover.md_data_addr.addr_type);
3427                         rv = -1;
3428                 }
3429         }
3430 
3431         return (rv);
3432 }
3433 
3434 
3435 /*
3436  * mover_tape_write_v3
3437  *
3438  * Writes a data record to tape. Detects and handles EOT conditions.
3439  *
3440  * Parameters:
3441  *   session (input) - session pointer.
3442  *   data    (input) - data to be written.
3443  *   length  (input) - length of data to be written.
3444  *
3445  * Returns:
3446  *    0 - operation aborted by client.
3447  *   -1 - error.
3448  *   otherwise - number of bytes written.
3449  */
3450 static int
3451 mover_tape_write_v3(ndmpd_session_t *session, char *data, ssize_t length)
3452 {
3453         ssize_t n;
3454         ssize_t count = length;
3455 
3456         while (count > 0) {
3457                 /*
3458                  * Enforce mover window on write.
3459                  */
3460                 if (session->ns_mover.md_position >=
3461                     session->ns_mover.md_window_offset +
3462                     session->ns_mover.md_window_length) {
3463                         NDMP_LOG(LOG_DEBUG, "MOVER_PAUSE_EOW");
3464 
3465                         if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOW) < 0)
3466                                 /* Operation aborted or connection terminated */
3467                                 return (-1);
3468 
3469                 }
3470 
3471                 n = write(session->ns_tape.td_fd, data, count);
3472                 if (n < 0) {
3473                         NDMP_LOG(LOG_ERR, "Tape write error: %m.");
3474                         return (-1);
3475                 } else if (n > 0) {
3476                         NS_ADD(wtape, n);
3477                         count -= n;
3478                         data += n;
3479                         session->ns_tape.td_record_count++;
3480                 }
3481 
3482                 /* EOM handling */
3483                 if (count > 0) {
3484                         struct mtget mtstatus;
3485 
3486                         (void) ioctl(session->ns_tape.td_fd, MTIOCGET,
3487                             &mtstatus);
3488                         NDMP_LOG(LOG_DEBUG, "EOM detected (%d written bytes, "
3489                             "mover record %d, file #%d, block #%d)", n,
3490                             session->ns_tape.td_record_count,
3491                             mtstatus.mt_fileno, mtstatus.mt_blkno);
3492 
3493                         /*
3494                          * Notify the client to either abort the operation
3495                          * or change the tape.
3496                          */
3497                         NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3498                             ++ndmp_log_msg_id,
3499                             "End of tape reached. Load next tape");
3500 
3501                         if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM) < 0)
3502                                 /* Operation aborted or connection terminated */
3503                                 return (-1);
3504                 }
3505         }
3506 
3507         return (length);
3508 }
3509 
3510 
3511 /*
3512  * mover_tape_flush_v3
3513  *
3514  * Writes all remaining buffered data to tape. A partial record is
3515  * padded out to a full record with zeros.
3516  *
3517  * Parameters:
3518  *   session (input) - session pointer.
3519  *   data    (input) - data to be written.
3520  *   length  (input) - length of data to be written.
3521  *
3522  * Returns:
3523  *   -1 - error.
3524  *   otherwise - number of bytes written.
3525  */
3526 static int
3527 mover_tape_flush_v3(ndmpd_session_t *session)
3528 {
3529         int n;
3530 
3531         if (session->ns_mover.md_w_index == 0)
3532                 return (0);
3533 
3534         (void) memset((void*)&session->ns_mover.md_buf[session->
3535             ns_mover.md_w_index], 0,
3536             session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3537 
3538         n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3539             session->ns_mover.md_record_size);
3540         if (n < 0) {
3541                 NDMP_LOG(LOG_ERR, "Tape write error: %m.");
3542                 return (-1);
3543         }
3544 
3545         session->ns_mover.md_w_index = 0;
3546         session->ns_mover.md_position += n;
3547         return (n);
3548 }
3549 
3550 
3551 /*
3552  * ndmpd_local_write_v3
3553  *
3554  * Buffers and writes data to the tape device.
3555  * A full tape record is buffered before being written.
3556  *
3557  * Parameters:
3558  *   session    (input) - session pointer.
3559  *   data       (input) - data to be written.
3560  *   length     (input) - data length.
3561  *
3562  * Returns:
3563  *   0 - data successfully written.
3564  *  -1 - error.
3565  */
3566 int
3567 ndmpd_local_write_v3(ndmpd_session_t *session, char *data, ulong_t length)
3568 {
3569         ulong_t count = 0;
3570         ssize_t n;
3571         ulong_t len;
3572 
3573         if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
3574             session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
3575             session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
3576                 NDMP_LOG(LOG_DEBUG, "Invalid mover state to write data");
3577                 return (-1);
3578         }
3579 
3580         /*
3581          * A length of 0 indicates that any buffered data should be
3582          * flushed to tape.
3583          */
3584         if (length == 0) {
3585                 if (session->ns_mover.md_w_index == 0)
3586                         return (0);
3587 
3588                 (void) memset((void*)&session->ns_mover.md_buf[session->
3589                     ns_mover.md_w_index], 0, session->ns_mover.md_record_size -
3590                     session->ns_mover.md_w_index);
3591 
3592                 n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3593                     session->ns_mover.md_record_size);
3594                 if (n <= 0) {
3595                         ndmpd_mover_error(session,
3596                             (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3597                             NDMP_MOVER_HALT_MEDIA_ERROR));
3598                         return (-1);
3599                 }
3600 
3601                 session->ns_mover.md_position += n;
3602                 session->ns_mover.md_data_written +=
3603                     session->ns_mover.md_w_index;
3604                 session->ns_mover.md_record_num++;
3605                 session->ns_mover.md_w_index = 0;
3606                 return (0);
3607         }
3608 
3609         /* Break the data into records. */
3610         while (count < length) {
3611                 /*
3612                  * Determine if data needs to be buffered or
3613                  * can be written directly from user supplied location.
3614                  * We can fast path the write if there is no pending
3615                  * buffered data and there is at least a full records worth
3616                  * of data to be written.
3617                  */
3618                 if (session->ns_mover.md_w_index == 0 &&
3619                     length - count >= session->ns_mover.md_record_size) {
3620                         n = mover_tape_write_v3(session, &data[count],
3621                             session->ns_mover.md_record_size);
3622                         if (n <= 0) {
3623                                 ndmpd_mover_error(session,
3624                                     (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3625                                     NDMP_MOVER_HALT_MEDIA_ERROR));
3626                                 return (-1);
3627                         }
3628 
3629                         session->ns_mover.md_position += n;
3630                         session->ns_mover.md_data_written += n;
3631                         session->ns_mover.md_record_num++;
3632                         count += n;
3633                         continue;
3634                 }
3635 
3636                 /* Buffer the data */
3637                 len = length - count;
3638                 if (len > session->ns_mover.md_record_size -
3639                     session->ns_mover.md_w_index)
3640                         len = session->ns_mover.md_record_size -
3641                             session->ns_mover.md_w_index;
3642 
3643                 (void) memcpy(&session->ns_mover.md_buf[session->
3644                     ns_mover.md_w_index], &data[count], len);
3645                 session->ns_mover.md_w_index += len;
3646                 count += len;
3647 
3648                 /* Write the buffer if its full */
3649                 if (session->ns_mover.md_w_index ==
3650                     session->ns_mover.md_record_size) {
3651                         n = mover_tape_write_v3(session,
3652                             session->ns_mover.md_buf,
3653                             session->ns_mover.md_record_size);
3654                         if (n <= 0) {
3655                                 ndmpd_mover_error(session,
3656                                     (n == 0 ?  NDMP_MOVER_HALT_ABORTED :
3657                                     NDMP_MOVER_HALT_MEDIA_ERROR));
3658                                 return (-1);
3659                         }
3660 
3661                         session->ns_mover.md_position += n;
3662                         session->ns_mover.md_data_written += n;
3663                         session->ns_mover.md_record_num++;
3664                         session->ns_mover.md_w_index = 0;
3665                 }
3666         }
3667 
3668         return (0);
3669 }
3670 
3671 
3672 /*
3673  * mover_data_read_v3
3674  *
3675  * Reads backup data from the data connection and writes the
3676  * received data to the tape device.
3677  *
3678  * Parameters:
3679  *   cookie  (input) - session pointer.
3680  *   fd      (input) - file descriptor.
3681  *   mode    (input) - select mode.
3682  *
3683  * Returns:
3684  *   void.
3685  */
3686 /*ARGSUSED*/
3687 static void
3688 mover_data_read_v3(void *cookie, int fd, ulong_t mode)
3689 {
3690         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3691         int n;
3692         ulong_t index;
3693 
3694         n = read(fd, &session->ns_mover.md_buf[session->ns_mover.md_w_index],
3695             session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3696 
3697         /*
3698          * Since this function is only called when select believes data
3699          * is available to be read, a return of zero indicates the
3700          * connection has been closed.
3701          */
3702         if (n <= 0) {
3703                 if (n == 0) {
3704                         NDMP_LOG(LOG_DEBUG, "Data connection closed");
3705                         ndmpd_mover_error(session,
3706                             NDMP_MOVER_HALT_CONNECT_CLOSED);
3707                 } else {
3708                         /* Socket is non-blocking, perhaps there are no data */
3709                         if (errno == EAGAIN) {
3710                                 NDMP_LOG(LOG_ERR, "No data to read");
3711                                 return;
3712                         }
3713 
3714                         NDMP_LOG(LOG_ERR, "Failed to read from socket: %m");
3715                         ndmpd_mover_error(session,
3716                             NDMP_MOVER_HALT_INTERNAL_ERROR);
3717                 }
3718 
3719                 /* Save the index since mover_tape_flush_v3 resets it. */
3720                 index = session->ns_mover.md_w_index;
3721 
3722                 /* Flush any buffered data to tape. */
3723                 if (mover_tape_flush_v3(session) > 0) {
3724                         session->ns_mover.md_data_written += index;
3725                         session->ns_mover.md_record_num++;
3726                 }
3727 
3728                 return;
3729         }
3730 
3731         NDMP_LOG(LOG_DEBUG, "n %d", n);
3732 
3733         session->ns_mover.md_w_index += n;
3734 
3735         if (session->ns_mover.md_w_index == session->ns_mover.md_record_size) {
3736                 n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3737                     session->ns_mover.md_record_size);
3738                 if (n <= 0) {
3739                         ndmpd_mover_error(session,
3740                             (n == 0 ? NDMP_MOVER_HALT_ABORTED :
3741                             NDMP_MOVER_HALT_MEDIA_ERROR));
3742                         return;
3743                 }
3744 
3745                 session->ns_mover.md_position += n;
3746                 session->ns_mover.md_w_index = 0;
3747                 session->ns_mover.md_data_written += n;
3748                 session->ns_mover.md_record_num++;
3749         }
3750 }
3751 
3752 /*
3753  * mover_tape_read_v3
3754  *
3755  * Reads a data record from tape. Detects and handles EOT conditions.
3756  *
3757  * Parameters:
3758  *   session (input) - session pointer.
3759  *   data    (input) - location to read data to.
3760  *
3761  * Returns:
3762  *   0 - operation aborted.
3763  *   TAPE_READ_ERR - tape read IO error.
3764  *   TAPE_NO_WRITER_ERR - no writer is running during tape read
3765  *   otherwise - number of bytes read.
3766  */
3767 static int
3768 mover_tape_read_v3(ndmpd_session_t *session, char *data)
3769 {
3770         int pause_reason;
3771         ssize_t  n;
3772         int err;
3773         int count;
3774 
3775         count = session->ns_mover.md_record_size;
3776         while (count > 0) {
3777                 pause_reason = NDMP_MOVER_PAUSE_NA;
3778 
3779                 n = read(session->ns_tape.td_fd, data, count);
3780                 if (n < 0) {
3781                         /*
3782                          * If at beginning of file and read fails with EIO,
3783                          * then it's repeated attempt to read at EOT.
3784                          */
3785                         if (errno == EIO && tape_is_at_bof(session)) {
3786                                 NDMP_LOG(LOG_DEBUG, "Repeated read at EOT");
3787                                 pause_reason = NDMP_MOVER_PAUSE_EOM;
3788                                 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3789                                     ++ndmp_log_msg_id,
3790                                     "End of tape reached. Load next tape");
3791                         }
3792                         /*
3793                          * According to NDMPv4 spec preferred error code when
3794                          * trying to read from blank tape is NDMP_EOM_ERR.
3795                          */
3796                         else if (errno == EIO && tape_is_at_bot(session)) {
3797                                 NDMP_LOG(LOG_ERR,
3798                                     "Blank tape detected, returning EOM");
3799                                 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3800                                     ++ndmp_log_msg_id,
3801                                     "Blank tape. Load another tape");
3802                                 pause_reason = NDMP_MOVER_PAUSE_EOM;
3803                         } else {
3804                                 NDMP_LOG(LOG_ERR, "Tape read error: %m.");
3805                                 return (TAPE_READ_ERR);
3806                         }
3807                 } else if (n > 0) {
3808                         NS_ADD(rtape, n);
3809                         data += n;
3810                         count -= n;
3811                         session->ns_tape.td_record_count++;
3812                 } else {
3813                         if (!is_writer_running_v3(session))
3814                                 return (TAPE_NO_WRITER_ERR);
3815 
3816                         /*
3817                          * End of file or media reached. Notify client and
3818                          * wait for the client to either abort the data
3819                          * operation or continue the operation after changing
3820                          * the tape.
3821                          */
3822                         if (tape_is_at_bof(session)) {
3823                                 NDMP_LOG(LOG_DEBUG, "EOT detected");
3824                                 pause_reason = NDMP_MOVER_PAUSE_EOM;
3825                                 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3826                                     ++ndmp_log_msg_id, "End of medium reached");
3827                         } else {
3828                                 NDMP_LOG(LOG_DEBUG, "EOF detected");
3829                                 /* reposition the tape to BOT side of FM */
3830                                 fm_dance(session);
3831                                 pause_reason = NDMP_MOVER_PAUSE_EOF;
3832                                 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3833                                     ++ndmp_log_msg_id, "End of file reached.");
3834                         }
3835                 }
3836 
3837                 if (pause_reason != NDMP_MOVER_PAUSE_NA) {
3838                         err = mover_pause_v3(session, pause_reason);
3839 
3840                         /* Operation aborted or connection terminated? */
3841                         if (err < 0) {
3842                                 return (0);
3843                         }
3844                         /* Retry the read from new location */
3845                 }
3846         }
3847         return (session->ns_mover.md_record_size);
3848 }
3849 
3850 
3851 /*
3852  * mover_data_write_v3
3853  *
3854  * Reads backup data from the tape device and writes the
3855  * data to the data connection.
3856  * This function is called by ndmpd_select when the data connection
3857  * is ready for more data to be written.
3858  *
3859  * Parameters:
3860  *   cookie  (input) - session pointer.
3861  *   fd      (input) - file descriptor.
3862  *   mode    (input) - select mode.
3863  *
3864  * Returns:
3865  *   void.
3866  */
3867 /*ARGSUSED*/
3868 static void
3869 mover_data_write_v3(void *cookie, int fd, ulong_t mode)
3870 {
3871         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3872         int n;
3873         ulong_t len;
3874         u_longlong_t wlen;
3875         ndmp_notify_mover_paused_request pause_request;
3876 
3877         /*
3878          * If the end of the mover window has been reached,
3879          * then notify the client that a seek is needed.
3880          * Remove the file handler to prevent this function from
3881          * being called. The handler will be reinstalled in
3882          * ndmpd_mover_continue.
3883          */
3884         if (session->ns_mover.md_position >= session->ns_mover.md_window_offset
3885             + session->ns_mover.md_window_length) {
3886                 NDMP_LOG(LOG_DEBUG,
3887                     "MOVER_PAUSE_SEEK(%llu)", session->ns_mover.md_position);
3888 
3889                 session->ns_mover.md_w_index = 0;
3890                 session->ns_mover.md_r_index = 0;
3891 
3892                 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3893                 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
3894                 pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
3895                 pause_request.seek_position =
3896                     long_long_to_quad(session->ns_mover.md_position);
3897                 session->ns_mover.md_seek_position =
3898                     session->ns_mover.md_position;
3899 
3900                 (void) ndmpd_remove_file_handler(session, fd);
3901 
3902                 if (ndmp_send_request(session->ns_connection,
3903                     NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
3904                     (void *)&pause_request, 0) < 0) {
3905                         NDMP_LOG(LOG_DEBUG,
3906                             "Sending notify_mover_paused request");
3907                         ndmpd_mover_error(session,
3908                             NDMP_MOVER_HALT_INTERNAL_ERROR);
3909                 }
3910                 return;
3911         }
3912 
3913         /*
3914          * Read more data into the tape buffer if the buffer is empty.
3915          */
3916         if (session->ns_mover.md_w_index == 0) {
3917                 n = mover_tape_read_v3(session, session->ns_mover.md_buf);
3918 
3919                 NDMP_LOG(LOG_DEBUG,
3920                     "read %u bytes from tape", n);
3921 
3922                 if (n <= 0) {
3923                         ndmpd_mover_error(session, (n == 0 ?
3924                             NDMP_MOVER_HALT_ABORTED
3925                             : NDMP_MOVER_HALT_MEDIA_ERROR));
3926                         return;
3927                 }
3928 
3929                 /*
3930                  * Discard data if the current data stream position is
3931                  * prior to the seek position. This is necessary if a seek
3932                  * request set the seek pointer to a position that is not a
3933                  * record boundary. The seek request handler can only position
3934                  * to the start of a record.
3935                  */
3936                 if (session->ns_mover.md_position <
3937                     session->ns_mover.md_seek_position) {
3938                         session->ns_mover.md_r_index =
3939                             session->ns_mover.md_seek_position -
3940                             session->ns_mover.md_position;
3941                         session->ns_mover.md_position =
3942                             session->ns_mover.md_seek_position;
3943                 }
3944 
3945                 session->ns_mover.md_w_index = n;
3946                 session->ns_mover.md_record_num++;
3947         }
3948 
3949         /*
3950          * The limit on the total amount of data to be sent can be
3951          * dictated by either the end of the mover window or the end of the
3952          * seek window.
3953          * First determine which window applies and then determine if the
3954          * send length needs to be less than a full record to avoid
3955          * exceeding the window.
3956          */
3957         if (session->ns_mover.md_position +
3958             session->ns_mover.md_bytes_left_to_read >
3959             session->ns_mover.md_window_offset +
3960             session->ns_mover.md_window_length)
3961                 wlen = session->ns_mover.md_window_offset +
3962                     session->ns_mover.md_window_length -
3963                     session->ns_mover.md_position;
3964         else
3965                 wlen = session->ns_mover.md_bytes_left_to_read;
3966 
3967         NDMP_LOG(LOG_DEBUG, "wlen window restrictions: %llu", wlen);
3968 
3969         /*
3970          * Now limit the length to the amount of data in the buffer.
3971          */
3972         if (wlen > session->ns_mover.md_w_index - session->ns_mover.md_r_index)
3973                 wlen = session->ns_mover.md_w_index -
3974                     session->ns_mover.md_r_index;
3975 
3976         len = wlen & 0xffffffff;
3977         NDMP_LOG(LOG_DEBUG,
3978             "buffer restrictions: wlen %llu len %u", wlen, len);
3979 
3980         /*
3981          * Write the data to the data connection.
3982          */
3983         n = write(session->ns_mover.md_sock,
3984             &session->ns_mover.md_buf[session->ns_mover.md_r_index], len);
3985 
3986         if (n < 0) {
3987                 /* Socket is non-blocking, perhaps the write queue is full */
3988                 if (errno == EAGAIN) {
3989                         NDMP_LOG(LOG_ERR, "Cannot write to socket");
3990                         return;
3991                 }
3992                 NDMP_LOG(LOG_ERR, "Failed to write to socket: %m");
3993                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
3994                 return;
3995         }
3996 
3997         NDMP_LOG(LOG_DEBUG,
3998             "wrote %u of %u bytes to data connection position %llu r_index %lu",
3999             n, len, session->ns_mover.md_position,
4000             session->ns_mover.md_r_index);
4001 
4002         session->ns_mover.md_r_index += n;
4003         session->ns_mover.md_position += n;
4004         session->ns_mover.md_bytes_left_to_read -= n;
4005 
4006         /*
4007          * If all data in the buffer has been written,
4008          * zero the buffer indices. The next call to this function
4009          * will read more data from the tape device into the buffer.
4010          */
4011         if (session->ns_mover.md_r_index == session->ns_mover.md_w_index) {
4012                 session->ns_mover.md_r_index = 0;
4013                 session->ns_mover.md_w_index = 0;
4014         }
4015 
4016         /*
4017          * If the read limit has been reached,
4018          * then remove the file handler to prevent this
4019          * function from getting called. The next mover_read request
4020          * will reinstall the handler.
4021          */
4022         if (session->ns_mover.md_bytes_left_to_read == 0)
4023                 (void) ndmpd_remove_file_handler(session, fd);
4024 }
4025 
4026 
4027 /*
4028  * accept_connection_v3
4029  *
4030  * Accept a data connection from a data server.
4031  * Called by ndmpd_select when a connection is pending on
4032  * the mover listen socket.
4033  *
4034  * Parameters:
4035  *   cookie  (input) - session pointer.
4036  *   fd      (input) - file descriptor.
4037  *   mode    (input) - select mode.
4038  *
4039  * Returns:
4040  *   void.
4041  */
4042 /*ARGSUSED*/
4043 static void
4044 accept_connection_v3(void *cookie, int fd, ulong_t mode)
4045 {
4046         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
4047         int from_len;
4048         struct sockaddr_in from;
4049 
4050         from_len = sizeof (from);
4051         session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
4052             &from_len);
4053 
4054         NDMP_LOG(LOG_DEBUG, "sin: port %d addr %s", ntohs(from.sin_port),
4055             inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
4056 
4057         (void) ndmpd_remove_file_handler(session, fd);
4058         (void) close(session->ns_mover.md_listen_sock);
4059         session->ns_mover.md_listen_sock = -1;
4060 
4061         if (session->ns_mover.md_sock < 0) {
4062                 NDMP_LOG(LOG_DEBUG, "Accept error: %m");
4063                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
4064                 return;
4065         }
4066 
4067         /*
4068          * Save the peer address.
4069          */
4070         session->ns_mover.md_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
4071         session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(from.sin_port);
4072 
4073         /* Set the parameter of the new socket */
4074         set_socket_options(session->ns_mover.md_sock);
4075 
4076         /*
4077          * Backup/restore is handled by a callback called from main event loop,
4078          * which reads/writes data to md_sock socket. IO on socket must be
4079          * non-blocking, otherwise ndmpd would be unable to process other
4080          * incoming requests.
4081          */
4082         if (!set_socket_nonblock(session->ns_mover.md_sock)) {
4083                 NDMP_LOG(LOG_ERR, "Could not set non-blocking mode "
4084                     "on socket: %m");
4085                 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
4086                 return;
4087         }
4088 
4089         NDMP_LOG(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
4090 
4091         if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
4092                 if (ndmpd_add_file_handler(session, (void*)session,
4093                     session->ns_mover.md_sock, NDMPD_SELECT_MODE_READ,
4094                     HC_MOVER, mover_data_read_v3) < 0) {
4095                         ndmpd_mover_error(session,
4096                             NDMP_MOVER_HALT_INTERNAL_ERROR);
4097                         return;
4098                 }
4099                 NDMP_LOG(LOG_DEBUG, "Backup connection established by %s:%d",
4100                     inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
4101                     ntohs(from.sin_port));
4102         } else {
4103                 NDMP_LOG(LOG_DEBUG, "Restore connection established by %s:%d",
4104                     inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
4105                     ntohs(from.sin_port));
4106         }
4107 
4108         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
4109 }
4110 
4111 
4112 /*
4113  * create_listen_socket_v3
4114  *
4115  * Creates a socket for listening for accepting data connections.
4116  *
4117  * Parameters:
4118  *   session (input)  - session pointer.
4119  *   addr    (output) - location to store address of socket.
4120  *   port    (output) - location to store port of socket.
4121  *
4122  * Returns:
4123  *   0 - success.
4124  *  -1 - error.
4125  */
4126 static int
4127 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
4128 {
4129         session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
4130         if (session->ns_mover.md_listen_sock < 0)
4131                 return (-1);
4132 
4133         /*
4134          * Add a file handler for the listen socket.
4135          * ndmpd_select will call accept_connection when a
4136          * connection is ready to be accepted.
4137          */
4138         if (ndmpd_add_file_handler(session, (void *) session,
4139             session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
4140             accept_connection_v3) < 0) {
4141                 (void) close(session->ns_mover.md_listen_sock);
4142                 session->ns_mover.md_listen_sock = -1;
4143                 return (-1);
4144         }
4145         NDMP_LOG(LOG_DEBUG, "IP %s port %d",
4146             inet_ntoa(*(struct in_addr *)addr), ntohs(*port));
4147         return (0);
4148 }
4149 
4150 
4151 /*
4152  * mover_connect_sock
4153  *
4154  * Connect the mover to the specified address
4155  *
4156  * Parameters:
4157  *   session (input)  - session pointer.
4158  *   mode    (input)  - mover mode.
4159  *   addr    (output) - location to store address of socket.
4160  *   port    (output) - location to store port of socket.
4161  *
4162  * Returns:
4163  *   error code.
4164  */
4165 static ndmp_error
4166 mover_connect_sock(ndmpd_session_t *session, ndmp_mover_mode mode,
4167     ulong_t addr, ushort_t port)
4168 {
4169         int sock;
4170 
4171         sock = ndmp_connect_sock_v3(addr, port);
4172         if (sock < 0)
4173                 return (NDMP_CONNECT_ERR);
4174 
4175         /*
4176          * Backup/restore is handled by a callback called from main event loop,
4177          * which reads/writes data to md_sock socket. IO on socket must be
4178          * non-blocking, otherwise ndmpd would be unable to process other
4179          * incoming requests.
4180          */
4181         if (!set_socket_nonblock(sock)) {
4182                 NDMP_LOG(LOG_ERR, "Could not set non-blocking mode "
4183                     "on socket: %m");
4184                 (void) close(sock);
4185                 return (NDMP_CONNECT_ERR);
4186         }
4187 
4188         if (mode == NDMP_MOVER_MODE_READ) {
4189                 if (ndmpd_add_file_handler(session, (void*)session, sock,
4190                     NDMPD_SELECT_MODE_READ, HC_MOVER, mover_data_read_v3) < 0) {
4191                         (void) close(sock);
4192                         return (NDMP_CONNECT_ERR);
4193                 }
4194         }
4195         session->ns_mover.md_sock = sock;
4196         session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
4197         session->ns_mover.md_data_addr.tcp_ip_v3 = ntohl(addr);
4198         session->ns_mover.md_data_addr.tcp_port_v3 = port;
4199         return (NDMP_NO_ERR);
4200 }
4201 
4202 
4203 /*
4204  * ndmpd_local_read_v3
4205  *
4206  * Reads data from the local tape device.
4207  * Full tape records are read and buffered.
4208  *
4209  * Parameters:
4210  *   session (input) - session pointer.
4211  *   data    (input) - location to store data.
4212  *   length  (input) - data length.
4213  *
4214  * Returns:
4215  *   1 - no read error but no writer running
4216  *   0 - data successfully read.
4217  *  -1 - error.
4218  */
4219 int
4220 ndmpd_local_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
4221 {
4222         ulong_t count;
4223         ulong_t len;
4224         ssize_t n;
4225 
4226         count = 0;
4227         if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
4228             session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
4229             session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {
4230                 NDMP_LOG(LOG_DEBUG, "Invalid mover state to read data");
4231                 return (-1);
4232         }
4233 
4234         /*
4235          * Automatically increase the seek window if necessary.
4236          * This is needed in the event the module attempts to read
4237          * past a seek window set via a prior call to ndmpd_seek() or
4238          * the module has not issued a seek. If no seek was issued then
4239          * pretend that a seek was issued to read the entire tape.
4240          */
4241         if (length > session->ns_mover.md_bytes_left_to_read) {
4242                 /* ndmpd_seek() never called? */
4243                 if (session->ns_data.dd_read_length == 0) {
4244                         session->ns_mover.md_bytes_left_to_read = ~0LL;
4245                         session->ns_data.dd_read_offset = 0LL;
4246                         session->ns_data.dd_read_length = ~0LL;
4247                 } else {
4248                         session->ns_mover.md_bytes_left_to_read = length;
4249                         session->ns_data.dd_read_offset =
4250                             session->ns_mover.md_position;
4251                         session->ns_data.dd_read_length = length;
4252                 }
4253         }
4254 
4255         /*
4256          * Read as many records as necessary to satisfy the request.
4257          */
4258         while (count < length) {
4259                 /*
4260                  * If the end of the mover window has been reached,
4261                  * then notify the client that a new data window is needed.
4262                  */
4263                 if (session->ns_mover.md_position >=
4264                     session->ns_mover.md_window_offset +
4265                     session->ns_mover.md_window_length) {
4266                         if (mover_pause_v3(session,
4267                             NDMP_MOVER_PAUSE_SEEK) < 0) {
4268                                 ndmpd_mover_error(session,
4269                                     NDMP_MOVER_HALT_INTERNAL_ERROR);
4270                                 return (-1);
4271                         }
4272                         continue;
4273                 }
4274 
4275                 len = length - count;
4276 
4277                 /*
4278                  * Prevent reading past the end of the window.
4279                  */
4280                 if (len > session->ns_mover.md_window_offset +
4281                     session->ns_mover.md_window_length -
4282                     session->ns_mover.md_position)
4283                         len = session->ns_mover.md_window_offset +
4284                             session->ns_mover.md_window_length -
4285                             session->ns_mover.md_position;
4286 
4287                 /*
4288                  * Copy from the data buffer first.
4289                  */
4290                 if (session->ns_mover.md_w_index -
4291                     session->ns_mover.md_r_index != 0) {
4292                         /*
4293                          * Limit the copy to the amount of data in the buffer.
4294                          */
4295                         if (len > session->ns_mover.md_w_index -
4296                             session->ns_mover.md_r_index)
4297                                 len = session->ns_mover.md_w_index -
4298                                     session->ns_mover.md_r_index;
4299                         (void) memcpy((void*)&data[count],
4300                             &session->ns_mover.md_buf[session->
4301                             ns_mover.md_r_index], len);
4302                         count += len;
4303                         session->ns_mover.md_r_index += len;
4304                         session->ns_mover.md_bytes_left_to_read -= len;
4305                         session->ns_mover.md_position += len;
4306                         continue;
4307                 }
4308 
4309                 /*
4310                  * Determine if data needs to be buffered or
4311                  * can be read directly to user supplied location.
4312                  * We can fast path the read if at least a full record
4313                  * needs to be read and there is no seek pending.
4314                  * This is done to eliminate a buffer copy.
4315                  */
4316                 if (len >= session->ns_mover.md_record_size &&
4317                     session->ns_mover.md_position >=
4318                     session->ns_mover.md_seek_position) {
4319                         n = mover_tape_read_v3(session, &data[count]);
4320                         if (n <= 0) {
4321                                 if (n == TAPE_NO_WRITER_ERR)
4322                                         return (1);
4323 
4324                                 ndmpd_mover_error(session,
4325                                     (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4326                                     NDMP_MOVER_HALT_MEDIA_ERROR));
4327                                 return ((n == 0) ? 1 : -1);
4328                         }
4329 
4330                         count += n;
4331                         session->ns_mover.md_bytes_left_to_read -= n;
4332                         session->ns_mover.md_position += n;
4333                         session->ns_mover.md_record_num++;
4334                         continue;
4335                 }
4336 
4337                 /* Read the next record into the buffer. */
4338                 n = mover_tape_read_v3(session, session->ns_mover.md_buf);
4339                 if (n <= 0) {
4340                         if (n == TAPE_NO_WRITER_ERR)
4341                                 return (1);
4342 
4343                         ndmpd_mover_error(session,
4344                             (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4345                             NDMP_MOVER_HALT_MEDIA_ERROR));
4346                         return ((n == 0) ? 1 : -1);
4347                 }
4348 
4349                 session->ns_mover.md_w_index = n;
4350                 session->ns_mover.md_r_index = 0;
4351                 session->ns_mover.md_record_num++;
4352 
4353                 NDMP_LOG(LOG_DEBUG, "n: %d", n);
4354 
4355                 /*
4356                  * Discard data if the current data stream position is
4357                  * prior to the seek position. This is necessary if a seek
4358                  * request set the seek pointer to a position that is not a
4359                  * record boundary. The seek request handler can only position
4360                  * to the start of a record.
4361                  */
4362                 if (session->ns_mover.md_position <
4363                     session->ns_mover.md_seek_position) {
4364                         session->ns_mover.md_r_index =
4365                             session->ns_mover.md_seek_position -
4366                             session->ns_mover.md_position;
4367                         session->ns_mover.md_position =
4368                             session->ns_mover.md_seek_position;
4369                 }
4370         }
4371 
4372         return (0);
4373 }