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