Print this page
NEX-13374 NDMP should be able to backup unmounted ZFS filesystems
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Revert "NEX-5801 Snapshots left over after failed backups"
This reverts commit f182fb95f09036db71fbfc6f0a6b90469b761f21.
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-2911 NDMP logging should use syslog and is too chatty
NEX-2690 NDMP V4 required to have Record size is persistent between mover connections and state transitions
NEX-2911 NDMP logging should use syslog and is too chatty
NEX-727 Netbackup Catalog verification hangs waiting for NDMP server
NEX-799 past last file mark returned NDMP_IO_ERR, should be NDMP_EOM_ERR (V4+)
NEX-812 NDMP backup terminate after hit the EOM in Netbackup backup
NEX-559 NDMP cannot backup/restore a file which spans multiple tapes
SUP-484 NDMP backup jobs error out when reaching the end of media (EOM)


  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);


 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         }


 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 /*


 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  *


 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)


 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 


 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.


 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 


 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  *


 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


 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)


 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 


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  */


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:


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)


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 


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.


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


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.


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                 }


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


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 =


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;


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


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);


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);


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 }


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 :


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 /*


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 }


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 -


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


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.


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 


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;


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 }


  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 2017 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 <syslog.h>
  47 #include <netinet/in.h>
  48 #include <arpa/inet.h>
  49 #include <net/if.h>
  50 #include <errno.h>
  51 #include <fcntl.h>
  52 #include <netdb.h>
  53 #include <stdlib.h>
  54 #include <unistd.h>
  55 #include <string.h>
  56 #include "ndmpd_common.h"
  57 #include "ndmpd.h"
  58 #include <sys/mtio.h>
  59 
  60 /*
  61  * Maximum mover record size
  62  */
  63 #define MAX_MOVER_RECSIZE       (512*KILOBYTE)
  64 
  65 static int create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr,
  66     ushort_t *port);


 170  * Parameters:
 171  *   connection (input) - connection handle.
 172  *   body       (input) - request message body.
 173  *
 174  * Returns:
 175  *   void
 176  */
 177 void
 178 ndmpd_mover_listen_v2(ndmp_connection_t *connection, void *body)
 179 {
 180         ndmp_mover_listen_request_v2 *request;
 181         ndmp_mover_listen_reply_v2 reply;
 182         ndmpd_session_t *session = ndmp_get_client_data(connection);
 183         ulong_t addr;
 184         ushort_t port;
 185 
 186         request = (ndmp_mover_listen_request_v2 *)body;
 187 
 188         if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE ||
 189             session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {

 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         }


 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 
 249                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 250                 ndmp_send_reply(connection, (void *) &reply,
 251                     "sending mover_continue reply");
 252                 return;
 253         }
 254         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
 255         reply.error = NDMP_NO_ERR;
 256         ndmp_send_reply(connection, (void *) &reply,
 257             "sending mover_continue reply");
 258 }
 259 
 260 
 261 /*
 262  * ndmpd_mover_abort_v2
 263  *
 264  * This handler handles mover_abort requests.
 265  *
 266  * Parameters:
 267  *   connection (input) - connection handle.
 268  *   body       (input) - request message body.
 269  *
 270  * Returns:
 271  *   void
 272  */
 273 /*ARGSUSED*/
 274 void
 275 ndmpd_mover_abort_v2(ndmp_connection_t *connection, void *body)
 276 {
 277         ndmp_mover_abort_reply reply;
 278         ndmpd_session_t *session = ndmp_get_client_data(connection);
 279 
 280         if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
 281             session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {

 282 
 283                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 284                 ndmp_send_reply(connection, (void *) &reply,
 285                     "sending mover_abort reply");
 286                 return;
 287         }
 288 
 289         reply.error = NDMP_NO_ERR;
 290         ndmp_send_reply(connection, (void *) &reply,
 291             "sending mover_abort reply");
 292 
 293         ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
 294         ndmp_stop_buffer_worker(session);
 295 }
 296 
 297 
 298 /*
 299  * ndmpd_mover_stop_v2
 300  *
 301  * This handler handles mover_stop requests.
 302  *
 303  * Parameters:
 304  *   connection (input) - connection handle.
 305  *   body       (input) - request message body.
 306  *
 307  * Returns:
 308  *   void
 309  */
 310 /*ARGSUSED*/
 311 void
 312 ndmpd_mover_stop_v2(ndmp_connection_t *connection, void *body)
 313 {
 314         ndmp_mover_stop_reply reply;
 315         ndmpd_session_t *session = ndmp_get_client_data(connection);
 316 
 317         if (session->ns_mover.md_state != NDMP_MOVER_STATE_HALTED) {

 318 
 319                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 320                 ndmp_send_reply(connection, (void *) &reply,
 321                     "sending mover_stop reply");
 322                 return;
 323         }
 324 
 325         ndmp_waitfor_op(session);
 326         reply.error = NDMP_NO_ERR;
 327         ndmp_send_reply(connection, (void *) &reply,
 328             "sending mover_stop reply");
 329 
 330         ndmp_lbr_cleanup(session);
 331         ndmpd_mover_cleanup(session);
 332         (void) ndmpd_mover_init(session);
 333         (void) ndmp_lbr_init(session);
 334 }
 335 
 336 
 337 /*


 350 void
 351 ndmpd_mover_set_window_v2(ndmp_connection_t *connection, void *body)
 352 {
 353         ndmp_mover_set_window_request *request;
 354         ndmp_mover_set_window_reply reply;
 355         ndmpd_session_t *session = ndmp_get_client_data(connection);
 356 
 357         request = (ndmp_mover_set_window_request *) body;
 358 
 359         /*
 360          * The NDMPv2 specification states that "a window can be set only
 361          * when in the listen or paused state."
 362          *
 363          * See the comment in ndmpd_mover_set_window_v3 regarding the reason for
 364          * allowing it in the idle state as well.
 365          */
 366         if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
 367             session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED &&
 368             session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {
 369                 reply.error = NDMP_ILLEGAL_STATE_ERR;


 370         } else {
 371                 if (quad_to_long_long(request->length) == 0) {
 372                         reply.error = NDMP_ILLEGAL_ARGS_ERR;
 373                         syslog(LOG_ERR, "Illegal window size %d",
 374                             quad_to_long_long(request->length));
 375                 } else {
 376                         reply.error = NDMP_NO_ERR;
 377                         session->ns_mover.md_window_offset =
 378                             quad_to_long_long(request->offset);
 379                         session->ns_mover.md_window_length =
 380                             quad_to_long_long(request->length);
 381                         session->ns_mover.md_position =
 382                             session->ns_mover.md_window_offset;
 383                 }
 384         }
 385 
 386         ndmp_send_reply(connection, (void *) &reply,
 387             "sending mover_set_window reply");
 388 }
 389 
 390 
 391 /*
 392  * ndmpd_mover_read_v2
 393  *


 400  * to the data connection.
 401  *
 402  * Parameters:
 403  *   connection (input) - connection handle.
 404  *   body       (input) - request message body.
 405  *
 406  * Returns:
 407  *   void
 408  */
 409 void
 410 ndmpd_mover_read_v2(ndmp_connection_t *connection, void *body)
 411 {
 412         ndmp_mover_read_request *request = (ndmp_mover_read_request *) body;
 413         ndmp_mover_read_reply reply;
 414         ndmpd_session_t *session = ndmp_get_client_data(connection);
 415         int err;
 416 
 417         if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
 418             session->ns_mover.md_bytes_left_to_read != 0 ||
 419             session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {

 420                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 421                 ndmp_send_reply(connection, &reply,
 422                     "sending mover_read reply");
 423                 return;
 424         }
 425         if (session->ns_tape.td_fd == -1) {
 426                 syslog(LOG_ERR, "Tape device is not open");
 427                 reply.error = NDMP_DEV_NOT_OPEN_ERR;
 428                 ndmp_send_reply(connection, &reply,
 429                     "sending mover_read reply");
 430                 return;
 431         }
 432 
 433         reply.error = NDMP_NO_ERR;
 434         ndmp_send_reply(connection, &reply, "sending mover_read reply");
 435 
 436         err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
 437             quad_to_long_long(request->length));
 438         if (err < 0) {
 439                 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
 440                 return;
 441         }
 442         /*
 443          * Just return if we are waiting for the NDMP client to
 444          * complete the seek.
 445          */
 446         if (err == 1)


 457 /*
 458  * ndmpd_mover_close_v2
 459  *
 460  * This handler handles mover_close requests.
 461  *
 462  * Parameters:
 463  *   connection (input) - connection handle.
 464  *   body       (input) - request message body.
 465  *
 466  * Returns:
 467  *   void
 468  */
 469 /*ARGSUSED*/
 470 void
 471 ndmpd_mover_close_v2(ndmp_connection_t *connection, void *body)
 472 {
 473         ndmp_mover_close_reply reply;
 474         ndmpd_session_t *session = ndmp_get_client_data(connection);
 475 
 476         if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {

 477 
 478                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 479                 ndmp_send_reply(connection, &reply,
 480                     "sending mover_close reply");
 481                 return;
 482         }
 483         free(session->ns_mover.md_data_addr_v4.tcp_addr_v4);
 484 
 485         reply.error = NDMP_NO_ERR;
 486         ndmp_send_reply(connection, &reply, "sending mover_close reply");
 487 
 488         ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
 489 }
 490 
 491 
 492 /*
 493  * ndmpd_mover_set_record_size_v2
 494  *
 495  * This handler handles mover_set_record_size requests.
 496  *
 497  * Parameters:
 498  *   connection (input) - connection handle.
 499  *   body       (input) - request message body.
 500  *
 501  * Returns:
 502  *   void
 503  */
 504 void
 505 ndmpd_mover_set_record_size_v2(ndmp_connection_t *connection, void *body)
 506 {
 507         ndmp_mover_set_record_size_request *request;
 508         ndmp_mover_set_record_size_reply reply;
 509 
 510         ndmpd_session_t *session = ndmp_get_client_data(connection);
 511 
 512         request = (ndmp_mover_set_record_size_request *) body;
 513 
 514         session->ns_mover.md_record_size = request->len;
 515         session->ns_mover.md_buf = realloc(session->ns_mover.md_buf,
 516             request->len);
 517 
 518         reply.error = NDMP_NO_ERR;
 519         ndmp_send_reply(connection, &reply,
 520             "sending mover_set_record_size reply");
 521 }
 522 
 523 
 524 /*
 525  * ************************************************************************
 526  * NDMP V3 HANDLERS
 527  * ************************************************************************
 528  */
 529 


 589  * Returns:
 590  *   void
 591  */
 592 void
 593 ndmpd_mover_listen_v3(ndmp_connection_t *connection, void *body)
 594 {
 595         ndmp_mover_listen_request_v3 *request;
 596         ndmp_mover_listen_reply_v3 reply;
 597         ndmpd_session_t *session = ndmp_get_client_data(connection);
 598         ulong_t addr;
 599         ushort_t port;
 600 
 601         request = (ndmp_mover_listen_request_v3 *)body;
 602 
 603         (void) memset((void*)&reply, 0, sizeof (reply));
 604         reply.error = NDMP_NO_ERR;
 605 
 606         if (request->mode != NDMP_MOVER_MODE_READ &&
 607             request->mode != NDMP_MOVER_MODE_WRITE) {
 608                 reply.error = NDMP_ILLEGAL_ARGS_ERR;

 609         } else if (!ndmp_valid_v3addr_type(request->addr_type)) {
 610                 reply.error = NDMP_ILLEGAL_ARGS_ERR;


 611         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
 612                 reply.error = NDMP_ILLEGAL_STATE_ERR;


 613         } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
 614                 reply.error = NDMP_ILLEGAL_STATE_ERR;


 615         } else if (session->ns_tape.td_fd == -1) {
 616                 reply.error = NDMP_DEV_NOT_OPEN_ERR;
 617                 syslog(LOG_ERR, "No tape device open");
 618         } else if (request->mode == NDMP_MOVER_MODE_READ &&
 619             session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
 620                 reply.error = NDMP_PERMISSION_ERR;
 621                 syslog(LOG_ERR, "Write protected device.");
 622         }
 623 
 624         if (reply.error != NDMP_NO_ERR) {
 625                 ndmp_send_reply(connection, &reply,
 626                     "error sending ndmp_mover_listen reply");
 627                 return;
 628         }
 629 
 630         switch (request->addr_type) {
 631         case NDMP_ADDR_LOCAL:
 632                 reply.data_connection_addr.addr_type = NDMP_ADDR_LOCAL;
 633                 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
 634                 reply.error = NDMP_NO_ERR;
 635                 break;
 636         case NDMP_ADDR_TCP:
 637                 if (create_listen_socket_v3(session, &addr, &port) < 0) {
 638                         reply.error = NDMP_IO_ERR;
 639                         break;
 640                 }
 641                 reply.error = NDMP_NO_ERR;
 642                 reply.data_connection_addr.addr_type = NDMP_ADDR_TCP;
 643                 reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
 644                 reply.data_connection_addr.tcp_port_v3 = htons(port);
 645                 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
 646                 session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
 647                 session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
 648                 syslog(LOG_DEBUG, "listen_socket: %d",
 649                     session->ns_mover.md_listen_sock);
 650                 break;
 651         default:
 652                 reply.error = NDMP_ILLEGAL_ARGS_ERR;


 653         }
 654 
 655         if (reply.error == NDMP_NO_ERR) {
 656                 session->ns_mover.md_mode = request->mode;
 657                 session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
 658         }
 659 
 660         ndmp_send_reply(connection, &reply,
 661             "error sending ndmp_mover_listen reply");
 662 }
 663 
 664 
 665 /*
 666  * ndmpd_mover_continue_v3
 667  *
 668  * This handler handles ndmp_mover_continue_requests.
 669  *
 670  * Parameters:
 671  *   connection (input) - connection handle.
 672  *   body       (input) - request message body.
 673  *
 674  * Returns:
 675  *   void
 676  */
 677 /*ARGSUSED*/
 678 void
 679 ndmpd_mover_continue_v3(ndmp_connection_t *connection, void *body)
 680 {
 681         ndmp_mover_continue_reply reply;
 682         ndmpd_session_t *session = ndmp_get_client_data(connection);
 683         ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
 684         int ret;
 685 
 686         (void) memset((void*)&reply, 0, sizeof (reply));
 687 
 688         if (session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {

 689                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 690                 ndmp_send_reply(connection, (void *) &reply,
 691                     "sending mover_continue reply");
 692                 return;
 693         }
 694 
 695         if (session->ns_protocol_version == NDMPV4 &&
 696             !session->ns_mover.md_pre_cond) {
 697                 syslog(LOG_DEBUG, "Precondition check");
 698                 reply.error = NDMP_PRECONDITION_ERR;
 699                 ndmp_send_reply(connection, (void *) &reply,
 700                     "sending mover_continue reply");
 701                 return;
 702         }
 703         /*
 704          * Restore the file handler if the mover is remote to the data
 705          * server and the handler was removed pending the continuation of a
 706          * seek request. The handler is removed in mover_data_write().
 707          */
 708         if (session->ns_mover.md_pause_reason == NDMP_MOVER_PAUSE_SEEK &&
 709             session->ns_mover.md_sock != -1) {
 710                 /*
 711                  * If we are here, it means that we needed DMA interference
 712                  * for seek. We should be on the right window, so we do not
 713                  * need the DMA interference anymore.
 714                  * We do another seek inside the Window to move to the
 715                  * exact position on the tape.
 716                  * If the resore is running without DAR the pause reason should
 717                  * not be seek.


 720                     session->ns_mover.md_seek_position,
 721                     session->ns_mover.md_bytes_left_to_read);
 722                 if (ret < 0) {
 723                         ndmpd_mover_error(session,
 724                             NDMP_MOVER_HALT_INTERNAL_ERROR);
 725                         return;
 726                 }
 727 
 728                 if (!ret) {
 729                         if (ndmpd_add_file_handler(session, (void*) session,
 730                             session->ns_mover.md_sock, NDMPD_SELECT_MODE_WRITE,
 731                             HC_MOVER, mover_data_write_v3) < 0)
 732                                 ndmpd_mover_error(session,
 733                                     NDMP_MOVER_HALT_INTERNAL_ERROR);
 734                 } else {
 735                         /*
 736                          * This should not happen because we should be in the
 737                          * right window. This means that DMA does not follow
 738                          * the V3 spec.
 739                          */

 740                         ndmpd_mover_error(session,
 741                             NDMP_MOVER_HALT_INTERNAL_ERROR);
 742                         return;
 743                 }
 744         }
 745 
 746         (void) mutex_lock(&nlp->nlp_mtx);
 747         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
 748         session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_NA;
 749         /* The tape has been likely exchanged, reset tape block counter */
 750         session->ns_tape.td_record_count = 0;
 751         (void) cond_broadcast(&nlp->nlp_cv);
 752         (void) mutex_unlock(&nlp->nlp_mtx);
 753 
 754         reply.error = NDMP_NO_ERR;
 755         ndmp_send_reply(connection, (void *) &reply,
 756             "sending mover_continue reply");
 757 }
 758 
 759 


 761  * ndmpd_mover_abort_v3
 762  *
 763  * This handler handles mover_abort requests.
 764  *
 765  * Parameters:
 766  *   connection (input) - connection handle.
 767  *   body       (input) - request message body.
 768  *
 769  * Returns:
 770  *   void
 771  */
 772 /*ARGSUSED*/
 773 void
 774 ndmpd_mover_abort_v3(ndmp_connection_t *connection, void *body)
 775 {
 776         ndmp_mover_abort_reply reply;
 777         ndmpd_session_t *session = ndmp_get_client_data(connection);
 778 
 779         if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
 780             session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {

 781 
 782                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 783                 ndmp_send_reply(connection, (void *) &reply,
 784                     "sending mover_abort reply");
 785                 return;
 786         }
 787 
 788         reply.error = NDMP_NO_ERR;
 789         ndmp_send_reply(connection, (void *) &reply,
 790             "sending mover_abort reply");
 791 
 792         ndmpd_mover_error(session, NDMP_MOVER_HALT_ABORTED);
 793 }
 794 
 795 
 796 /*
 797  * ndmpd_mover_set_window_v3
 798  *
 799  * This handler handles mover_set_window requests.
 800  *


 808  */
 809 void
 810 ndmpd_mover_set_window_v3(ndmp_connection_t *connection, void *body)
 811 {
 812         ndmp_mover_set_window_request *request;
 813         ndmp_mover_set_window_reply reply;
 814         ndmpd_session_t *session = ndmp_get_client_data(connection);
 815 
 816         request = (ndmp_mover_set_window_request *) body;
 817 
 818         /*
 819          * Note: The spec says that the window can be set only in the listen
 820          * and paused states.  We let this happen when mover is in the idle
 821          * state as well.  I can't rememebr which NDMP client (net_backup 4.5
 822          * or net_worker 6.1.1) forced us to do this!
 823          */
 824         if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE &&
 825             session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN &&
 826             session->ns_mover.md_state != NDMP_MOVER_STATE_PAUSED) {
 827                 reply.error = NDMP_ILLEGAL_STATE_ERR;


 828         } else if (session->ns_mover.md_record_size == 0) {
 829                 if (session->ns_protocol_version == NDMPV4)
 830                         reply.error = NDMP_PRECONDITION_ERR;
 831                 else
 832                         reply.error = NDMP_ILLEGAL_ARGS_ERR;

 833         } else
 834                 reply.error = NDMP_NO_ERR;
 835 
 836         if (quad_to_long_long(request->length) == 0) {
 837                 reply.error = NDMP_ILLEGAL_ARGS_ERR;


 838         }
 839 
 840         if (reply.error != NDMP_NO_ERR) {
 841                 ndmp_send_reply(connection, (void *) &reply,
 842                     "sending mover_set_window_v3 reply");
 843                 return;
 844         }
 845 
 846         session->ns_mover.md_pre_cond = TRUE;
 847         session->ns_mover.md_window_offset = quad_to_long_long(request->offset);
 848         session->ns_mover.md_window_length = quad_to_long_long(request->length);
 849 
 850         /*
 851          * We have to update the position for DAR. DAR needs this
 852          * information to position to the right index on tape,
 853          * especially when we span the tapes.
 854          */
 855 #ifdef  NO_POSITION_CHANGE
 856         /*
 857          * Do not change the mover position if we are reading from


 884  * Parameters:
 885  *   connection (input) - connection handle.
 886  *   body       (input) - request message body.
 887  *
 888  * Returns:
 889  *   void
 890  */
 891 void
 892 ndmpd_mover_read_v3(ndmp_connection_t *connection, void *body)
 893 {
 894         ndmp_mover_read_request *request = (ndmp_mover_read_request *)body;
 895         ndmp_mover_read_reply reply;
 896         ndmpd_session_t *session = ndmp_get_client_data(connection);
 897         int err;
 898 
 899         (void) memset((void*)&reply, 0, sizeof (reply));
 900 
 901         if (session->ns_mover.md_state != NDMP_MOVER_STATE_ACTIVE ||
 902             session->ns_mover.md_mode != NDMP_MOVER_MODE_WRITE) {
 903                 reply.error = NDMP_ILLEGAL_STATE_ERR;

 904         } else if (session->ns_mover.md_bytes_left_to_read != 0) {
 905                 reply.error = NDMP_READ_IN_PROGRESS_ERR;

 906         } else if (session->ns_tape.td_fd == -1) {
 907                 reply.error = NDMP_DEV_NOT_OPEN_ERR;
 908                 syslog(LOG_ERR, "Tape device is not open");
 909         } else if (quad_to_long_long(request->length) == 0 ||
 910             (quad_to_long_long(request->length) == MAX_WINDOW_SIZE &&
 911             quad_to_long_long(request->offset) != 0)) {
 912                 reply.error = NDMP_ILLEGAL_ARGS_ERR;

 913         } else {
 914                 reply.error = NDMP_NO_ERR;
 915         }
 916 
 917         ndmp_send_reply(connection, (void *) &reply,
 918             "sending ndmp_mover_read_reply");
 919         if (reply.error != NDMP_NO_ERR)
 920                 return;
 921 
 922         err = ndmpd_mover_seek(session, quad_to_long_long(request->offset),
 923             quad_to_long_long(request->length));
 924         if (err < 0) {
 925                 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
 926                 return;
 927         }
 928 
 929         /*
 930          * Just return if we are waiting for the DMA to complete the seek.
 931          */
 932         if (err == 1)


 952  *
 953  * Parameters:
 954  *   connection (input) - connection handle.
 955  *   body       (input) - request message body.
 956  *
 957  * Returns:
 958  *   void
 959  */
 960 void
 961 ndmpd_mover_set_record_size_v3(ndmp_connection_t *connection, void *body)
 962 {
 963         ndmp_mover_set_record_size_request *request;
 964         ndmp_mover_set_record_size_reply reply;
 965         ndmpd_session_t *session = ndmp_get_client_data(connection);
 966         char *cp;
 967 
 968         request = (ndmp_mover_set_record_size_request *) body;
 969 
 970         if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
 971                 reply.error = NDMP_ILLEGAL_STATE_ERR;


 972         } else if (request->len > (unsigned int)ndmp_max_mover_recsize) {
 973                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 974         } else if (request->len == session->ns_mover.md_record_size) {



 975                 reply.error = NDMP_NO_ERR;
 976                 session->ns_mover.md_pre_cond = TRUE;
 977         } else if (!(cp = realloc(session->ns_mover.md_buf, request->len))) {
 978                 reply.error = NDMP_NO_MEM_ERR;
 979         } else {
 980                 reply.error = NDMP_NO_ERR;
 981                 session->ns_mover.md_buf = cp;
 982                 session->ns_mover.md_record_size = request->len;
 983                 session->ns_mover.md_window_offset = 0;
 984                 session->ns_mover.md_window_length = 0;
 985         }
 986 
 987         ndmp_send_reply(connection, (void *) &reply,
 988             "sending mover_set_record_size reply");
 989 }
 990 
 991 
 992 /*
 993  * ndmpd_mover_connect_v3
 994  *   Request handler. Connects the mover to either a local
 995  *   or remote data server.
 996  *
 997  * Parameters:
 998  *   connection (input) - connection handle.
 999  *   body       (input) - request message body.
1000  *
1001  * Returns:
1002  *   void
1003  */
1004 void
1005 ndmpd_mover_connect_v3(ndmp_connection_t *connection, void *body)
1006 {
1007         ndmp_mover_connect_request_v3 *request;
1008         ndmp_mover_connect_reply_v3 reply;
1009         ndmpd_session_t *session = ndmp_get_client_data(connection);
1010 
1011         request = (ndmp_mover_connect_request_v3*)body;
1012 
1013         (void) memset((void*)&reply, 0, sizeof (reply));
1014 
1015         if (request->mode != NDMP_MOVER_MODE_READ &&
1016             request->mode != NDMP_MOVER_MODE_WRITE) {
1017                 reply.error = NDMP_ILLEGAL_ARGS_ERR;

1018         } else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
1019                 reply.error = NDMP_ILLEGAL_ARGS_ERR;


1020         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1021                 reply.error = NDMP_ILLEGAL_STATE_ERR;


1022         } else if (session->ns_tape.td_fd == -1) {
1023                 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1024                 syslog(LOG_ERR, "No tape device open");
1025         } else if (request->mode == NDMP_MOVER_MODE_READ &&
1026             session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1027                 reply.error = NDMP_WRITE_PROTECT_ERR;
1028                 syslog(LOG_ERR, "Write protected device.");
1029         } else
1030                 reply.error = NDMP_NO_ERR;
1031 
1032         if (reply.error != NDMP_NO_ERR) {
1033                 ndmp_send_reply(connection, (void *) &reply,
1034                     "sending ndmp_mover_connect reply");
1035                 return;
1036         }
1037 
1038         switch (request->addr.addr_type) {
1039         case NDMP_ADDR_LOCAL:
1040                 /*
1041                  * Verify that the data server is listening for a
1042                  * local connection.
1043                  */
1044                 if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
1045                     session->ns_data.dd_listen_sock != -1) {


1046                         reply.error = NDMP_ILLEGAL_STATE_ERR;
1047                 } else
1048                         session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1049                 break;
1050 
1051         case NDMP_ADDR_TCP:
1052                 reply.error = mover_connect_sock(session, request->mode,
1053                     request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
1054                 break;
1055 
1056         default:
1057                 reply.error = NDMP_ILLEGAL_ARGS_ERR;


1058         }
1059 
1060         if (reply.error == NDMP_NO_ERR) {
1061                 session->ns_mover.md_data_addr.addr_type =
1062                     request->addr.addr_type;
1063                 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1064                 session->ns_mover.md_mode = request->mode;
1065         }
1066 
1067         ndmp_send_reply(connection, (void *) &reply,
1068             "sending ndmp_mover_connect reply");
1069 }
1070 
1071 
1072 /*
1073  * ************************************************************************
1074  * NDMP V4 HANDLERS
1075  * ************************************************************************
1076  */
1077 


1140  *   void
1141  */
1142 void
1143 ndmpd_mover_listen_v4(ndmp_connection_t *connection, void *body)
1144 {
1145         ndmp_mover_listen_request_v4 *request;
1146 
1147         ndmp_mover_listen_reply_v4 reply;
1148         ndmpd_session_t *session = ndmp_get_client_data(connection);
1149         ulong_t addr;
1150         ushort_t port;
1151 
1152         request = (ndmp_mover_listen_request_v4 *)body;
1153 
1154         (void) memset((void*)&reply, 0, sizeof (reply));
1155         reply.error = NDMP_NO_ERR;
1156 
1157         if (request->mode != NDMP_MOVER_MODE_READ &&
1158             request->mode != NDMP_MOVER_MODE_WRITE) {
1159                 reply.error = NDMP_ILLEGAL_ARGS_ERR;

1160         } else if (!ndmp_valid_v3addr_type(request->addr_type)) {
1161                 reply.error = NDMP_ILLEGAL_ARGS_ERR;


1162         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1163                 reply.error = NDMP_ILLEGAL_STATE_ERR;


1164         } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1165                 reply.error = NDMP_ILLEGAL_STATE_ERR;


1166         } else if (session->ns_tape.td_fd == -1) {
1167                 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1168                 syslog(LOG_ERR, "No tape device open");
1169         } else if (session->ns_mover.md_record_size == 0) {
1170                 reply.error = NDMP_PRECONDITION_ERR;

1171         } else if (request->mode == NDMP_MOVER_MODE_READ &&
1172             session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1173                 reply.error = NDMP_PERMISSION_ERR;
1174                 syslog(LOG_ERR, "Write protected device.");
1175         }
1176 
1177         if (reply.error != NDMP_NO_ERR) {
1178                 ndmp_send_reply(connection, (void *) &reply,
1179                     "error sending ndmp_mover_listen reply");
1180                 return;
1181         }
1182 
1183         switch (request->addr_type) {
1184         case NDMP_ADDR_LOCAL:
1185                 reply.connect_addr.addr_type = NDMP_ADDR_LOCAL;
1186                 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_LOCAL;
1187                 reply.error = NDMP_NO_ERR;
1188                 break;
1189         case NDMP_ADDR_TCP:
1190                 if (create_listen_socket_v3(session, &addr, &port) < 0) {
1191                         reply.error = NDMP_IO_ERR;
1192                         break;
1193                 }
1194                 reply.error = NDMP_NO_ERR;
1195 
1196                 session->ns_mover.md_data_addr_v4.addr_type = NDMP_ADDR_TCP;
1197                 session->ns_mover.md_data_addr_v4.tcp_len_v4 = 1;
1198                 session->ns_mover.md_data_addr_v4.tcp_addr_v4 =
1199                     ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1200 
1201                 session->ns_mover.md_data_addr_v4.tcp_ip_v4(0) = addr;
1202                 session->ns_mover.md_data_addr_v4.tcp_port_v4(0) = ntohs(port);
1203 
1204                 ndmp_copy_addr_v4(&reply.connect_addr,
1205                     &session->ns_mover.md_data_addr_v4);
1206 
1207                 /* For compatibility with V3 */
1208                 session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
1209                 session->ns_mover.md_data_addr.tcp_ip_v3 = addr;
1210                 session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(port);
1211                 syslog(LOG_DEBUG, "listen_socket: %d",
1212                     session->ns_mover.md_listen_sock);
1213                 break;
1214         default:
1215                 reply.error = NDMP_ILLEGAL_ARGS_ERR;


1216         }
1217 
1218         if (reply.error == NDMP_NO_ERR) {
1219                 session->ns_mover.md_mode = request->mode;
1220                 session->ns_mover.md_state = NDMP_MOVER_STATE_LISTEN;
1221         }
1222 
1223         ndmp_send_reply(connection, (void *) &reply,
1224             "error sending ndmp_mover_listen reply");
1225         free(reply.connect_addr.tcp_addr_v4);
1226 }
1227 
1228 /*
1229  * ndmpd_mover_connect_v4
1230  *   Request handler. Connects the mover to either a local
1231  *   or remote data server.
1232  *
1233  * Parameters:
1234  *   connection (input) - connection handle.
1235  *   body       (input) - request message body.
1236  *
1237  * Returns:
1238  *   void
1239  */
1240 void
1241 ndmpd_mover_connect_v4(ndmp_connection_t *connection, void *body)
1242 {
1243         ndmp_mover_connect_request_v4 *request;
1244         ndmp_mover_connect_reply_v4 reply;
1245         ndmpd_session_t *session = ndmp_get_client_data(connection);
1246 
1247         request = (ndmp_mover_connect_request_v4 *)body;
1248         (void) memset((void*)&reply, 0, sizeof (reply));
1249 
1250         if (request->mode != NDMP_MOVER_MODE_READ &&
1251             request->mode != NDMP_MOVER_MODE_WRITE) {
1252                 reply.error = NDMP_ILLEGAL_ARGS_ERR;

1253         } else if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
1254                 reply.error = NDMP_ILLEGAL_ARGS_ERR;


1255         } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
1256                 reply.error = NDMP_ILLEGAL_STATE_ERR;


1257         } else if (session->ns_tape.td_fd == -1) {
1258                 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1259                 syslog(LOG_ERR, "No tape device open");
1260         } else if (request->mode == NDMP_MOVER_MODE_READ &&
1261             session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1262                 reply.error = NDMP_PERMISSION_ERR;
1263                 syslog(LOG_ERR, "Write protected device.");
1264         } else if (session->ns_mover.md_record_size == 0) {
1265                 reply.error = NDMP_PRECONDITION_ERR;

1266         } else
1267                 reply.error = NDMP_NO_ERR;
1268 
1269         if (reply.error != NDMP_NO_ERR) {
1270                 ndmp_send_reply(connection, (void *) &reply,
1271                     "sending ndmp_mover_connect reply");
1272                 return;
1273         }
1274 
1275         switch (request->addr.addr_type) {
1276         case NDMP_ADDR_LOCAL:
1277                 /*
1278                  * Verify that the data server is listening for a
1279                  * local connection.
1280                  */
1281                 if (session->ns_data.dd_state != NDMP_DATA_STATE_LISTEN ||
1282                     session->ns_data.dd_listen_sock != -1) {


1283                         reply.error = NDMP_ILLEGAL_STATE_ERR;
1284                 } else
1285                         session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1286                 break;
1287 
1288         case NDMP_ADDR_TCP:
1289                 reply.error = mover_connect_sock(session, request->mode,
1290                     request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
1291                 break;
1292 
1293         default:
1294                 reply.error = NDMP_ILLEGAL_ARGS_ERR;


1295         }
1296 
1297         if (reply.error == NDMP_NO_ERR) {
1298                 session->ns_mover.md_data_addr.addr_type =
1299                     request->addr.addr_type;
1300                 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1301                 session->ns_mover.md_mode = request->mode;
1302         }
1303 
1304         ndmp_send_reply(connection, (void *) &reply,
1305             "sending ndmp_mover_connect reply");
1306 }
1307 
1308 
1309 
1310 /*
1311  * ************************************************************************
1312  * LOCALS
1313  * ************************************************************************
1314  */


1435  *   data       (input) - data to be written.
1436  *   length     (input) - data length.
1437  *
1438  * Returns:
1439  *   0 - data successfully written.
1440  *  -1 - error.
1441  */
1442 int
1443 ndmpd_remote_write(ndmpd_session_t *session, char *data, ulong_t length)
1444 {
1445         ssize_t n;
1446         ulong_t count = 0;
1447 
1448         while (count < length) {
1449                 if (session->ns_eof == TRUE ||
1450                     session->ns_data.dd_abort == TRUE)
1451                         return (-1);
1452 
1453                 if ((n = write(session->ns_data.dd_sock, &data[count],
1454                     length - count)) < 0) {
1455                         syslog(LOG_ERR, "Socket write error: %m.");
1456                         return (-1);
1457                 }
1458                 count += n;
1459         }
1460 
1461         return (0);
1462 }
1463 
1464 /*
1465  * ndmpd_local_read
1466  *
1467  * Reads data from the local tape device.
1468  * Full tape records are read and buffered.
1469  *
1470  * Parameters:
1471  *   session (input) - session pointer.
1472  *   data    (input) - location to store data.
1473  *   length  (input) - data length.
1474  *
1475  * Returns:


1510          */
1511         while (count < length) {
1512                 /*
1513                  * If the end of the mover window has been reached,
1514                  * then notify the client that a new data window is needed.
1515                  */
1516                 if (session->ns_mover.md_position >=
1517                     session->ns_mover.md_window_offset +
1518                     session->ns_mover.md_window_length) {
1519 
1520                         session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
1521                         session->ns_mover.md_pause_reason =
1522                             NDMP_MOVER_PAUSE_SEEK;
1523                         pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
1524                         pause_request.seek_position =
1525                             long_long_to_quad(session->ns_mover.md_position);
1526 
1527                         if (ndmp_send_request(session->ns_connection,
1528                             NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
1529                             (void *) &pause_request, 0) < 0) {


1530                                 ndmpd_mover_error(session,
1531                                     NDMP_MOVER_HALT_INTERNAL_ERROR);
1532                                 return (-1);
1533                         }
1534                         /*
1535                          * Wait until the state is changed by
1536                          * an abort or continue request.
1537                          */
1538                         if (ndmp_wait_for_mover(session) != 0)
1539                                 return (1);
1540                 }
1541                 len = length - count;
1542 
1543                 /*
1544                  * Prevent reading past the end of the window.
1545                  */
1546                 if (len >
1547                     session->ns_mover.md_window_offset +
1548                     session->ns_mover.md_window_length -
1549                     session->ns_mover.md_position)


1595                         }
1596                         count += n;
1597                         session->ns_mover.md_bytes_left_to_read -= n;
1598                         session->ns_mover.md_position += n;
1599                         continue;
1600                 }
1601                 /* Read the next record into the buffer. */
1602                 n = tape_read(session, session->ns_mover.md_buf);
1603                 if (n <= 0) {
1604                         if (n == TAPE_NO_WRITER_ERR)
1605                                 return (1);
1606 
1607                         ndmpd_mover_error(session,
1608                             (n == 0 ? NDMP_MOVER_HALT_ABORTED :
1609                             NDMP_MOVER_HALT_INTERNAL_ERROR));
1610                         return (n == 0) ? (1) : (-1);
1611                 }
1612                 session->ns_mover.md_w_index = n;
1613                 session->ns_mover.md_r_index = 0;
1614 


1615                 /*
1616                  * Discard data if the current data stream position is
1617                  * prior to the seek position. This is necessary if a seek
1618                  * request set the seek pointer to a position that is not a
1619                  * record boundary. The seek request handler can only position
1620                  * to the start of a record.
1621                  */
1622                 if (session->ns_mover.md_position <
1623                     session->ns_mover.md_seek_position) {
1624                         session->ns_mover.md_r_index =
1625                             session->ns_mover.md_seek_position -
1626                             session->ns_mover.md_position;
1627                         session->ns_mover.md_position =
1628                             session->ns_mover.md_seek_position;
1629                 }
1630         }
1631 
1632         return (0);
1633 }
1634 


1673                         /* ndmpd_seek() never called? */
1674                         if (session->ns_data.dd_read_length == 0) {
1675                                 session->ns_mover.md_bytes_left_to_read = ~0LL;
1676                                 session->ns_data.dd_read_offset = 0LL;
1677                                 session->ns_data.dd_read_length = ~0LL;
1678                         } else {
1679                                 session->ns_mover.md_bytes_left_to_read = len;
1680                                 session->ns_data.dd_read_offset =
1681                                     session->ns_mover.md_position;
1682                                 session->ns_data.dd_read_length = len;
1683                         }
1684 
1685                         request.offset =
1686                             long_long_to_quad(session->ns_data.dd_read_offset);
1687                         request.length =
1688                             long_long_to_quad(session->ns_data.dd_read_length);
1689 
1690                         if (ndmp_send_request_lock(session->ns_connection,
1691                             NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1692                             (void *) &request, 0) < 0) {


1693                                 return (-1);
1694                         }
1695                 }
1696                 if (session->ns_eof == TRUE ||
1697                     session->ns_data.dd_abort == TRUE)
1698                         return (1);
1699 
1700                 /*
1701                  * If the module called ndmpd_seek() prior to reading all of the
1702                  * data that the remote mover was requested to send, then the
1703                  * excess data from the seek has to be discardd.
1704                  */
1705                 if (session->ns_mover.md_discard_length != 0) {
1706                         n = discard_data(session,
1707                             (ulong_t)session->ns_mover.md_discard_length);
1708                         if (n < 0)
1709                                 return (-1);
1710                         session->ns_mover.md_discard_length -= n;
1711                         continue;
1712                 }
1713                 /*
1714                  * Don't attempt to read more data than the remote is sending.
1715                  */
1716                 if (len > session->ns_mover.md_bytes_left_to_read)
1717                         len = session->ns_mover.md_bytes_left_to_read;
1718 


1719                 if ((n = read(session->ns_data.dd_sock, &data[count],
1720                     len)) < 0) {
1721                         syslog(LOG_ERR, "Socket read error: %m.");
1722                         return (-1);
1723                 }
1724                 /* read returns 0 if the connection was closed */
1725                 if (n == 0)
1726                         return (-1);
1727 
1728                 count += n;
1729                 session->ns_mover.md_bytes_left_to_read -= n;
1730                 session->ns_mover.md_position += n;
1731         }
1732 
1733         return (0);
1734 }
1735 
1736 /* *** ndmpd internal functions ***************************************** */
1737 
1738 /*
1739  * ndmpd_mover_init
1740  *
1741  * Initialize mover specific session variables.


1787  * ndmpd_mover_shut_down
1788  *
1789  * Shutdown the mover. It closes all the sockets.
1790  *
1791  * Parameters:
1792  *   session (input) - session pointer.
1793  *
1794  * Returns:
1795  *   void
1796  */
1797 void
1798 ndmpd_mover_shut_down(ndmpd_session_t *session)
1799 {
1800         ndmp_lbr_params_t *nlp;
1801 
1802         if ((nlp = ndmp_get_nlp(session)) == NULL)
1803                 return;
1804 
1805         (void) mutex_lock(&nlp->nlp_mtx);
1806         if (session->ns_mover.md_listen_sock != -1) {


1807                 (void) ndmpd_remove_file_handler(session,
1808                     session->ns_mover.md_listen_sock);
1809                 (void) close(session->ns_mover.md_listen_sock);
1810                 session->ns_mover.md_listen_sock = -1;
1811         }
1812         if (session->ns_mover.md_sock != -1) {


1813                 (void) ndmpd_remove_file_handler(session,
1814                     session->ns_mover.md_sock);
1815                 (void) close(session->ns_mover.md_sock);
1816                 session->ns_mover.md_sock = -1;
1817         }
1818         (void) cond_broadcast(&nlp->nlp_cv);
1819         (void) mutex_unlock(&nlp->nlp_mtx);
1820 }
1821 
1822 
1823 /*
1824  * ndmpd_mover_cleanup
1825  *
1826  * Parameters:
1827  *   session (input) - session pointer.
1828  *
1829  * Returns:
1830  *   void
1831  */
1832 void


1860                         sin.sin_addr.s_addr =
1861                             htonl(mover->ndmp_mover_addr_u.addr.ip_addr);
1862                         sin.sin_port =
1863                             htons(mover->ndmp_mover_addr_u.addr.port);
1864 
1865                         /*
1866                          * If the address type is TCP but both the address and
1867                          * the port number are zero, we have to use a different
1868                          * socket than the mover socket. This can happen when
1869                          * using NDMP disk to disk copy (AKA D2D copy).
1870                          * The NDMPCopy client will send a zero address to
1871                          * direct the server to use the mover socket as the
1872                          * data socket to receive the recovery data.
1873                          */
1874                         if (sin.sin_addr.s_addr == 0 && sin.sin_port == 0) {
1875                                 session->ns_data.dd_sock =
1876                                     session->ns_mover.md_sock;
1877                                 return (NDMP_NO_ERR);
1878                         }
1879 
1880                         syslog(LOG_DEBUG, "addr: %u port: %u",
1881                             mover->ndmp_mover_addr_u.addr.ip_addr,
1882                             (ulong_t)sin.sin_port);
1883 
1884                         if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1885                                 syslog(LOG_ERR, "Socket error: %m");
1886                                 return (NDMP_IO_ERR);
1887                         }
1888                         if (connect(sock, (struct sockaddr *)&sin,
1889                             sizeof (sin)) < 0) {
1890                                 syslog(LOG_ERR, "Connect error: %m");
1891                                 (void) close(sock);
1892                                 return (NDMP_IO_ERR);
1893                         }
1894                         set_socket_options(sock);
1895                 } else {
1896                         if ((session->ns_mover.md_state !=
1897                             NDMP_MOVER_STATE_ACTIVE) ||
1898                             (session->ns_mover.md_sock == -1)) {
1899 
1900                                 syslog(LOG_DEBUG,
1901                                     "Not in active  state mover"
1902                                     "  state = %d or Illegal mover sock=%d",
1903                                     session->ns_mover.md_state,
1904                                     session->ns_mover.md_sock);
1905                                 return (NDMP_ILLEGAL_STATE_ERR);
1906                         }
1907 
1908                         sock = session->ns_mover.md_sock;
1909                         syslog(LOG_DEBUG,
1910                             "session: 0x%x setting data sock fd: %d to be"
1911                             " same as listen_sock", session, sock);
1912                 }
1913 


1914                 session->ns_data.dd_sock = sock;
1915 


1916                 return (NDMP_NO_ERR);
1917         }
1918         /* Local mover connection. */
1919 
1920         if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN) {

1921                 return (NDMP_ILLEGAL_STATE_ERR);
1922         }
1923         if (session->ns_tape.td_fd == -1) {
1924                 syslog(LOG_ERR, "Tape device not open");
1925                 return (NDMP_DEV_NOT_OPEN_ERR);
1926         }
1927         if (mover_mode == NDMP_MOVER_MODE_READ &&
1928             session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
1929                 syslog(LOG_ERR, "Write protected device.");
1930                 return (NDMP_WRITE_PROTECT_ERR);
1931         }
1932         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
1933         session->ns_mover.md_mode = mover_mode;
1934 
1935         return (NDMP_NO_ERR);
1936 }
1937 
1938 
1939 
1940 /*
1941  * ndmpd_mover_seek
1942  *
1943  * Seek to the requested data stream position.
1944  * If the requested offset is outside of the current window,
1945  * the mover is paused and a notify_mover_paused request is sent
1946  * notifying the client that a seek is required.
1947  * If the requested offest is within the window but not within the
1948  * current record, then the tape is positioned to the record containing
1949  * the requested offest.


1965     u_longlong_t length)
1966 {
1967         int ctlcmd;
1968         int ctlcnt;
1969         u_longlong_t tape_position;
1970         u_longlong_t buf_position;
1971         ndmp_notify_mover_paused_request pause_request;
1972 
1973         session->ns_mover.md_seek_position = offset;
1974         session->ns_mover.md_bytes_left_to_read = length;
1975 
1976         /*
1977          * If the requested position is outside of the window,
1978          * notify the client that a seek is required.
1979          */
1980         if (session->ns_mover.md_seek_position <
1981             session->ns_mover.md_window_offset ||
1982             session->ns_mover.md_seek_position >=
1983             session->ns_mover.md_window_offset +
1984             session->ns_mover.md_window_length) {


1985 
1986                 session->ns_mover.md_w_index = 0;
1987                 session->ns_mover.md_r_index = 0;
1988 
1989                 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
1990                 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
1991                 pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
1992                 pause_request.seek_position = long_long_to_quad(offset);
1993 
1994                 if (ndmp_send_request(session->ns_connection,
1995                     NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
1996                     (void *) &pause_request, 0) < 0) {


1997                         return (-1);
1998                 }
1999                 return (1);
2000         }
2001         /*
2002          * Determine the data stream position of the first byte in the
2003          * data buffer.
2004          */
2005         buf_position = session->ns_mover.md_position -
2006             (session->ns_mover.md_position % session->ns_mover.md_record_size);
2007 
2008         /*
2009          * Determine the data stream position of the next byte that
2010          * will be read from tape.
2011          */
2012         tape_position = buf_position;
2013         if (session->ns_mover.md_w_index != 0)
2014                 tape_position += session->ns_mover.md_record_size;
2015 
2016         /*
2017          * Check if requested position is for data that has been read and is
2018          * in the buffer.
2019          */
2020         if (offset >= buf_position && offset < tape_position) {
2021                 session->ns_mover.md_position = offset;
2022                 session->ns_mover.md_r_index = session->ns_mover.md_position -
2023                     buf_position;





2024                 return (0);
2025         }
2026 
2027         ctlcmd = 0;
2028         if (tape_position > session->ns_mover.md_seek_position) {
2029                 /* Need to seek backward. */
2030                 ctlcmd = MTBSR;
2031                 ctlcnt = (int)((tape_position - offset - 1)
2032                     / session->ns_mover.md_record_size) + 1;
2033                 tape_position -= ((u_longlong_t)(((tape_position - offset - 1) /
2034                     session->ns_mover.md_record_size) + 1) *
2035                     (u_longlong_t)session->ns_mover.md_record_size);
2036 
2037         } else if (offset >= tape_position + session->ns_mover.md_record_size) {
2038                 /* Need to seek forward. */
2039                 ctlcmd = MTFSR;
2040                 ctlcnt = (int)((offset - tape_position)
2041                     / session->ns_mover.md_record_size);
2042                 tape_position += ((u_longlong_t)(((offset - tape_position) /
2043                     session->ns_mover.md_record_size)) *
2044                     (u_longlong_t)session->ns_mover.md_record_size);
2045         }
2046         /* Reposition the tape if necessary. */
2047         if (ctlcmd) {


2048                 (void) ndmp_mtioctl(session->ns_tape.td_fd, ctlcmd, ctlcnt);
2049         }
2050 
2051         session->ns_mover.md_position = tape_position;
2052         session->ns_mover.md_r_index = 0;
2053         session->ns_mover.md_w_index = 0;
2054 


2055         return (0);
2056 }
2057 
2058 
2059 /* ** static functions ************************************************** */
2060 
2061 /*
2062  * create_listen_socket_v2
2063  *
2064  * Creates a socket for listening for accepting data connections.
2065  *
2066  * Parameters:
2067  *   session (input)  - session pointer.
2068  *   addr    (output) - location to store address of socket.
2069  *   port    (output) - location to store port of socket.
2070  *
2071  * Returns:
2072  *   0 - success.
2073  *  -1 - error.
2074  */
2075 static int
2076 create_listen_socket_v2(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
2077 {
2078         session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
2079         if (session->ns_mover.md_listen_sock < 0)
2080                 return (-1);
2081 
2082         /*
2083          * Add a file handler for the listen socket.
2084          * ndmpd_select will call accept_connection when a
2085          * connection is ready to be accepted.
2086          */
2087         if (ndmpd_add_file_handler(session, (void *) session,
2088             session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
2089             accept_connection) < 0) {
2090                 (void) close(session->ns_mover.md_listen_sock);
2091                 session->ns_mover.md_listen_sock = -1;
2092                 return (-1);
2093         }
2094 

2095         return (0);
2096 }
2097 
2098 /*
2099  * accept_connection
2100  *
2101  * Accept a data connection from a data server.
2102  * Called by ndmpd_select when a connection is pending on
2103  * the mover listen socket.
2104  *
2105  * Parameters:
2106  *   cookie  (input) - session pointer.
2107  *   fd      (input) - file descriptor.
2108  *   mode    (input) - select mode.
2109  *
2110  * Returns:
2111  *   void.
2112  */
2113 /*ARGSUSED*/
2114 static void
2115 accept_connection(void *cookie, int fd, ulong_t mode)
2116 {
2117         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
2118         struct sockaddr_in from;
2119         int from_len;
2120 
2121         from_len = sizeof (from);
2122         session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
2123             &from_len);
2124 
2125         (void) ndmpd_remove_file_handler(session, fd);
2126         (void) close(session->ns_mover.md_listen_sock);
2127         session->ns_mover.md_listen_sock = -1;
2128 
2129         if (session->ns_mover.md_sock < 0) {
2130                 syslog(LOG_ERR, "Accept error: %m");
2131                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
2132                 return;
2133         }
2134         set_socket_options(session->ns_mover.md_sock);
2135 


2136         if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
2137                 if (start_mover_for_backup(session) < 0) {
2138                         ndmpd_mover_error(session,
2139                             NDMP_MOVER_HALT_INTERNAL_ERROR);
2140                         return;
2141                 }
2142                 syslog(LOG_DEBUG, "Backup connection established by %s:%d",
2143                     inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2144                     ntohs(from.sin_port));
2145         } else {
2146                 syslog(LOG_DEBUG, "Restore connection established by %s:%d",
2147                     inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
2148                     ntohs(from.sin_port));
2149         }
2150 


2151         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
2152 }
2153 
2154 /*
2155  * tape_read
2156  *
2157  * Reads a data record from tape. Detects and handles EOT conditions.
2158  *
2159  * Parameters:
2160  *   session (input) - session pointer.
2161  *   data    (input) - location to read data to.
2162  *
2163  * Returns:
2164  *    0 - operation aborted.
2165  *   -1 - tape read error.
2166  *   otherwise - number of bytes read.
2167  */
2168 static int
2169 tape_read(ndmpd_session_t *session, char *data)
2170 {
2171         ssize_t n;
2172         int err;
2173         int count = session->ns_mover.md_record_size;
2174 
2175         for (; ; ) {
2176                 n = read(session->ns_tape.td_fd, data, count);
2177                 if (n < 0) {
2178                         syslog(LOG_ERR, "Tape read error: %m.");
2179                         return (TAPE_READ_ERR);
2180                 }
2181                 NS_ADD(rtape, n);
2182 
2183                 if (n == 0) {
2184                         if (!is_writer_running(session))
2185                                 return (TAPE_NO_WRITER_ERR);
2186 
2187                         /*
2188                          * End of media reached.
2189                          * Notify client and wait for the client to
2190                          * either abort the data operation or continue the
2191                          * operation after changing the tape.
2192                          */
2193                         NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
2194                             ++ndmp_log_msg_id,
2195                             "End of tape reached. Load next tape");
2196 
2197                         syslog(LOG_DEBUG,
2198                             "End of tape reached. Load next tape");
2199 
2200                         err = change_tape(session);
2201 
2202                         /* Operation aborted or connection terminated? */
2203                         if (err < 0) {
2204                                 /*
2205                                  * K.L. Go back one record if it is read
2206                                  * but not used.
2207                                  */
2208 
2209                                 if (count != session->ns_mover.md_record_size) {
2210                                         (void) ndmp_mtioctl(
2211                                             session->ns_tape.td_fd, MTBSR, 1);
2212                                 }
2213                                 return (0);
2214                         }
2215                         /* Retry the read from the new tape. */
2216                         continue;
2217                 }


2242  *
2243  * Returns:
2244  *   0 - operation has been continued.
2245  *  -1 - operation has been aborted.
2246  */
2247 static int
2248 change_tape(ndmpd_session_t *session)
2249 {
2250         ndmp_notify_mover_paused_request request;
2251 
2252         session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2253 
2254         if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ)
2255                 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOM;
2256         else
2257                 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_EOF;
2258 
2259         request.reason = session->ns_mover.md_pause_reason;
2260         request.seek_position = long_long_to_quad(0LL);
2261 
2262         syslog(LOG_DEBUG, "ndmp_send_request: MOVER_PAUSED, reason: %d",
2263             session->ns_mover.md_pause_reason);
2264 
2265         if (ndmp_send_request(session->ns_connection,
2266             NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2267             (void *) &request, 0) < 0) {


2268                 return (-1);
2269         }
2270         /*
2271          * Wait for until the state is changed by
2272          * an abort or continue request.
2273          */
2274         return (ndmp_wait_for_mover(session));
2275 }
2276 
2277 
2278 /*
2279  * discard_data
2280  *
2281  * Read and discard data from the data connection.
2282  * Called when a module has called ndmpd_seek() prior to
2283  * reading all of the data from the previous seek.
2284  *
2285  * Parameters:
2286  *   session (input) - session pointer.
2287  *
2288  * Returns:
2289  *   number of bytes read and discarded.
2290  *  -1 - error.
2291  */
2292 static int
2293 discard_data(ndmpd_session_t *session, ulong_t length)
2294 {
2295         int n;
2296         char *addr;
2297 
2298         if ((addr = ndmp_malloc(length)) == NULL)
2299                 return (-1);
2300 
2301         /* Read and discard the data. */
2302         n = read(session->ns_mover.md_sock, addr, length);
2303         if (n < 0) {
2304                 syslog(LOG_ERR, "Socket read error: %m.");
2305                 free(addr);
2306                 return (-1);
2307         }
2308 
2309         free(addr);
2310         return (n);
2311 }
2312 
2313 
2314 /*
2315  * mover_tape_read_one_buf
2316  *
2317  * Read one buffer from the tape. This is used by mover_tape_reader
2318  *
2319  * Parameters:
2320  *   session (input) - session pointer.
2321  *   buf (input) - buffer read
2322  *
2323  * Returns:
2324  *   0: on success


2327 static int
2328 mover_tape_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2329 {
2330         int n;
2331 
2332         tlm_buffer_mark_empty(buf);
2333 
2334         /*
2335          * If the end of the mover window has been reached,
2336          * then notify the client that a seek is needed.
2337          * Remove the file handler to prevent this function from
2338          * being called. The handler will be reinstalled in
2339          * ndmpd_mover_continue.
2340          */
2341 
2342         if (session->ns_mover.md_position >=
2343             session->ns_mover.md_window_offset +
2344             session->ns_mover.md_window_length) {
2345                 ndmp_notify_mover_paused_request pause_request;
2346 


2347                 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
2348                 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
2349                 pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
2350                 pause_request.seek_position =
2351                     long_long_to_quad(session->ns_mover.md_position);
2352 
2353                 if (ndmp_send_request(session->ns_connection,
2354                     NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
2355                     (void *) &pause_request, 0) < 0) {


2356                         ndmpd_mover_error(session,
2357                             NDMP_MOVER_HALT_INTERNAL_ERROR);
2358                 }
2359                 buf->tb_errno = EIO;
2360                 return (TAPE_READ_ERR);
2361         }
2362 
2363         n = tape_read(session, buf->tb_buffer_data);
2364 


2365         if (n <= 0) {
2366                 if (n < 0)
2367                         ndmpd_mover_error(session,
2368                             (n == 0 ? NDMP_MOVER_HALT_ABORTED :
2369                             NDMP_MOVER_HALT_INTERNAL_ERROR));
2370                 return (TAPE_READ_ERR);
2371         }
2372 
2373         buf->tb_full = TRUE;
2374         buf->tb_buffer_size = session->ns_mover.md_record_size;
2375 
2376         /*
2377          * Discard data if the current data stream position is
2378          * prior to the seek position. This is necessary if a seek
2379          * request set the seek pointer to a position that is not a
2380          * record boundary. The seek request handler can only position
2381          * to the start of a record.
2382          */
2383         if (session->ns_mover.md_position < session->ns_mover.md_seek_position)
2384                 session->ns_mover.md_position =


2396  *
2397  * Parameters:
2398  *   session (input) - session pointer.
2399  *
2400  * Returns:
2401  *   0: on success
2402  *  -1: otherwise
2403  */
2404 int
2405 mover_tape_reader(ndmpd_session_t *session)
2406 {
2407         int bidx;       /* buffer index */
2408         int rv;
2409         ndmp_lbr_params_t *nlp;
2410         tlm_buffer_t *buf;
2411         tlm_buffers_t *bufs;
2412         tlm_cmd_t *lcmd;        /* Local command */
2413         tlm_commands_t *cmds;   /* Commands structure */
2414 
2415         if ((nlp = ndmp_get_nlp(session)) == NULL) {

2416                 return (-1);
2417         }
2418 
2419         cmds = &nlp->nlp_cmds;
2420         lcmd = cmds->tcs_command;
2421         bufs = lcmd->tc_buffers;
2422 
2423         lcmd->tc_ref++;
2424         cmds->tcs_reader_count++;
2425 
2426         /*
2427          * Let our parent thread know that we are running.
2428          */
2429         tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_READER);
2430 
2431         buf = tlm_buffer_in_buf(bufs, &bidx);
2432         while (cmds->tcs_reader == TLM_RESTORE_RUN &&
2433             lcmd->tc_reader == TLM_RESTORE_RUN) {
2434                 buf = tlm_buffer_in_buf(bufs, NULL);
2435 
2436                 if (buf->tb_full) {
2437                         syslog(LOG_DEBUG, "R%d", bidx);
2438                         /*
2439                          * The buffer is still full, wait for the consumer
2440                          * thread to use it.
2441                          */
2442                         tlm_buffer_out_buf_timed_wait(bufs, 100);
2443 
2444                 } else {
2445                         syslog(LOG_DEBUG, "r%d", bidx);
2446 
2447                         rv = mover_tape_read_one_buf(session, buf);
2448                         /*
2449                          * If there was an error while reading, such as
2450                          * end of stream.
2451                          */
2452                         if (rv < 0) {
2453                                 syslog(LOG_DEBUG, "Exiting, rv: %d", rv);
2454                                 break;
2455                         }
2456 
2457                         /*
2458                          * Can we do more buffering?
2459                          */
2460                         if (is_buffer_erroneous(buf)) {
2461                                 syslog(LOG_DEBUG,
2462                                     "Exiting, errno: %d, eot: %d, eof: %d",
2463                                     buf->tb_errno, buf->tb_eot, buf->tb_eof);
2464                                 break;
2465                         }
2466 
2467                         (void) tlm_buffer_advance_in_idx(bufs);
2468                         tlm_buffer_release_in_buf(bufs);
2469                         bidx = bufs->tbs_buffer_in;
2470                 }
2471         }
2472 
2473         /* If the consumer is waiting for us, wake it up. */
2474         tlm_buffer_release_in_buf(bufs);
2475 
2476         /*
2477          * Clean up.
2478          */
2479         cmds->tcs_reader_count--;
2480         lcmd->tc_ref--;
2481         lcmd->tc_writer = TLM_STOP;


2489  * Write one buffer to the network socket. This is used by mover_socket_writer
2490  *
2491  * Parameters:
2492  *   session (input) - session pointer.
2493  *   buf (input) - buffer read
2494  *
2495  * Returns:
2496  *   0: on success
2497  *  -1: otherwise
2498  */
2499 static int
2500 mover_socket_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2501 {
2502         int n;
2503 
2504         /* Write the data to the data connection. */
2505         errno = 0;
2506         n = write(session->ns_mover.md_sock, buf->tb_buffer_data,
2507             buf->tb_buffer_size);
2508 


2509         if (n < 0) {

2510                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
2511                 return (-1);
2512         }
2513 
2514         session->ns_mover.md_position += n;
2515         session->ns_mover.md_bytes_left_to_read -= n;
2516         tlm_buffer_mark_empty(buf);
2517 
2518         /*
2519          * If the read limit has been reached,
2520          * then remove the file handler to prevent this
2521          * function from getting called. The next mover_read request
2522          * will reinstall the handler.
2523          */
2524         if (session->ns_mover.md_bytes_left_to_read == 0) {

2525                 (void) ndmpd_remove_file_handler(session,
2526                     session->ns_mover.md_sock);
2527                 return (-1);
2528         }
2529 
2530         return (0);
2531 }
2532 
2533 
2534 
2535 /*
2536  * mover_socket_writer
2537  *
2538  * Mover's socket writer thread. This thread sends the read buffer
2539  * from the tape to the data server through the network socket.
2540  *
2541  * Parameters:
2542  *   session (input) - session pointer.
2543  *
2544  * Returns:
2545  *   0: on success
2546  *  -1: otherwise
2547  */
2548 int
2549 mover_socket_writer(ndmpd_session_t *session)
2550 {
2551         int bidx;       /* buffer index */
2552         ndmp_lbr_params_t *nlp;
2553         tlm_buffer_t *buf;
2554         tlm_buffers_t *bufs;
2555         tlm_cmd_t *lcmd;        /* Local command */
2556         tlm_commands_t *cmds;   /* Commands structure */
2557 
2558         if ((nlp = ndmp_get_nlp(session)) == NULL) {

2559                 return (-1);
2560         }
2561 
2562         cmds = &nlp->nlp_cmds;
2563         lcmd = cmds->tcs_command;
2564         bufs = lcmd->tc_buffers;
2565 
2566         lcmd->tc_ref++;
2567         cmds->tcs_writer_count++;
2568 
2569         /*
2570          * Let our parent thread know that we are running.
2571          */
2572         tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_WRITER);
2573 
2574         bidx = bufs->tbs_buffer_out;
2575         while (cmds->tcs_writer != (int)TLM_ABORT &&
2576             lcmd->tc_writer != (int)TLM_ABORT) {
2577                 buf = &bufs->tbs_buffer[bidx];
2578 
2579                 if (buf->tb_full) {
2580                         syslog(LOG_DEBUG, "w%d", bidx);
2581 
2582                         if (mover_socket_write_one_buf(session, buf) < 0) {


2583                                 break;
2584                         }
2585 
2586                         (void) tlm_buffer_advance_out_idx(bufs);
2587                         tlm_buffer_release_out_buf(bufs);
2588                         bidx = bufs->tbs_buffer_out;
2589                 } else {
2590                         if (lcmd->tc_writer != TLM_RESTORE_RUN) {
2591                                 /* No more data is coming, time to exit */

2592                                 break;
2593                         }
2594                         syslog(LOG_DEBUG, "W%d", bidx);
2595                         /*
2596                          * The buffer is not full, wait for the producer
2597                          * thread to fill it.
2598                          */
2599                         tlm_buffer_in_buf_timed_wait(bufs, 100);
2600                 }
2601         }
2602 
2603         if (cmds->tcs_writer == (int)TLM_ABORT)
2604                 syslog(LOG_DEBUG, "cmds->tcs_writer == (int)TLM_ABORT");
2605         if (lcmd->tc_writer == (int)TLM_ABORT)
2606                 syslog(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");
2607 
2608         /* If the producer is waiting for us, wake it up. */
2609         tlm_buffer_release_out_buf(bufs);
2610 
2611         /*
2612          * Clean up.
2613          */
2614         cmds->tcs_writer_count--;
2615         lcmd->tc_ref--;
2616         lcmd->tc_reader = TLM_STOP;
2617         return (0);
2618 }
2619 
2620 
2621 /*
2622  * start_mover_for_restore
2623  *
2624  * Creates the mover tape reader and network writer threads for
2625  * the mover to perform the 3-way restore.
2626  *
2627  * Parameters:
2628  *   session (input) - session pointer.
2629  *
2630  * Returns:
2631  *   0: on success
2632  *  -1: otherwise
2633  */
2634 static int
2635 start_mover_for_restore(ndmpd_session_t *session)
2636 {
2637         ndmp_lbr_params_t *nlp;
2638         tlm_commands_t *cmds;
2639         long xfer_size;
2640         int rc;
2641 
2642         if ((nlp = ndmp_get_nlp(session)) == NULL) {

2643                 return (-1);
2644         }
2645 
2646         cmds = &nlp->nlp_cmds;
2647         (void) memset(cmds, 0, sizeof (*cmds));
2648         cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
2649         xfer_size = ndmp_buffer_get_size(session);
2650         cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2651         if (cmds->tcs_command == NULL)
2652                 return (-1);
2653 
2654         cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
2655         cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
2656 
2657         /*
2658          * We intentionnally don't wait for the threads to start since the
2659          * reply of the request (which resulted in calling this function)
2660          * must be sent to the client before probable errors are sent
2661          * to the client.
2662          */
2663         rc = pthread_create(NULL, NULL, (funct_t)mover_tape_reader, session);
2664         if (rc == 0) {
2665                 tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_READER);
2666         } else {


2667                 return (-1);
2668         }
2669 
2670         rc = pthread_create(NULL, NULL, (funct_t)mover_socket_writer, session);
2671         if (rc == 0) {
2672                 tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_WRITER);
2673         } else {


2674                 return (-1);
2675         }
2676 
2677         tlm_release_reader_writer_ipc(cmds->tcs_command);
2678         return (0);
2679 }
2680 
2681 
2682 /*
2683  * mover_socket_read_one_buf
2684  *
2685  * Read one buffer from the network socket for the mover. This is used
2686  * by mover_socket_reader
2687  *
2688  * Parameters:
2689  *   session (input) - session pointer.
2690  *   buf (input) - buffer read
2691  *   read_size (input) - size to be read
2692  *
2693  * Returns:
2694  *   0: on success
2695  *  -1: otherwise
2696  */
2697 static int
2698 mover_socket_read_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf,
2699     long read_size)
2700 {
2701         int n, index;
2702         long toread;
2703 
2704         tlm_buffer_mark_empty(buf);
2705         for (index = 0, toread = read_size; toread > 0; ) {
2706                 errno = 0;


2707                 n = read(session->ns_mover.md_sock, &buf->tb_buffer_data[index],
2708                     toread);
2709                 if (n == 0) {

2710                         break;
2711                 } else if (n > 0) {

2712                         index += n;
2713                         toread -= n;
2714                 } else {
2715                         buf->tb_eof = TRUE;
2716                         buf->tb_errno = errno;
2717                         buf->tb_buffer_size = 0;

2718                         return (-1);
2719                 }
2720         }
2721 
2722         if (index > 0) {
2723                 buf->tb_full = TRUE;
2724                 buf->tb_buffer_size = read_size;
2725                 if (read_size > 0)
2726                         (void) memset(&buf->tb_buffer_data[index], 0,
2727                             read_size - index);
2728         } else {
2729                 buf->tb_eof = TRUE;
2730                 buf->tb_buffer_size = 0;
2731         }
2732 
2733         syslog(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
2734             " errno: %d, size: %d, data: 0x%x",
2735             buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
2736             buf->tb_buffer_size, buf->tb_buffer_data);
2737 
2738         return (0);
2739 }
2740 
2741 
2742 
2743 /*
2744  * mover_socket_reader
2745  *
2746  * Mover socket reader thread. This is used when reading data from the
2747  * network socket for performing remote backups.
2748  *
2749  * Parameters:
2750  *   session (input) - session pointer.
2751  *
2752  * Returns:
2753  *   0: on success
2754  *  -1: otherwise
2755  */
2756 int
2757 mover_socket_reader(ndmpd_session_t *session)
2758 {
2759         int bidx;       /* buffer index */
2760         ndmp_lbr_params_t *nlp;
2761         tlm_buffer_t *buf;
2762         tlm_buffers_t *bufs;
2763         tlm_cmd_t *lcmd;        /* Local command */
2764         tlm_commands_t *cmds;   /* Commands structure */
2765         static int nr = 0;
2766 
2767         if ((nlp = ndmp_get_nlp(session)) == NULL) {

2768                 return (-1);
2769         }
2770 
2771         cmds = &nlp->nlp_cmds;
2772         lcmd = cmds->tcs_command;
2773         bufs = lcmd->tc_buffers;
2774 
2775         lcmd->tc_ref++;
2776         cmds->tcs_reader_count++;
2777 
2778         /*
2779          * Let our parent thread know that we are running.
2780          */
2781         tlm_cmd_signal(cmds->tcs_command, TLM_SOCK_READER);
2782 
2783         bidx = bufs->tbs_buffer_in;
2784         while (cmds->tcs_reader == TLM_BACKUP_RUN &&
2785             lcmd->tc_reader == TLM_BACKUP_RUN) {
2786                 buf = &bufs->tbs_buffer[bidx];
2787 
2788                 if (buf->tb_full) {
2789                         syslog(LOG_DEBUG, "R%d", bidx);
2790                         /*
2791                          * The buffer is still full, wait for the consumer
2792                          * thread to use it.
2793                          */
2794                         tlm_buffer_out_buf_timed_wait(bufs, 100);
2795                 } else {
2796                         syslog(LOG_DEBUG, "r%d, nr: %d", bidx, ++nr);
2797 
2798                         (void) mover_socket_read_one_buf(session, buf,
2799                             bufs->tbs_data_transfer_size);
2800 
2801                         /*
2802                          * Can we do more buffering?
2803                          */
2804                         if (is_buffer_erroneous(buf)) {
2805                                 syslog(LOG_DEBUG,
2806                                     "Exiting, errno: %d, eot: %d, eof: %d",
2807                                     buf->tb_errno, buf->tb_eot, buf->tb_eof);
2808                                 break;
2809                         }
2810 
2811                         (void) tlm_buffer_advance_in_idx(bufs);
2812                         tlm_buffer_release_in_buf(bufs);
2813                         bidx = bufs->tbs_buffer_in;
2814                 }
2815         }
2816 
2817         if (cmds->tcs_reader != TLM_BACKUP_RUN)
2818                 syslog(LOG_DEBUG, "cmds->tcs_reader != TLM_BACKUP_RUN");
2819         if (lcmd->tc_reader != TLM_BACKUP_RUN)
2820                 syslog(LOG_DEBUG, "lcmd->tc_reader != TLM_BACKUP_RUN");
2821         syslog(LOG_DEBUG, "nr: %d", nr);
2822 
2823         /* If the consumer is waiting for us, wake it up. */
2824         tlm_buffer_release_in_buf(bufs);
2825 
2826         /*
2827          * Clean up.
2828          */
2829         cmds->tcs_reader_count--;
2830         lcmd->tc_ref--;
2831         lcmd->tc_writer = TLM_STOP;
2832         return (0);
2833 }
2834 
2835 
2836 /*
2837  * mover_tape_writer_one_buf
2838  *
2839  * Write one buffer for the mover to the local tape device. This is
2840  * used by mover_tape_writer thread.
2841  *
2842  * Parameters:
2843  *   session (input) - session pointer.
2844  *   buf (input) - buffer read
2845  *
2846  * Returns:
2847  *   0: on success
2848  *  -1: otherwise
2849  */
2850 static int
2851 mover_tape_write_one_buf(ndmpd_session_t *session, tlm_buffer_t *buf)
2852 {
2853         int n;
2854 
2855         syslog(LOG_DEBUG, "full: %d, eot: %d, eof: %d,"
2856             " errno: %d, size: %d, data: 0x%x",
2857             buf->tb_full, buf->tb_eot, buf->tb_eof, buf->tb_errno,
2858             buf->tb_buffer_size, buf->tb_buffer_data);
2859 
2860         n = mover_tape_write_v3(session, buf->tb_buffer_data,
2861             buf->tb_buffer_size);
2862 


2863         if (n <= 0) {
2864                 ndmpd_mover_error(session, (n == 0 ? NDMP_MOVER_HALT_ABORTED
2865                     : NDMP_MOVER_HALT_INTERNAL_ERROR));
2866                 return (-1);
2867         }
2868         session->ns_mover.md_position += n;
2869         session->ns_mover.md_data_written += n;
2870         session->ns_mover.md_record_num++;
2871 

2872         tlm_buffer_mark_empty(buf);
2873 
2874         return (0);
2875 }
2876 
2877 
2878 /*
2879  * mover_tape_writer
2880  *
2881  * Mover tape writer thread. This is used for performing remote backups
2882  * in a 3-way configuration. It writes the data from network socket to
2883  * the locally attached tape device.
2884  *
2885  * Parameters:
2886  *   session (input) - session pointer.
2887  *
2888  * Returns:
2889  *   0: on success
2890  *  -1: otherwise
2891  */
2892 int
2893 mover_tape_writer(ndmpd_session_t *session)
2894 {
2895         int bidx;
2896         ndmp_lbr_params_t *nlp;
2897         tlm_buffer_t *buf;
2898         tlm_buffers_t *bufs;
2899         tlm_cmd_t *lcmd;
2900         tlm_commands_t *cmds;
2901         static int nw = 0;
2902 
2903         if ((nlp = ndmp_get_nlp(session)) == NULL) {

2904                 return (-1);
2905         }
2906 
2907         cmds = &nlp->nlp_cmds;
2908         lcmd = cmds->tcs_command;
2909         bufs = lcmd->tc_buffers;
2910 
2911         lcmd->tc_ref++;
2912         cmds->tcs_writer_count++;
2913 
2914         /*
2915          * Let our parent thread know that we are running.
2916          */
2917         tlm_cmd_signal(cmds->tcs_command, TLM_TAPE_WRITER);
2918 
2919         bidx = bufs->tbs_buffer_out;
2920         buf = &bufs->tbs_buffer[bidx];
2921         while (cmds->tcs_writer != (int)TLM_ABORT &&
2922             lcmd->tc_writer != (int)TLM_ABORT) {
2923                 if (buf->tb_full) {
2924                         syslog(LOG_DEBUG, "w%d, nw: %d", bidx, ++nw);
2925 
2926                         if (mover_tape_write_one_buf(session, buf) < 0) {
2927                                 syslog(LOG_DEBUG,
2928                                     "mover_tape_write_one_buf() failed");
2929                                 break;
2930                         }
2931 
2932                         (void) tlm_buffer_advance_out_idx(bufs);
2933                         tlm_buffer_release_out_buf(bufs);
2934                         bidx = bufs->tbs_buffer_out;
2935                         buf = &bufs->tbs_buffer[bidx];
2936                 } else {
2937                         if (lcmd->tc_writer != TLM_BACKUP_RUN) {
2938                                 /* No more data is coming, time to exit */

2939                                 break;
2940                         }
2941                         syslog(LOG_DEBUG, "W%d", bidx);
2942                         /*
2943                          * The buffer is not full, wait for the producer
2944                          * thread to fill it.
2945                          */
2946                         tlm_buffer_in_buf_timed_wait(bufs, 100);
2947                 }
2948         }
2949 
2950         if (cmds->tcs_writer == (int)TLM_ABORT)
2951                 syslog(LOG_DEBUG, "cmds->tcs_writer == TLM_ABORT");
2952         if (lcmd->tc_writer == (int)TLM_ABORT)
2953                 syslog(LOG_DEBUG, "lcmd->tc_writer == TLM_ABORT");

2954 
2955         if (buf->tb_errno == 0) {
2956                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
2957         } else {

2958                 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
2959         }
2960 
2961         /* If the producer is waiting for us, wake it up. */
2962         tlm_buffer_release_out_buf(bufs);
2963 
2964         /*
2965          * Clean up.
2966          */
2967         cmds->tcs_writer_count--;
2968         lcmd->tc_ref--;
2969         lcmd->tc_reader = TLM_STOP;
2970         return (0);
2971 }
2972 
2973 
2974 /*
2975  * start_mover_for_backup
2976  *
2977  * Starts a remote backup by running socket reader and tape
2978  * writer threads. The mover runs a remote backup in a 3-way backup
2979  * configuration.
2980  *
2981  * Parameters:
2982  *   session (input) - session pointer.
2983  *
2984  * Returns:
2985  *   0: on success
2986  *  -1: otherwise
2987  */
2988 static int
2989 start_mover_for_backup(ndmpd_session_t *session)
2990 {
2991         ndmp_lbr_params_t *nlp;
2992         tlm_commands_t *cmds;
2993         int rc;
2994 
2995         if ((nlp = ndmp_get_nlp(session)) == NULL) {

2996                 return (-1);
2997         }
2998 
2999         cmds = &nlp->nlp_cmds;
3000         (void) memset(cmds, 0, sizeof (*cmds));
3001         cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
3002         cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE,
3003             session->ns_mover.md_record_size);
3004         if (cmds->tcs_command == NULL)
3005                 return (-1);
3006 
3007         cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
3008         cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
3009 
3010         /*
3011          * We intentionally don't wait for the threads to start since the
3012          * reply of the request (which resulted in calling this function)
3013          * must be sent to the client before probable errors are sent
3014          * to the client.
3015          */
3016         rc = pthread_create(NULL, NULL, (funct_t)mover_socket_reader, session);
3017         if (rc == 0) {
3018                 tlm_cmd_wait(cmds->tcs_command, TLM_SOCK_READER);
3019         } else {


3020                 return (-1);
3021         }
3022 
3023         rc = pthread_create(NULL, NULL, (funct_t)mover_tape_writer, session);
3024         if (rc == 0) {
3025                 tlm_cmd_wait(cmds->tcs_command, TLM_TAPE_WRITER);
3026         } else {


3027                 return (-1);
3028         }
3029 
3030         tlm_release_reader_writer_ipc(cmds->tcs_command);
3031         return (0);
3032 }
3033 
3034 
3035 /*
3036  * is_writer_running
3037  *
3038  * Find out if the writer thread has started or not.
3039  *
3040  * Parameters:
3041  *   session (input) - session pointer.
3042  *
3043  * Returns:
3044  *   0: not started
3045  *   non-zero: started
3046  *      Note: non-zero is also returned if the backup type is


3165  *
3166  * Parameters:
3167  *   session (input) - session pointer.
3168  *   reason  (input) - halt reason.
3169  *
3170  * Returns:
3171  *   void.
3172  */
3173 void
3174 ndmpd_mover_error(ndmpd_session_t *session, ndmp_mover_halt_reason reason)
3175 {
3176         ndmp_lbr_params_t *nlp = ndmp_get_nlp(session);
3177 
3178         if (session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED ||
3179             (session->ns_protocol_version > NDMPV2 &&
3180             session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE))
3181                 return;
3182 
3183         if (session->ns_protocol_version == NDMPV4) {
3184                 if (ndmpd_mover_error_send_v4(session, reason) < 0)
3185                         syslog(LOG_ERR,
3186                             "Error sending notify_mover_halted request");
3187         } else {
3188                 /* No media error in V3 */
3189                 if (reason == NDMP_MOVER_HALT_MEDIA_ERROR)
3190                         reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
3191                 if (ndmpd_mover_error_send(session, reason) < 0)
3192                         syslog(LOG_ERR,
3193                             "Error sending notify_mover_halted request");
3194         }
3195 
3196         (void) mutex_lock(&nlp->nlp_mtx);
3197         if (session->ns_mover.md_listen_sock != -1) {
3198                 (void) ndmpd_remove_file_handler(session,
3199                     session->ns_mover.md_listen_sock);
3200                 (void) close(session->ns_mover.md_listen_sock);
3201                 session->ns_mover.md_listen_sock = -1;
3202         }
3203         if (session->ns_mover.md_sock != -1) {
3204                 (void) ndmpd_remove_file_handler(session,
3205                     session->ns_mover.md_sock);
3206                 (void) close(session->ns_mover.md_sock);
3207                 session->ns_mover.md_sock = -1;
3208         }
3209 
3210         session->ns_mover.md_state = NDMP_MOVER_STATE_HALTED;
3211         session->ns_mover.md_halt_reason = reason;
3212         (void) cond_broadcast(&nlp->nlp_cv);


3230  *   0 - operation has been continued.
3231  *  -1 - operation has been aborted.
3232  */
3233 static int
3234 mover_pause_v3(ndmpd_session_t *session, ndmp_mover_pause_reason reason)
3235 {
3236         int rv;
3237         ndmp_notify_mover_paused_request request;
3238 
3239         rv = 0;
3240         session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3241         session->ns_mover.md_pause_reason = reason;
3242         session->ns_mover.md_pre_cond = FALSE;
3243 
3244         request.reason = session->ns_mover.md_pause_reason;
3245         request.seek_position =
3246             long_long_to_quad(session->ns_mover.md_position);
3247 
3248         if (ndmp_send_request(session->ns_connection, NDMP_NOTIFY_MOVER_PAUSED,
3249             NDMP_NO_ERR, (void *)&request, 0) < 0) {
3250                 syslog(LOG_ERR,
3251                     "Error sending notify_mover_paused_request");
3252                 return (-1);
3253         }
3254 
3255         /*
3256          * 3-way operations are single-thread.  The same thread
3257          * should process the messages.
3258          *
3259          * 2-way operations are multi-thread.  The main thread
3260          * processes the messages.  We just need to wait and
3261          * see if the mover state changes or the operation aborts.
3262          */
3263         if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_TCP) {
3264                 /*
3265                  * Process messages until the state is changed by
3266                  * an abort, continue, or close request .
3267                  */
3268                 for (; ; ) {
3269                         if (ndmpd_select(session, TRUE, HC_CLIENT) < 0)
3270                                 return (-1);


3273                                 return (-1);
3274 
3275                         switch (session->ns_mover.md_state) {
3276                         case NDMP_MOVER_STATE_ACTIVE:
3277                                 session->ns_tape.td_record_count = 0;
3278                                 return (0);
3279 
3280                         case NDMP_MOVER_STATE_PAUSED:
3281                                 continue;
3282 
3283                         default:
3284                                 return (-1);
3285                         }
3286                 }
3287 
3288         } else {
3289                 if (session->ns_mover.md_data_addr.addr_type ==
3290                     NDMP_ADDR_LOCAL) {
3291                         rv = ndmp_wait_for_mover(session);
3292                 } else {


3293                         rv = -1;
3294                 }
3295         }
3296 
3297         return (rv);
3298 }
3299 
3300 
3301 /*
3302  * mover_tape_write_v3
3303  *
3304  * Writes a data record to tape. Detects and handles EOT conditions.
3305  *
3306  * Parameters:
3307  *   session (input) - session pointer.
3308  *   data    (input) - data to be written.
3309  *   length  (input) - length of data to be written.
3310  *
3311  * Returns:
3312  *    0 - operation aborted by client.
3313  *   -1 - error.
3314  *   otherwise - number of bytes written.
3315  */
3316 static int
3317 mover_tape_write_v3(ndmpd_session_t *session, char *data, ssize_t length)
3318 {
3319         ssize_t n;
3320         ssize_t count = length;
3321 
3322         while (count > 0) {
3323                 /*
3324                  * Enforce mover window on write.
3325                  */
3326                 if (session->ns_mover.md_position >=
3327                     session->ns_mover.md_window_offset +
3328                     session->ns_mover.md_window_length) {
3329                         syslog(LOG_DEBUG, "MOVER_PAUSE_EOW");
3330 
3331                         if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOW) < 0)
3332                                 /* Operation aborted or connection terminated */
3333                                 return (-1);
3334 
3335                 }
3336 
3337                 n = write(session->ns_tape.td_fd, data, count);
3338                 if (n < 0) {
3339                         syslog(LOG_ERR, "Tape write error: %m.");
3340                         return (-1);
3341                 } else if (n > 0) {
3342                         NS_ADD(wtape, n);
3343                         count -= n;
3344                         data += n;
3345                         session->ns_tape.td_record_count++;
3346                 }
3347 
3348                 /* EOM handling */
3349                 if (count > 0) {
3350                         struct mtget mtstatus;
3351 
3352                         (void) ioctl(session->ns_tape.td_fd, MTIOCGET,
3353                             &mtstatus);
3354                         syslog(LOG_DEBUG, "EOM detected (%d written bytes, "
3355                             "mover record %d, file #%d, block #%d)", n,
3356                             session->ns_tape.td_record_count,
3357                             mtstatus.mt_fileno, mtstatus.mt_blkno);
3358 
3359                         /*
3360                          * Notify the client to either abort the operation
3361                          * or change the tape.
3362                          */
3363                         NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3364                             ++ndmp_log_msg_id,
3365                             "End of tape reached. Load next tape");
3366 
3367                         if (mover_pause_v3(session, NDMP_MOVER_PAUSE_EOM) < 0)
3368                                 /* Operation aborted or connection terminated */
3369                                 return (-1);
3370                 }
3371         }
3372 
3373         return (length);
3374 }


3387  *
3388  * Returns:
3389  *   -1 - error.
3390  *   otherwise - number of bytes written.
3391  */
3392 static int
3393 mover_tape_flush_v3(ndmpd_session_t *session)
3394 {
3395         int n;
3396 
3397         if (session->ns_mover.md_w_index == 0)
3398                 return (0);
3399 
3400         (void) memset((void*)&session->ns_mover.md_buf[session->
3401             ns_mover.md_w_index], 0,
3402             session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3403 
3404         n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3405             session->ns_mover.md_record_size);
3406         if (n < 0) {
3407                 syslog(LOG_ERR, "Tape write error: %m.");
3408                 return (-1);
3409         }
3410 
3411         session->ns_mover.md_w_index = 0;
3412         session->ns_mover.md_position += n;
3413         return (n);
3414 }
3415 
3416 
3417 /*
3418  * ndmpd_local_write_v3
3419  *
3420  * Buffers and writes data to the tape device.
3421  * A full tape record is buffered before being written.
3422  *
3423  * Parameters:
3424  *   session    (input) - session pointer.
3425  *   data       (input) - data to be written.
3426  *   length     (input) - data length.
3427  *
3428  * Returns:
3429  *   0 - data successfully written.
3430  *  -1 - error.
3431  */
3432 int
3433 ndmpd_local_write_v3(ndmpd_session_t *session, char *data, ulong_t length)
3434 {
3435         ulong_t count = 0;
3436         ssize_t n;
3437         ulong_t len;
3438 
3439         if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
3440             session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
3441             session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {

3442                 return (-1);
3443         }
3444 
3445         /*
3446          * A length of 0 indicates that any buffered data should be
3447          * flushed to tape.
3448          */
3449         if (length == 0) {
3450                 if (session->ns_mover.md_w_index == 0)
3451                         return (0);
3452 
3453                 (void) memset((void*)&session->ns_mover.md_buf[session->
3454                     ns_mover.md_w_index], 0, session->ns_mover.md_record_size -
3455                     session->ns_mover.md_w_index);
3456 
3457                 n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3458                     session->ns_mover.md_record_size);
3459                 if (n <= 0) {
3460                         ndmpd_mover_error(session,
3461                             (n == 0 ?  NDMP_MOVER_HALT_ABORTED :


3549  *   void.
3550  */
3551 /*ARGSUSED*/
3552 static void
3553 mover_data_read_v3(void *cookie, int fd, ulong_t mode)
3554 {
3555         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3556         int n;
3557         ulong_t index;
3558 
3559         n = read(fd, &session->ns_mover.md_buf[session->ns_mover.md_w_index],
3560             session->ns_mover.md_record_size - session->ns_mover.md_w_index);
3561 
3562         /*
3563          * Since this function is only called when select believes data
3564          * is available to be read, a return of zero indicates the
3565          * connection has been closed.
3566          */
3567         if (n <= 0) {
3568                 if (n == 0) {
3569                         syslog(LOG_DEBUG, "Data connection closed");
3570                         ndmpd_mover_error(session,
3571                             NDMP_MOVER_HALT_CONNECT_CLOSED);
3572                 } else {
3573                         /* Socket is non-blocking, perhaps there are no data */
3574                         if (errno == EAGAIN) {
3575                                 syslog(LOG_DEBUG, "No data to read");
3576                                 return;
3577                         }
3578 
3579                         syslog(LOG_ERR,
3580                             "Failed to read from socket %d: %m", fd);
3581                         ndmpd_mover_error(session,
3582                             NDMP_MOVER_HALT_INTERNAL_ERROR);
3583                 }
3584 
3585                 /* Save the index since mover_tape_flush_v3 resets it. */
3586                 index = session->ns_mover.md_w_index;
3587 
3588                 /* Flush any buffered data to tape. */
3589                 if (mover_tape_flush_v3(session) > 0) {
3590                         session->ns_mover.md_data_written += index;
3591                         session->ns_mover.md_record_num++;
3592                 }
3593 
3594                 return;
3595         }
3596 


3597         session->ns_mover.md_w_index += n;
3598 
3599         if (session->ns_mover.md_w_index == session->ns_mover.md_record_size) {
3600                 n = mover_tape_write_v3(session, session->ns_mover.md_buf,
3601                     session->ns_mover.md_record_size);
3602                 if (n <= 0) {
3603                         ndmpd_mover_error(session,
3604                             (n == 0 ? NDMP_MOVER_HALT_ABORTED :
3605                             NDMP_MOVER_HALT_MEDIA_ERROR));
3606                         return;
3607                 }
3608 
3609                 session->ns_mover.md_position += n;
3610                 session->ns_mover.md_w_index = 0;
3611                 session->ns_mover.md_data_written += n;
3612                 session->ns_mover.md_record_num++;
3613         }
3614 }
3615 
3616 /*


3630  */
3631 static int
3632 mover_tape_read_v3(ndmpd_session_t *session, char *data)
3633 {
3634         int pause_reason;
3635         ssize_t  n;
3636         int err;
3637         int count;
3638 
3639         count = session->ns_mover.md_record_size;
3640         while (count > 0) {
3641                 pause_reason = NDMP_MOVER_PAUSE_NA;
3642 
3643                 n = read(session->ns_tape.td_fd, data, count);
3644                 if (n < 0) {
3645                         /*
3646                          * If at beginning of file and read fails with EIO,
3647                          * then it's repeated attempt to read at EOT.
3648                          */
3649                         if (errno == EIO && tape_is_at_bof(session)) {

3650                                 pause_reason = NDMP_MOVER_PAUSE_EOM;
3651                                 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3652                                     ++ndmp_log_msg_id,
3653                                     "End of tape reached. Load next tape");
3654                         }
3655                         /*
3656                          * According to NDMPv4 spec preferred error code when
3657                          * trying to read from blank tape is NDMP_EOM_ERR.
3658                          */
3659                         else if (errno == EIO && tape_is_at_bot(session)) {
3660                                 syslog(LOG_ERR,
3661                                     "Blank tape detected, returning EOM");
3662                                 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3663                                     ++ndmp_log_msg_id,
3664                                     "Blank tape. Load another tape");
3665                                 pause_reason = NDMP_MOVER_PAUSE_EOM;
3666                         } else {
3667                                 syslog(LOG_ERR, "Tape read error: %m.");
3668                                 return (TAPE_READ_ERR);
3669                         }
3670                 } else if (n > 0) {
3671                         NS_ADD(rtape, n);
3672                         data += n;
3673                         count -= n;
3674                         session->ns_tape.td_record_count++;
3675                 } else {
3676                         if (!is_writer_running_v3(session))
3677                                 return (TAPE_NO_WRITER_ERR);
3678 
3679                         /*
3680                          * End of file or media reached. Notify client and
3681                          * wait for the client to either abort the data
3682                          * operation or continue the operation after changing
3683                          * the tape.
3684                          */
3685                         if (tape_is_at_bof(session)) {
3686                                 syslog(LOG_DEBUG, "EOT detected");
3687                                 pause_reason = NDMP_MOVER_PAUSE_EOM;
3688                                 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3689                                     ++ndmp_log_msg_id, "End of medium reached");
3690                         } else {
3691                                 syslog(LOG_DEBUG, "EOF detected");
3692                                 /* reposition the tape to BOT side of FM */
3693                                 fm_dance(session);
3694                                 pause_reason = NDMP_MOVER_PAUSE_EOF;
3695                                 NDMP_APILOG((void*)session, NDMP_LOG_NORMAL,
3696                                     ++ndmp_log_msg_id, "End of file reached.");
3697                         }
3698                 }
3699 
3700                 if (pause_reason != NDMP_MOVER_PAUSE_NA) {
3701                         err = mover_pause_v3(session, pause_reason);
3702 
3703                         /* Operation aborted or connection terminated? */
3704                         if (err < 0) {
3705                                 return (0);
3706                         }
3707                         /* Retry the read from new location */
3708                 }
3709         }
3710         return (session->ns_mover.md_record_size);
3711 }


3729  */
3730 /*ARGSUSED*/
3731 static void
3732 mover_data_write_v3(void *cookie, int fd, ulong_t mode)
3733 {
3734         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3735         int n;
3736         ulong_t len;
3737         u_longlong_t wlen;
3738         ndmp_notify_mover_paused_request pause_request;
3739 
3740         /*
3741          * If the end of the mover window has been reached,
3742          * then notify the client that a seek is needed.
3743          * Remove the file handler to prevent this function from
3744          * being called. The handler will be reinstalled in
3745          * ndmpd_mover_continue.
3746          */
3747         if (session->ns_mover.md_position >= session->ns_mover.md_window_offset
3748             + session->ns_mover.md_window_length) {
3749                 syslog(LOG_DEBUG,
3750                     "MOVER_PAUSE_SEEK(%llu)", session->ns_mover.md_position);
3751 
3752                 session->ns_mover.md_w_index = 0;
3753                 session->ns_mover.md_r_index = 0;
3754 
3755                 session->ns_mover.md_state = NDMP_MOVER_STATE_PAUSED;
3756                 session->ns_mover.md_pause_reason = NDMP_MOVER_PAUSE_SEEK;
3757                 pause_request.reason = NDMP_MOVER_PAUSE_SEEK;
3758                 pause_request.seek_position =
3759                     long_long_to_quad(session->ns_mover.md_position);
3760                 session->ns_mover.md_seek_position =
3761                     session->ns_mover.md_position;
3762 
3763                 (void) ndmpd_remove_file_handler(session, fd);
3764 
3765                 if (ndmp_send_request(session->ns_connection,
3766                     NDMP_NOTIFY_MOVER_PAUSED, NDMP_NO_ERR,
3767                     (void *)&pause_request, 0) < 0) {
3768                         syslog(LOG_DEBUG,
3769                             "Sending notify_mover_paused request");
3770                         ndmpd_mover_error(session,
3771                             NDMP_MOVER_HALT_INTERNAL_ERROR);
3772                 }
3773                 return;
3774         }
3775 
3776         /*
3777          * Read more data into the tape buffer if the buffer is empty.
3778          */
3779         if (session->ns_mover.md_w_index == 0) {
3780                 n = mover_tape_read_v3(session, session->ns_mover.md_buf);
3781 
3782                 syslog(LOG_DEBUG,
3783                     "read %u bytes from tape", n);
3784 
3785                 if (n <= 0) {
3786                         ndmpd_mover_error(session, (n == 0 ?
3787                             NDMP_MOVER_HALT_ABORTED
3788                             : NDMP_MOVER_HALT_MEDIA_ERROR));
3789                         return;
3790                 }
3791 
3792                 /*
3793                  * Discard data if the current data stream position is
3794                  * prior to the seek position. This is necessary if a seek
3795                  * request set the seek pointer to a position that is not a
3796                  * record boundary. The seek request handler can only position
3797                  * to the start of a record.
3798                  */
3799                 if (session->ns_mover.md_position <
3800                     session->ns_mover.md_seek_position) {
3801                         session->ns_mover.md_r_index =
3802                             session->ns_mover.md_seek_position -


3810         }
3811 
3812         /*
3813          * The limit on the total amount of data to be sent can be
3814          * dictated by either the end of the mover window or the end of the
3815          * seek window.
3816          * First determine which window applies and then determine if the
3817          * send length needs to be less than a full record to avoid
3818          * exceeding the window.
3819          */
3820         if (session->ns_mover.md_position +
3821             session->ns_mover.md_bytes_left_to_read >
3822             session->ns_mover.md_window_offset +
3823             session->ns_mover.md_window_length)
3824                 wlen = session->ns_mover.md_window_offset +
3825                     session->ns_mover.md_window_length -
3826                     session->ns_mover.md_position;
3827         else
3828                 wlen = session->ns_mover.md_bytes_left_to_read;
3829 


3830         /*
3831          * Now limit the length to the amount of data in the buffer.
3832          */
3833         if (wlen > session->ns_mover.md_w_index - session->ns_mover.md_r_index)
3834                 wlen = session->ns_mover.md_w_index -
3835                     session->ns_mover.md_r_index;
3836 
3837         len = wlen & 0xffffffff;


3838 
3839         /*
3840          * Write the data to the data connection.
3841          */
3842         n = write(session->ns_mover.md_sock,
3843             &session->ns_mover.md_buf[session->ns_mover.md_r_index], len);
3844 
3845         if (n < 0) {
3846                 /* Socket is non-blocking, perhaps the write queue is full */
3847                 if (errno == EAGAIN) {
3848                         syslog(LOG_ERR, "Cannot write to socket");
3849                         return;
3850                 }
3851                 syslog(LOG_ERR, "Failed to write to socket: %m");
3852                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
3853                 return;
3854         }
3855 
3856         syslog(LOG_DEBUG,
3857             "wrote %u of %u bytes to data connection position %lu r_index %lu",
3858             n, len, session->ns_mover.md_position,
3859             session->ns_mover.md_r_index);
3860 
3861         session->ns_mover.md_r_index += n;
3862         session->ns_mover.md_position += n;
3863         session->ns_mover.md_bytes_left_to_read -= n;
3864 
3865         /*
3866          * If all data in the buffer has been written,
3867          * zero the buffer indices. The next call to this function
3868          * will read more data from the tape device into the buffer.
3869          */
3870         if (session->ns_mover.md_r_index == session->ns_mover.md_w_index) {
3871                 session->ns_mover.md_r_index = 0;
3872                 session->ns_mover.md_w_index = 0;
3873         }
3874 
3875         /*
3876          * If the read limit has been reached,
3877          * then remove the file handler to prevent this


3893  * Parameters:
3894  *   cookie  (input) - session pointer.
3895  *   fd      (input) - file descriptor.
3896  *   mode    (input) - select mode.
3897  *
3898  * Returns:
3899  *   void.
3900  */
3901 /*ARGSUSED*/
3902 static void
3903 accept_connection_v3(void *cookie, int fd, ulong_t mode)
3904 {
3905         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
3906         int from_len;
3907         struct sockaddr_in from;
3908 
3909         from_len = sizeof (from);
3910         session->ns_mover.md_sock = accept(fd, (struct sockaddr *)&from,
3911             &from_len);
3912 
3913         syslog(LOG_DEBUG, "sin: port %d addr %s", ntohs(from.sin_port),
3914             inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
3915 
3916         (void) ndmpd_remove_file_handler(session, fd);
3917         (void) close(session->ns_mover.md_listen_sock);
3918         session->ns_mover.md_listen_sock = -1;
3919 
3920         if (session->ns_mover.md_sock < 0) {
3921                 syslog(LOG_DEBUG, "Accept error: %m");
3922                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_ERROR);
3923                 return;
3924         }
3925 
3926         /*
3927          * Save the peer address.
3928          */
3929         session->ns_mover.md_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
3930         session->ns_mover.md_data_addr.tcp_port_v3 = ntohs(from.sin_port);
3931 
3932         /* Set the parameter of the new socket */
3933         set_socket_options(session->ns_mover.md_sock);
3934 
3935         /*
3936          * Backup/restore is handled by a callback called from main event loop,
3937          * which reads/writes data to md_sock socket. IO on socket must be
3938          * non-blocking, otherwise ndmpd would be unable to process other
3939          * incoming requests.
3940          */
3941         if (!set_socket_nonblock(session->ns_mover.md_sock)) {
3942                 syslog(LOG_ERR, "Could not set non-blocking mode "
3943                     "on socket: %m");
3944                 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
3945                 return;
3946         }
3947 
3948         syslog(LOG_DEBUG, "sock fd: %d", session->ns_mover.md_sock);
3949 
3950         if (session->ns_mover.md_mode == NDMP_MOVER_MODE_READ) {
3951                 if (ndmpd_add_file_handler(session, (void*)session,
3952                     session->ns_mover.md_sock, NDMPD_SELECT_MODE_READ,
3953                     HC_MOVER, mover_data_read_v3) < 0) {
3954                         ndmpd_mover_error(session,
3955                             NDMP_MOVER_HALT_INTERNAL_ERROR);
3956                         return;
3957                 }
3958                 syslog(LOG_DEBUG, "Backup connection established by %s:%d",
3959                     inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
3960                     ntohs(from.sin_port));
3961         } else {
3962                 syslog(LOG_DEBUG, "Restore connection established by %s:%d",
3963                     inet_ntoa(IN_ADDR(from.sin_addr.s_addr)),
3964                     ntohs(from.sin_port));
3965         }
3966 
3967         session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
3968 }
3969 
3970 
3971 /*
3972  * create_listen_socket_v3
3973  *
3974  * Creates a socket for listening for accepting data connections.
3975  *
3976  * Parameters:
3977  *   session (input)  - session pointer.
3978  *   addr    (output) - location to store address of socket.
3979  *   port    (output) - location to store port of socket.
3980  *
3981  * Returns:
3982  *   0 - success.


3984  */
3985 static int
3986 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
3987 {
3988         session->ns_mover.md_listen_sock = ndmp_create_socket(addr, port);
3989         if (session->ns_mover.md_listen_sock < 0)
3990                 return (-1);
3991 
3992         /*
3993          * Add a file handler for the listen socket.
3994          * ndmpd_select will call accept_connection when a
3995          * connection is ready to be accepted.
3996          */
3997         if (ndmpd_add_file_handler(session, (void *) session,
3998             session->ns_mover.md_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
3999             accept_connection_v3) < 0) {
4000                 (void) close(session->ns_mover.md_listen_sock);
4001                 session->ns_mover.md_listen_sock = -1;
4002                 return (-1);
4003         }
4004         syslog(LOG_DEBUG, "IP %s port %d",
4005             inet_ntoa(*(struct in_addr *)addr), ntohs(*port));
4006         return (0);
4007 }
4008 
4009 
4010 /*
4011  * mover_connect_sock
4012  *
4013  * Connect the mover to the specified address
4014  *
4015  * Parameters:
4016  *   session (input)  - session pointer.
4017  *   mode    (input)  - mover mode.
4018  *   addr    (output) - location to store address of socket.
4019  *   port    (output) - location to store port of socket.
4020  *
4021  * Returns:
4022  *   error code.
4023  */
4024 static ndmp_error
4025 mover_connect_sock(ndmpd_session_t *session, ndmp_mover_mode mode,
4026     ulong_t addr, ushort_t port)
4027 {
4028         int sock;
4029 
4030         sock = ndmp_connect_sock_v3(addr, port);
4031         if (sock < 0)
4032                 return (NDMP_CONNECT_ERR);
4033 
4034         /*
4035          * Backup/restore is handled by a callback called from main event loop,
4036          * which reads/writes data to md_sock socket. IO on socket must be
4037          * non-blocking, otherwise ndmpd would be unable to process other
4038          * incoming requests.
4039          */
4040         if (!set_socket_nonblock(sock)) {
4041                 syslog(LOG_ERR, "Could not set non-blocking mode "
4042                     "on socket: %m");
4043                 (void) close(sock);
4044                 return (NDMP_CONNECT_ERR);
4045         }
4046 
4047         if (mode == NDMP_MOVER_MODE_READ) {
4048                 if (ndmpd_add_file_handler(session, (void*)session, sock,
4049                     NDMPD_SELECT_MODE_READ, HC_MOVER, mover_data_read_v3) < 0) {
4050                         (void) close(sock);
4051                         return (NDMP_CONNECT_ERR);
4052                 }
4053         }
4054         session->ns_mover.md_sock = sock;
4055         session->ns_mover.md_data_addr.addr_type = NDMP_ADDR_TCP;
4056         session->ns_mover.md_data_addr.tcp_ip_v3 = ntohl(addr);
4057         session->ns_mover.md_data_addr.tcp_port_v3 = port;
4058         return (NDMP_NO_ERR);
4059 }
4060 
4061 


4069  *   session (input) - session pointer.
4070  *   data    (input) - location to store data.
4071  *   length  (input) - data length.
4072  *
4073  * Returns:
4074  *   1 - no read error but no writer running
4075  *   0 - data successfully read.
4076  *  -1 - error.
4077  */
4078 int
4079 ndmpd_local_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
4080 {
4081         ulong_t count;
4082         ulong_t len;
4083         ssize_t n;
4084 
4085         count = 0;
4086         if (session->ns_mover.md_state == NDMP_MOVER_STATE_IDLE ||
4087             session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
4088             session->ns_mover.md_state == NDMP_MOVER_STATE_HALTED) {

4089                 return (-1);
4090         }
4091 
4092         /*
4093          * Automatically increase the seek window if necessary.
4094          * This is needed in the event the module attempts to read
4095          * past a seek window set via a prior call to ndmpd_seek() or
4096          * the module has not issued a seek. If no seek was issued then
4097          * pretend that a seek was issued to read the entire tape.
4098          */
4099         if (length > session->ns_mover.md_bytes_left_to_read) {
4100                 /* ndmpd_seek() never called? */
4101                 if (session->ns_data.dd_read_length == 0) {
4102                         session->ns_mover.md_bytes_left_to_read = ~0LL;
4103                         session->ns_data.dd_read_offset = 0LL;
4104                         session->ns_data.dd_read_length = ~0LL;
4105                 } else {
4106                         session->ns_mover.md_bytes_left_to_read = length;
4107                         session->ns_data.dd_read_offset =
4108                             session->ns_mover.md_position;


4191                         session->ns_mover.md_record_num++;
4192                         continue;
4193                 }
4194 
4195                 /* Read the next record into the buffer. */
4196                 n = mover_tape_read_v3(session, session->ns_mover.md_buf);
4197                 if (n <= 0) {
4198                         if (n == TAPE_NO_WRITER_ERR)
4199                                 return (1);
4200 
4201                         ndmpd_mover_error(session,
4202                             (n == 0 ? NDMP_MOVER_HALT_ABORTED :
4203                             NDMP_MOVER_HALT_MEDIA_ERROR));
4204                         return ((n == 0) ? 1 : -1);
4205                 }
4206 
4207                 session->ns_mover.md_w_index = n;
4208                 session->ns_mover.md_r_index = 0;
4209                 session->ns_mover.md_record_num++;
4210 


4211                 /*
4212                  * Discard data if the current data stream position is
4213                  * prior to the seek position. This is necessary if a seek
4214                  * request set the seek pointer to a position that is not a
4215                  * record boundary. The seek request handler can only position
4216                  * to the start of a record.
4217                  */
4218                 if (session->ns_mover.md_position <
4219                     session->ns_mover.md_seek_position) {
4220                         session->ns_mover.md_r_index =
4221                             session->ns_mover.md_seek_position -
4222                             session->ns_mover.md_position;
4223                         session->ns_mover.md_position =
4224                             session->ns_mover.md_seek_position;
4225                 }
4226         }
4227 
4228         return (0);
4229 }