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