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