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