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