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