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