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