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 if (session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) { 1138 session->ns_tape.td_record_count = 0; 1139 return (0); 1140 } 1141 1142 return (-1); 1143 } 1144 1145 /* 1146 * is_buffer_erroneous 1147 * 1148 * Run a sanity check on the buffer 1149 * 1150 * returns: 1151 * TRUE: if the buffer seems to have error 1152 * FALSE: if the buffer is full and has valid data. 1153 */ 1154 boolean_t 1155 is_buffer_erroneous(tlm_buffer_t *buf) 1156 { 1157 boolean_t rv; 1158 1159 rv = (buf == NULL || buf->tb_eot || buf->tb_eof || 1160 buf->tb_errno != 0); 1161 if (rv) { 1162 if (buf == NULL) { 1163 NDMP_LOG(LOG_DEBUG, "buf == NULL"); 1164 } else { 1165 NDMP_LOG(LOG_DEBUG, "eot: %u, eof: %u, errno: %d", 1166 buf->tb_eot, buf->tb_eof, buf->tb_errno); 1167 } 1168 } 1169 1170 return (rv); 1171 } 1172 1173 /* 1174 * ndmp_execute_cdb 1175 * 1176 * Main SCSI CDB execution program, this is used by message handler 1177 * for the NDMP tape/SCSI execute CDB requests. This function uses 1178 * USCSI interface to run the CDB command and sets all the CDB parameters 1179 * in the SCSI query before calling the USCSI ioctl. The result of the 1180 * CDB is returned in two places: 1181 * cmd.uscsi_status The status of CDB execution 1182 * cmd.uscsi_rqstatus The status of sense requests 1183 * reply.error The general errno (ioctl) 1184 * 1185 * Parameters: 1186 * session (input) - session pointer 1187 * adapter_name (input) - name of SCSI adapter 1188 * sid (input) - SCSI target ID 1189 * lun (input) - LUN number 1190 * request (input) - NDMP client CDB request 1191 * 1192 * Returns: 1193 * void 1194 */ 1195 /*ARGSUSED*/ 1196 void 1197 ndmp_execute_cdb(ndmpd_session_t *session, char *adapter_name, int sid, int lun, 1198 ndmp_execute_cdb_request *request) 1199 { 1200 ndmp_execute_cdb_reply reply; 1201 struct uscsi_cmd cmd; 1202 int fd; 1203 struct open_list *olp; 1204 char rq_buf[255]; 1205 1206 (void) memset((void *)&cmd, 0, sizeof (cmd)); 1207 (void) memset((void *)&reply, 0, sizeof (reply)); 1208 (void) memset((void *)rq_buf, 0, sizeof (rq_buf)); 1209 1210 if (request->flags == NDMP_SCSI_DATA_IN) { 1211 cmd.uscsi_flags = USCSI_READ | USCSI_RQENABLE; 1212 if ((cmd.uscsi_bufaddr = 1213 ndmp_malloc(request->datain_len)) == 0) { 1214 reply.error = NDMP_NO_MEM_ERR; 1215 if (ndmp_send_response(session->ns_connection, 1216 NDMP_NO_ERR, (void *)&reply) < 0) 1217 NDMP_LOG(LOG_DEBUG, "error sending" 1218 " scsi_execute_cdb reply."); 1219 return; 1220 } 1221 1222 cmd.uscsi_buflen = request->datain_len; 1223 } else if (request->flags == NDMP_SCSI_DATA_OUT) { 1224 cmd.uscsi_flags = USCSI_WRITE | USCSI_RQENABLE; 1225 cmd.uscsi_bufaddr = request->dataout.dataout_val; 1226 cmd.uscsi_buflen = request->dataout.dataout_len; 1227 } else { 1228 cmd.uscsi_flags = USCSI_RQENABLE; 1229 cmd.uscsi_bufaddr = 0; 1230 cmd.uscsi_buflen = 0; 1231 } 1232 cmd.uscsi_rqlen = sizeof (rq_buf); 1233 cmd.uscsi_rqbuf = rq_buf; 1234 1235 cmd.uscsi_timeout = (request->timeout < 1000) ? 1236 1 : (request->timeout / 1000); 1237 1238 cmd.uscsi_cdb = (caddr_t)request->cdb.cdb_val; 1239 cmd.uscsi_cdblen = request->cdb.cdb_len; 1240 1241 NDMP_LOG(LOG_DEBUG, "cmd: 0x%x, len: %d, flags: %d, datain_len: %d", 1242 request->cdb.cdb_val[0] & 0xff, request->cdb.cdb_len, 1243 request->flags, request->datain_len); 1244 NDMP_LOG(LOG_DEBUG, "dataout_len: %d, timeout: %d", 1245 request->dataout.dataout_len, request->timeout); 1246 1247 if (request->cdb.cdb_len > 12) { 1248 reply.error = NDMP_ILLEGAL_ARGS_ERR; 1249 ndmp_send_reply(session->ns_connection, (void *) &reply, 1250 "sending execute_cdb reply"); 1251 if (request->flags == NDMP_SCSI_DATA_IN) 1252 free(cmd.uscsi_bufaddr); 1253 return; 1254 } 1255 1256 reply.error = NDMP_NO_ERR; 1257 1258 if ((olp = ndmp_open_list_find(adapter_name, sid, lun)) != NULL) { 1259 fd = olp->ol_fd; 1260 } else { 1261 reply.error = NDMP_DEV_NOT_OPEN_ERR; 1262 ndmp_send_reply(session->ns_connection, (void *) &reply, 1263 "sending execute_cdb reply"); 1264 if (request->flags == NDMP_SCSI_DATA_IN) 1265 free(cmd.uscsi_bufaddr); 1266 return; 1267 } 1268 1269 if (ioctl(fd, USCSICMD, &cmd) < 0) { 1270 if (errno != EIO && errno != 0) 1271 NDMP_LOG(LOG_ERR, 1272 "Failed to send command to device: %m"); 1273 NDMP_LOG(LOG_DEBUG, "ioctl(USCSICMD) error: %m"); 1274 if (cmd.uscsi_status == 0) 1275 reply.error = NDMP_IO_ERR; 1276 } 1277 1278 reply.status = cmd.uscsi_status; 1279 1280 if (request->flags == NDMP_SCSI_DATA_IN) { 1281 reply.datain.datain_len = cmd.uscsi_buflen; 1282 reply.datain.datain_val = cmd.uscsi_bufaddr; 1283 } else { 1284 reply.dataout_len = request->dataout.dataout_len; 1285 } 1286 1287 reply.ext_sense.ext_sense_len = cmd.uscsi_rqlen - cmd.uscsi_rqresid; 1288 reply.ext_sense.ext_sense_val = rq_buf; 1289 1290 if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR, 1291 (void *)&reply) < 0) 1292 NDMP_LOG(LOG_DEBUG, "Error sending scsi_execute_cdb reply."); 1293 1294 if (request->flags == NDMP_SCSI_DATA_IN) 1295 free(cmd.uscsi_bufaddr); 1296 } 1297 1298 1299 /* 1300 * ndmp_stop_local_reader 1301 * 1302 * Stops a mover reader thread (for local backup only) 1303 * 1304 * Parameters: 1305 * session (input) - session pointer 1306 * cmds (input) - reader/writer command struct 1307 * 1308 * Returns: 1309 * void 1310 */ 1311 void 1312 ndmp_stop_local_reader(ndmpd_session_t *session, tlm_commands_t *cmds) 1313 { 1314 ndmp_lbr_params_t *nlp; 1315 1316 if (session != NULL && session->ns_data.dd_sock == -1) { 1317 /* 2-way restore */ 1318 if (cmds != NULL && cmds->tcs_reader_count > 0) { 1319 if ((nlp = ndmp_get_nlp(session)) != NULL) { 1320 (void) mutex_lock(&nlp->nlp_mtx); 1321 cmds->tcs_command->tc_reader = TLM_STOP; 1322 (void) cond_broadcast(&nlp->nlp_cv); 1323 (void) mutex_unlock(&nlp->nlp_mtx); 1324 } 1325 } 1326 } 1327 } 1328 1329 1330 /* 1331 * Stops a mover reader thread (for remote backup only) 1332 * 1333 * Parameters: 1334 * session (input) - session pointer 1335 * cmds (input) - reader/writer command struct 1336 * 1337 * Returns: 1338 * void 1339 */ 1340 void 1341 ndmp_stop_remote_reader(ndmpd_session_t *session) 1342 { 1343 if (session != NULL) { 1344 if (session->ns_data.dd_sock >= 0) { 1345 /* 1346 * 3-way restore. 1347 */ 1348 NDMP_LOG(LOG_DEBUG, 1349 "data.sock: %d", session->ns_data.dd_sock); 1350 (void) close(session->ns_data.dd_sock); 1351 session->ns_data.dd_sock = -1; 1352 } 1353 } 1354 } 1355 1356 1357 /* 1358 * ndmp_wait_for_reader 1359 * 1360 * Wait for a reader until get done (busy wait) 1361 */ 1362 void 1363 ndmp_wait_for_reader(tlm_commands_t *cmds) 1364 { 1365 if (cmds == NULL) { 1366 NDMP_LOG(LOG_DEBUG, "cmds == NULL"); 1367 } else { 1368 NDMP_LOG(LOG_DEBUG, 1369 "reader_count: %d", cmds->tcs_reader_count); 1370 1371 while (cmds->tcs_reader_count > 0) 1372 (void) sleep(1); 1373 } 1374 } 1375 1376 1377 /* 1378 * ndmp_open_list_find 1379 * 1380 * Find a specific device in the open list 1381 * 1382 * Parameters: 1383 * dev (input) - device name 1384 * sid (input) - SCSI target ID 1385 * lun (input) - LUN number 1386 * 1387 * Returns: 1388 * pointer to the open list entry 1389 */ 1390 struct open_list * 1391 ndmp_open_list_find(char *dev, int sid, int lun) 1392 { 1393 struct ol_head *olhp; 1394 struct open_list *olp; 1395 1396 if (dev == NULL || *dev == '\0') { 1397 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 1398 return (NULL); 1399 } 1400 1401 (void) mutex_lock(&ol_mutex); 1402 olhp = &ol_head; 1403 for (olp = LIST_FIRST(olhp); olp != NULL; olp = LIST_NEXT(olp, ol_q)) 1404 if (strcmp(olp->ol_devnm, dev) == 0 && olp->ol_sid == sid && 1405 olp->ol_lun == lun) { 1406 (void) mutex_unlock(&ol_mutex); 1407 return (olp); 1408 } 1409 1410 (void) mutex_unlock(&ol_mutex); 1411 return (NULL); 1412 } 1413 1414 1415 /* 1416 * ndmp_open_list_add 1417 * 1418 * Add a specific device to the open list 1419 * 1420 * Parameters: 1421 * conn (input) - connection pointer 1422 * dev (input) - device name 1423 * sid (input) - SCSI target ID 1424 * lun (input) - LUN number 1425 * fd (input) - the device file descriptor 1426 * 1427 * Returns: 1428 * errno 1429 */ 1430 int 1431 ndmp_open_list_add(ndmp_connection_t *conn, char *dev, int sid, int lun, int fd) 1432 { 1433 int err; 1434 struct ol_head *olhp; 1435 struct open_list *olp; 1436 1437 if (dev == NULL || *dev == '\0') { 1438 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 1439 return (EINVAL); 1440 } 1441 NDMP_LOG(LOG_DEBUG, 1442 "conn: 0x%08x, dev: %s, sid: %d, lun: %d", conn, dev, sid, lun); 1443 1444 err = 0; 1445 olhp = &ol_head; 1446 1447 if ((olp = ndmp_open_list_find(dev, sid, lun)) != NULL) { 1448 NDMP_LOG(LOG_DEBUG, "already in list"); 1449 /* 1450 * The adapter handle can be opened many times by the clients. 1451 * Only when the target is set, we must check and reject the 1452 * open request if the device is already being used by another 1453 * session. 1454 */ 1455 if (sid == -1) 1456 olp->ol_nref++; 1457 else 1458 err = EBUSY; 1459 } else if ((olp = ndmp_malloc(sizeof (struct open_list))) == NULL) { 1460 err = ENOMEM; 1461 } else if ((olp->ol_devnm = strdup(dev)) == NULL) { 1462 NDMP_LOG(LOG_ERR, "Out of memory."); 1463 free(olp); 1464 err = ENOMEM; 1465 } else { 1466 olp->cl_conn = conn; 1467 olp->ol_nref = 1; 1468 olp->ol_sid = sid; 1469 olp->ol_lun = lun; 1470 if (fd > 0) 1471 olp->ol_fd = fd; 1472 else 1473 olp->ol_fd = -1; 1474 (void) mutex_lock(&ol_mutex); 1475 LIST_INSERT_HEAD(olhp, olp, ol_q); 1476 (void) mutex_unlock(&ol_mutex); 1477 } 1478 1479 return (err); 1480 } 1481 1482 1483 /* 1484 * ndmp_open_list_del 1485 * 1486 * Delete a specific device from the open list 1487 * 1488 * Parameters: 1489 * dev (input) - device name 1490 * sid (input) - SCSI target ID 1491 * lun (input) - LUN number 1492 * 1493 * Returns: 1494 * errno 1495 */ 1496 int 1497 ndmp_open_list_del(char *dev, int sid, int lun) 1498 { 1499 struct open_list *olp; 1500 1501 if (dev == NULL || *dev == '\0') { 1502 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 1503 return (EINVAL); 1504 } 1505 if ((olp = ndmp_open_list_find(dev, sid, lun)) == NULL) { 1506 NDMP_LOG(LOG_DEBUG, "%s not found", dev); 1507 return (ENOENT); 1508 } 1509 1510 (void) mutex_lock(&ol_mutex); 1511 if (--olp->ol_nref <= 0) { 1512 NDMP_LOG(LOG_DEBUG, 1513 "Removed dev: %s, sid: %d, lun: %d", dev, sid, lun); 1514 LIST_REMOVE(olp, ol_q); 1515 free(olp->ol_devnm); 1516 free(olp); 1517 } 1518 (void) mutex_unlock(&ol_mutex); 1519 1520 return (0); 1521 } 1522 1523 1524 /* 1525 * ndmp_open_list_release 1526 * 1527 * Close all the resources belonging to this connection. 1528 * 1529 * Parameters: 1530 * ndmp_connection_t *conn : connection identifier 1531 * 1532 * Returns: 1533 * void 1534 */ 1535 void 1536 ndmp_open_list_release(ndmp_connection_t *conn) 1537 { 1538 struct ol_head *olhp = &ol_head; 1539 struct open_list *olp; 1540 struct open_list *next; 1541 1542 (void) mutex_lock(&ol_mutex); 1543 olp = LIST_FIRST(olhp); 1544 while (olp != NULL) { 1545 next = LIST_NEXT(olp, ol_q); 1546 NDMP_LOG(LOG_DEBUG, "olp->conn 0x%08x", olp->cl_conn); 1547 if (olp->cl_conn == conn) { 1548 NDMP_LOG(LOG_DEBUG, 1549 "Removed dev: %s, sid: %d, lun: %d", 1550 olp->ol_devnm, olp->ol_sid, olp->ol_lun); 1551 LIST_REMOVE(olp, ol_q); 1552 if (olp->ol_fd > 0) 1553 (void) close(olp->ol_fd); 1554 free(olp->ol_devnm); 1555 free(olp); 1556 } 1557 olp = next; 1558 } 1559 (void) mutex_unlock(&ol_mutex); 1560 } 1561 1562 1563 /* 1564 * ndmp_stop_buffer_worker 1565 * 1566 * Stop all reader and writer threads for a specific buffer. 1567 * 1568 * Parameters: 1569 * session (input) - session pointer 1570 * 1571 * Returns: 1572 * void 1573 */ 1574 void 1575 ndmp_stop_buffer_worker(ndmpd_session_t *session) 1576 { 1577 ndmp_lbr_params_t *nlp; 1578 tlm_commands_t *cmds; 1579 1580 session->ns_tape.td_pos = 0; 1581 if ((nlp = ndmp_get_nlp(session)) == NULL) { 1582 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1583 } else { 1584 cmds = &nlp->nlp_cmds; 1585 if (cmds->tcs_command == NULL) { 1586 NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL"); 1587 } else { 1588 cmds->tcs_reader = cmds->tcs_writer = TLM_ABORT; 1589 cmds->tcs_command->tc_reader = TLM_ABORT; 1590 cmds->tcs_command->tc_writer = TLM_ABORT; 1591 while (cmds->tcs_reader_count > 0 || 1592 cmds->tcs_writer_count > 0) { 1593 NDMP_LOG(LOG_DEBUG, 1594 "trying to stop buffer worker"); 1595 (void) sleep(1); 1596 } 1597 } 1598 } 1599 } 1600 1601 1602 /* 1603 * ndmp_stop_reader_thread 1604 * 1605 * Stop only the reader threads of a specific buffer 1606 * 1607 * Parameters: 1608 * session (input) - session pointer 1609 * 1610 * Returns: 1611 * void 1612 */ 1613 void 1614 ndmp_stop_reader_thread(ndmpd_session_t *session) 1615 { 1616 ndmp_lbr_params_t *nlp; 1617 tlm_commands_t *cmds; 1618 1619 if ((nlp = ndmp_get_nlp(session)) == NULL) { 1620 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1621 } else { 1622 cmds = &nlp->nlp_cmds; 1623 if (cmds->tcs_command == NULL) { 1624 NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL"); 1625 } else { 1626 cmds->tcs_reader = TLM_ABORT; 1627 cmds->tcs_command->tc_reader = TLM_ABORT; 1628 while (cmds->tcs_reader_count > 0) { 1629 NDMP_LOG(LOG_DEBUG, 1630 "trying to stop reader thread"); 1631 (void) sleep(1); 1632 } 1633 } 1634 } 1635 } 1636 1637 1638 /* 1639 * ndmp_stop_reader_thread 1640 * 1641 * Stop only the writer threads of a specific buffer 1642 * 1643 * Parameters: 1644 * session (input) - session pointer 1645 * 1646 * Returns: 1647 * void 1648 */ 1649 void 1650 ndmp_stop_writer_thread(ndmpd_session_t *session) 1651 { 1652 ndmp_lbr_params_t *nlp; 1653 tlm_commands_t *cmds; 1654 1655 if ((nlp = ndmp_get_nlp(session)) == NULL) { 1656 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 1657 } else { 1658 cmds = &nlp->nlp_cmds; 1659 if (cmds->tcs_command == NULL) { 1660 NDMP_LOG(LOG_DEBUG, "cmds->tcs_command == NULL"); 1661 } else { 1662 (void) mutex_lock(&nlp->nlp_mtx); 1663 cmds->tcs_writer = TLM_ABORT; 1664 cmds->tcs_command->tc_writer = TLM_ABORT; 1665 (void) cond_broadcast(&nlp->nlp_cv); 1666 (void) mutex_unlock(&nlp->nlp_mtx); 1667 while (cmds->tcs_writer_count > 0) { 1668 NDMP_LOG(LOG_DEBUG, 1669 "trying to stop writer thread"); 1670 (void) sleep(1); 1671 } 1672 } 1673 } 1674 } 1675 1676 1677 /* 1678 * ndmp_free_reader_writer_ipc 1679 * 1680 * Free and release the reader/writer buffers and the IPC structure 1681 * for reader and writer threads. 1682 * 1683 * Parameters: 1684 * session (input) - session pointer 1685 * 1686 * Returns: 1687 * void 1688 */ 1689 void 1690 ndmp_free_reader_writer_ipc(ndmpd_session_t *session) 1691 { 1692 ndmp_lbr_params_t *nlp; 1693 tlm_commands_t *cmds; 1694 1695 if ((nlp = ndmp_get_nlp(session)) != NULL) { 1696 cmds = &nlp->nlp_cmds; 1697 if (cmds->tcs_command != NULL) { 1698 NDMP_LOG(LOG_DEBUG, "cmds->tcs_command->tc_ref: %d", 1699 cmds->tcs_command->tc_ref); 1700 tlm_release_reader_writer_ipc(cmds->tcs_command); 1701 } 1702 } 1703 } 1704 1705 1706 /* 1707 * ndmp_waitfor_op 1708 * 1709 * Wait for a session reference count to drop to zero 1710 * 1711 * Parameters: 1712 * session (input) - session pointer 1713 * 1714 * Returns: 1715 * void 1716 */ 1717 void 1718 ndmp_waitfor_op(ndmpd_session_t *session) 1719 { 1720 if (session != NULL) { 1721 while (session->ns_nref > 0) { 1722 (void) sleep(1); 1723 NDMP_LOG(LOG_DEBUG, 1724 "waiting for session nref: %d", session->ns_nref); 1725 } 1726 } 1727 } 1728 1729 1730 /* 1731 * ndmp_session_ref 1732 * 1733 * Increment the reference count of the session 1734 * 1735 * Parameters: 1736 * session (input) - session pointer 1737 * 1738 * Returns: 1739 * void 1740 */ 1741 void 1742 ndmp_session_ref(ndmpd_session_t *session) 1743 { 1744 (void) mutex_lock(&session->ns_lock); 1745 session->ns_nref++; 1746 (void) mutex_unlock(&session->ns_lock); 1747 } 1748 1749 1750 /* 1751 * ndmp_session_unref 1752 * 1753 * Decrement the reference count of the session 1754 * 1755 * Parameters: 1756 * session (input) - session pointer 1757 * 1758 * Returns: 1759 * void 1760 */ 1761 void 1762 ndmp_session_unref(ndmpd_session_t *session) 1763 { 1764 (void) mutex_lock(&session->ns_lock); 1765 session->ns_nref--; 1766 (void) mutex_unlock(&session->ns_lock); 1767 } 1768 1769 1770 /* 1771 * ndmp_addr2str_v3 1772 * 1773 * Convert the address type to a string 1774 * 1775 * Parameters: 1776 * type (input) - address type 1777 * 1778 * Returns: 1779 * type in string 1780 */ 1781 char * 1782 ndmp_addr2str_v3(ndmp_addr_type type) 1783 { 1784 char *rv; 1785 1786 switch (type) { 1787 case NDMP_ADDR_LOCAL: 1788 rv = "Local"; 1789 break; 1790 case NDMP_ADDR_TCP: 1791 rv = "TCP"; 1792 break; 1793 case NDMP_ADDR_FC: 1794 rv = "FC"; 1795 break; 1796 case NDMP_ADDR_IPC: 1797 rv = "IPC"; 1798 break; 1799 default: 1800 rv = "Unknown"; 1801 } 1802 1803 return (rv); 1804 } 1805 1806 1807 /* 1808 * ndmp_valid_v3addr_type 1809 * 1810 * Make sure that the NDMP address is from any of the 1811 * valid types 1812 * 1813 * Parameters: 1814 * type (input) - address type 1815 * 1816 * Returns: 1817 * 1: valid 1818 * 0: invalid 1819 */ 1820 boolean_t 1821 ndmp_valid_v3addr_type(ndmp_addr_type type) 1822 { 1823 boolean_t rv; 1824 1825 switch (type) { 1826 case NDMP_ADDR_LOCAL: 1827 case NDMP_ADDR_TCP: 1828 case NDMP_ADDR_FC: 1829 case NDMP_ADDR_IPC: 1830 rv = TRUE; 1831 break; 1832 default: 1833 rv = FALSE; 1834 } 1835 1836 return (rv); 1837 } 1838 1839 1840 /* 1841 * ndmp_copy_addr_v3 1842 * 1843 * Copy NDMP address from source to destination (V2 and V3 only) 1844 * 1845 * Parameters: 1846 * dst (ouput) - destination address 1847 * src (input) - source address 1848 * 1849 * Returns: 1850 * void 1851 */ 1852 void 1853 ndmp_copy_addr_v3(ndmp_addr_v3 *dst, ndmp_addr_v3 *src) 1854 { 1855 dst->addr_type = src->addr_type; 1856 switch (src->addr_type) { 1857 case NDMP_ADDR_LOCAL: 1858 /* nothing */ 1859 break; 1860 case NDMP_ADDR_TCP: 1861 dst->tcp_ip_v3 = htonl(src->tcp_ip_v3); 1862 dst->tcp_port_v3 = src->tcp_port_v3; 1863 break; 1864 case NDMP_ADDR_FC: 1865 case NDMP_ADDR_IPC: 1866 default: 1867 break; 1868 } 1869 } 1870 1871 1872 /* 1873 * ndmp_copy_addr_v4 1874 * 1875 * Copy NDMP address from source to destination. V4 has a extra 1876 * environment list inside the address too which needs to be copied. 1877 * 1878 * Parameters: 1879 * dst (ouput) - destination address 1880 * src (input) - source address 1881 * 1882 * Returns: 1883 * void 1884 */ 1885 void 1886 ndmp_copy_addr_v4(ndmp_addr_v4 *dst, ndmp_addr_v4 *src) 1887 { 1888 int i; 1889 1890 dst->addr_type = src->addr_type; 1891 dst->tcp_len_v4 = src->tcp_len_v4; 1892 switch (src->addr_type) { 1893 case NDMP_ADDR_LOCAL: 1894 /* nothing */ 1895 break; 1896 case NDMP_ADDR_TCP: 1897 dst->tcp_addr_v4 = ndmp_malloc(sizeof (ndmp_tcp_addr_v4) * 1898 src->tcp_len_v4); 1899 if (dst->tcp_addr_v4 == 0) 1900 return; 1901 1902 for (i = 0; i < src->tcp_len_v4; i++) { 1903 dst->tcp_ip_v4(i) = htonl(src->tcp_ip_v4(i)); 1904 dst->tcp_port_v4(i) = src->tcp_port_v4(i); 1905 dst->tcp_env_v4(i).addr_env_len = 0; /* Solaris */ 1906 dst->tcp_env_v4(i).addr_env_val = 0; /* Solaris */ 1907 } 1908 break; 1909 case NDMP_ADDR_FC: 1910 case NDMP_ADDR_IPC: 1911 default: 1912 break; 1913 } 1914 } 1915 1916 1917 /* 1918 * ndmp_connect_sock_v3 1919 * 1920 * Creates a socket and connects to the specified address/port 1921 * 1922 * Parameters: 1923 * addr (input) - IP address 1924 * port (input) - port number 1925 * 1926 * Returns: 1927 * 0: on success 1928 * -1: otherwise 1929 */ 1930 int 1931 ndmp_connect_sock_v3(ulong_t addr, ushort_t port) 1932 { 1933 int sock; 1934 struct sockaddr_in sin; 1935 1936 NDMP_LOG(LOG_DEBUG, "addr %s:%d", inet_ntoa(IN_ADDR(addr)), port); 1937 1938 sock = socket(AF_INET, SOCK_STREAM, 0); 1939 if (sock < 0) { 1940 NDMP_LOG(LOG_DEBUG, "Socket error: %m"); 1941 return (-1); 1942 } 1943 1944 (void) memset((void *) &sin, 0, sizeof (sin)); 1945 sin.sin_family = AF_INET; 1946 sin.sin_addr.s_addr = htonl(addr); 1947 sin.sin_port = htons(port); 1948 if (connect(sock, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 1949 NDMP_LOG(LOG_DEBUG, "Connect error: %m"); 1950 (void) close(sock); 1951 return (-1); 1952 } 1953 1954 set_socket_options(sock); 1955 NDMP_LOG(LOG_DEBUG, "sock %d", sock); 1956 1957 return (sock); 1958 } 1959 1960 /* 1961 * ndmp_create_socket 1962 * 1963 * Creates a socket for listening for accepting data connections. 1964 * 1965 * Parameters: 1966 * session (input) - session pointer. 1967 * addr (output) - location to store address of socket. 1968 * port (output) - location to store port of socket. 1969 * 1970 * Returns: 1971 * 0 - success. 1972 * -1 - error. 1973 */ 1974 int 1975 ndmp_create_socket(ulong_t *addr, ushort_t *port) 1976 { 1977 char *p; 1978 int length; 1979 int sd; 1980 struct sockaddr_in sin; 1981 1982 /* Try the user's prefered NIC IP address */ 1983 p = ndmpd_get_prop(NDMP_MOVER_NIC); 1984 1985 /* Try host's IP address */ 1986 if (!p || *p == 0) 1987 p = gethostaddr(); 1988 1989 /* Try default NIC's IP address (if DNS failed) */ 1990 if (!p) 1991 p = get_default_nic_addr(); 1992 1993 /* Fail if no IP can be obtained */ 1994 if (!p) { 1995 NDMP_LOG(LOG_ERR, "Undetermined network port."); 1996 return (-1); 1997 } 1998 1999 *addr = inet_addr(p); 2000 2001 sd = socket(AF_INET, SOCK_STREAM, 0); 2002 if (sd < 0) { 2003 NDMP_LOG(LOG_DEBUG, "Socket error: %m"); 2004 return (-1); 2005 } 2006 sin.sin_family = AF_INET; 2007 sin.sin_addr.s_addr = INADDR_ANY; 2008 sin.sin_port = 0; 2009 length = sizeof (sin); 2010 2011 if (bind(sd, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 2012 NDMP_LOG(LOG_DEBUG, "Bind error: %m"); 2013 (void) close(sd); 2014 sd = -1; 2015 } else if (getsockname(sd, (struct sockaddr *)&sin, &length) < 0) { 2016 NDMP_LOG(LOG_DEBUG, "getsockname error: %m"); 2017 (void) close(sd); 2018 sd = -1; 2019 } else if (listen(sd, 5) < 0) { 2020 NDMP_LOG(LOG_DEBUG, "Listen error: %m"); 2021 (void) close(sd); 2022 sd = -1; 2023 } else 2024 *port = sin.sin_port; 2025 2026 return (sd); 2027 } 2028 2029 2030 /* 2031 * cctime 2032 * 2033 * Convert the specified time into a string. It's like 2034 * ctime(), but: 2035 * - chops the trailing '\n' of ctime. 2036 * - and returns "the epoch" if time is 0. 2037 * 2038 * Returns: 2039 * "": invalid argument. 2040 * "the epoch": if time is 0. 2041 * string format of the time. 2042 */ 2043 char * 2044 cctime(time_t *t) 2045 { 2046 char *bp, *cp; 2047 static char tbuf[BUFSIZ]; 2048 2049 if (!t) 2050 return (""); 2051 2052 if (*t == (time_t)0) 2053 return ("the epoch"); 2054 2055 if ((bp = ctime_r(t, tbuf, BUFSIZ)) == NULL) 2056 return (""); 2057 2058 cp = strchr(bp, '\n'); 2059 if (cp) 2060 *cp = '\0'; 2061 2062 return (bp); 2063 } 2064 2065 2066 /* 2067 * ndmp_new_job_name 2068 * 2069 * Create a job name for each backup/restore to keep track 2070 * 2071 * Parameters: 2072 * jname (output) - job name 2073 * 2074 * Returns: 2075 * jname 2076 */ 2077 char * 2078 ndmp_new_job_name(char *jname) 2079 { 2080 if (jname != NULL) { 2081 (void) snprintf(jname, TLM_MAX_BACKUP_JOB_NAME, "%s%d", 2082 NDMP_RCF_BASENAME, ndmp_job_cnt++); 2083 NDMP_LOG(LOG_DEBUG, "jname: \"%s\"", jname); 2084 } 2085 2086 return (jname); 2087 } 2088 2089 2090 /* 2091 * fs_is_valid_logvol 2092 * 2093 * Check if the log path exists 2094 * 2095 * Parameters: 2096 * path (input) - log path 2097 * 2098 * Returns: 2099 * FALSE: invalid 2100 * TRUE: valid 2101 */ 2102 boolean_t 2103 fs_is_valid_logvol(char *path) 2104 { 2105 struct stat64 st; 2106 2107 if (stat64(path, &st) < 0) 2108 return (FALSE); 2109 2110 return (TRUE); 2111 } 2112 2113 2114 /* 2115 * ndmpd_mk_temp 2116 * 2117 * Make a temporary file using the working directory path and the 2118 * jobname 2119 * 2120 * Parameters: 2121 * buf (output) - the temporary file name path 2122 * 2123 * Returns: 2124 * buf 2125 */ 2126 char * 2127 ndmpd_mk_temp(char *buf) 2128 { 2129 char fname[TLM_MAX_BACKUP_JOB_NAME]; 2130 const char *dir; 2131 char *rv; 2132 2133 if (!buf) 2134 return (NULL); 2135 2136 dir = ndmpd_get_prop(NDMP_DEBUG_PATH); 2137 if (dir == 0 || *dir == '\0') { 2138 NDMP_LOG(LOG_DEBUG, "NDMP work path not specified"); 2139 return (0); 2140 } 2141 2142 if (!fs_is_valid_logvol((char *)dir)) { 2143 NDMP_LOG(LOG_ERR, 2144 "Log file path cannot be on system volumes."); 2145 return (0); 2146 } 2147 2148 dir += strspn(dir, " \t"); 2149 if (!*dir) { 2150 NDMP_LOG(LOG_DEBUG, "NDMP work path not specified"); 2151 return (0); 2152 } 2153 2154 rv = buf; 2155 (void) ndmp_new_job_name(fname); 2156 (void) tlm_cat_path(buf, (char *)dir, fname); 2157 2158 return (rv); 2159 } 2160 2161 2162 /* 2163 * ndmpd_make_bk_dir_path 2164 * 2165 * Make a directory path for temporary files under the NDMP 2166 * working directory. 2167 * 2168 * Parameters: 2169 * buf (output) - result path 2170 * fname (input) - the file name 2171 * 2172 * Returns: 2173 * buf 2174 */ 2175 char * 2176 ndmpd_make_bk_dir_path(char *buf, char *fname) 2177 { 2178 const char *p; 2179 char *name; 2180 char path[PATH_MAX]; 2181 2182 if (!buf || !fname || !*fname) 2183 return (NULL); 2184 2185 p = ndmpd_get_prop(NDMP_DEBUG_PATH); 2186 if (p == NULL || *p == '\0' || !fs_is_valid_logvol((char *)p)) { 2187 return (NULL); 2188 } 2189 2190 (void) strlcpy(path, (char *)p, PATH_MAX); 2191 (void) trim_whitespace(path); 2192 2193 if ((name = strrchr(fname, '/')) == 0) 2194 name = fname; 2195 2196 (void) tlm_cat_path(buf, path, name); 2197 return (buf); 2198 } 2199 2200 2201 /* 2202 * ndmp_is_chkpnt_root 2203 * 2204 * Is this a root checkpoint (snapshot) directory. 2205 * Note: a temporary function 2206 */ 2207 boolean_t 2208 ndmp_is_chkpnt_root(char *path) 2209 { 2210 struct stat64 st; 2211 2212 if (stat64(path, &st) != 0) { 2213 NDMP_LOG(LOG_DEBUG, "Couldn't stat path \"%s\"", path); 2214 return (TRUE); 2215 } 2216 return (FALSE); 2217 } 2218 2219 2220 /* 2221 * ndmpd_make_exc_list 2222 * 2223 * Make a list of files that should not be backed up. 2224 * 2225 * Parameters: 2226 * void 2227 * 2228 * Returns: 2229 * list - array of character strings 2230 */ 2231 char ** 2232 ndmpd_make_exc_list(void) 2233 { 2234 char *val, **cpp; 2235 int i, n; 2236 2237 n = sizeof (exls); 2238 if ((cpp = ndmp_malloc(n)) != NULL) { 2239 for (i = 0; exls[i] != NULL; i++) 2240 cpp[i] = exls[i]; 2241 2242 /* 2243 * If ndmpd_get_prop returns NULL, the array will be 2244 * null-terminated. 2245 */ 2246 val = ndmpd_get_prop(NDMP_DEBUG_PATH); 2247 cpp[i] = val; 2248 } 2249 2250 return (cpp); 2251 } 2252 2253 2254 /* 2255 * ndmp_get_bk_dir_ino 2256 * 2257 * Get the inode number of the backup directory 2258 */ 2259 int 2260 ndmp_get_bk_dir_ino(ndmp_lbr_params_t *nlp) 2261 { 2262 int rv; 2263 struct stat64 st; 2264 2265 if (stat64(nlp->nlp_backup_path, &st) != 0) { 2266 rv = -1; 2267 NDMP_LOG(LOG_DEBUG, "Getting inode # of \"%s\"", 2268 nlp->nlp_backup_path); 2269 } else { 2270 rv = 0; 2271 nlp->nlp_bkdirino = st.st_ino; 2272 NDMP_LOG(LOG_DEBUG, "nlp_bkdirino: %lu", 2273 (uint_t)nlp->nlp_bkdirino); 2274 } 2275 2276 return (rv); 2277 } 2278 2279 2280 /* 2281 * ndmp_check_utf8magic 2282 * 2283 * Check if the magic string for exists in the tar header. This 2284 * magic string (which also indicates that the file names are in 2285 * UTF8 format) is used as a crest to indetify our own tapes. 2286 * This checking is always done before all restores except DAR 2287 * restores. 2288 */ 2289 boolean_t 2290 ndmp_check_utf8magic(tlm_cmd_t *cmd) 2291 { 2292 char *cp; 2293 int err, len, actual_size; 2294 2295 if (cmd == NULL) { 2296 NDMP_LOG(LOG_DEBUG, "cmd == NULL"); 2297 return (FALSE); 2298 } 2299 if (cmd->tc_buffers == NULL) { 2300 NDMP_LOG(LOG_DEBUG, "cmd->tc_buffers == NULL"); 2301 return (FALSE); 2302 } 2303 2304 /* wait until the first buffer gets full. */ 2305 tlm_buffer_in_buf_wait(cmd->tc_buffers); 2306 2307 err = actual_size = 0; 2308 cp = tlm_get_read_buffer(RECORDSIZE, &err, cmd->tc_buffers, 2309 &actual_size); 2310 if (cp == NULL) { 2311 NDMP_LOG(LOG_DEBUG, "Can't read from buffers, err: %d", err); 2312 return (FALSE); 2313 } 2314 len = strlen(NDMPUTF8MAGIC); 2315 if (actual_size < len) { 2316 NDMP_LOG(LOG_DEBUG, "Not enough data in the buffers"); 2317 return (FALSE); 2318 } 2319 2320 return ((strncmp(cp, NDMPUTF8MAGIC, len) == 0) ? TRUE : FALSE); 2321 } 2322 2323 2324 /* 2325 * ndmp_get_cur_bk_time 2326 * 2327 * Get the backup checkpoint time. 2328 */ 2329 int 2330 ndmp_get_cur_bk_time(ndmp_lbr_params_t *nlp, time_t *tp, char *jname) 2331 { 2332 int err; 2333 2334 if (!nlp || !nlp->nlp_backup_path || !tp) { 2335 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 2336 return (-1); 2337 } 2338 2339 if (!fs_is_chkpnt_enabled(nlp->nlp_backup_path)) { 2340 NDMP_LOG(LOG_DEBUG, "Not a chkpnt volume %s", 2341 nlp->nlp_backup_path); 2342 *tp = time(NULL); 2343 return (0); 2344 } 2345 2346 err = tlm_get_chkpnt_time(nlp->nlp_backup_path, !NLP_ISCHKPNTED(nlp), 2347 tp, jname); 2348 if (err != 0) { 2349 NDMP_LOG(LOG_DEBUG, "Can't checkpoint time"); 2350 } else { 2351 NDMP_LOG(LOG_DEBUG, "%s", cctime(tp)); 2352 } 2353 2354 return (err); 2355 } 2356 2357 2358 /* 2359 * get_relative_path 2360 */ 2361 char * 2362 ndmp_get_relative_path(char *base, char *fullpath) 2363 { 2364 char *p = fullpath; 2365 2366 if (!base || !*base) 2367 return (fullpath); 2368 2369 while (*base) { 2370 if (*base != *p) 2371 break; 2372 p++; base++; 2373 } 2374 2375 if (*p == '/') 2376 p++; 2377 2378 return ((*base) ? fullpath : p); 2379 } 2380 2381 2382 /* 2383 * ndmp_get_nlp 2384 * 2385 * Get NDMP local backup parameters 2386 * 2387 * Parameter: 2388 * session cooke 2389 * 2390 * Returns: 2391 * LBR structure 2392 */ 2393 ndmp_lbr_params_t * 2394 ndmp_get_nlp(void *cookie) 2395 { 2396 if (cookie == NULL) 2397 return (NULL); 2398 2399 return (((ndmpd_session_t *)cookie)->ns_ndmp_lbr_params); 2400 } 2401 2402 2403 /* 2404 * is_tape_unit_ready 2405 * 2406 * Check if the tape device is ready or not 2407 */ 2408 boolean_t 2409 is_tape_unit_ready(char *adptnm, int dev_id) 2410 { 2411 int try; 2412 int fd = 0; 2413 2414 try = TUR_MAX_TRY; 2415 if (dev_id <= 0) { 2416 if ((fd = open(adptnm, O_RDONLY | O_NDELAY)) < 0) 2417 return (FALSE); 2418 } else { 2419 fd = dev_id; 2420 } 2421 do { 2422 if (scsi_test_unit_ready(fd) >= 0) { 2423 NDMP_LOG(LOG_DEBUG, "Unit is ready"); 2424 2425 if (dev_id <= 0) 2426 (void) close(fd); 2427 2428 return (TRUE); 2429 } 2430 2431 NDMP_LOG(LOG_DEBUG, "Unit not ready"); 2432 (void) usleep(TUR_WAIT); 2433 2434 } while (--try > 0); 2435 2436 if (dev_id <= 0) 2437 (void) close(fd); 2438 2439 NDMP_LOG(LOG_DEBUG, "Unit didn't get ready"); 2440 return (FALSE); 2441 } 2442 2443 2444 /* 2445 * scsi_test_unit_ready 2446 * 2447 * This is for Test Unit Read, without this function, the only 2448 * impact is getting EBUSY's before each operation which we have 2449 * busy waiting loops checking EBUSY error code. 2450 */ 2451 static int 2452 scsi_test_unit_ready(int dev_id) 2453 { 2454 struct uscsi_cmd ucmd; 2455 union scsi_cdb cdb; 2456 int retval; 2457 2458 (void) memset(&ucmd, 0, sizeof (struct uscsi_cmd)); 2459 (void) memset(&cdb, 0, sizeof (union scsi_cdb)); 2460 cdb.scc_cmd = SCMD_TEST_UNIT_READY; 2461 ucmd.uscsi_cdb = (caddr_t)&cdb; 2462 ucmd.uscsi_cdblen = CDB_GROUP0; 2463 ucmd.uscsi_flags |= USCSI_SILENT; 2464 ucmd.uscsi_timeout = 60; /* Allow maximum 1 min */ 2465 2466 retval = ioctl(dev_id, USCSICMD, &ucmd); 2467 2468 if (retval != 0 && errno != EIO) { 2469 NDMP_LOG(LOG_ERR, 2470 "Failed to send inquiry request to device: %m."); 2471 NDMP_LOG(LOG_DEBUG, "Inquiry request failed for" 2472 " dev_id:%d err=%d -%m", dev_id, errno); 2473 retval = -errno; 2474 } else 2475 retval = -(ucmd.uscsi_status); 2476 2477 return (retval); 2478 } 2479 2480 2481 /* 2482 * ndmp_load_params 2483 * 2484 * Load the parameters. 2485 * 2486 * Parameter: 2487 * void 2488 * 2489 * Returns: 2490 * void 2491 */ 2492 void 2493 ndmp_load_params(void) 2494 { 2495 ndmp_dump_path_node = ndmpd_get_prop_yorn(NDMP_DUMP_PATHNODE_ENV) ? 2496 TRUE : FALSE; 2497 ndmp_tar_path_node = ndmpd_get_prop_yorn(NDMP_TAR_PATHNODE_ENV) ? 2498 TRUE : FALSE; 2499 ndmp_ignore_ctime = 2500 ndmpd_get_prop_yorn(NDMP_IGNCTIME_ENV) ? TRUE : FALSE; 2501 ndmp_include_lmtime = ndmpd_get_prop_yorn(NDMP_INCLMTIME_ENV) ? 2502 TRUE : FALSE; 2503 ndmp_max_tok_seq = atoi(ndmpd_get_prop_default(NDMP_MAXSEQ_ENV, "9")); 2504 2505 ndmp_full_restore_path = ndmpd_get_prop_yorn(NDMP_FULL_RESTORE_PATH) ? 2506 TRUE : FALSE; 2507 2508 ndmp_fhinode = ndmpd_get_prop_yorn(NDMP_FHIST_INCR_ENV) ? TRUE : FALSE; 2509 2510 /* Get the value from ndmp SMF property. */ 2511 ndmp_dar_support = ndmpd_get_prop_yorn(NDMP_DAR_SUPPORT); 2512 2513 if ((ndmp_ver = atoi(ndmpd_get_prop(NDMP_VERSION_ENV))) == 0) 2514 ndmp_ver = NDMPVER; 2515 } 2516 2517 /* 2518 * randomize 2519 * 2520 * Randomize the contents of a buffer 2521 * 2522 * Parameter: 2523 * buffer (output) - destination buffer 2524 * size (input) - buffer size 2525 * 2526 * Returns: 2527 * void 2528 */ 2529 void 2530 randomize(unsigned char *buffer, int size) 2531 { 2532 /* LINTED improper alignment */ 2533 unsigned int *p = (unsigned int *)buffer; 2534 unsigned int dwlen = size / sizeof (unsigned int); 2535 unsigned int remlen = size % sizeof (unsigned int); 2536 unsigned int tmp; 2537 unsigned int i; 2538 2539 for (i = 0; i < dwlen; i++) 2540 *p++ = random(); 2541 2542 if (remlen) { 2543 tmp = random(); 2544 (void) memcpy(p, &tmp, remlen); 2545 } 2546 } 2547 2548 /* 2549 * ndmpd_get_file_entry_type 2550 * 2551 * Converts the mode to the NDMP file type 2552 * 2553 * Parameter: 2554 * mode (input) - file mode 2555 * ftype (output) - file type 2556 * 2557 * Returns: 2558 * void 2559 */ 2560 void 2561 ndmpd_get_file_entry_type(int mode, ndmp_file_type *ftype) 2562 { 2563 switch (mode & S_IFMT) { 2564 case S_IFIFO: 2565 *ftype = NDMP_FILE_FIFO; 2566 break; 2567 case S_IFCHR: 2568 *ftype = NDMP_FILE_CSPEC; 2569 break; 2570 case S_IFDIR: 2571 *ftype = NDMP_FILE_DIR; 2572 break; 2573 case S_IFBLK: 2574 *ftype = NDMP_FILE_BSPEC; 2575 break; 2576 case S_IFREG: 2577 *ftype = NDMP_FILE_REG; 2578 break; 2579 case S_IFLNK: 2580 *ftype = NDMP_FILE_SLINK; 2581 break; 2582 default: 2583 *ftype = NDMP_FILE_SOCK; 2584 break; 2585 } 2586 } 2587 2588 /* 2589 * Set a private data in the plugin context 2590 */ 2591 void 2592 ndmp_context_set_specific(ndmp_context_t *nctx, void *ptr) 2593 { 2594 nctx->nc_pldata = ptr; 2595 } 2596 2597 /* 2598 * Get a private data in the plugin context 2599 */ 2600 void * 2601 ndmp_context_get_specific(ndmp_context_t *nctx) 2602 { 2603 return (nctx->nc_pldata); 2604 } 2605 2606 ndmpd_backup_type_t 2607 ndmp_get_backup_type(ndmp_context_t *ctx) 2608 { 2609 ndmpd_session_t *session = (ndmpd_session_t *)ctx->nc_ddata; 2610 2611 return (session->ns_butype); 2612 } 2613