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 41 #include <sys/types.h> 42 #include <sys/socket.h> 43 #include <assert.h> 44 #include <ctype.h> 45 #include <errno.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <unistd.h> 49 #include <strings.h> 50 #include <time.h> 51 #include "ndmpd.h" 52 #include <bitmap.h> 53 #include <sys/queue.h> 54 #include <sys/socket.h> 55 #include <netinet/in.h> 56 #include <netinet/tcp.h> 57 #include <arpa/inet.h> 58 #include <sys/socketvar.h> 59 #include <net/if.h> 60 #include <netdb.h> 61 #include <sys/filio.h> 62 #include <sys/mtio.h> 63 #include <sys/scsi/impl/uscsi.h> 64 #include <sys/scsi/scsi.h> 65 #include "tlm.h" 66 67 /* 68 * Mutex to protect Nlp 69 */ 70 mutex_t nlp_mtx; 71 72 /* 73 * Patchable socket buffer sizes in kilobytes. 74 * ssb: send buffer size. 75 * rsb: receive buffer size. 76 */ 77 int ndmp_sbs = 60; 78 int ndmp_rbs = 60; 79 80 81 /* 82 * Force to backup all the intermediate directories leading to an object 83 * to be backed up in 'dump' format backup. 84 */ 85 boolean_t ndmp_dump_path_node = FALSE; 86 87 88 /* 89 * Force to backup all the intermediate directories leading to an object 90 * to be backed up in 'tar' format backup. 91 */ 92 boolean_t ndmp_tar_path_node = FALSE; 93 94 95 /* 96 * Should the 'st_ctime' be ignored during incremental level backup? 97 */ 98 boolean_t ndmp_ignore_ctime = FALSE; 99 100 /* 101 * Should the 'st_lmtime' be included during incremental level backup? 102 */ 103 boolean_t ndmp_include_lmtime = FALSE; 104 105 /* 106 * Force to send the file history node entries along with the file history 107 * dir entries for all directories containing the changed files to the client 108 * for incremental backup. 109 * 110 * Note: This variable is added to support Bakbone Software's Netvault DMA 111 * which expects to get the FH ADD NODES for all upper directories which 112 * contain the changed files in incremental backup along with the FH ADD DIRS. 113 */ 114 boolean_t ndmp_fhinode = FALSE; 115 116 /* 117 * Maximum permitted sequence number in the token-based backup. The 118 * value of this variable can be changed by the administrator and is 119 * saved in the NDMP configuration file. 120 */ 121 static int ndmp_max_tok_seq = NDMP_MAX_TOKSEQ; 122 123 /* 124 * Force backup directories in incremental backups. If the 125 * directory is not modified itself, it's not backed up by 126 * default. 127 */ 128 int ndmp_force_bk_dirs = 0; 129 130 /* 131 * Keeps track of the open SCSI (including tape and robot) devices. 132 * When a SCSI device is opened its name must be added to this list and 133 * when it's closed its name must be removed from this list. The main 134 * purpose of this list is the robot device. If the robot devices are not 135 * attached in SASD layer, Local Backup won't see them. If they are 136 * attached and we open the robot devices, then wrong commands are sent 137 * to robot by SASD since it assumes that the robot is a tape (sequential 138 * access) device. 139 */ 140 struct open_list { 141 LIST_ENTRY(open_list) ol_q; 142 int ol_nref; 143 char *ol_devnm; 144 int ol_sid; 145 int ol_lun; 146 int ol_fd; 147 ndmp_connection_t *cl_conn; 148 }; 149 LIST_HEAD(ol_head, open_list); 150 151 152 /* 153 * Head of the opened SCSI devices list. 154 */ 155 static struct ol_head ol_head; 156 157 mutex_t ol_mutex = DEFAULTMUTEX; 158 159 160 /* 161 * List of things to be exluded from backup. 162 */ 163 static char *exls[] = { 164 EXCL_PROC, 165 EXCL_TMP, 166 NULL, /* reserved for a copy of the "backup.directory" */ 167 NULL 168 }; 169 170 171 /* 172 * The counter for creating unique names with "ndmp.%d" format. 173 */ 174 #define NDMP_RCF_BASENAME "ndmp." 175 static int ndmp_job_cnt = 0; 176 177 static int scsi_test_unit_ready(int dev_id); 178 179 /* 180 * ndmpd_add_file_handler 181 * 182 * Adds a file handler to the file handler list. 183 * The file handler list is used by ndmpd_api_dispatch. 184 * 185 * Parameters: 186 * session (input) - session pointer. 187 * cookie (input) - opaque data to be passed to file hander when called. 188 * fd (input) - file descriptor. 189 * mode (input) - bitmask of the following: 190 * 1 = watch file for ready for reading 191 * 2 = watch file for ready for writing 192 * 4 = watch file for exception 193 * class (input) - handler class. (HC_CLIENT, HC_MOVER, HC_MODULE) 194 * func (input) - function to call when the file meets one of the 195 * conditions specified by mode. 196 * 197 * Returns: 198 * 0 - success. 199 * -1 - error. 200 */ 201 int 202 ndmpd_add_file_handler(ndmpd_session_t *session, void *cookie, int fd, 203 ulong_t mode, ulong_t class, ndmpd_file_handler_func_t *func) 204 { 205 ndmpd_file_handler_t *new; 206 207 new = ndmp_malloc(sizeof (ndmpd_file_handler_t)); 208 if (new == 0) 209 return (-1); 210 211 new->fh_cookie = cookie; 212 new->fh_fd = fd; 213 new->fh_mode = mode; 214 new->fh_class = class; 215 new->fh_func = func; 216 new->fh_next = session->ns_file_handler_list; 217 session->ns_file_handler_list = new; 218 return (0); 219 } 220 221 222 /* 223 * ndmpd_remove_file_handler 224 * 225 * Removes a file handler from the file handler list. 226 * 227 * Parameters: 228 * session (input) - session pointer. 229 * fd (input) - file descriptor. 230 * 231 * Returns: 232 * 0 - success. 233 * -1 - error. 234 */ 235 int 236 ndmpd_remove_file_handler(ndmpd_session_t *session, int fd) 237 { 238 ndmpd_file_handler_t **last; 239 ndmpd_file_handler_t *handler; 240 241 last = &session->ns_file_handler_list; 242 while (*last != 0) { 243 handler = *last; 244 245 if (handler->fh_fd == fd) { 246 *last = handler->fh_next; 247 (void) free(handler); 248 return (1); 249 } 250 last = &handler->fh_next; 251 } 252 253 return (0); 254 } 255 256 257 /* 258 * ndmp_connection_closed 259 * 260 * If the connection closed or not. 261 * 262 * Parameters: 263 * fd (input) : file descriptor 264 * 265 * Returns: 266 * 0 - connection is still valid 267 * 1 - connection is not valid anymore 268 * -1 - Internal kernel error 269 */ 270 int 271 ndmp_connection_closed(int fd) 272 { 273 fd_set fds; 274 int closed, ret; 275 struct timeval timeout; 276 277 if (fd < 0) /* We are not using the mover */ 278 return (-1); 279 280 timeout.tv_sec = 0; 281 timeout.tv_usec = 1000; 282 283 FD_ZERO(&fds); 284 FD_SET(fd, &fds); 285 ret = select(FD_SETSIZE, &fds, NULL, NULL, &timeout); 286 287 closed = (ret == -1 && errno == EBADF); 288 289 return (closed); 290 } 291 292 /* 293 * ndmp_check_mover_state 294 * 295 * Checks the mover connection status and sends an appropriate 296 * NDMP message to client based on that. 297 * 298 * Parameters: 299 * ndmpd_session_t *session (input) : session pointer 300 * 301 * Returns: 302 * void. 303 */ 304 void 305 ndmp_check_mover_state(ndmpd_session_t *session) 306 { 307 int moverfd; 308 /* 309 * NDMPV3 Spec (Three-way restore): 310 * Once all of the files have been recovered, NDMP DATA Server closes 311 * the connection to the mover on the NDMP TAPE Server. THEN 312 * The NDMP client should receive an NDMP_NOTIFY_MOVER_HALTED message 313 * with an NDMP_MOVER_CONNECT_CLOSED reason from the NDMP TAPE Server 314 */ 315 moverfd = session->ns_mover.md_sock; 316 /* If connection is closed by the peer */ 317 if (moverfd >= 0 && 318 session->ns_mover.md_mode == NDMP_MOVER_MODE_WRITE) { 319 int closed, reason; 320 321 closed = ndmp_connection_closed(moverfd); 322 if (closed) { 323 /* Connection closed or internal error */ 324 if (closed > 0) { 325 NDMP_LOG(LOG_DEBUG, 326 "ndmp mover: connection closed by peer"); 327 reason = NDMP_MOVER_HALT_CONNECT_CLOSED; 328 } else { 329 NDMP_LOG(LOG_DEBUG, 330 "ndmp mover: Internal error"); 331 reason = NDMP_MOVER_HALT_INTERNAL_ERROR; 332 } 333 ndmpd_mover_error(session, reason); 334 335 } 336 } 337 } 338 339 340 /* 341 * ndmpd_select 342 * 343 * Calls select on the the set of file descriptors from the 344 * file handler list masked by the fd_class argument. 345 * Calls the file handler function for each 346 * file descriptor that is ready for I/O. 347 * 348 * Parameters: 349 * session (input) - session pointer. 350 * block (input) - if TRUE, ndmpd_select waits until at least one 351 * file descriptor is ready for I/O. Otherwise, 352 * it returns immediately if no file descriptors are 353 * ready for I/O. 354 * class_mask (input) - bit mask of handler classes to be examined. 355 * Provides for excluding some of the handlers from 356 * being called. 357 * 358 * Returns: 359 * -1 - error. 360 * 0 - no handlers were called. 361 * 1 - at least one handler was called. 362 */ 363 int 364 ndmpd_select(ndmpd_session_t *session, boolean_t block, ulong_t class_mask) 365 { 366 fd_set rfds; 367 fd_set wfds; 368 fd_set efds; 369 int n; 370 ndmpd_file_handler_t *handler; 371 struct timeval timeout; 372 373 nlp_event_rv_set(session, 0); 374 375 if (session->ns_file_handler_list == 0) 376 return (0); 377 378 379 /* 380 * If select should be blocked, then we poll every ten seconds. 381 * The reason is in case of three-way restore we should be able 382 * to detect if the other end closed the connection or not. 383 * NDMP client(DMA) does not send any information about the connection 384 * that was closed in the other end. 385 */ 386 387 if (block == TRUE) 388 timeout.tv_sec = 10; 389 else 390 timeout.tv_sec = 0; 391 timeout.tv_usec = 0; 392 393 do { 394 /* Create the fd_sets for select. */ 395 FD_ZERO(&rfds); 396 FD_ZERO(&wfds); 397 FD_ZERO(&efds); 398 399 for (handler = session->ns_file_handler_list; handler != 0; 400 handler = handler->fh_next) { 401 if ((handler->fh_class & class_mask) == 0) 402 continue; 403 404 if (handler->fh_mode & NDMPD_SELECT_MODE_READ) 405 FD_SET(handler->fh_fd, &rfds); 406 if (handler->fh_mode & NDMPD_SELECT_MODE_WRITE) 407 FD_SET(handler->fh_fd, &wfds); 408 if (handler->fh_mode & NDMPD_SELECT_MODE_EXCEPTION) 409 FD_SET(handler->fh_fd, &efds); 410 } 411 ndmp_check_mover_state(session); 412 n = select(FD_SETSIZE, &rfds, &wfds, &efds, &timeout); 413 } while (n == 0 && block == TRUE); 414 415 if (n < 0) { 416 int connection_fd = ndmp_get_fd(session->ns_connection); 417 418 if (errno == EINTR) 419 return (0); 420 421 NDMP_LOG(LOG_DEBUG, "Select error: %m"); 422 423 for (handler = session->ns_file_handler_list; handler != 0; 424 handler = handler->fh_next) { 425 if ((handler->fh_class & class_mask) == 0) 426 continue; 427 428 if (handler->fh_mode & NDMPD_SELECT_MODE_READ) { 429 if (FD_ISSET(handler->fh_fd, &rfds) && 430 connection_fd == handler->fh_fd) 431 session->ns_eof = TRUE; 432 } 433 if (handler->fh_mode & NDMPD_SELECT_MODE_WRITE) { 434 if (FD_ISSET(handler->fh_fd, &wfds) && 435 connection_fd == handler->fh_fd) 436 session->ns_eof = TRUE; 437 } 438 if (handler->fh_mode & NDMPD_SELECT_MODE_EXCEPTION) { 439 if (FD_ISSET(handler->fh_fd, &efds) && 440 connection_fd == handler->fh_fd) 441 session->ns_eof = TRUE; 442 } 443 } 444 445 nlp_event_rv_set(session, -1); 446 return (-1); 447 } 448 if (n == 0) 449 return (0); 450 451 handler = session->ns_file_handler_list; 452 while (handler != 0) { 453 ulong_t mode = 0; 454 455 if ((handler->fh_class & class_mask) == 0) { 456 handler = handler->fh_next; 457 continue; 458 } 459 if (handler->fh_mode & NDMPD_SELECT_MODE_READ) { 460 if (FD_ISSET(handler->fh_fd, &rfds)) { 461 mode |= NDMPD_SELECT_MODE_READ; 462 FD_CLR(handler->fh_fd, &rfds); 463 } 464 } 465 if (handler->fh_mode & NDMPD_SELECT_MODE_WRITE) { 466 if (FD_ISSET(handler->fh_fd, &wfds)) { 467 mode |= NDMPD_SELECT_MODE_WRITE; 468 FD_CLR(handler->fh_fd, &wfds); 469 } 470 } 471 if (handler->fh_mode & NDMPD_SELECT_MODE_EXCEPTION) { 472 if (FD_ISSET(handler->fh_fd, &efds)) { 473 mode |= NDMPD_SELECT_MODE_EXCEPTION; 474 FD_CLR(handler->fh_fd, &efds); 475 } 476 } 477 if (mode) { 478 (*handler->fh_func) (handler->fh_cookie, 479 handler->fh_fd, mode); 480 481 /* 482 * K.L. The list can be modified during the execution 483 * of handler->fh_func. Therefore, handler will start 484 * from the beginning of the handler list after 485 * each execution. 486 */ 487 handler = session->ns_file_handler_list; 488 489 /* 490 * Release the thread which is waiting for a request 491 * to be proccessed. 492 */ 493 nlp_event_nw(session); 494 } else 495 handler = handler->fh_next; 496 497 } 498 499 nlp_event_rv_set(session, 1); 500 return (1); 501 } 502 503 504 /* 505 * ndmpd_save_env 506 * 507 * Saves a copy of the environment variable list from the data_start_backup 508 * request or data_start_recover request. 509 * 510 * Parameters: 511 * session (input) - session pointer. 512 * env (input) - environment variable list to be saved. 513 * envlen (input) - length of variable array. 514 * 515 * Returns: 516 * error code. 517 */ 518 ndmp_error 519 ndmpd_save_env(ndmpd_session_t *session, ndmp_pval *env, ulong_t envlen) 520 { 521 ulong_t i; 522 char *namebuf; 523 char *valbuf; 524 525 session->ns_data.dd_env_len = 0; 526 527 if (envlen == 0) 528 return (NDMP_NO_ERR); 529 530 session->ns_data.dd_env = ndmp_malloc(sizeof (ndmp_pval) * envlen); 531 if (session->ns_data.dd_env == 0) 532 return (NDMP_NO_MEM_ERR); 533 534 for (i = 0; i < envlen; i++) { 535 namebuf = strdup(env[i].name); 536 if (namebuf == 0) 537 return (NDMP_NO_MEM_ERR); 538 539 valbuf = strdup(env[i].value); 540 if (valbuf == 0) { 541 free(namebuf); 542 return (NDMP_NO_MEM_ERR); 543 } 544 545 NDMP_LOG(LOG_DEBUG, "env(%s): \"%s\"", 546 namebuf, valbuf); 547 548 (void) mutex_lock(&session->ns_lock); 549 session->ns_data.dd_env[i].name = namebuf; 550 session->ns_data.dd_env[i].value = valbuf; 551 session->ns_data.dd_env_len++; 552 (void) mutex_unlock(&session->ns_lock); 553 } 554 555 return (NDMP_NO_ERR); 556 } 557 558 559 /* 560 * ndmpd_free_env 561 * 562 * Free the previously saved environment variable array. 563 * 564 * Parameters: 565 * session - NDMP session pointer. 566 * 567 * Returns: 568 * void. 569 */ 570 void 571 ndmpd_free_env(ndmpd_session_t *session) 572 { 573 ulong_t i; 574 int count = session->ns_data.dd_env_len; 575 576 (void) mutex_lock(&session->ns_lock); 577 session->ns_data.dd_env_len = 0; 578 for (i = 0; i < count; i++) { 579 free(session->ns_data.dd_env[i].name); 580 free(session->ns_data.dd_env[i].value); 581 } 582 583 free((char *)session->ns_data.dd_env); 584 session->ns_data.dd_env = 0; 585 (void) mutex_unlock(&session->ns_lock); 586 } 587 588 589 /* 590 * ndmpd_save_nlist_v2 591 * 592 * Save a copy of list of file names to be restored. 593 * 594 * Parameters: 595 * nlist (input) - name list from data_start_recover request. 596 * nlistlen (input) - length of name list. 597 * 598 * Returns: 599 * array of file name pointers. 600 * 601 * Notes: 602 * free_nlist should be called to free the returned list. 603 * A null pointer indicates the end of the list. 604 */ 605 ndmp_error 606 ndmpd_save_nlist_v2(ndmpd_session_t *session, ndmp_name *nlist, 607 ulong_t nlistlen) 608 { 609 ulong_t i; 610 char *namebuf; 611 char *destbuf; 612 613 if (nlistlen == 0) 614 return (NDMP_NO_ERR); 615 616 session->ns_data.dd_nlist_len = 0; 617 session->ns_data.dd_nlist = ndmp_malloc(sizeof (ndmp_name)*nlistlen); 618 if (session->ns_data.dd_nlist == 0) 619 return (NDMP_NO_MEM_ERR); 620 621 for (i = 0; i < nlistlen; i++) { 622 namebuf = ndmp_malloc(strlen(nlist[i].name) + 1); 623 if (namebuf == 0) 624 return (NDMP_NO_MEM_ERR); 625 626 destbuf = ndmp_malloc(strlen(nlist[i].dest) + 1); 627 if (destbuf == 0) { 628 free(namebuf); 629 return (NDMP_NO_MEM_ERR); 630 } 631 (void) strlcpy(namebuf, nlist[i].name, 632 strlen(nlist[i].name) + 1); 633 (void) strlcpy(destbuf, nlist[i].dest, 634 strlen(nlist[i].dest) + 1); 635 636 session->ns_data.dd_nlist[i].name = namebuf; 637 session->ns_data.dd_nlist[i].dest = destbuf; 638 session->ns_data.dd_nlist[i].ssid = nlist[i].ssid; 639 session->ns_data.dd_nlist[i].fh_info = nlist[i].fh_info; 640 session->ns_data.dd_nlist_len++; 641 } 642 643 return (NDMP_NO_ERR); 644 } 645 646 647 /* 648 * ndmpd_free_nlist_v2 649 * 650 * Free a list created by ndmpd_save_nlist_v2. 651 * 652 * Parameters: 653 * session (input) - session pointer. 654 * 655 * Returns: 656 * void 657 */ 658 void 659 ndmpd_free_nlist_v2(ndmpd_session_t *session) 660 { 661 ulong_t i; 662 663 for (i = 0; i < session->ns_data.dd_nlist_len; i++) { 664 free(session->ns_data.dd_nlist[i].name); 665 free(session->ns_data.dd_nlist[i].dest); 666 } 667 668 if (session->ns_data.dd_nlist != NULL) 669 free((char *)session->ns_data.dd_nlist); 670 session->ns_data.dd_nlist = 0; 671 session->ns_data.dd_nlist_len = 0; 672 } 673 674 675 /* 676 * ndmpd_free_nlist_v3 677 * 678 * Free a list created by ndmpd_save_nlist_v3. 679 * 680 * Parameters: 681 * session (input) - session pointer. 682 * 683 * Returns: 684 * void 685 */ 686 void 687 ndmpd_free_nlist_v3(ndmpd_session_t *session) 688 { 689 ulong_t i; 690 mem_ndmp_name_v3_t *tp; /* destination entry */ 691 692 tp = session->ns_data.dd_nlist_v3; 693 for (i = 0; i < session->ns_data.dd_nlist_len; tp++, i++) { 694 NDMP_FREE(tp->nm3_opath); 695 NDMP_FREE(tp->nm3_dpath); 696 NDMP_FREE(tp->nm3_newnm); 697 } 698 699 NDMP_FREE(session->ns_data.dd_nlist_v3); 700 session->ns_data.dd_nlist_len = 0; 701 } 702 703 704 /* 705 * ndmpd_save_nlist_v3 706 * 707 * Save a copy of list of file names to be restored. 708 * 709 * Parameters: 710 * nlist (input) - name list from data_start_recover request. 711 * nlistlen (input) - length of name list. 712 * 713 * Returns: 714 * array of file name pointers. 715 * 716 * Notes: 717 * free_nlist should be called to free the returned list. 718 * A null pointer indicates the end of the list. 719 */ 720 ndmp_error 721 ndmpd_save_nlist_v3(ndmpd_session_t *session, ndmp_name_v3 *nlist, 722 ulong_t nlistlen) 723 { 724 ulong_t i; 725 ndmp_error rv; 726 ndmp_name_v3 *sp; /* source entry */ 727 mem_ndmp_name_v3_t *tp; /* destination entry */ 728 729 if (nlistlen == 0) 730 return (NDMP_ILLEGAL_ARGS_ERR); 731 732 session->ns_data.dd_nlist_len = 0; 733 tp = session->ns_data.dd_nlist_v3 = 734 ndmp_malloc(sizeof (mem_ndmp_name_v3_t) * nlistlen); 735 if (session->ns_data.dd_nlist_v3 == 0) 736 return (NDMP_NO_MEM_ERR); 737 738 rv = NDMP_NO_ERR; 739 sp = nlist; 740 for (i = 0; i < nlistlen; tp++, sp++, i++) { 741 tp->nm3_opath = strdup(sp->original_path); 742 if (!tp->nm3_opath) { 743 rv = NDMP_NO_MEM_ERR; 744 break; 745 } 746 if (!*sp->destination_dir) { 747 tp->nm3_dpath = NULL; 748 /* In V4 destination dir cannot be NULL */ 749 if (session->ns_protocol_version == NDMPV4) { 750 rv = NDMP_ILLEGAL_ARGS_ERR; 751 break; 752 } 753 } else if (!(tp->nm3_dpath = strdup(sp->destination_dir))) { 754 rv = NDMP_NO_MEM_ERR; 755 break; 756 } 757 if (!*sp->new_name) 758 tp->nm3_newnm = NULL; 759 else if (!(tp->nm3_newnm = strdup(sp->new_name))) { 760 rv = NDMP_NO_MEM_ERR; 761 break; 762 } 763 764 tp->nm3_node = quad_to_long_long(sp->node); 765 tp->nm3_fh_info = quad_to_long_long(sp->fh_info); 766 tp->nm3_err = NDMP_NO_ERR; 767 session->ns_data.dd_nlist_len++; 768 769 NDMP_LOG(LOG_DEBUG, "orig \"%s\"", tp->nm3_opath); 770 NDMP_LOG(LOG_DEBUG, "dest \"%s\"", NDMP_SVAL(tp->nm3_dpath)); 771 NDMP_LOG(LOG_DEBUG, "name \"%s\"", NDMP_SVAL(tp->nm3_newnm)); 772 NDMP_LOG(LOG_DEBUG, "node %lld", tp->nm3_node); 773 NDMP_LOG(LOG_DEBUG, "fh_info %lld", tp->nm3_fh_info); 774 } 775 776 if (rv != NDMP_NO_ERR) 777 ndmpd_free_nlist_v3(session); 778 779 return (rv); 780 } 781 782 783 /* 784 * ndmpd_free_nlist 785 * 786 * Free the recovery list based on the version 787 * 788 * Parameters: 789 * session (input) - session pointer. 790 * 791 * Returns: 792 * void 793 */ 794 void 795 ndmpd_free_nlist(ndmpd_session_t *session) 796 { 797 switch (session->ns_protocol_version) { 798 case 1: 799 case 2: 800 ndmpd_free_nlist_v2(session); 801 break; 802 case 3: 803 case 4: 804 ndmpd_free_nlist_v3(session); 805 break; 806 807 default: 808 NDMP_LOG(LOG_DEBUG, "Unknown version %d", 809 session->ns_protocol_version); 810 } 811 } 812 813 814 /* 815 * fh_cmpv3 816 * 817 * Comparison function used in sorting the Nlist based on their 818 * file history info (offset of the entry on the tape) 819 * 820 * Parameters: 821 * p (input) - pointer to P 822 * q (input) - pointer to Q 823 * 824 * Returns: 825 * -1: P < Q 826 * 0: P = Q 827 * 1: P > Q 828 */ 829 static int 830 fh_cmpv3(const void *p, 831 const void *q) 832 { 833 #define FH_INFOV3(p) (((mem_ndmp_name_v3_t *)p)->nm3_fh_info) 834 835 if (FH_INFOV3(p) < FH_INFOV3(q)) 836 return (-1); 837 else if (FH_INFOV3(p) == FH_INFOV3(q)) 838 return (0); 839 else 840 return (1); 841 842 #undef FH_INFOV3 843 } 844 845 846 /* 847 * ndmp_sort_nlist_v3 848 * 849 * Sort the recovery list based on their offset on the tape 850 * 851 * Parameters: 852 * session (input) - session pointer. 853 * 854 * Returns: 855 * void 856 */ 857 void 858 ndmp_sort_nlist_v3(ndmpd_session_t *session) 859 { 860 if (!session || session->ns_data.dd_nlist_len == 0 || 861 !session->ns_data.dd_nlist_v3) 862 return; 863 864 (void) qsort(session->ns_data.dd_nlist_v3, 865 session->ns_data.dd_nlist_len, 866 sizeof (mem_ndmp_name_v3_t), fh_cmpv3); 867 } 868 869 870 /* 871 * ndmp_send_reply 872 * 873 * Send the reply, check for error and print the msg if any error 874 * occured when sending the reply. 875 * 876 * Parameters: 877 * connection (input) - connection pointer. 878 * 879 * Return: 880 * void 881 */ 882 void 883 ndmp_send_reply(ndmp_connection_t *connection, void *reply, char *msg) 884 { 885 if (ndmp_send_response(connection, NDMP_NO_ERR, reply) < 0) 886 NDMP_LOG(LOG_DEBUG, "%s", msg); 887 } 888 889 890 /* 891 * ndmp_mtioctl 892 * 893 * Performs numerous filemark operations. 894 * 895 * Parameters: 896 * fd - file descriptor of the device 897 * cmd - filemark or record command 898 * count - the number of operations to be performed 899 */ 900 int 901 ndmp_mtioctl(int fd, int cmd, int count) 902 { 903 struct mtop mp; 904 905 mp.mt_op = cmd; 906 mp.mt_count = count; 907 if (ioctl(fd, MTIOCTOP, &mp) < 0) { 908 NDMP_LOG(LOG_ERR, "Failed to send command to tape: %m."); 909 return (-1); 910 } 911 912 return (0); 913 } 914 915 916 /* 917 * quad_to_long_long 918 * 919 * Convert type quad to longlong_t 920 */ 921 u_longlong_t 922 quad_to_long_long(ndmp_u_quad q) 923 { 924 u_longlong_t ull; 925 926 ull = ((u_longlong_t)q.high << 32) + q.low; 927 return (ull); 928 } 929 930 931 /* 932 * long_long_to_quad 933 * 934 * Convert long long to quad type 935 */ 936 ndmp_u_quad 937 long_long_to_quad(u_longlong_t ull) 938 { 939 ndmp_u_quad q; 940 941 q.high = (ulong_t)(ull >> 32); 942 q.low = (ulong_t)ull; 943 return (q); 944 } 945 946 947 /* 948 * ndmp_set_socket_nodelay 949 * 950 * Set the TCP socket option to nodelay mode 951 */ 952 void 953 ndmp_set_socket_nodelay(int sock) 954 { 955 int flag = 1; 956 957 (void) setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof (flag)); 958 } 959 960 961 /* 962 * ndmp_set_socket_snd_buf 963 * 964 * Set the socket send buffer size 965 */ 966 void 967 ndmp_set_socket_snd_buf(int sock, int size) 968 { 969 if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0) 970 NDMP_LOG(LOG_DEBUG, "SO_SNDBUF failed errno=%d", errno); 971 } 972 973 974 /* 975 * ndmp_set_socket_rcv_buf 976 * 977 * Set the socket receive buffer size 978 */ 979 void 980 ndmp_set_socket_rcv_buf(int sock, int size) 981 { 982 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0) 983 NDMP_LOG(LOG_DEBUG, "SO_RCVBUF failed errno=%d", errno); 984 } 985 986 /* 987 * ndmp_get_max_tok_seq 988 * 989 * Get the maximum permitted token sequence for token-based 990 * backups. 991 * 992 * Parameters: 993 * void 994 * 995 * Returns: 996 * ndmp_max_tok_seq 997 */ 998 int 999 ndmp_get_max_tok_seq(void) 1000 { 1001 return (ndmp_max_tok_seq); 1002 } 1003 1004 /* 1005 * ndmp_buffer_get_size 1006 * 1007 * Return the NDMP transfer buffer size 1008 * 1009 * Parameters: 1010 * session (input) - session pointer. 1011 * 1012 * Returns: 1013 * buffer size 1014 */ 1015 long 1016 ndmp_buffer_get_size(ndmpd_session_t *session) 1017 { 1018 long xfer_size; 1019 1020 if (session == NULL) 1021 return (0); 1022 1023 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) { 1024 xfer_size = atoi(ndmpd_get_prop_default(NDMP_MOVER_RECSIZE, 1025 "60")); 1026 if (xfer_size > 0) 1027 xfer_size *= KILOBYTE; 1028 else 1029 xfer_size = REMOTE_RECORD_SIZE; 1030 NDMP_LOG(LOG_DEBUG, "Remote operation: %d", xfer_size); 1031 } else { 1032 NDMP_LOG(LOG_DEBUG, 1033 "Local operation: %lu", session->ns_mover.md_record_size); 1034 if ((xfer_size = session->ns_mover.md_record_size) == 0) 1035 xfer_size = MAX_RECORD_SIZE; 1036 } 1037 1038 NDMP_LOG(LOG_DEBUG, "xfer_size: %d", xfer_size); 1039 return (xfer_size); 1040 } 1041 1042 1043 /* 1044 * ndmp_lbr_init 1045 * 1046 * Initialize the LBR/NDMP backup parameters 1047 * 1048 * Parameters: 1049 * session (input) - session pointer. 1050 * 1051 * Returns: 1052 * 0: on success 1053 * -1: otherwise 1054 */ 1055 int 1056 ndmp_lbr_init(ndmpd_session_t *session) 1057 { 1058 if (session->ns_ndmp_lbr_params != NULL) { 1059 NDMP_LOG(LOG_DEBUG, "ndmp_lbr_params already allocated."); 1060 return (0); 1061 } 1062 1063 session->ns_ndmp_lbr_params = ndmp_malloc(sizeof (ndmp_lbr_params_t)); 1064 if (session->ns_ndmp_lbr_params == NULL) 1065 return (-1); 1066 1067 session->ns_ndmp_lbr_params->nlp_bkmap = -1; 1068 session->ns_ndmp_lbr_params->nlp_session = session; 1069 (void) cond_init(&session->ns_ndmp_lbr_params->nlp_cv, 0, NULL); 1070 (void) mutex_init(&session->ns_lock, 0, NULL); 1071 session->ns_nref = 0; 1072 return (0); 1073 } 1074 1075 1076 /* 1077 * ndmp_lbr_cleanup 1078 * 1079 * Deallocate and cleanup all NDMP/LBR parameters 1080 * 1081 * Parameters: 1082 * session (input) - session pointer. 1083 * 1084 * Returns: 1085 * 0: on success 1086 * -1: otherwise 1087 */ 1088 void 1089 ndmp_lbr_cleanup(ndmpd_session_t *session) 1090 { 1091 /* 1092 * If in 3-way restore, the connection close is detected after 1093 * check in tape_read(), the reader thread of mover may wait forever 1094 * for the tape to be changed. Force the reader thread to exit. 1095 */ 1096 nlp_event_rv_set(session, -2); 1097 nlp_event_nw(session); 1098 1099 ndmpd_abort_marking_v2(session); 1100 ndmp_stop_buffer_worker(session); 1101 ndmp_waitfor_op(session); 1102 ndmp_free_reader_writer_ipc(session); 1103 if (session->ns_ndmp_lbr_params) { 1104 if (session->ns_ndmp_lbr_params->nlp_bkmap != -1) 1105 (void) dbm_free(session->ns_ndmp_lbr_params->nlp_bkmap); 1106 tlm_release_list(session->ns_ndmp_lbr_params->nlp_exl); 1107 tlm_release_list(session->ns_ndmp_lbr_params->nlp_inc); 1108 (void) cond_destroy(&session->ns_ndmp_lbr_params->nlp_cv); 1109 } 1110 1111 NDMP_FREE(session->ns_ndmp_lbr_params); 1112 } 1113 1114 1115 /* 1116 * nlp_ref_nw 1117 * 1118 * Increase the references to the NDMP/LBR parameter to prevent 1119 * unwanted release 1120 * 1121 * Parameters: 1122 * session (input) - session pointer. 1123 * 1124 * Returns: 1125 * void 1126 */ 1127 void 1128 nlp_ref_nw(ndmpd_session_t *session) 1129 { 1130 ndmp_lbr_params_t *nlp; 1131 1132 (void) mutex_lock(&nlp_mtx); 1133 if ((nlp = ndmp_get_nlp(session)) != NULL) { 1134 nlp->nlp_nw++; 1135 NDMP_LOG(LOG_DEBUG, "nw: %d", nlp->nlp_nw); 1136 } else 1137 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1138 (void) mutex_unlock(&nlp_mtx); 1139 } 1140 1141 1142 /* 1143 * nlp_unref_nw 1144 * 1145 * Decrease the references to the NDMP/LBR parameter before 1146 * release 1147 * 1148 * Parameters: 1149 * session (input) - session pointer. 1150 * 1151 * Returns: 1152 * void 1153 */ 1154 void 1155 nlp_unref_nw(ndmpd_session_t *session) 1156 { 1157 ndmp_lbr_params_t *nlp; 1158 1159 (void) mutex_lock(&nlp_mtx); 1160 if ((nlp = ndmp_get_nlp(session)) != NULL) { 1161 NDMP_LOG(LOG_DEBUG, "nw: %d", nlp->nlp_nw); 1162 if (nlp->nlp_nw > 0) 1163 nlp->nlp_nw--; 1164 } else 1165 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1166 (void) mutex_unlock(&nlp_mtx); 1167 } 1168 1169 1170 /* 1171 * nlp_wait_nw 1172 * 1173 * Wait for a NDMP/LBR parameter to get available 1174 * 1175 * Parameters: 1176 * session (input) - session pointer. 1177 * 1178 * Returns: 1179 * void 1180 */ 1181 void 1182 nlp_wait_nw(ndmpd_session_t *session) 1183 { 1184 ndmp_lbr_params_t *nlp; 1185 1186 (void) mutex_lock(&nlp_mtx); 1187 if ((nlp = ndmp_get_nlp(session)) != NULL) { 1188 NDMP_LOG(LOG_DEBUG, "nw: %d", nlp->nlp_nw); 1189 if (nlp->nlp_nw > 0) { 1190 NDMP_LOG(LOG_DEBUG, "Waiting"); 1191 while ((nlp->nlp_flag & NLP_READY) == 0) 1192 (void) cond_wait(&nlp->nlp_cv, &nlp_mtx); 1193 } 1194 } else 1195 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1196 (void) mutex_unlock(&nlp_mtx); 1197 } 1198 1199 1200 /* 1201 * nlp_event_nw 1202 * 1203 * Signal that a NDMP/LBR parameter is available to wake up the 1204 * threads waiting on that 1205 * 1206 * Parameters: 1207 * session (input) - session pointer. 1208 * 1209 * Returns: 1210 * void 1211 */ 1212 void 1213 nlp_event_nw(ndmpd_session_t *session) 1214 { 1215 ndmp_lbr_params_t *nlp; 1216 1217 (void) mutex_lock(&nlp_mtx); 1218 if ((nlp = ndmp_get_nlp(session)) != NULL) { 1219 if (nlp->nlp_nw > 0) { 1220 NDMP_LOG(LOG_DEBUG, "nw: %d", nlp->nlp_nw); 1221 nlp->nlp_flag |= NLP_READY; 1222 (void) cond_signal(&nlp->nlp_cv); 1223 } 1224 } else 1225 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1226 (void) mutex_unlock(&nlp_mtx); 1227 } 1228 1229 1230 /* 1231 * nlp_event_rv_get 1232 * 1233 * Get the return value for each NLP 1234 * 1235 * Parameters: 1236 * session (input) - session pointer. 1237 * 1238 * Returns: 1239 * return value 1240 */ 1241 int 1242 nlp_event_rv_get(ndmpd_session_t *session) 1243 { 1244 ndmp_lbr_params_t *nlp; 1245 1246 if ((nlp = ndmp_get_nlp(session)) == NULL) { 1247 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1248 return (0); 1249 } 1250 1251 return (nlp->nlp_rv); 1252 } 1253 1254 1255 /* 1256 * nlp_event_rv_set 1257 * 1258 * Set the return value for an NLP 1259 * 1260 * Parameters: 1261 * session (input) - session pointer. 1262 * rv (input) - return value 1263 * 1264 * Returns: 1265 * void 1266 */ 1267 void 1268 nlp_event_rv_set(ndmpd_session_t *session, 1269 int rv) 1270 { 1271 ndmp_lbr_params_t *nlp; 1272 1273 (void) mutex_lock(&nlp_mtx); 1274 if (rv != 0) 1275 NDMP_LOG(LOG_DEBUG, "rv: %d", rv); 1276 1277 if ((nlp = ndmp_get_nlp(session)) != NULL) 1278 nlp->nlp_rv = rv; 1279 else 1280 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1281 (void) mutex_unlock(&nlp_mtx); 1282 } 1283 1284 /* 1285 * is_buffer_erroneous 1286 * 1287 * Run a sanity check on the buffer 1288 * 1289 * returns: 1290 * TRUE: if the buffer seems to have error 1291 * FALSE: if the buffer is full and has valid data. 1292 */ 1293 boolean_t 1294 is_buffer_erroneous(tlm_buffer_t *buf) 1295 { 1296 boolean_t rv; 1297 1298 rv = (buf == NULL || buf->tb_eot || buf->tb_eof || 1299 buf->tb_errno != 0); 1300 if (rv) { 1301 if (buf == NULL) { 1302 NDMP_LOG(LOG_DEBUG, "buf == NULL"); 1303 } else { 1304 NDMP_LOG(LOG_DEBUG, "eot: %u, eof: %u, errno: %d", 1305 buf->tb_eot, buf->tb_eof, buf->tb_errno); 1306 } 1307 } 1308 1309 return (rv); 1310 } 1311 1312 /* 1313 * ndmp_execute_cdb 1314 * 1315 * Main SCSI CDB execution program, this is used by message handler 1316 * for the NDMP tape/SCSI execute CDB requests. This function uses 1317 * USCSI interface to run the CDB command and sets all the CDB parameters 1318 * in the SCSI query before calling the USCSI ioctl. The result of the 1319 * CDB is returned in two places: 1320 * cmd.uscsi_status The status of CDB execution 1321 * cmd.uscsi_rqstatus The status of sense requests 1322 * reply.error The general errno (ioctl) 1323 * 1324 * Parameters: 1325 * session (input) - session pointer 1326 * adapter_name (input) - name of SCSI adapter 1327 * sid (input) - SCSI target ID 1328 * lun (input) - LUN number 1329 * request (input) - NDMP client CDB request 1330 * 1331 * Returns: 1332 * void 1333 */ 1334 /*ARGSUSED*/ 1335 void 1336 ndmp_execute_cdb(ndmpd_session_t *session, char *adapter_name, int sid, int lun, 1337 ndmp_execute_cdb_request *request) 1338 { 1339 ndmp_execute_cdb_reply reply; 1340 struct uscsi_cmd cmd; 1341 int fd; 1342 struct open_list *olp; 1343 char rq_buf[255]; 1344 1345 (void) memset((void *)&cmd, 0, sizeof (cmd)); 1346 (void) memset((void *)&reply, 0, sizeof (reply)); 1347 (void) memset((void *)rq_buf, 0, sizeof (rq_buf)); 1348 1349 if (request->flags == NDMP_SCSI_DATA_IN) { 1350 cmd.uscsi_flags = USCSI_READ | USCSI_RQENABLE; 1351 if ((cmd.uscsi_bufaddr = 1352 ndmp_malloc(request->datain_len)) == 0) { 1353 reply.error = NDMP_NO_MEM_ERR; 1354 if (ndmp_send_response(session->ns_connection, 1355 NDMP_NO_ERR, (void *)&reply) < 0) 1356 NDMP_LOG(LOG_DEBUG, "error sending" 1357 " scsi_execute_cdb reply."); 1358 return; 1359 } 1360 1361 cmd.uscsi_buflen = request->datain_len; 1362 } else if (request->flags == NDMP_SCSI_DATA_OUT) { 1363 cmd.uscsi_flags = USCSI_WRITE | USCSI_RQENABLE; 1364 cmd.uscsi_bufaddr = request->dataout.dataout_val; 1365 cmd.uscsi_buflen = request->dataout.dataout_len; 1366 } else { 1367 cmd.uscsi_flags = USCSI_RQENABLE; 1368 cmd.uscsi_bufaddr = 0; 1369 cmd.uscsi_buflen = 0; 1370 } 1371 cmd.uscsi_rqlen = sizeof (rq_buf); 1372 cmd.uscsi_rqbuf = rq_buf; 1373 1374 cmd.uscsi_timeout = (request->timeout < 1000) ? 1375 1 : (request->timeout / 1000); 1376 1377 cmd.uscsi_cdb = (caddr_t)request->cdb.cdb_val; 1378 cmd.uscsi_cdblen = request->cdb.cdb_len; 1379 1380 NDMP_LOG(LOG_DEBUG, "cmd: 0x%x, len: %d, flags: %d, datain_len: %d", 1381 request->cdb.cdb_val[0] & 0xff, request->cdb.cdb_len, 1382 request->flags, request->datain_len); 1383 NDMP_LOG(LOG_DEBUG, "dataout_len: %d, timeout: %d", 1384 request->dataout.dataout_len, request->timeout); 1385 1386 if (request->cdb.cdb_len > 12) { 1387 reply.error = NDMP_ILLEGAL_ARGS_ERR; 1388 ndmp_send_reply(session->ns_connection, (void *) &reply, 1389 "sending execute_cdb reply"); 1390 if (request->flags == NDMP_SCSI_DATA_IN) 1391 free(cmd.uscsi_bufaddr); 1392 return; 1393 } 1394 1395 reply.error = NDMP_NO_ERR; 1396 1397 if ((olp = ndmp_open_list_find(adapter_name, sid, lun)) != NULL) { 1398 fd = olp->ol_fd; 1399 } else { 1400 reply.error = NDMP_DEV_NOT_OPEN_ERR; 1401 ndmp_send_reply(session->ns_connection, (void *) &reply, 1402 "sending execute_cdb reply"); 1403 if (request->flags == NDMP_SCSI_DATA_IN) 1404 free(cmd.uscsi_bufaddr); 1405 return; 1406 } 1407 1408 if (ioctl(fd, USCSICMD, &cmd) < 0) { 1409 if (errno != EIO && errno != 0) 1410 NDMP_LOG(LOG_ERR, 1411 "Failed to send command to device: %m"); 1412 NDMP_LOG(LOG_DEBUG, "ioctl(USCSICMD) error: %m"); 1413 if (cmd.uscsi_status == 0) 1414 reply.error = NDMP_IO_ERR; 1415 } 1416 1417 reply.status = cmd.uscsi_status; 1418 1419 if (request->flags == NDMP_SCSI_DATA_IN) { 1420 reply.datain.datain_len = cmd.uscsi_buflen; 1421 reply.datain.datain_val = cmd.uscsi_bufaddr; 1422 } else { 1423 reply.dataout_len = request->dataout.dataout_len; 1424 } 1425 1426 reply.ext_sense.ext_sense_len = cmd.uscsi_rqlen - cmd.uscsi_rqresid; 1427 reply.ext_sense.ext_sense_val = rq_buf; 1428 1429 if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR, 1430 (void *)&reply) < 0) 1431 NDMP_LOG(LOG_DEBUG, "Error sending scsi_execute_cdb reply."); 1432 1433 if (request->flags == NDMP_SCSI_DATA_IN) 1434 free(cmd.uscsi_bufaddr); 1435 } 1436 1437 1438 /* 1439 * ndmp_stop_local_reader 1440 * 1441 * Stops a mover reader thread (for local backup only) 1442 * 1443 * Parameters: 1444 * session (input) - session pointer 1445 * cmds (input) - reader/writer command struct 1446 * 1447 * Returns: 1448 * void 1449 */ 1450 void 1451 ndmp_stop_local_reader(ndmpd_session_t *session, tlm_commands_t *cmds) 1452 { 1453 if (session != NULL) { 1454 if (session->ns_data.dd_sock == -1) { 1455 /* 1456 * 2-way restore. 1457 */ 1458 NDMP_LOG(LOG_DEBUG, "2-way restore"); 1459 if (cmds != NULL && cmds->tcs_reader_count > 0) { 1460 nlp_event_rv_set(session, -2); 1461 nlp_event_nw(session); 1462 } 1463 } 1464 } 1465 } 1466 1467 1468 /* 1469 * Stops a mover reader thread (for remote backup only) 1470 * 1471 * Parameters: 1472 * session (input) - session pointer 1473 * cmds (input) - reader/writer command struct 1474 * 1475 * Returns: 1476 * void 1477 */ 1478 void 1479 ndmp_stop_remote_reader(ndmpd_session_t *session) 1480 { 1481 if (session != NULL) { 1482 if (session->ns_data.dd_sock >= 0) { 1483 /* 1484 * 3-way restore. 1485 */ 1486 NDMP_LOG(LOG_DEBUG, 1487 "data.sock: %d", session->ns_data.dd_sock); 1488 (void) close(session->ns_data.dd_sock); 1489 session->ns_data.dd_sock = -1; 1490 } 1491 } 1492 } 1493 1494 1495 /* 1496 * ndmp_wait_for_reader 1497 * 1498 * Wait for a reader until get done (busy wait) 1499 */ 1500 void 1501 ndmp_wait_for_reader(tlm_commands_t *cmds) 1502 { 1503 if (cmds == NULL) { 1504 NDMP_LOG(LOG_DEBUG, "cmds == NULL"); 1505 } else { 1506 NDMP_LOG(LOG_DEBUG, 1507 "reader_count: %d", cmds->tcs_reader_count); 1508 1509 while (cmds->tcs_reader_count > 0) 1510 (void) sleep(1); 1511 } 1512 } 1513 1514 1515 /* 1516 * ndmp_open_list_find 1517 * 1518 * Find a specific device in the open list 1519 * 1520 * Parameters: 1521 * dev (input) - device name 1522 * sid (input) - SCSI target ID 1523 * lun (input) - LUN number 1524 * 1525 * Returns: 1526 * pointer to the open list entry 1527 */ 1528 struct open_list * 1529 ndmp_open_list_find(char *dev, int sid, int lun) 1530 { 1531 struct ol_head *olhp; 1532 struct open_list *olp; 1533 1534 if (dev == NULL || *dev == '\0') { 1535 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 1536 return (NULL); 1537 } 1538 1539 (void) mutex_lock(&ol_mutex); 1540 olhp = &ol_head; 1541 for (olp = LIST_FIRST(olhp); olp != NULL; olp = LIST_NEXT(olp, ol_q)) 1542 if (strcmp(olp->ol_devnm, dev) == 0 && olp->ol_sid == sid && 1543 olp->ol_lun == lun) { 1544 (void) mutex_unlock(&ol_mutex); 1545 return (olp); 1546 } 1547 1548 (void) mutex_unlock(&ol_mutex); 1549 return (NULL); 1550 } 1551 1552 1553 /* 1554 * ndmp_open_list_add 1555 * 1556 * Add a specific device to the open list 1557 * 1558 * Parameters: 1559 * conn (input) - connection pointer 1560 * dev (input) - device name 1561 * sid (input) - SCSI target ID 1562 * lun (input) - LUN number 1563 * fd (input) - the device file descriptor 1564 * 1565 * Returns: 1566 * errno 1567 */ 1568 int 1569 ndmp_open_list_add(ndmp_connection_t *conn, char *dev, int sid, int lun, int fd) 1570 { 1571 int err; 1572 struct ol_head *olhp; 1573 struct open_list *olp; 1574 1575 if (dev == NULL || *dev == '\0') { 1576 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 1577 return (EINVAL); 1578 } 1579 NDMP_LOG(LOG_DEBUG, 1580 "conn: 0x%08x, dev: %s, sid: %d, lun: %d", conn, dev, sid, lun); 1581 1582 err = 0; 1583 olhp = &ol_head; 1584 1585 if ((olp = ndmp_open_list_find(dev, sid, lun)) != NULL) { 1586 NDMP_LOG(LOG_DEBUG, "already in list"); 1587 /* 1588 * The adapter handle can be opened many times by the clients. 1589 * Only when the target is set, we must check and reject the 1590 * open request if the device is already being used by another 1591 * session. 1592 */ 1593 if (sid == -1) 1594 olp->ol_nref++; 1595 else 1596 err = EBUSY; 1597 } else if ((olp = ndmp_malloc(sizeof (struct open_list))) == NULL) { 1598 err = ENOMEM; 1599 } else if ((olp->ol_devnm = strdup(dev)) == NULL) { 1600 NDMP_LOG(LOG_ERR, "Out of memory."); 1601 free(olp); 1602 err = ENOMEM; 1603 } else { 1604 olp->cl_conn = conn; 1605 olp->ol_nref = 1; 1606 olp->ol_sid = sid; 1607 olp->ol_lun = lun; 1608 if (fd > 0) 1609 olp->ol_fd = fd; 1610 else 1611 olp->ol_fd = -1; 1612 (void) mutex_lock(&ol_mutex); 1613 LIST_INSERT_HEAD(olhp, olp, ol_q); 1614 (void) mutex_unlock(&ol_mutex); 1615 } 1616 1617 return (err); 1618 } 1619 1620 1621 /* 1622 * ndmp_open_list_del 1623 * 1624 * Delete a specific device from the open list 1625 * 1626 * Parameters: 1627 * dev (input) - device name 1628 * sid (input) - SCSI target ID 1629 * lun (input) - LUN number 1630 * 1631 * Returns: 1632 * errno 1633 */ 1634 int 1635 ndmp_open_list_del(char *dev, int sid, int lun) 1636 { 1637 struct open_list *olp; 1638 1639 if (dev == NULL || *dev == '\0') { 1640 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 1641 return (EINVAL); 1642 } 1643 if ((olp = ndmp_open_list_find(dev, sid, lun)) == NULL) { 1644 NDMP_LOG(LOG_DEBUG, "%s not found", dev); 1645 return (ENOENT); 1646 } 1647 1648 (void) mutex_lock(&ol_mutex); 1649 if (--olp->ol_nref <= 0) { 1650 NDMP_LOG(LOG_DEBUG, 1651 "Removed dev: %s, sid: %d, lun: %d", dev, sid, lun); 1652 LIST_REMOVE(olp, ol_q); 1653 free(olp->ol_devnm); 1654 free(olp); 1655 } 1656 (void) mutex_unlock(&ol_mutex); 1657 1658 return (0); 1659 } 1660 1661 1662 /* 1663 * ndmp_open_list_release 1664 * 1665 * Close all the resources belonging to this connection. 1666 * 1667 * Parameters: 1668 * ndmp_connection_t *conn : connection identifier 1669 * 1670 * Returns: 1671 * void 1672 */ 1673 void 1674 ndmp_open_list_release(ndmp_connection_t *conn) 1675 { 1676 struct ol_head *olhp = &ol_head; 1677 struct open_list *olp; 1678 struct open_list *next; 1679 1680 (void) mutex_lock(&ol_mutex); 1681 olp = LIST_FIRST(olhp); 1682 while (olp != NULL) { 1683 next = LIST_NEXT(olp, ol_q); 1684 NDMP_LOG(LOG_DEBUG, "olp->conn 0x%08x", olp->cl_conn); 1685 if (olp->cl_conn == conn) { 1686 NDMP_LOG(LOG_DEBUG, 1687 "Removed dev: %s, sid: %d, lun: %d", 1688 olp->ol_devnm, olp->ol_sid, olp->ol_lun); 1689 LIST_REMOVE(olp, ol_q); 1690 if (olp->ol_fd > 0) 1691 (void) close(olp->ol_fd); 1692 free(olp->ol_devnm); 1693 free(olp); 1694 } 1695 olp = next; 1696 } 1697 (void) mutex_unlock(&ol_mutex); 1698 } 1699 1700 1701 /* 1702 * ndmp_stop_buffer_worker 1703 * 1704 * Stop all reader and writer threads for a specific buffer. 1705 * 1706 * Parameters: 1707 * session (input) - session pointer 1708 * 1709 * Returns: 1710 * void 1711 */ 1712 void 1713 ndmp_stop_buffer_worker(ndmpd_session_t *session) 1714 { 1715 ndmp_lbr_params_t *nlp; 1716 tlm_commands_t *cmds; 1717 1718 session->ns_tape.td_pos = 0; 1719 if ((nlp = ndmp_get_nlp(session)) == NULL) { 1720 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1721 } else { 1722 cmds = &nlp->nlp_cmds; 1723 if (cmds->tcs_command == NULL) { 1724 NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL"); 1725 } else { 1726 cmds->tcs_reader = cmds->tcs_writer = TLM_ABORT; 1727 cmds->tcs_command->tc_reader = TLM_ABORT; 1728 cmds->tcs_command->tc_writer = TLM_ABORT; 1729 while (cmds->tcs_reader_count > 0 || 1730 cmds->tcs_writer_count > 0) { 1731 NDMP_LOG(LOG_DEBUG, 1732 "trying to stop buffer worker"); 1733 (void) sleep(1); 1734 } 1735 } 1736 } 1737 } 1738 1739 1740 /* 1741 * ndmp_stop_reader_thread 1742 * 1743 * Stop only the reader threads of a specific buffer 1744 * 1745 * Parameters: 1746 * session (input) - session pointer 1747 * 1748 * Returns: 1749 * void 1750 */ 1751 void 1752 ndmp_stop_reader_thread(ndmpd_session_t *session) 1753 { 1754 ndmp_lbr_params_t *nlp; 1755 tlm_commands_t *cmds; 1756 1757 if ((nlp = ndmp_get_nlp(session)) == NULL) { 1758 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1759 } else { 1760 cmds = &nlp->nlp_cmds; 1761 if (cmds->tcs_command == NULL) { 1762 NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL"); 1763 } else { 1764 cmds->tcs_reader = TLM_ABORT; 1765 cmds->tcs_command->tc_reader = TLM_ABORT; 1766 while (cmds->tcs_reader_count > 0) { 1767 NDMP_LOG(LOG_DEBUG, 1768 "trying to stop reader thread"); 1769 (void) sleep(1); 1770 } 1771 } 1772 } 1773 } 1774 1775 1776 /* 1777 * ndmp_stop_reader_thread 1778 * 1779 * Stop only the writer threads of a specific buffer 1780 * 1781 * Parameters: 1782 * session (input) - session pointer 1783 * 1784 * Returns: 1785 * void 1786 */ 1787 void 1788 ndmp_stop_writer_thread(ndmpd_session_t *session) 1789 { 1790 ndmp_lbr_params_t *nlp; 1791 tlm_commands_t *cmds; 1792 1793 if ((nlp = ndmp_get_nlp(session)) == NULL) { 1794 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1795 } else { 1796 cmds = &nlp->nlp_cmds; 1797 if (cmds->tcs_command == NULL) { 1798 NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL"); 1799 } else { 1800 cmds->tcs_writer = TLM_ABORT; 1801 cmds->tcs_command->tc_writer = TLM_ABORT; 1802 while (cmds->tcs_writer_count > 0) { 1803 NDMP_LOG(LOG_DEBUG, 1804 "trying to stop writer thread"); 1805 (void) sleep(1); 1806 } 1807 } 1808 } 1809 } 1810 1811 1812 /* 1813 * ndmp_free_reader_writer_ipc 1814 * 1815 * Free and release the reader/writer buffers and the IPC structure 1816 * for reader and writer threads. 1817 * 1818 * Parameters: 1819 * session (input) - session pointer 1820 * 1821 * Returns: 1822 * void 1823 */ 1824 void 1825 ndmp_free_reader_writer_ipc(ndmpd_session_t *session) 1826 { 1827 ndmp_lbr_params_t *nlp; 1828 tlm_commands_t *cmds; 1829 1830 if ((nlp = ndmp_get_nlp(session)) != NULL) { 1831 cmds = &nlp->nlp_cmds; 1832 if (cmds->tcs_command != NULL) { 1833 NDMP_LOG(LOG_DEBUG, "cmds->tcs_command->tc_ref: %d", 1834 cmds->tcs_command->tc_ref); 1835 tlm_release_reader_writer_ipc(cmds->tcs_command); 1836 } 1837 } 1838 } 1839 1840 1841 /* 1842 * ndmp_waitfor_op 1843 * 1844 * Wait for a session reference count to drop to zero 1845 * 1846 * Parameters: 1847 * session (input) - session pointer 1848 * 1849 * Returns: 1850 * void 1851 */ 1852 void 1853 ndmp_waitfor_op(ndmpd_session_t *session) 1854 { 1855 if (session != NULL) { 1856 while (session->ns_nref > 0) { 1857 (void) sleep(1); 1858 NDMP_LOG(LOG_DEBUG, 1859 "waiting for session nref: %d", session->ns_nref); 1860 } 1861 } 1862 } 1863 1864 1865 /* 1866 * ndmp_session_ref 1867 * 1868 * Increment the reference count of the session 1869 * 1870 * Parameters: 1871 * session (input) - session pointer 1872 * 1873 * Returns: 1874 * void 1875 */ 1876 void 1877 ndmp_session_ref(ndmpd_session_t *session) 1878 { 1879 (void) mutex_lock(&session->ns_lock); 1880 session->ns_nref++; 1881 (void) mutex_unlock(&session->ns_lock); 1882 } 1883 1884 1885 /* 1886 * ndmp_session_unref 1887 * 1888 * Decrement the reference count of the session 1889 * 1890 * Parameters: 1891 * session (input) - session pointer 1892 * 1893 * Returns: 1894 * void 1895 */ 1896 void 1897 ndmp_session_unref(ndmpd_session_t *session) 1898 { 1899 (void) mutex_lock(&session->ns_lock); 1900 session->ns_nref--; 1901 (void) mutex_unlock(&session->ns_lock); 1902 } 1903 1904 1905 /* 1906 * ndmp_addr2str_v3 1907 * 1908 * Convert the address type to a string 1909 * 1910 * Parameters: 1911 * type (input) - address type 1912 * 1913 * Returns: 1914 * type in string 1915 */ 1916 char * 1917 ndmp_addr2str_v3(ndmp_addr_type type) 1918 { 1919 char *rv; 1920 1921 switch (type) { 1922 case NDMP_ADDR_LOCAL: 1923 rv = "Local"; 1924 break; 1925 case NDMP_ADDR_TCP: 1926 rv = "TCP"; 1927 break; 1928 case NDMP_ADDR_FC: 1929 rv = "FC"; 1930 break; 1931 case NDMP_ADDR_IPC: 1932 rv = "IPC"; 1933 break; 1934 default: 1935 rv = "Unknown"; 1936 } 1937 1938 return (rv); 1939 } 1940 1941 1942 /* 1943 * ndmp_valid_v3addr_type 1944 * 1945 * Make sure that the NDMP address is from any of the 1946 * valid types 1947 * 1948 * Parameters: 1949 * type (input) - address type 1950 * 1951 * Returns: 1952 * 1: valid 1953 * 0: invalid 1954 */ 1955 boolean_t 1956 ndmp_valid_v3addr_type(ndmp_addr_type type) 1957 { 1958 boolean_t rv; 1959 1960 switch (type) { 1961 case NDMP_ADDR_LOCAL: 1962 case NDMP_ADDR_TCP: 1963 case NDMP_ADDR_FC: 1964 case NDMP_ADDR_IPC: 1965 rv = TRUE; 1966 break; 1967 default: 1968 rv = FALSE; 1969 } 1970 1971 return (rv); 1972 } 1973 1974 1975 /* 1976 * ndmp_copy_addr_v3 1977 * 1978 * Copy NDMP address from source to destination (V2 and V3 only) 1979 * 1980 * Parameters: 1981 * dst (ouput) - destination address 1982 * src (input) - source address 1983 * 1984 * Returns: 1985 * void 1986 */ 1987 void 1988 ndmp_copy_addr_v3(ndmp_addr_v3 *dst, ndmp_addr_v3 *src) 1989 { 1990 dst->addr_type = src->addr_type; 1991 switch (src->addr_type) { 1992 case NDMP_ADDR_LOCAL: 1993 /* nothing */ 1994 break; 1995 case NDMP_ADDR_TCP: 1996 dst->tcp_ip_v3 = htonl(src->tcp_ip_v3); 1997 dst->tcp_port_v3 = src->tcp_port_v3; 1998 break; 1999 case NDMP_ADDR_FC: 2000 case NDMP_ADDR_IPC: 2001 default: 2002 break; 2003 } 2004 } 2005 2006 2007 /* 2008 * ndmp_copy_addr_v4 2009 * 2010 * Copy NDMP address from source to destination. V4 has a extra 2011 * environment list inside the address too which needs to be copied. 2012 * 2013 * Parameters: 2014 * dst (ouput) - destination address 2015 * src (input) - source address 2016 * 2017 * Returns: 2018 * void 2019 */ 2020 void 2021 ndmp_copy_addr_v4(ndmp_addr_v4 *dst, ndmp_addr_v4 *src) 2022 { 2023 int i; 2024 2025 dst->addr_type = src->addr_type; 2026 dst->tcp_len_v4 = src->tcp_len_v4; 2027 switch (src->addr_type) { 2028 case NDMP_ADDR_LOCAL: 2029 /* nothing */ 2030 break; 2031 case NDMP_ADDR_TCP: 2032 dst->tcp_addr_v4 = ndmp_malloc(sizeof (ndmp_tcp_addr_v4) * 2033 src->tcp_len_v4); 2034 if (dst->tcp_addr_v4 == 0) 2035 return; 2036 2037 for (i = 0; i < src->tcp_len_v4; i++) { 2038 dst->tcp_ip_v4(i) = htonl(src->tcp_ip_v4(i)); 2039 dst->tcp_port_v4(i) = src->tcp_port_v4(i); 2040 dst->tcp_env_v4(i).addr_env_len = 0; /* Solaris */ 2041 dst->tcp_env_v4(i).addr_env_val = 0; /* Solaris */ 2042 } 2043 break; 2044 case NDMP_ADDR_FC: 2045 case NDMP_ADDR_IPC: 2046 default: 2047 break; 2048 } 2049 } 2050 2051 2052 /* 2053 * ndmp_connect_sock_v3 2054 * 2055 * Creates a socket and connects to the specified address/port 2056 * 2057 * Parameters: 2058 * addr (input) - IP address 2059 * port (input) - port number 2060 * 2061 * Returns: 2062 * 0: on success 2063 * -1: otherwise 2064 */ 2065 int 2066 ndmp_connect_sock_v3(ulong_t addr, ushort_t port) 2067 { 2068 int sock; 2069 struct sockaddr_in sin; 2070 int flag = 1; 2071 2072 NDMP_LOG(LOG_DEBUG, "addr %s:%d", inet_ntoa(IN_ADDR(addr)), port); 2073 2074 sock = socket(AF_INET, SOCK_STREAM, 0); 2075 if (sock < 0) { 2076 NDMP_LOG(LOG_DEBUG, "Socket error: %m"); 2077 return (-1); 2078 } 2079 2080 (void) memset((void *) &sin, 0, sizeof (sin)); 2081 sin.sin_family = AF_INET; 2082 sin.sin_addr.s_addr = htonl(addr); 2083 sin.sin_port = htons(port); 2084 if (connect(sock, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 2085 NDMP_LOG(LOG_DEBUG, "Connect error: %m"); 2086 (void) close(sock); 2087 sock = -1; 2088 } else { 2089 if (ndmp_sbs > 0) 2090 ndmp_set_socket_snd_buf(sock, ndmp_sbs*KILOBYTE); 2091 if (ndmp_rbs > 0) 2092 ndmp_set_socket_rcv_buf(sock, ndmp_rbs*KILOBYTE); 2093 2094 ndmp_set_socket_nodelay(sock); 2095 (void) setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &flag, 2096 sizeof (flag)); 2097 2098 NDMP_LOG(LOG_DEBUG, "sock %d", sock); 2099 } 2100 2101 return (sock); 2102 } 2103 2104 /* 2105 * ndmp_create_socket 2106 * 2107 * Creates a socket for listening for accepting data connections. 2108 * 2109 * Parameters: 2110 * session (input) - session pointer. 2111 * addr (output) - location to store address of socket. 2112 * port (output) - location to store port of socket. 2113 * 2114 * Returns: 2115 * 0 - success. 2116 * -1 - error. 2117 */ 2118 int 2119 ndmp_create_socket(ulong_t *addr, ushort_t *port) 2120 { 2121 char *p; 2122 int length; 2123 int sd; 2124 struct sockaddr_in sin; 2125 2126 /* Try the user's prefered NIC IP address */ 2127 p = ndmpd_get_prop(NDMP_MOVER_NIC); 2128 2129 /* Try host's IP address */ 2130 if (!p || *p == 0) 2131 p = gethostaddr(); 2132 2133 /* Try default NIC's IP address (if DNS failed) */ 2134 if (!p) 2135 p = get_default_nic_addr(); 2136 2137 /* Fail if no IP can be obtained */ 2138 if (!p) { 2139 NDMP_LOG(LOG_ERR, "Undetermined network port."); 2140 return (-1); 2141 } 2142 2143 *addr = inet_addr(p); 2144 2145 sd = socket(AF_INET, SOCK_STREAM, 0); 2146 if (sd < 0) { 2147 NDMP_LOG(LOG_DEBUG, "Socket error: %m"); 2148 return (-1); 2149 } 2150 sin.sin_family = AF_INET; 2151 sin.sin_addr.s_addr = INADDR_ANY; 2152 sin.sin_port = 0; 2153 length = sizeof (sin); 2154 2155 if (bind(sd, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 2156 NDMP_LOG(LOG_DEBUG, "Bind error: %m"); 2157 (void) close(sd); 2158 sd = -1; 2159 } else if (getsockname(sd, (struct sockaddr *)&sin, &length) < 0) { 2160 NDMP_LOG(LOG_DEBUG, "getsockname error: %m"); 2161 (void) close(sd); 2162 sd = -1; 2163 } else if (listen(sd, 5) < 0) { 2164 NDMP_LOG(LOG_DEBUG, "Listen error: %m"); 2165 (void) close(sd); 2166 sd = -1; 2167 } else 2168 *port = sin.sin_port; 2169 2170 return (sd); 2171 } 2172 2173 2174 /* 2175 * cctime 2176 * 2177 * Convert the specified time into a string. It's like 2178 * ctime(), but: 2179 * - chops the trailing '\n' of ctime. 2180 * - and returns "the epoch" if time is 0. 2181 * 2182 * Returns: 2183 * "": invalid argument. 2184 * "the epoch": if time is 0. 2185 * string format of the time. 2186 */ 2187 char * 2188 cctime(time_t *t) 2189 { 2190 char *bp, *cp; 2191 static char tbuf[BUFSIZ]; 2192 2193 if (!t) 2194 return (""); 2195 2196 if (*t == (time_t)0) 2197 return ("the epoch"); 2198 2199 if ((bp = ctime_r(t, tbuf, BUFSIZ)) == NULL) 2200 return (""); 2201 2202 cp = strchr(bp, '\n'); 2203 if (cp) 2204 *cp = '\0'; 2205 2206 return (bp); 2207 } 2208 2209 2210 /* 2211 * ndmp_new_job_name 2212 * 2213 * Create a job name for each backup/restore to keep track 2214 * 2215 * Parameters: 2216 * jname (output) - job name 2217 * 2218 * Returns: 2219 * jname 2220 */ 2221 char * 2222 ndmp_new_job_name(char *jname) 2223 { 2224 if (jname != NULL) { 2225 (void) snprintf(jname, TLM_MAX_BACKUP_JOB_NAME, "%s%d", 2226 NDMP_RCF_BASENAME, ndmp_job_cnt++); 2227 NDMP_LOG(LOG_DEBUG, "jname: \"%s\"", jname); 2228 } 2229 2230 return (jname); 2231 } 2232 2233 2234 /* 2235 * fs_is_valid_logvol 2236 * 2237 * Check if the log path exists 2238 * 2239 * Parameters: 2240 * path (input) - log path 2241 * 2242 * Returns: 2243 * FALSE: invalid 2244 * TRUE: valid 2245 */ 2246 boolean_t 2247 fs_is_valid_logvol(char *path) 2248 { 2249 struct stat64 st; 2250 2251 if (stat64(path, &st) < 0) 2252 return (FALSE); 2253 2254 return (TRUE); 2255 } 2256 2257 2258 /* 2259 * ndmpd_mk_temp 2260 * 2261 * Make a temporary file using the working directory path and the 2262 * jobname 2263 * 2264 * Parameters: 2265 * buf (output) - the temporary file name path 2266 * 2267 * Returns: 2268 * buf 2269 */ 2270 char * 2271 ndmpd_mk_temp(char *buf) 2272 { 2273 char fname[TLM_MAX_BACKUP_JOB_NAME]; 2274 const char *dir; 2275 char *rv; 2276 2277 if (!buf) 2278 return (NULL); 2279 2280 dir = ndmpd_get_prop(NDMP_DEBUG_PATH); 2281 if (dir == 0 || *dir == '\0') { 2282 NDMP_LOG(LOG_DEBUG, "NDMP work path not specified"); 2283 return (0); 2284 } 2285 2286 if (!fs_is_valid_logvol((char *)dir)) { 2287 NDMP_LOG(LOG_ERR, 2288 "Log file path cannot be on system volumes."); 2289 return (0); 2290 } 2291 2292 dir += strspn(dir, " \t"); 2293 if (!*dir) { 2294 NDMP_LOG(LOG_DEBUG, "NDMP work path not specified"); 2295 return (0); 2296 } 2297 2298 rv = buf; 2299 (void) ndmp_new_job_name(fname); 2300 (void) tlm_cat_path(buf, (char *)dir, fname); 2301 2302 return (rv); 2303 } 2304 2305 2306 /* 2307 * ndmpd_make_bk_dir_path 2308 * 2309 * Make a directory path for temporary files under the NDMP 2310 * working directory. 2311 * 2312 * Parameters: 2313 * buf (output) - result path 2314 * fname (input) - the file name 2315 * 2316 * Returns: 2317 * buf 2318 */ 2319 char * 2320 ndmpd_make_bk_dir_path(char *buf, char *fname) 2321 { 2322 const char *p; 2323 char *name; 2324 char path[PATH_MAX]; 2325 2326 if (!buf || !fname || !*fname) 2327 return (NULL); 2328 2329 p = ndmpd_get_prop(NDMP_DEBUG_PATH); 2330 if (p == NULL || *p == '\0' || !fs_is_valid_logvol((char *)p)) { 2331 return (NULL); 2332 } 2333 2334 (void) strlcpy(path, (char *)p, PATH_MAX); 2335 (void) trim_whitespace(path); 2336 2337 if ((name = strrchr(fname, '/')) == 0) 2338 name = fname; 2339 2340 (void) tlm_cat_path(buf, path, name); 2341 return (buf); 2342 } 2343 2344 2345 /* 2346 * ndmp_is_chkpnt_root 2347 * 2348 * Is this a root checkpoint (snapshot) directory. 2349 * Note: a temporary function 2350 */ 2351 boolean_t 2352 ndmp_is_chkpnt_root(char *path) 2353 { 2354 struct stat64 st; 2355 2356 if (stat64(path, &st) != 0) { 2357 NDMP_LOG(LOG_DEBUG, "Couldn't stat path \"%s\"", path); 2358 return (TRUE); 2359 } 2360 return (FALSE); 2361 } 2362 2363 2364 /* 2365 * ndmpd_make_exc_list 2366 * 2367 * Make a list of files that should not be backed up. 2368 * 2369 * Parameters: 2370 * void 2371 * 2372 * Returns: 2373 * list - array of character strings 2374 */ 2375 char ** 2376 ndmpd_make_exc_list(void) 2377 { 2378 char *val, **cpp; 2379 int i, n; 2380 2381 n = sizeof (exls); 2382 if ((cpp = ndmp_malloc(n)) != NULL) { 2383 for (i = 0; exls[i] != NULL; i++) 2384 cpp[i] = exls[i]; 2385 2386 /* 2387 * If ndmpd_get_prop returns NULL, the array will be 2388 * null-terminated. 2389 */ 2390 val = ndmpd_get_prop(NDMP_DEBUG_PATH); 2391 cpp[i] = val; 2392 } 2393 2394 return (cpp); 2395 } 2396 2397 2398 /* 2399 * ndmp_get_bk_dir_ino 2400 * 2401 * Get the inode number of the backup directory 2402 */ 2403 int 2404 ndmp_get_bk_dir_ino(ndmp_lbr_params_t *nlp) 2405 { 2406 int rv; 2407 struct stat64 st; 2408 2409 if (stat64(nlp->nlp_backup_path, &st) != 0) { 2410 rv = -1; 2411 NDMP_LOG(LOG_DEBUG, "Getting inode # of \"%s\"", 2412 nlp->nlp_backup_path); 2413 } else { 2414 rv = 0; 2415 nlp->nlp_bkdirino = st.st_ino; 2416 NDMP_LOG(LOG_DEBUG, "nlp_bkdirino: %lu", 2417 (uint_t)nlp->nlp_bkdirino); 2418 } 2419 2420 return (rv); 2421 } 2422 2423 2424 /* 2425 * ndmp_check_utf8magic 2426 * 2427 * Check if the magic string for exists in the tar header. This 2428 * magic string (which also indicates that the file names are in 2429 * UTF8 format) is used as a crest to indetify our own tapes. 2430 * This checking is always done before all restores except DAR 2431 * restores. 2432 */ 2433 boolean_t 2434 ndmp_check_utf8magic(tlm_cmd_t *cmd) 2435 { 2436 char *cp; 2437 int err, len, actual_size; 2438 2439 if (cmd == NULL) { 2440 NDMP_LOG(LOG_DEBUG, "cmd == NULL"); 2441 return (FALSE); 2442 } 2443 if (cmd->tc_buffers == NULL) { 2444 NDMP_LOG(LOG_DEBUG, "cmd->tc_buffers == NULL"); 2445 return (FALSE); 2446 } 2447 2448 /* wait until the first buffer gets full. */ 2449 tlm_buffer_in_buf_wait(cmd->tc_buffers); 2450 2451 err = actual_size = 0; 2452 cp = tlm_get_read_buffer(RECORDSIZE, &err, cmd->tc_buffers, 2453 &actual_size); 2454 if (cp == NULL) { 2455 NDMP_LOG(LOG_DEBUG, "Can't read from buffers, err: %d", err); 2456 return (FALSE); 2457 } 2458 len = strlen(NDMPUTF8MAGIC); 2459 if (actual_size < len) { 2460 NDMP_LOG(LOG_DEBUG, "Not enough data in the buffers"); 2461 return (FALSE); 2462 } 2463 2464 return ((strncmp(cp, NDMPUTF8MAGIC, len) == 0) ? TRUE : FALSE); 2465 } 2466 2467 2468 /* 2469 * ndmp_get_cur_bk_time 2470 * 2471 * Get the backup checkpoint time. 2472 */ 2473 int 2474 ndmp_get_cur_bk_time(ndmp_lbr_params_t *nlp, time_t *tp, char *jname) 2475 { 2476 int err; 2477 2478 if (!nlp || !nlp->nlp_backup_path || !tp) { 2479 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 2480 return (-1); 2481 } 2482 2483 if (!fs_is_chkpnt_enabled(nlp->nlp_backup_path)) { 2484 NDMP_LOG(LOG_DEBUG, "Not a chkpnt volume %s", 2485 nlp->nlp_backup_path); 2486 *tp = time(NULL); 2487 return (0); 2488 } 2489 2490 err = tlm_get_chkpnt_time(nlp->nlp_backup_path, !NLP_ISCHKPNTED(nlp), 2491 tp, jname); 2492 if (err != 0) { 2493 NDMP_LOG(LOG_DEBUG, "Can't checkpoint time"); 2494 } else { 2495 NDMP_LOG(LOG_DEBUG, "%s", cctime(tp)); 2496 } 2497 2498 return (err); 2499 } 2500 2501 2502 /* 2503 * get_relative_path 2504 */ 2505 char * 2506 ndmp_get_relative_path(char *base, char *fullpath) 2507 { 2508 char *p = fullpath; 2509 2510 if (!base || !*base) 2511 return (fullpath); 2512 2513 while (*base) { 2514 if (*base != *p) 2515 break; 2516 p++; base++; 2517 } 2518 2519 if (*p == '/') 2520 p++; 2521 2522 return ((*base) ? fullpath : p); 2523 } 2524 2525 2526 /* 2527 * ndmp_get_nlp 2528 * 2529 * Get NDMP local backup parameters 2530 * 2531 * Parameter: 2532 * session cooke 2533 * 2534 * Returns: 2535 * LBR structure 2536 */ 2537 ndmp_lbr_params_t * 2538 ndmp_get_nlp(void *cookie) 2539 { 2540 if (cookie == NULL) 2541 return (NULL); 2542 2543 return (((ndmpd_session_t *)cookie)->ns_ndmp_lbr_params); 2544 } 2545 2546 2547 /* 2548 * is_tape_unit_ready 2549 * 2550 * Check if the tape device is ready or not 2551 */ 2552 boolean_t 2553 is_tape_unit_ready(char *adptnm, int dev_id) 2554 { 2555 int try; 2556 int fd = 0; 2557 2558 try = TUR_MAX_TRY; 2559 if (dev_id <= 0) { 2560 if ((fd = open(adptnm, O_RDONLY | O_NDELAY)) < 0) 2561 return (FALSE); 2562 } else { 2563 fd = dev_id; 2564 } 2565 do { 2566 if (scsi_test_unit_ready(fd) >= 0) { 2567 NDMP_LOG(LOG_DEBUG, "Unit is ready"); 2568 2569 if (dev_id <= 0) 2570 (void) close(fd); 2571 2572 return (TRUE); 2573 } 2574 2575 NDMP_LOG(LOG_DEBUG, "Unit not ready"); 2576 (void) usleep(TUR_WAIT); 2577 2578 } while (--try > 0); 2579 2580 if (dev_id <= 0) 2581 (void) close(fd); 2582 2583 NDMP_LOG(LOG_DEBUG, "Unit didn't get ready"); 2584 return (FALSE); 2585 } 2586 2587 2588 /* 2589 * scsi_test_unit_ready 2590 * 2591 * This is for Test Unit Read, without this function, the only 2592 * impact is getting EBUSY's before each operation which we have 2593 * busy waiting loops checking EBUSY error code. 2594 */ 2595 static int 2596 scsi_test_unit_ready(int dev_id) 2597 { 2598 struct uscsi_cmd ucmd; 2599 union scsi_cdb cdb; 2600 int retval; 2601 2602 (void) memset(&ucmd, 0, sizeof (struct uscsi_cmd)); 2603 (void) memset(&cdb, 0, sizeof (union scsi_cdb)); 2604 cdb.scc_cmd = SCMD_TEST_UNIT_READY; 2605 ucmd.uscsi_cdb = (caddr_t)&cdb; 2606 ucmd.uscsi_cdblen = CDB_GROUP0; 2607 ucmd.uscsi_flags |= USCSI_SILENT; 2608 ucmd.uscsi_timeout = 60; /* Allow maximum 1 min */ 2609 2610 retval = ioctl(dev_id, USCSICMD, &ucmd); 2611 2612 if (retval != 0 && errno != EIO) { 2613 NDMP_LOG(LOG_ERR, 2614 "Failed to send inquiry request to device: %m."); 2615 NDMP_LOG(LOG_DEBUG, "Inquiry request failed for" 2616 " dev_id:%d err=%d -%m", dev_id, errno); 2617 retval = -errno; 2618 } else 2619 retval = -(ucmd.uscsi_status); 2620 2621 return (retval); 2622 } 2623 2624 2625 /* 2626 * ndmp_load_params 2627 * 2628 * Load the parameters. 2629 * 2630 * Parameter: 2631 * void 2632 * 2633 * Returns: 2634 * void 2635 */ 2636 void 2637 ndmp_load_params(void) 2638 { 2639 ndmp_dump_path_node = ndmpd_get_prop_yorn(NDMP_DUMP_PATHNODE_ENV) ? 2640 TRUE : FALSE; 2641 ndmp_tar_path_node = ndmpd_get_prop_yorn(NDMP_TAR_PATHNODE_ENV) ? 2642 TRUE : FALSE; 2643 ndmp_ignore_ctime = 2644 ndmpd_get_prop_yorn(NDMP_IGNCTIME_ENV) ? TRUE : FALSE; 2645 ndmp_include_lmtime = ndmpd_get_prop_yorn(NDMP_INCLMTIME_ENV) ? 2646 TRUE : FALSE; 2647 ndmp_max_tok_seq = atoi(ndmpd_get_prop_default(NDMP_MAXSEQ_ENV, "9")); 2648 2649 ndmp_full_restore_path = ndmpd_get_prop_yorn(NDMP_FULL_RESTORE_PATH) ? 2650 TRUE : FALSE; 2651 2652 ndmp_fhinode = ndmpd_get_prop_yorn(NDMP_FHIST_INCR_ENV) ? TRUE : FALSE; 2653 2654 /* Get the value from ndmp SMF property. */ 2655 ndmp_dar_support = ndmpd_get_prop_yorn(NDMP_DAR_SUPPORT); 2656 2657 if ((ndmp_ver = atoi(ndmpd_get_prop(NDMP_VERSION_ENV))) == 0) 2658 ndmp_ver = NDMPVER; 2659 } 2660 2661 /* 2662 * randomize 2663 * 2664 * Randomize the contents of a buffer 2665 * 2666 * Parameter: 2667 * buffer (output) - destination buffer 2668 * size (input) - buffer size 2669 * 2670 * Returns: 2671 * void 2672 */ 2673 void 2674 randomize(unsigned char *buffer, int size) 2675 { 2676 /* LINTED improper alignment */ 2677 unsigned int *p = (unsigned int *)buffer; 2678 unsigned int dwlen = size / sizeof (unsigned int); 2679 unsigned int remlen = size % sizeof (unsigned int); 2680 unsigned int tmp; 2681 unsigned int i; 2682 2683 for (i = 0; i < dwlen; i++) 2684 *p++ = random(); 2685 2686 if (remlen) { 2687 tmp = random(); 2688 (void) memcpy(p, &tmp, remlen); 2689 } 2690 } 2691 2692 /* 2693 * ndmpd_get_file_entry_type 2694 * 2695 * Converts the mode to the NDMP file type 2696 * 2697 * Parameter: 2698 * mode (input) - file mode 2699 * ftype (output) - file type 2700 * 2701 * Returns: 2702 * void 2703 */ 2704 void 2705 ndmpd_get_file_entry_type(int mode, ndmp_file_type *ftype) 2706 { 2707 switch (mode & S_IFMT) { 2708 case S_IFIFO: 2709 *ftype = NDMP_FILE_FIFO; 2710 break; 2711 case S_IFCHR: 2712 *ftype = NDMP_FILE_CSPEC; 2713 break; 2714 case S_IFDIR: 2715 *ftype = NDMP_FILE_DIR; 2716 break; 2717 case S_IFBLK: 2718 *ftype = NDMP_FILE_BSPEC; 2719 break; 2720 case S_IFREG: 2721 *ftype = NDMP_FILE_REG; 2722 break; 2723 case S_IFLNK: 2724 *ftype = NDMP_FILE_SLINK; 2725 break; 2726 default: 2727 *ftype = NDMP_FILE_SOCK; 2728 break; 2729 } 2730 } 2731 2732 /* 2733 * Set a private data in the plugin context 2734 */ 2735 void 2736 ndmp_context_set_specific(ndmp_context_t *nctx, void *ptr) 2737 { 2738 nctx->nc_pldata = ptr; 2739 } 2740 2741 /* 2742 * Get a private data in the plugin context 2743 */ 2744 void * 2745 ndmp_context_get_specific(ndmp_context_t *nctx) 2746 { 2747 return (nctx->nc_pldata); 2748 } 2749 2750 ndmpd_backup_type_t 2751 ndmp_get_backup_type(ndmp_context_t *ctx) 2752 { 2753 ndmpd_session_t *session = (ndmpd_session_t *)ctx->nc_ddata; 2754 2755 return (session->ns_butype); 2756 } 2757