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