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