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