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