1 /*
   2  * Copyright (c) 2008, 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 <stdlib.h>
  44 #include <errno.h>
  45 #include <stdarg.h>
  46 #include <stdio.h>
  47 #include <string.h>
  48 #include "ndmpd.h"
  49 
  50 
  51 /*
  52  * Message Id counter.  This number is increased by MOD_LOGV3 macro.
  53  * MOD_LOGCONTV3 macro uses the number generated by the last MOD_LOGV3.
  54  *
  55  */
  56 int ndmp_log_msg_id = 0;
  57 
  58 
  59 /*
  60  * ************************************************************************
  61  * NDMP V2 CALLBACKS
  62  * ************************************************************************
  63  */
  64 
  65 /*
  66  * ndmpd_api_done_v2
  67  *
  68  * Called when dump/restore has completed.
  69  * Sends a notify_halt request to the NDMP client.
  70  *
  71  * Parameters:
  72  *   session (input) - session pointer.
  73  *   err     (input) - UNIX error code.
  74  *
  75  * Returns:
  76  *   void
  77  */
  78 void
  79 ndmpd_api_done_v2(void *cookie, int err)
  80 {
  81         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
  82         ndmp_notify_data_halted_request req_v2;
  83 
  84         if (session == NULL)
  85                 return;
  86 
  87         if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
  88             session->ns_data.dd_state == NDMP_DATA_STATE_HALTED)
  89                 return;
  90 
  91         NDMP_LOG(LOG_DEBUG, "data.operation: %d",
  92             session->ns_data.dd_operation);
  93 
  94         if (session->ns_data.dd_operation == NDMP_DATA_OP_BACKUP) {
  95                 /*
  96                  * Send/discard any buffered file history data.
  97                  */
  98                 ndmpd_file_history_cleanup(session, (err == 0 ? TRUE : FALSE));
  99 
 100                 /*
 101                  * If mover local and successfull backup, write any
 102                  * remaining buffered data to tape.
 103                  */
 104                 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_LOCAL &&
 105                     err == 0) {
 106                         if (ndmpd_local_write(session, 0, 0) < 0)
 107                                 err = EIO;
 108                 }
 109         }
 110 
 111         session->ns_data.dd_state = NDMP_DATA_STATE_HALTED;
 112 
 113         switch (err) {
 114         case 0:
 115                 session->ns_data.dd_halt_reason = NDMP_DATA_HALT_SUCCESSFUL;
 116                 break;
 117         case EINTR:
 118                 session->ns_data.dd_halt_reason = NDMP_DATA_HALT_ABORTED;
 119                 break;
 120         case EIO:
 121                 session->ns_data.dd_halt_reason = NDMP_DATA_HALT_CONNECT_ERROR;
 122                 break;
 123         default:
 124                 session->ns_data.dd_halt_reason = NDMP_DATA_HALT_INTERNAL_ERROR;
 125         }
 126 
 127         req_v2.reason = session->ns_data.dd_halt_reason;
 128         req_v2.text_reason = "";
 129 
 130         NDMP_LOG(LOG_DEBUG, "ndmp_send_request(NDMP_NOTIFY_DATA_HALTED)");
 131 
 132         if (ndmp_send_request_lock(session->ns_connection,
 133             NDMP_NOTIFY_DATA_HALTED, NDMP_NO_ERR, (void *)&req_v2, 0) < 0)
 134                 NDMP_LOG(LOG_DEBUG, "Sending notify_data_halted request");
 135 
 136         if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
 137 
 138                 if (session->ns_mover.md_sock != session->ns_data.dd_sock) {
 139                         (void) close(session->ns_data.dd_sock);
 140                 } else {
 141                         NDMP_LOG(LOG_DEBUG, "Not closing as used by mover");
 142                 }
 143 
 144                 session->ns_data.dd_sock = -1;
 145         } else {
 146                 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
 147         }
 148 }
 149 
 150 
 151 /*
 152  * ndmpd_api_log_v2
 153  *
 154  * Sends a log request to the NDMP client.
 155  *
 156  * Parameters:
 157  *   cookie (input) - session pointer.
 158  *   str    (input) - null terminated string
 159  *   format (input) - printf style format.
 160  *   ...    (input) - format arguments.
 161  *
 162  * Returns:
 163  *   0 - success.
 164  *  -1 - error.
 165  */
 166 /*ARGSUSED*/
 167 int
 168 ndmpd_api_log_v2(void *cookie, char *format, ...)
 169 {
 170         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 171         ndmp_log_log_request request;
 172         static char buf[1024];
 173         va_list ap;
 174 
 175         if (session == NULL)
 176                 return (-1);
 177 
 178         va_start(ap, format);
 179 
 180         /*LINTED variable format specifier */
 181         (void) vsnprintf(buf, sizeof (buf), format, ap);
 182         va_end(ap);
 183 
 184         request.entry = buf;
 185 
 186 
 187         if (ndmp_send_request(session->ns_connection, _NDMP_LOG_LOG,
 188             NDMP_NO_ERR, (void *)&request, 0) < 0) {
 189                 NDMP_LOG(LOG_DEBUG, "Sending log request");
 190                 return (-1);
 191         }
 192         return (0);
 193 
 194 }
 195 
 196 
 197 /*
 198  * ndmpd_api_read_v2
 199  *
 200  * Callback function called by the backup/recover module.
 201  * Reads data from the mover.
 202  * If the mover is remote, the data is read from the data connection.
 203  * If the mover is local, the data is read from the tape device.
 204  *
 205  * Parameters:
 206  *   client_data (input) - session pointer.
 207  *   data       (input) - data to be written.
 208  *   length     (input) - data length.
 209  *
 210  * Returns:
 211  *   0 - data successfully read.
 212  *  -1 - error.
 213  *   1 - session terminated or operation aborted.
 214  */
 215 int
 216 ndmpd_api_read_v2(void *client_data, char *data, ulong_t length)
 217 {
 218         ndmpd_session_t *session = (ndmpd_session_t *)client_data;
 219 
 220         if (session == NULL)
 221                 return (-1);
 222 
 223         /*
 224          * Read the data from the data connection if the mover is remote.
 225          */
 226         if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP)
 227                 return (ndmpd_remote_read(session, data, length));
 228         else
 229                 return (ndmpd_local_read(session, data, length));
 230 }
 231 
 232 
 233 /*
 234  * ndmpd_api_seek_v2
 235  *
 236  * Seek to the specified position in the data stream and start a
 237  * read for the specified amount of data.
 238  *
 239  * Parameters:
 240  *   cookie (input) - session pointer.
 241  *   offset (input) - stream position to seek to.
 242  *   length (input) - amount of data that will be read using ndmpd_api_read
 243  *
 244  * Returns:
 245  *   0 - seek successful.
 246  *  -1 - error.
 247  */
 248 int
 249 ndmpd_api_seek_v2(void *cookie, u_longlong_t offset, u_longlong_t length)
 250 {
 251         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 252         int err;
 253 
 254         if (session == NULL)
 255                 return (-1);
 256 
 257         session->ns_data.dd_read_offset = offset;
 258         session->ns_data.dd_read_length = length;
 259 
 260         /*
 261          * Send a notify_data_read request if the mover is remote.
 262          */
 263         if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
 264                 ndmp_notify_data_read_request request;
 265 
 266                 session->ns_mover.md_discard_length =
 267                     session->ns_mover.md_bytes_left_to_read;
 268                 session->ns_mover.md_bytes_left_to_read = length;
 269                 session->ns_mover.md_position = offset;
 270 
 271                 request.offset = long_long_to_quad(offset);
 272                 request.length = long_long_to_quad(length);
 273 
 274                 if (ndmp_send_request_lock(session->ns_connection,
 275                     NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
 276                     (void *)&request, 0) < 0) {
 277 
 278                         NDMP_LOG(LOG_DEBUG,
 279                             "Sending notify_data_read request");
 280                         return (-1);
 281                 }
 282                 return (0);
 283         }
 284         /* Mover is local. */
 285 
 286         err = ndmpd_mover_seek(session, offset, length);
 287         if (err < 0) {
 288                 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
 289                 return (-1);
 290         }
 291         if (err == 0)
 292                 return (0);
 293 
 294         /*
 295          * NDMP client intervention is required to perform the seek.
 296          * Wait for the client to either do the seek and send a continue
 297          * request or send an abort request.
 298          */
 299         return (ndmp_wait_for_mover(session));
 300 }
 301 
 302 
 303 /*
 304  * ndmpd_api_file_recovered_v2
 305  *
 306  * Notify the NDMP client that the specified file was recovered.
 307  *
 308  * Parameters:
 309  *   cookie (input) - session pointer.
 310  *   name   (input) - name of recovered file.
 311  *   error  (input) - 0 if file successfully recovered.
 312  *                  otherwise, error code indicating why recovery failed.
 313  *
 314  * Returns:
 315  *   void.
 316  */
 317 int
 318 ndmpd_api_file_recovered_v2(void *cookie, char *name, int error)
 319 {
 320         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 321         ndmp_log_file_request_v2 request;
 322 
 323         if (session == NULL)
 324                 return (-1);
 325 
 326         request.name = name;
 327         request.ssid = 0;
 328 
 329         switch (error) {
 330         case 0:
 331                 request.error = NDMP_NO_ERR;
 332                 break;
 333         case ENOENT:
 334                 request.error = NDMP_FILE_NOT_FOUND_ERR;
 335                 break;
 336         default:
 337                 request.error = NDMP_PERMISSION_ERR;
 338         }
 339 
 340         if (ndmp_send_request_lock(session->ns_connection, NDMP_LOG_FILE,
 341             NDMP_NO_ERR, (void *)&request, 0) < 0) {
 342                 NDMP_LOG(LOG_DEBUG, "Sending log file request");
 343                 return (-1);
 344         }
 345         return (0);
 346 }
 347 
 348 
 349 /*
 350  * ndmpd_api_write_v2
 351  *
 352  * Callback function called by the backup/restore module.
 353  * Writes data to the mover.
 354  * If the mover is remote, the data is written to the data connection.
 355  * If the mover is local, the data is buffered and written to the
 356  * tape device after a full record has been buffered.
 357  *
 358  * Parameters:
 359  *   client_data (input) - session pointer.
 360  *   data       (input) - data to be written.
 361  *   length     (input) - data length.
 362  *
 363  * Returns:
 364  *   0 - data successfully written.
 365  *  -1 - error.
 366  */
 367 int
 368 ndmpd_api_write_v2(void *client_data, char *data, ulong_t length)
 369 {
 370         ndmpd_session_t *session = (ndmpd_session_t *)client_data;
 371 
 372         if (session == NULL)
 373                 return (-1);
 374 
 375         /*
 376          * Write the data to the data connection if the mover is remote.
 377          */
 378         if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP)
 379                 return (ndmpd_remote_write(session, data, length));
 380         else
 381                 return (ndmpd_local_write(session, data, length));
 382 }
 383 
 384 
 385 /*
 386  * ************************************************************************
 387  * NDMP V3 CALLBACKS
 388  * ************************************************************************
 389  */
 390 
 391 /*
 392  * ndmpd_api_done_v3
 393  *
 394  * Called when the data module has completed.
 395  * Sends a notify_halt request to the NDMP client.
 396  *
 397  * Parameters:
 398  *   session (input) - session pointer.
 399  *   err     (input) - UNIX error code.
 400  *
 401  * Returns:
 402  *   void
 403  */
 404 void
 405 ndmpd_api_done_v3(void *cookie, int err)
 406 {
 407         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 408         ndmp_data_halt_reason reason;
 409 
 410         switch (err) {
 411         case 0:
 412                 reason = NDMP_DATA_HALT_SUCCESSFUL;
 413                 break;
 414 
 415         case EINTR:
 416                 reason = NDMP_DATA_HALT_ABORTED;
 417                 break;
 418 
 419         case EIO:
 420                 reason = NDMP_DATA_HALT_CONNECT_ERROR;
 421                 break;
 422 
 423         default:
 424                 reason = NDMP_DATA_HALT_INTERNAL_ERROR;
 425         }
 426 
 427         ndmpd_data_error(session, reason);
 428 }
 429 
 430 /*
 431  * ndmpd_api_log_v3
 432  *
 433  * Sends a log request to the NDMP client.
 434  *
 435  * Parameters:
 436  *   cookie (input) - session pointer.
 437  *   format (input) - printf style format.
 438  *   ...    (input) - format arguments.
 439  *
 440  * Returns:
 441  *   0 - success.
 442  *  -1 - error.
 443  */
 444 /*ARGSUSED*/
 445 int
 446 ndmpd_api_log_v3(void *cookie, ndmp_log_type type, ulong_t msg_id,
 447     char *format, ...)
 448 {
 449         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 450         ndmp_log_message_request_v3 request;
 451         static char buf[1024];
 452         va_list ap;
 453 
 454         if (session == NULL)
 455                 return (-1);
 456 
 457         va_start(ap, format);
 458 
 459         /*LINTED variable format specifier */
 460         (void) vsnprintf(buf, sizeof (buf), format, ap);
 461         va_end(ap);
 462 
 463         request.entry = buf;
 464         request.log_type = type;
 465         request.message_id = msg_id;
 466 
 467         if (ndmp_send_request(session->ns_connection, NDMP_LOG_MESSAGE,
 468             NDMP_NO_ERR, (void *)&request, 0) < 0) {
 469                 NDMP_LOG(LOG_DEBUG, "Error sending log message request.");
 470                 return (-1);
 471         }
 472         return (0);
 473 }
 474 
 475 
 476 /*
 477  * ndmpd_api_write_v3
 478  *
 479  * Callback function called by the backup/restore module.
 480  * Writes data to the mover.
 481  * If the mover is remote, the data is written to the data connection.
 482  * If the mover is local, the data is buffered and written to the
 483  * tape device after a full record has been buffered.
 484  *
 485  * Parameters:
 486  *   client_data (input) - session pointer.
 487  *   data       (input) - data to be written.
 488  *   length     (input) - data length.
 489  *
 490  * Returns:
 491  *   0 - data successfully written.
 492  *  -1 - error.
 493  */
 494 int
 495 ndmpd_api_write_v3(void *client_data, char *data, ulong_t length)
 496 {
 497         ndmpd_session_t *session = (ndmpd_session_t *)client_data;
 498 
 499         if (session == NULL)
 500                 return (-1);
 501 
 502         /*
 503          * Write the data to the tape if the mover is local, otherwise,
 504          * write the data to the data connection.
 505          *
 506          * The same write function for of v2 can be used in V3
 507          * for writing data to the data connection to the mover.
 508          * So we don't need ndmpd_remote_write_v3().
 509          */
 510         if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL)
 511                 return (ndmpd_local_write_v3(session, data, length));
 512         else
 513                 return (ndmpd_remote_write(session, data, length));
 514 }
 515 
 516 
 517 /*
 518  * ndmpd_api_read_v3
 519  *
 520  * Callback function called by the backup/recover module.
 521  * Reads data from the mover.
 522  * If the mover is remote, the data is read from the data connection.
 523  * If the mover is local, the data is read from the tape device.
 524  *
 525  * Parameters:
 526  *   client_data (input) - session pointer.
 527  *   data       (input) - data to be written.
 528  *   length     (input) - data length.
 529  *
 530  * Returns:
 531  *   0 - data successfully read.
 532  *  -1 - error.
 533  *   1 - session terminated or operation aborted.
 534  */
 535 int
 536 ndmpd_api_read_v3(void *client_data, char *data, ulong_t length)
 537 {
 538         ndmpd_session_t *session = (ndmpd_session_t *)client_data;
 539 
 540         if (session == NULL)
 541                 return (-1);
 542 
 543         /*
 544          * Read the data from the data connection if the mover is remote.
 545          */
 546         if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL)
 547                 return (ndmpd_local_read_v3(session, data, length));
 548         else
 549                 return (ndmpd_remote_read_v3(session, data, length));
 550 }
 551 
 552 
 553 /*
 554  * ndmpd_api_get_name_v3
 555  *
 556  * Return the name entry at the specified index from the
 557  * recover file name list.
 558  *
 559  * Parameters:
 560  *       cookie    (input) - NDMP session pointer.
 561  *       name_index (input) - index of entry to be returned.
 562  *
 563  * Returns:
 564  *   Pointer to name entry.
 565  *   0 if requested entry does not exist.
 566  */
 567 void *
 568 ndmpd_api_get_name_v3(void *cookie, ulong_t name_index)
 569 {
 570         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 571 
 572         if (session == NULL)
 573                 return (NULL);
 574 
 575         if (name_index >= session->ns_data.dd_nlist_len)
 576                 return (NULL);
 577 
 578         return (&session->ns_data.dd_nlist_v3[name_index]);
 579 }
 580 
 581 
 582 /*
 583  * ndmpd_api_file_recovered_v3
 584  *
 585  * Notify the NDMP client that the specified file was recovered.
 586  *
 587  * Parameters:
 588  *   cookie (input) - session pointer.
 589  *   name   (input) - name of recovered file.
 590  *   ssid   (input) - selection set id.
 591  *   error  (input) - 0 if file successfully recovered.
 592  *                  otherwise, error code indicating why recovery failed.
 593  *
 594  * Returns:
 595  *   0 - success.
 596  *  -1 - error.
 597  */
 598 int
 599 ndmpd_api_file_recovered_v3(void *cookie, char *name, int error)
 600 {
 601         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 602         ndmp_log_file_request_v3 request;
 603 
 604         if (session == NULL)
 605                 return (-1);
 606 
 607         request.name  = name;
 608 
 609         switch (error) {
 610         case 0:
 611                 request.error = NDMP_NO_ERR;
 612                 break;
 613         case ENOENT:
 614                 request.error = NDMP_FILE_NOT_FOUND_ERR;
 615                 break;
 616         default:
 617                 request.error = NDMP_PERMISSION_ERR;
 618         }
 619 
 620         if (ndmp_send_request_lock(session->ns_connection, NDMP_LOG_FILE,
 621             NDMP_NO_ERR, (void *)&request, 0) < 0) {
 622                 NDMP_LOG(LOG_DEBUG, "Error sending log file request");
 623                 return (-1);
 624         }
 625 
 626         return (0);
 627 }
 628 
 629 
 630 /*
 631  * ndmpd_api_seek_v3
 632  *
 633  * Seek to the specified position in the data stream and start a
 634  * read for the specified amount of data.
 635  *
 636  * Parameters:
 637  *   cookie (input) - session pointer.
 638  *   offset (input) - stream position to seek to.
 639  *   length (input) - amount of data that will be read using ndmpd_api_read
 640  *
 641  * Returns:
 642  *   0 - seek successful.
 643  *   1 - seek needed DMA(client) intervention.
 644  *  -1 - error.
 645  */
 646 int
 647 ndmpd_api_seek_v3(void *cookie, u_longlong_t offset, u_longlong_t length)
 648 {
 649         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 650         int err;
 651         ndmp_notify_data_read_request request;
 652 
 653         if (session == NULL)
 654                 return (-1);
 655 
 656         session->ns_data.dd_read_offset = offset;
 657         session->ns_data.dd_read_length = length;
 658 
 659         /*
 660          * Send a notify_data_read request if the mover is remote.
 661          */
 662         if (session->ns_data.dd_data_addr.addr_type != NDMP_ADDR_LOCAL) {
 663                 session->ns_data.dd_discard_length =
 664                     session->ns_data.dd_bytes_left_to_read;
 665                 session->ns_data.dd_bytes_left_to_read = length;
 666                 session->ns_data.dd_position = offset;
 667 
 668                 request.offset = long_long_to_quad(offset);
 669                 request.length = long_long_to_quad(length);
 670 
 671                 if (ndmp_send_request_lock(session->ns_connection,
 672                     NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
 673                     (void *)&request, 0) < 0) {
 674                         NDMP_LOG(LOG_DEBUG,
 675                             "Sending notify_data_read request");
 676                         return (-1);
 677                 }
 678 
 679                 return (0);
 680         }
 681 
 682         /* Mover is local. */
 683 
 684         err = ndmpd_mover_seek(session, offset, length);
 685         if (err < 0) {
 686                 ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR);
 687                 return (-1);
 688         }
 689 
 690         if (err == 0)
 691                 return (0);
 692 
 693         /*
 694          * NDMP client intervention is required to perform the seek.
 695          * Wait for the client to either do the seek and send a continue
 696          * request or send an abort request.
 697          */
 698         err = ndmp_wait_for_mover(session);
 699 
 700         /*
 701          * If we needed a client intervention, then we should be able to
 702          * detect this in DAR.
 703          */
 704         if (err == 0)
 705                 err = 1;
 706         return (err);
 707 }
 708 
 709 
 710 /*
 711  * ************************************************************************
 712  * NDMP V4 CALLBACKS
 713  * ************************************************************************
 714  */
 715 
 716 /*
 717  * ndmpd_api_log_v4
 718  *
 719  * Sends a log request to the NDMP client.
 720  * No message association is supported now, but can be added later on
 721  * in this function.
 722  *
 723  * Parameters:
 724  *   cookie (input) - session pointer.
 725  *   format (input) - printf style format.
 726  *   ...    (input) - format arguments.
 727  *
 728  * Returns:
 729  *   0 - success.
 730  *  -1 - error.
 731  */
 732 /*ARGSUSED*/
 733 int
 734 ndmpd_api_log_v4(void *cookie, ndmp_log_type type, ulong_t msg_id,
 735     char *format, ...)
 736 {
 737         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 738         ndmp_log_message_request_v4 request;
 739         static char buf[1024];
 740         va_list ap;
 741 
 742         if (session == NULL)
 743                 return (-1);
 744 
 745         va_start(ap, format);
 746 
 747         /*LINTED variable format specifier */
 748         (void) vsnprintf(buf, sizeof (buf), format, ap);
 749         va_end(ap);
 750 
 751         request.entry = buf;
 752         request.log_type = type;
 753         request.message_id = msg_id;
 754         request.associated_message_valid = NDMP_NO_ASSOCIATED_MESSAGE;
 755         request.associated_message_sequence = 0;
 756 
 757         if (ndmp_send_request(session->ns_connection, NDMP_LOG_MESSAGE,
 758             NDMP_NO_ERR, (void *)&request, 0) < 0) {
 759                 NDMP_LOG(LOG_DEBUG, "Error sending log message request.");
 760                 return (-1);
 761         }
 762         return (0);
 763 }
 764 
 765 
 766 /*
 767  * ndmpd_api_file_recovered_v4
 768  *
 769  * Notify the NDMP client that the specified file was recovered.
 770  *
 771  * Parameters:
 772  *   cookie (input) - session pointer.
 773  *   name   (input) - name of recovered file.
 774  *   ssid   (input) - selection set id.
 775  *   error  (input) - 0 if file successfully recovered.
 776  *                  otherwise, error code indicating why recovery failed.
 777  *
 778  * Returns:
 779  *   void.
 780  */
 781 int
 782 ndmpd_api_file_recovered_v4(void *cookie, char *name, int error)
 783 {
 784         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 785         ndmp_log_file_request_v4 request;
 786 
 787         if (session == NULL)
 788                 return (-1);
 789 
 790         request.name  = name;
 791 
 792         switch (error) {
 793         case 0:
 794                 request.recovery_status = NDMP_RECOVERY_SUCCESSFUL;
 795                 break;
 796         case EPERM:
 797                 request.recovery_status = NDMP_RECOVERY_FAILED_PERMISSION;
 798                 break;
 799         case ENOENT:
 800                 request.recovery_status = NDMP_RECOVERY_FAILED_NOT_FOUND;
 801                 break;
 802         case ENOTDIR:
 803                 request.recovery_status = NDMP_RECOVERY_FAILED_NO_DIRECTORY;
 804                 break;
 805         case ENOMEM:
 806                 request.recovery_status = NDMP_RECOVERY_FAILED_OUT_OF_MEMORY;
 807                 break;
 808         case EIO:
 809                 request.recovery_status = NDMP_RECOVERY_FAILED_IO_ERROR;
 810                 break;
 811         case EEXIST:
 812                 request.recovery_status = NDMP_RECOVERY_FAILED_FILE_PATH_EXISTS;
 813                 break;
 814         default:
 815                 request.recovery_status = NDMP_RECOVERY_FAILED_UNDEFINED_ERROR;
 816                 break;
 817         }
 818 
 819         if (ndmp_send_request_lock(session->ns_connection, NDMP_LOG_FILE,
 820             NDMP_NO_ERR, (void *)&request, 0) < 0) {
 821                 NDMP_LOG(LOG_DEBUG, "Error sending log file request");
 822                 return (-1);
 823         }
 824 
 825         return (0);
 826 }
 827 
 828 
 829 /*
 830  * ************************************************************************
 831  * LOCALS
 832  * ************************************************************************
 833  */
 834 
 835 /*
 836  * ndmpd_api_find_env
 837  *
 838  * Return the pointer of the environment variable from the variable
 839  * array for the spcified environment variable.
 840  *
 841  * Parameters:
 842  *       cookie (input) - NDMP session pointer.
 843  *       name   (input) - name of variable.
 844  *
 845  * Returns:
 846  *   Pointer to variable.
 847  *   NULL if variable not found.
 848  *
 849  */
 850 ndmp_pval *
 851 ndmpd_api_find_env(void *cookie, char *name)
 852 {
 853         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 854         ulong_t i;
 855         ndmp_pval *envp;
 856 
 857         if (session == NULL)
 858                 return (NULL);
 859 
 860         envp = session->ns_data.dd_env;
 861         for (i = 0; envp && i < session->ns_data.dd_env_len; envp++, i++)
 862                 if (strcmp(name, envp->name) == NULL)
 863                         return (envp);
 864 
 865         return (NULL);
 866 }
 867 
 868 
 869 /*
 870  * ndmpd_api_get_env
 871  *
 872  * Return the value of an environment variable from the variable array.
 873  *
 874  * Parameters:
 875  *       cookie (input) - NDMP session pointer.
 876  *       name   (input) - name of variable.
 877  *
 878  * Returns:
 879  *   Pointer to variable value.
 880  *   0 if variable not found.
 881  *
 882  */
 883 char *
 884 ndmpd_api_get_env(void *cookie, char *name)
 885 {
 886         ndmp_pval *envp;
 887 
 888         envp = ndmpd_api_find_env(cookie, name);
 889         if (envp)
 890                 return (envp->value);
 891 
 892         return (NULL);
 893 }
 894 
 895 
 896 /*
 897  * ndmpd_api_add_env
 898  *
 899  * Adds an environment variable name/value pair to the environment
 900  * variable list.
 901  *
 902  * Parameters:
 903  *   session (input) - session pointer.
 904  *   name    (input) - variable name.
 905  *   val     (input) - value.
 906  *
 907  * Returns:
 908  *   0 - success.
 909  *  -1 - error.
 910  */
 911 int
 912 ndmpd_api_add_env(void *cookie, char *name, char *value)
 913 {
 914         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
 915         char *namebuf;
 916         char *valbuf;
 917 
 918         if (session == NULL)
 919                 return (-1);
 920 
 921         session->ns_data.dd_env = realloc((void *)session->ns_data.dd_env,
 922             sizeof (ndmp_pval) * (session->ns_data.dd_env_len + 1));
 923 
 924         if (session->ns_data.dd_env == NULL) {
 925                 NDMP_LOG(LOG_ERR, "Out of memory.");
 926                 return (-1);
 927         }
 928         namebuf = strdup(name);
 929         if (namebuf == NULL)
 930                 return (-1);
 931 
 932         valbuf = strdup(value);
 933         if (valbuf == NULL) {
 934                 free(namebuf);
 935                 return (-1);
 936         }
 937 
 938         (void) mutex_lock(&session->ns_lock);
 939         session->ns_data.dd_env[session->ns_data.dd_env_len].name = namebuf;
 940         session->ns_data.dd_env[session->ns_data.dd_env_len].value = valbuf;
 941         session->ns_data.dd_env_len++;
 942         (void) mutex_unlock(&session->ns_lock);
 943 
 944         return (0);
 945 }
 946 
 947 
 948 /*
 949  * ndmpd_api_set_env
 950  *
 951  * Sets an environment variable name/value pair in the environment
 952  * variable list.  If the variable exists, it gets the new value,
 953  * otherwise it's added as a new variable.
 954  *
 955  * Parameters:
 956  *   session (input) - session pointer.
 957  *   name    (input) - variable name.
 958  *   val     (input) - value.
 959  *
 960  * Returns:
 961  *   0 - success.
 962  *  -1 - error.
 963  */
 964 int
 965 ndmpd_api_set_env(void *cookie, char *name, char *value)
 966 {
 967         char *valbuf;
 968         int rv;
 969         ndmp_pval *envp;
 970 
 971         envp = ndmpd_api_find_env(cookie, name);
 972         if (!envp) {
 973                 rv = ndmpd_api_add_env(cookie, name, value);
 974         } else if (!(valbuf = strdup(value))) {
 975                 rv = -1;
 976         } else {
 977                 rv = 0;
 978                 free(envp->value);
 979                 envp->value = valbuf;
 980         }
 981 
 982         return (rv);
 983 }
 984 
 985 
 986 /*
 987  * ndmpd_api_get_name
 988  *
 989  * Return the name entry at the specified index from the
 990  * recover file name list.
 991  *
 992  * Parameters:
 993  *   cookie    (input) - NDMP session pointer.
 994  *   name_index (input) - index of entry to be returned.
 995  *
 996  * Returns:
 997  *   Pointer to name entry.
 998  *   0 if requested entry does not exist.
 999  */
1000 void *
1001 ndmpd_api_get_name(void *cookie, ulong_t name_index)
1002 {
1003         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1004 
1005         if (session == NULL)
1006                 return (NULL);
1007 
1008         if (name_index >= session->ns_data.dd_nlist_len)
1009                 return (NULL);
1010 
1011         return (&session->ns_data.dd_nlist[name_index]);
1012 }
1013 
1014 
1015 /*
1016  * ndmpd_api_dispatch
1017  *
1018  * Process pending NDMP client requests and check registered files for
1019  * data availability.
1020  *
1021  * Parameters:
1022  *   cookie (input) - session pointer.
1023  *   block  (input) -
1024  *              TRUE    block until a request has been processed or
1025  *                      until a file handler has been called.
1026  *              FALSE   don't block.
1027  *
1028  * Returns:
1029  *  -1 - abort request received or connection closed.
1030  *   0 - success.
1031  */
1032 int
1033 ndmpd_api_dispatch(void *cookie, boolean_t block)
1034 {
1035         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1036         int err;
1037 
1038         if (session == NULL)
1039                 return (-1);
1040 
1041         for (; ; ) {
1042                 err = ndmpd_select(session, block, HC_ALL);
1043                 if (err < 0 || session->ns_data.dd_abort == TRUE ||
1044                     session->ns_eof)
1045                         return (-1);
1046 
1047                 if (err == 0)
1048                         return (0);
1049 
1050                 /*
1051                  * Something was processed.
1052                  * Set the block flag to false so that we will return as
1053                  * soon as everything available to be processed has been
1054                  * processed.
1055                  */
1056                 block = FALSE;
1057         }
1058 }
1059 
1060 
1061 /*
1062  * ndmpd_api_add_file_handler
1063  *
1064  * Adds a file handler to the file handler list.
1065  * The file handler list is used by ndmpd_api_dispatch.
1066  *
1067  * Parameters:
1068  *   daemon_cookie (input) - session pointer.
1069  *   cookie  (input) - opaque data to be passed to file hander when called.
1070  *   fd      (input) - file descriptor.
1071  *   mode    (input) - bitmask of the following:
1072  *      NDMP_SELECT_MODE_READ = watch file for ready for reading
1073  *      NDMP_SELECT_MODE_WRITE = watch file for ready for writing
1074  *      NDMP_SELECT_MODE_EXCEPTION = watch file for exception
1075  *   func    (input) - function to call when the file meets one of the
1076  *                   conditions specified by mode.
1077  *
1078  * Returns:
1079  *   0 - success.
1080  *  -1 - error.
1081  */
1082 int
1083 ndmpd_api_add_file_handler(void *daemon_cookie, void *cookie, int fd,
1084     ulong_t mode, ndmpd_file_handler_func_t *func)
1085 {
1086         ndmpd_session_t *session = (ndmpd_session_t *)daemon_cookie;
1087 
1088         return (ndmpd_add_file_handler(session, cookie, fd, mode, HC_MODULE,
1089             func));
1090 }
1091 
1092 
1093 /*
1094  * ndmpd_api_remove_file_handler
1095  *
1096  * Removes a file handler from the file handler list.
1097  *
1098  * Parameters:
1099  *   cookie  (input) - session pointer.
1100  *   fd      (input) - file descriptor.
1101  *
1102  * Returns:
1103  *   0 - success.
1104  *  -1 - error.
1105  */
1106 int
1107 ndmpd_api_remove_file_handler(void *cookie, int fd)
1108 {
1109         ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1110 
1111         return (ndmpd_remove_file_handler(session, fd));
1112 }