Print this page
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Revert "NEX-5801 Snapshots left over after failed backups"
This reverts commit f182fb95f09036db71fbfc6f0a6b90469b761f21.
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-2911 NDMP logging should use syslog and is too chatty
NEX-1123 NDMP commands can not uniquely identify Nexenta and the file server version (currently 4.0.1) and Sun Microsystems.
OS-49 Switch back to illumos' version of wcwidth()
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-426 ndmp_config_get_ext_list failed
NEX-250 Failed to open device /dev/rmt/0n because of too many files open


  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 <dirent.h>
  43 #include <errno.h>
  44 #include <stdio.h>
  45 #include <stdlib.h>
  46 #include <string.h>

  47 #include <sys/stat.h>
  48 #include <sys/mnttab.h>
  49 #include <sys/mntent.h>
  50 #include <sys/mntio.h>
  51 #include <sys/statvfs.h>
  52 #include <sys/utsname.h>
  53 #include <sys/scsi/scsi.h>
  54 #include <unistd.h>
  55 #include <sys/systeminfo.h>
  56 #include "ndmpd_common.h"
  57 #include "ndmpd.h"
  58 
  59 static void simple_get_attrs(ulong_t *attributes);
  60 
  61 /*
  62  * Number of environment variable for the file system
  63  * info in V3 net_fs_info.
  64  */
  65 #define V3_N_FS_ENVS    4
  66 


 105 ndmpd_config_get_host_info_v2(ndmp_connection_t *connection, void *body)
 106 {
 107         ndmp_config_get_host_info_reply_v2 reply;
 108         ndmp_auth_type auth_types[2];
 109         char buf[HOSTNAMELEN + 1];
 110         struct utsname uts;
 111         char hostidstr[16];
 112         ulong_t hostid;
 113 
 114         (void) memset((void*)&reply, 0, sizeof (reply));
 115         (void) memset(buf, 0, sizeof (buf));
 116         (void) gethostname(buf, sizeof (buf));
 117 
 118         reply.error = NDMP_NO_ERR;
 119         reply.hostname = buf;
 120         (void) uname(&uts);
 121         reply.os_type = uts.sysname;
 122         reply.os_vers = uts.release;
 123 
 124         if (sysinfo(SI_HW_SERIAL, hostidstr, sizeof (hostidstr)) < 0) {
 125                 NDMP_LOG(LOG_DEBUG, "sysinfo error: %m.");
 126                 reply.error = NDMP_UNDEFINED_ERR;
 127         }
 128 
 129         /*
 130          * Convert the hostid to hex. The returned string must match
 131          * the string returned by hostid(1).
 132          */
 133         hostid = strtoul(hostidstr, 0, 0);
 134         (void) snprintf(hostidstr, sizeof (hostidstr), "%lx", hostid);
 135         reply.hostid = hostidstr;
 136 
 137         auth_types[0] = NDMP_AUTH_TEXT;
 138         reply.auth_type.auth_type_len = 1;
 139         reply.auth_type.auth_type_val = auth_types;
 140 
 141         ndmp_send_reply(connection, (void *) &reply,
 142             "sending ndmp_config_get_host_info reply");
 143 }
 144 
 145 


 154  *   body       (input) - request message body.
 155  *
 156  * Returns:
 157  *   void
 158  */
 159 void
 160 ndmpd_config_get_butype_attr_v2(ndmp_connection_t *connection, void *body)
 161 {
 162         ndmp_config_get_butype_attr_request *request;
 163         ndmp_config_get_butype_attr_reply reply;
 164 
 165         request = (ndmp_config_get_butype_attr_request *)body;
 166 
 167         reply.error = NDMP_NO_ERR;
 168 
 169         if (strcmp(request->name, "dump") == 0) {
 170                 (void) simple_get_attrs(&reply.attrs);
 171         } else if (strcmp(request->name, "tar") == 0) {
 172                 reply.attrs = NDMP_NO_BACKUP_FILELIST;
 173         } else {
 174                 NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", request->name);
 175                 NDMP_LOG(LOG_ERR,
 176                     "Supported backup types are 'dump' and 'tar' only.");
 177                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 178         }
 179 
 180         ndmp_send_reply(connection, (void *) &reply,
 181             "sending ndmp_config_get_butype_attr reply");
 182 }
 183 
 184 
 185 /*
 186  * ndmpd_config_get_mover_type_v2
 187  *
 188  * This handler handles the ndmp_config_get_mover_type request.
 189  * Information about the supported mover types is returned.
 190  *
 191  * Parameters:
 192  *   connection (input) - connection handle.
 193  *   body       (input) - request message body.
 194  *
 195  * Returns:


 235         ndmp_config_get_auth_attr_reply reply;
 236         ndmpd_session_t *session = ndmp_get_client_data(connection);
 237 
 238         request = (ndmp_config_get_auth_attr_request *)body;
 239 
 240         reply.error = NDMP_NO_ERR;
 241         reply.server_attr.auth_type = request->auth_type;
 242 
 243         switch (request->auth_type) {
 244         case NDMP_AUTH_TEXT:
 245                 break;
 246         case NDMP_AUTH_MD5:
 247                 /* Create a 64 byte random session challenge */
 248                 randomize(session->ns_challenge, MD5_CHALLENGE_SIZE);
 249                 (void) memcpy(reply.server_attr.ndmp_auth_attr_u.challenge,
 250                     session->ns_challenge, MD5_CHALLENGE_SIZE);
 251                 break;
 252         case NDMP_AUTH_NONE:
 253                 /* FALL THROUGH */
 254         default:
 255                 NDMP_LOG(LOG_ERR, "Invalid authentication type: %d.",
 256                     request->auth_type);
 257                 NDMP_LOG(LOG_ERR,
 258                     "Supported authentication types are md5 and cleartext.");
 259                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 260                 break;
 261         }
 262 
 263         ndmp_send_reply(connection, (void *) &reply,
 264             "sending ndmp_config_get_auth_attr reply");
 265 }
 266 
 267 
 268 /*
 269  * ************************************************************************
 270  * NDMP V3 HANDLERS
 271  * ************************************************************************
 272  */
 273 
 274 /*
 275  * ndmpd_config_get_host_info_v3
 276  *
 277  * This handler handles the ndmp_config_get_host_info request.


 290 {
 291         ndmp_config_get_host_info_reply_v3 reply;
 292         char buf[HOSTNAMELEN+1];
 293         struct utsname uts;
 294         char hostidstr[16];
 295         ulong_t hostid;
 296 
 297         (void) memset((void*)&reply, 0, sizeof (reply));
 298         (void) memset(buf, 0, sizeof (buf));
 299         (void) gethostname(buf, sizeof (buf));
 300 
 301 
 302         reply.error = NDMP_NO_ERR;
 303         reply.hostname = buf;
 304         (void) uname(&uts);
 305         reply.os_type = uts.sysname;
 306         reply.os_vers = uts.release;
 307 
 308         if (sysinfo(SI_HW_SERIAL, hostidstr, sizeof (hostidstr)) < 0) {
 309 
 310                 NDMP_LOG(LOG_DEBUG, "sysinfo error: %m.");
 311                 reply.error = NDMP_UNDEFINED_ERR;
 312         }
 313 
 314         /*
 315          * Convert the hostid to hex. The returned string must match
 316          * the string returned by hostid(1).
 317          */
 318         hostid = strtoul(hostidstr, 0, 0);
 319         (void) snprintf(hostidstr, sizeof (hostidstr), "%lx", hostid);
 320         reply.hostid = hostidstr;
 321 
 322         ndmp_send_reply(connection, (void *) &reply,
 323             "sending ndmp_config_get_host_info reply");
 324 }
 325 
 326 
 327 /*
 328  * ndmpd_config_get_connection_type_v3
 329  *
 330  * This handler handles the ndmp_config_get_connection_type_request.


 381         ndmpd_session_t *session = ndmp_get_client_data(connection);
 382 
 383         request = (ndmp_config_get_auth_attr_request *)body;
 384 
 385         (void) memset((void*)&reply, 0, sizeof (reply));
 386         reply.error = NDMP_NO_ERR;
 387         reply.server_attr.auth_type = request->auth_type;
 388 
 389         switch (request->auth_type) {
 390         case NDMP_AUTH_TEXT:
 391                 break;
 392         case NDMP_AUTH_MD5:
 393                 /* Create a 64 bytes random session challenge */
 394                 randomize(session->ns_challenge, MD5_CHALLENGE_SIZE);
 395                 (void) memcpy(reply.server_attr.ndmp_auth_attr_u.challenge,
 396                     session->ns_challenge, MD5_CHALLENGE_SIZE);
 397                 break;
 398         case NDMP_AUTH_NONE:
 399                 /* FALL THROUGH */
 400         default:
 401                 NDMP_LOG(LOG_ERR, "Invalid authentication type: %d.",
 402                     request->auth_type);
 403                 NDMP_LOG(LOG_ERR,
 404                     "Supported authentication types are md5 and cleartext.");
 405                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 406                 break;
 407         }
 408 
 409         ndmp_send_reply(connection, (void *) &reply,
 410             "sending ndmp_config_get_auth_attr_v3 reply");
 411 }
 412 
 413 
 414 /*
 415  * ndmpd_config_get_butype_info_v3
 416  *
 417  * This handler handles the ndmp_config_get_butype_info_request.
 418  * Information about all supported backup types are returned.
 419  *
 420  * Parameters:
 421  *   connection (input) - connection handle.
 422  *   body       (input) - request message body.
 423  *


 526  * Returns:
 527  *   void
 528  */
 529 /*ARGSUSED*/
 530 void
 531 ndmpd_config_get_fs_info_v3(ndmp_connection_t *connection, void *body)
 532 {
 533         ndmp_config_get_fs_info_reply_v3 reply;
 534         ndmp_fs_info_v3 *fsip = NULL, *fsip_save = NULL; /* FS info pointer */
 535         int len = 0, nmnt, fd;
 536         int log_dev_len;
 537         FILE *fp = NULL;
 538         struct mnttab mt, *fs;
 539         struct statvfs64 stat_buf;
 540         ndmp_pval *envp, *save;
 541 
 542         (void) memset((void*)&reply, 0, sizeof (reply));
 543         reply.error = NDMP_NO_ERR;
 544 
 545         if ((fd = open(MNTTAB, O_RDONLY)) == -1) {
 546                 NDMP_LOG(LOG_ERR, "File mnttab open error: %m.");
 547                 reply.error = NDMP_UNDEFINED_ERR;
 548                 goto send_reply;
 549         }
 550 
 551         /* nothing was found, send an empty reply */
 552         if (ioctl(fd, MNTIOC_NMNTS, &nmnt) != 0 || nmnt <= 0) {
 553                 (void) close(fd);
 554                 NDMP_LOG(LOG_ERR, "No file system found.");
 555                 goto send_reply;
 556         }
 557 
 558         fp = fdopen(fd, "r");
 559         if (!fp) {
 560                 (void) close(fd);
 561                 NDMP_LOG(LOG_ERR, "File mnttab open error: %m.");
 562                 reply.error = NDMP_UNDEFINED_ERR;
 563                 goto send_reply;
 564         }
 565 
 566         fsip_save = fsip = ndmp_malloc(sizeof (ndmp_fs_info_v3) * nmnt);
 567         if (!fsip) {
 568                 (void) fclose(fp);
 569                 reply.error = NDMP_NO_MEM_ERR;
 570                 goto send_reply;
 571         }
 572 
 573         /*
 574          * Re-read the directory and set up file system information.
 575          */
 576         rewind(fp);
 577         while (len < nmnt && (getmntent(fp, &mt) == 0))
 578 
 579         {
 580                 fs = &mt;
 581                 log_dev_len = strlen(mt.mnt_mountp)+2;
 582                 if (!IS_VALID_FS(fs))
 583                         continue;
 584 
 585                 fsip->fs_logical_device = ndmp_malloc(log_dev_len);
 586                 fsip->fs_type = ndmp_malloc(MNTTYPE_LEN);
 587                 if (!fsip->fs_logical_device || !fsip->fs_type) {
 588                         free(fsip->fs_logical_device);
 589                         free(fsip->fs_type);
 590                         reply.error = NDMP_NO_MEM_ERR;
 591                         break;
 592                 }
 593                 (void) snprintf(fsip->fs_type, MNTTYPE_LEN, "%s",
 594                     fs->mnt_fstype);
 595                 (void) snprintf(fsip->fs_logical_device, log_dev_len, "%s",
 596                     fs->mnt_mountp);
 597                 fsip->invalid = 0;
 598 
 599                 if (statvfs64(fs->mnt_mountp, &stat_buf) < 0) {
 600                         NDMP_LOG(LOG_DEBUG,
 601                             "statvfs(%s) error.", fs->mnt_mountp);
 602                         fsip->fs_status =
 603                             "statvfs error: unable to determine filesystem"
 604                             " attributes";
 605                 } else {
 606                         fsip->invalid = 0;
 607                         fsip->total_size =
 608                             long_long_to_quad((u_longlong_t)stat_buf.f_frsize *
 609                             (u_longlong_t)stat_buf.f_blocks);
 610                         fsip->used_size =
 611                             long_long_to_quad((u_longlong_t)stat_buf.f_frsize *
 612                             (u_longlong_t)(stat_buf.f_blocks-stat_buf.f_bfree));
 613 
 614                         fsip->avail_size =
 615                             long_long_to_quad((u_longlong_t)stat_buf.f_frsize *
 616                             (u_longlong_t)stat_buf.f_bfree);
 617                         fsip->total_inodes =
 618                             long_long_to_quad((u_longlong_t)stat_buf.f_files);
 619                         fsip->used_inodes =
 620                             long_long_to_quad((u_longlong_t)(stat_buf.f_files -


 704                 free(envp_save);
 705                 reply.error = NDMP_NO_MEM_ERR;
 706                 ndmp_send_reply(connection, (void *)&reply,
 707                     "error sending ndmp_config_get_tape_info reply");
 708                 return;
 709         }
 710 
 711         reply.error = NDMP_NO_ERR;
 712 
 713         for (i = n = 0; i < max; i++) {
 714                 if (!(sl = sasd_dev_slink(i)) || !(sd = sasd_drive(i)))
 715                         continue;
 716                 if (sl->sl_type != DTYPE_SEQUENTIAL)
 717                         continue;
 718                 /*
 719                  * Don't report dead links.
 720                  */
 721                 if ((access(sd->sd_name, F_OK) == -1) && (errno == ENOENT))
 722                         continue;
 723 
 724                 NDMP_LOG(LOG_DEBUG,
 725                     "model \"%s\" dev \"%s\"", sd->sd_id, sd->sd_name);
 726 
 727                 envp_head = envp;
 728                 NDMP_SETENV(envp, "EXECUTE_CDB", "b");
 729                 NDMP_SETENV(envp, "SERIAL_NUMBER", sd->sd_serial);
 730                 NDMP_SETENV(envp, "WORLD_WIDE_NAME", sd->sd_wwn);
 731 
 732                 tip->model = sd->sd_id; /* like "DLT7000   " */
 733                 tip->caplist.caplist_len = 1;
 734                 tip->caplist.caplist_val = dcp;
 735                 dcp->device = sd->sd_name; /* like "isp1t060" */
 736                 dcp->attr = 0;
 737                 dcp->capability.capability_len = 3;
 738                 dcp->capability.capability_val = envp_head;
 739                 tip++;
 740                 dcp++;
 741                 n++;
 742         }
 743 
 744         NDMP_LOG(LOG_DEBUG, "n %d", n);
 745 
 746         /*
 747          * We should not receive the get_tape_info when three-way backup is
 748          * running and we are acting as just data, but some clients try
 749          * to get the Tape information anyway.
 750          */
 751         if (n == 0 || max <= 0) {
 752                 reply.error = NDMP_NO_DEVICE_ERR;
 753                 ndmp_send_reply(connection, (void *)&reply,
 754                     "error sending ndmp_config_get_tape_info reply");
 755                 free(tip_save); free(dcp_save); free(envp_save);
 756                 return;
 757         }
 758 
 759 
 760         reply.tape_info.tape_info_len = n;
 761         reply.tape_info.tape_info_val = tip_save;
 762 
 763         ndmp_send_reply(connection, (void *)&reply,
 764             "error sending ndmp_config_get_tape_info reply");
 765 


 806                 free(dcp_save);
 807                 free(envp_save);
 808                 reply.error = NDMP_NO_MEM_ERR;
 809                 ndmp_send_reply(connection, (void *)&reply,
 810                     "error sending ndmp_config_get_scsi_info reply");
 811                 return;
 812         }
 813 
 814         reply.error = NDMP_NO_ERR;
 815         for (i = n = 0; i < max; i++) {
 816                 if (!(sl = sasd_dev_slink(i)) || !(sd = sasd_drive(i)))
 817                         continue;
 818                 if (sl->sl_type != DTYPE_CHANGER)
 819                         continue;
 820                 /*
 821                  * Don't report dead links.
 822                  */
 823                 if ((access(sd->sd_name, F_OK) == -1) && (errno == ENOENT))
 824                         continue;
 825 
 826                 NDMP_LOG(LOG_DEBUG,
 827                     "model \"%s\" dev \"%s\"", sd->sd_id, sd->sd_name);
 828 
 829                 envp_head = envp;
 830                 NDMP_SETENV(envp, "SERIAL_NUMBER", sd->sd_serial);
 831                 NDMP_SETENV(envp, "WORLD_WIDE_NAME", sd->sd_wwn);
 832 
 833                 sip->model = sd->sd_id; /* like "Powerstor L200  " */
 834                 sip->caplist.caplist_len = 1;
 835                 sip->caplist.caplist_val = dcp;
 836                 dcp->device = sd->sd_name; /* like "isp1m000" */
 837 
 838                 dcp->attr = 0;
 839                 dcp->capability.capability_len = 2;
 840                 dcp->capability.capability_val = envp_head;
 841                 sip++;
 842                 dcp++;
 843                 n++;
 844         }
 845 
 846         NDMP_LOG(LOG_DEBUG, "n %d", n);
 847 
 848         reply.scsi_info.scsi_info_len = n;
 849         reply.scsi_info.scsi_info_val = sip_save;
 850 
 851         ndmp_send_reply(connection, (void *)&reply,
 852             "error sending ndmp_config_get_scsi_info reply");
 853 
 854         free(sip_save);
 855         free(dcp_save);
 856         free(envp_save);
 857 }
 858 
 859 
 860 /*
 861  * ndmpd_config_get_server_info_v3
 862  *
 863  * This handler handles the ndmp_config_get_server_info request.
 864  * Host specific information is returned.
 865  *
 866  * Parameters:
 867  *   connection (input) - connection handle.
 868  *   body       (input) - request message body.
 869  *
 870  * Returns:
 871  *   void
 872  */
 873 /*ARGSUSED*/
 874 void
 875 ndmpd_config_get_server_info_v3(ndmp_connection_t *connection, void *body)
 876 {
 877         ndmp_config_get_server_info_reply_v3 reply;
 878         ndmp_auth_type auth_types[2];
 879         char rev_number[10];
 880         ndmpd_session_t *session = ndmp_get_client_data(connection);


 881 
 882         (void) memset((void*)&reply, 0, sizeof (reply));
 883         reply.error = NDMP_NO_ERR;
 884 
 885         if (connection->conn_authorized ||
 886             session->ns_protocol_version != NDMPV4) {


 887                 reply.vendor_name = VENDOR_NAME;





 888                 reply.product_name = PRODUCT_NAME;



 889                 (void) snprintf(rev_number, sizeof (rev_number), "%d",
 890                     ndmp_ver);
 891                 reply.revision_number = rev_number;
 892         } else {
 893                 reply.vendor_name = "\0";
 894                 reply.product_name = "\0";
 895                 reply.revision_number = "\0";
 896         }
 897 
 898         NDMP_LOG(LOG_DEBUG,
 899             "vendor \"%s\", product \"%s\" rev \"%s\"",
 900             reply.vendor_name, reply.product_name, reply.revision_number);
 901 
 902         auth_types[0] = NDMP_AUTH_TEXT;
 903         auth_types[1] = NDMP_AUTH_MD5;
 904         reply.auth_type.auth_type_len = ARRAY_LEN(auth_types, ndmp_auth_type);
 905         reply.auth_type.auth_type_val = auth_types;
 906 
 907         ndmp_send_reply(connection, (void *)&reply,
 908             "error sending ndmp_config_get_server_info reply");
 909 }
 910 
 911 
 912 
 913 /*
 914  * ************************************************************************
 915  * NDMP V4 HANDLERS
 916  * ************************************************************************
 917  */
 918 
 919 /*
 920  * ndmpd_config_get_butype_info_v4
 921  *


1038  * Parameters:
1039  *   connection (input) - connection handle.
1040  *   body       (input) - request message body.
1041  *
1042  * Returns:
1043  *   void
1044  */
1045 /*ARGSUSED*/
1046 void
1047 ndmpd_config_get_ext_list_v4(ndmp_connection_t *connection, void *body)
1048 {
1049         ndmp_config_get_ext_list_reply_v4 reply;
1050         ndmpd_session_t *session = ndmp_get_client_data(connection);
1051 
1052         (void) memset((void*)&reply, 0, sizeof (reply));
1053 
1054         if (session->ns_set_ext_list) {
1055                 /*
1056                  * Illegal request if extensions have already been selected.
1057                  */
1058                 NDMP_LOG(LOG_ERR, "Extensions have already been selected.");
1059                 reply.error = NDMP_EXT_DANDN_ILLEGAL_ERR;
1060         } else {
1061                 /*
1062                  * Reply with an empty set of extensions.
1063                  */
1064                 session->ns_get_ext_list = B_TRUE;
1065                 reply.error = NDMP_NO_ERR;
1066         }
1067 
1068         reply.class_list.class_list_val = NULL;
1069         reply.class_list.class_list_len = 0;
1070 
1071         ndmp_send_reply(connection, (void *)&reply,
1072             "error sending ndmp_config_get_ext_list reply");
1073 }
1074 
1075 /*
1076  * ndmpd_config_set_ext_list_v4
1077  *
1078  * This handler handles the ndmpd_config_get_ext_list_v4 request.


1083  *
1084  * Returns:
1085  *   void
1086  */
1087 void
1088 ndmpd_config_set_ext_list_v4(ndmp_connection_t *connection, void *body)
1089 {
1090         ndmp_config_set_ext_list_reply_v4 reply;
1091         ndmp_config_set_ext_list_request_v4 *request;
1092         ndmpd_session_t *session = ndmp_get_client_data(connection);
1093 
1094         request = (ndmp_config_set_ext_list_request_v4 *)body;
1095 
1096         (void) memset((void*)&reply, 0, sizeof (reply));
1097 
1098         if (!session->ns_get_ext_list) {
1099                 /*
1100                  * The DMA is required to issue a NDMP_GET_EXT_LIST request
1101                  * prior sending a NDMP_SET_EXT_LIST request.
1102                  */
1103                 NDMP_LOG(LOG_ERR, "No prior ndmp_config_get_ext_list issued.");
1104                 reply.error = NDMP_PRECONDITION_ERR;
1105         } else if (session->ns_set_ext_list) {
1106                 /*
1107                  * Illegal request if extensions have already been selected.
1108                  */
1109                 NDMP_LOG(LOG_ERR, "Extensions have already been selected.");
1110                 reply.error = NDMP_EXT_DANDN_ILLEGAL_ERR;
1111         } else {
1112                 /*
1113                  * We currently do not support any extensions, but the DMA
1114                  * may test NDMP_CONFIG_SET_EXT_LIST with an empty list.
1115                  */
1116                 if (request->ndmp_selected_ext.ndmp_selected_ext_len != 0) {
1117                         reply.error = NDMP_CLASS_NOT_SUPPORTED_ERR;
1118                 } else {
1119                         session->ns_set_ext_list = B_TRUE;
1120                         reply.error = NDMP_NO_ERR;
1121                 }
1122         }
1123 
1124         ndmp_send_reply(connection, (void *)&reply,
1125             "error sending ndmp_config_set_ext_list reply");
1126 }
1127 
1128 
1129 




  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 2016 Nexenta Systems, Inc.  All rights reserved. */
  41 
  42 #include <dirent.h>
  43 #include <errno.h>
  44 #include <stdio.h>
  45 #include <stdlib.h>
  46 #include <string.h>
  47 #include <syslog.h>
  48 #include <sys/stat.h>
  49 #include <sys/mnttab.h>
  50 #include <sys/mntent.h>
  51 #include <sys/mntio.h>
  52 #include <sys/statvfs.h>
  53 #include <sys/utsname.h>
  54 #include <sys/scsi/scsi.h>
  55 #include <unistd.h>
  56 #include <sys/systeminfo.h>
  57 #include "ndmpd_common.h"
  58 #include "ndmpd.h"
  59 
  60 static void simple_get_attrs(ulong_t *attributes);
  61 
  62 /*
  63  * Number of environment variable for the file system
  64  * info in V3 net_fs_info.
  65  */
  66 #define V3_N_FS_ENVS    4
  67 


 106 ndmpd_config_get_host_info_v2(ndmp_connection_t *connection, void *body)
 107 {
 108         ndmp_config_get_host_info_reply_v2 reply;
 109         ndmp_auth_type auth_types[2];
 110         char buf[HOSTNAMELEN + 1];
 111         struct utsname uts;
 112         char hostidstr[16];
 113         ulong_t hostid;
 114 
 115         (void) memset((void*)&reply, 0, sizeof (reply));
 116         (void) memset(buf, 0, sizeof (buf));
 117         (void) gethostname(buf, sizeof (buf));
 118 
 119         reply.error = NDMP_NO_ERR;
 120         reply.hostname = buf;
 121         (void) uname(&uts);
 122         reply.os_type = uts.sysname;
 123         reply.os_vers = uts.release;
 124 
 125         if (sysinfo(SI_HW_SERIAL, hostidstr, sizeof (hostidstr)) < 0) {
 126                 syslog(LOG_ERR, "sysinfo error: %m.");
 127                 reply.error = NDMP_UNDEFINED_ERR;
 128         }
 129 
 130         /*
 131          * Convert the hostid to hex. The returned string must match
 132          * the string returned by hostid(1).
 133          */
 134         hostid = strtoul(hostidstr, 0, 0);
 135         (void) snprintf(hostidstr, sizeof (hostidstr), "%lx", hostid);
 136         reply.hostid = hostidstr;
 137 
 138         auth_types[0] = NDMP_AUTH_TEXT;
 139         reply.auth_type.auth_type_len = 1;
 140         reply.auth_type.auth_type_val = auth_types;
 141 
 142         ndmp_send_reply(connection, (void *) &reply,
 143             "sending ndmp_config_get_host_info reply");
 144 }
 145 
 146 


 155  *   body       (input) - request message body.
 156  *
 157  * Returns:
 158  *   void
 159  */
 160 void
 161 ndmpd_config_get_butype_attr_v2(ndmp_connection_t *connection, void *body)
 162 {
 163         ndmp_config_get_butype_attr_request *request;
 164         ndmp_config_get_butype_attr_reply reply;
 165 
 166         request = (ndmp_config_get_butype_attr_request *)body;
 167 
 168         reply.error = NDMP_NO_ERR;
 169 
 170         if (strcmp(request->name, "dump") == 0) {
 171                 (void) simple_get_attrs(&reply.attrs);
 172         } else if (strcmp(request->name, "tar") == 0) {
 173                 reply.attrs = NDMP_NO_BACKUP_FILELIST;
 174         } else {
 175                 syslog(LOG_ERR, "Invalid backup type: %s.", request->name);
 176                 syslog(LOG_ERR,
 177                     "Supported backup types are 'dump' and 'tar' only.");
 178                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 179         }
 180 
 181         ndmp_send_reply(connection, (void *) &reply,
 182             "sending ndmp_config_get_butype_attr reply");
 183 }
 184 
 185 
 186 /*
 187  * ndmpd_config_get_mover_type_v2
 188  *
 189  * This handler handles the ndmp_config_get_mover_type request.
 190  * Information about the supported mover types is returned.
 191  *
 192  * Parameters:
 193  *   connection (input) - connection handle.
 194  *   body       (input) - request message body.
 195  *
 196  * Returns:


 236         ndmp_config_get_auth_attr_reply reply;
 237         ndmpd_session_t *session = ndmp_get_client_data(connection);
 238 
 239         request = (ndmp_config_get_auth_attr_request *)body;
 240 
 241         reply.error = NDMP_NO_ERR;
 242         reply.server_attr.auth_type = request->auth_type;
 243 
 244         switch (request->auth_type) {
 245         case NDMP_AUTH_TEXT:
 246                 break;
 247         case NDMP_AUTH_MD5:
 248                 /* Create a 64 byte random session challenge */
 249                 randomize(session->ns_challenge, MD5_CHALLENGE_SIZE);
 250                 (void) memcpy(reply.server_attr.ndmp_auth_attr_u.challenge,
 251                     session->ns_challenge, MD5_CHALLENGE_SIZE);
 252                 break;
 253         case NDMP_AUTH_NONE:
 254                 /* FALL THROUGH */
 255         default:
 256                 syslog(LOG_ERR, "Invalid authentication type: %d.",
 257                     request->auth_type);
 258                 syslog(LOG_ERR,
 259                     "Supported authentication types are md5 and cleartext.");
 260                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 261                 break;
 262         }
 263 
 264         ndmp_send_reply(connection, (void *) &reply,
 265             "sending ndmp_config_get_auth_attr reply");
 266 }
 267 
 268 
 269 /*
 270  * ************************************************************************
 271  * NDMP V3 HANDLERS
 272  * ************************************************************************
 273  */
 274 
 275 /*
 276  * ndmpd_config_get_host_info_v3
 277  *
 278  * This handler handles the ndmp_config_get_host_info request.


 291 {
 292         ndmp_config_get_host_info_reply_v3 reply;
 293         char buf[HOSTNAMELEN+1];
 294         struct utsname uts;
 295         char hostidstr[16];
 296         ulong_t hostid;
 297 
 298         (void) memset((void*)&reply, 0, sizeof (reply));
 299         (void) memset(buf, 0, sizeof (buf));
 300         (void) gethostname(buf, sizeof (buf));
 301 
 302 
 303         reply.error = NDMP_NO_ERR;
 304         reply.hostname = buf;
 305         (void) uname(&uts);
 306         reply.os_type = uts.sysname;
 307         reply.os_vers = uts.release;
 308 
 309         if (sysinfo(SI_HW_SERIAL, hostidstr, sizeof (hostidstr)) < 0) {
 310 
 311                 syslog(LOG_ERR, "sysinfo error: %m.");
 312                 reply.error = NDMP_UNDEFINED_ERR;
 313         }
 314 
 315         /*
 316          * Convert the hostid to hex. The returned string must match
 317          * the string returned by hostid(1).
 318          */
 319         hostid = strtoul(hostidstr, 0, 0);
 320         (void) snprintf(hostidstr, sizeof (hostidstr), "%lx", hostid);
 321         reply.hostid = hostidstr;
 322 
 323         ndmp_send_reply(connection, (void *) &reply,
 324             "sending ndmp_config_get_host_info reply");
 325 }
 326 
 327 
 328 /*
 329  * ndmpd_config_get_connection_type_v3
 330  *
 331  * This handler handles the ndmp_config_get_connection_type_request.


 382         ndmpd_session_t *session = ndmp_get_client_data(connection);
 383 
 384         request = (ndmp_config_get_auth_attr_request *)body;
 385 
 386         (void) memset((void*)&reply, 0, sizeof (reply));
 387         reply.error = NDMP_NO_ERR;
 388         reply.server_attr.auth_type = request->auth_type;
 389 
 390         switch (request->auth_type) {
 391         case NDMP_AUTH_TEXT:
 392                 break;
 393         case NDMP_AUTH_MD5:
 394                 /* Create a 64 bytes random session challenge */
 395                 randomize(session->ns_challenge, MD5_CHALLENGE_SIZE);
 396                 (void) memcpy(reply.server_attr.ndmp_auth_attr_u.challenge,
 397                     session->ns_challenge, MD5_CHALLENGE_SIZE);
 398                 break;
 399         case NDMP_AUTH_NONE:
 400                 /* FALL THROUGH */
 401         default:
 402                 syslog(LOG_ERR, "Invalid authentication type: %d.",
 403                     request->auth_type);
 404                 syslog(LOG_ERR,
 405                     "Supported authentication types are md5 and cleartext.");
 406                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 407                 break;
 408         }
 409 
 410         ndmp_send_reply(connection, (void *) &reply,
 411             "sending ndmp_config_get_auth_attr_v3 reply");
 412 }
 413 
 414 
 415 /*
 416  * ndmpd_config_get_butype_info_v3
 417  *
 418  * This handler handles the ndmp_config_get_butype_info_request.
 419  * Information about all supported backup types are returned.
 420  *
 421  * Parameters:
 422  *   connection (input) - connection handle.
 423  *   body       (input) - request message body.
 424  *


 527  * Returns:
 528  *   void
 529  */
 530 /*ARGSUSED*/
 531 void
 532 ndmpd_config_get_fs_info_v3(ndmp_connection_t *connection, void *body)
 533 {
 534         ndmp_config_get_fs_info_reply_v3 reply;
 535         ndmp_fs_info_v3 *fsip = NULL, *fsip_save = NULL; /* FS info pointer */
 536         int len = 0, nmnt, fd;
 537         int log_dev_len;
 538         FILE *fp = NULL;
 539         struct mnttab mt, *fs;
 540         struct statvfs64 stat_buf;
 541         ndmp_pval *envp, *save;
 542 
 543         (void) memset((void*)&reply, 0, sizeof (reply));
 544         reply.error = NDMP_NO_ERR;
 545 
 546         if ((fd = open(MNTTAB, O_RDONLY)) == -1) {
 547                 syslog(LOG_ERR, "File mnttab open error: %m.");
 548                 reply.error = NDMP_UNDEFINED_ERR;
 549                 goto send_reply;
 550         }
 551 
 552         /* nothing was found, send an empty reply */
 553         if (ioctl(fd, MNTIOC_NMNTS, &nmnt) != 0 || nmnt <= 0) {
 554                 (void) close(fd);
 555                 syslog(LOG_ERR, "No file system found.");
 556                 goto send_reply;
 557         }
 558 
 559         fp = fdopen(fd, "r");
 560         if (!fp) {
 561                 (void) close(fd);
 562                 syslog(LOG_ERR, "File mnttab open error: %m.");
 563                 reply.error = NDMP_UNDEFINED_ERR;
 564                 goto send_reply;
 565         }
 566 
 567         fsip_save = fsip = ndmp_malloc(sizeof (ndmp_fs_info_v3) * nmnt);
 568         if (!fsip) {
 569                 (void) fclose(fp);
 570                 reply.error = NDMP_NO_MEM_ERR;
 571                 goto send_reply;
 572         }
 573 
 574         /*
 575          * Re-read the directory and set up file system information.
 576          */
 577         rewind(fp);
 578         while (len < nmnt && (getmntent(fp, &mt) == 0))
 579 
 580         {
 581                 fs = &mt;
 582                 log_dev_len = strlen(mt.mnt_mountp)+2;
 583                 if (!IS_VALID_FS(fs))
 584                         continue;
 585 
 586                 fsip->fs_logical_device = ndmp_malloc(log_dev_len);
 587                 fsip->fs_type = ndmp_malloc(MNTTYPE_LEN);
 588                 if (!fsip->fs_logical_device || !fsip->fs_type) {
 589                         free(fsip->fs_logical_device);
 590                         free(fsip->fs_type);
 591                         reply.error = NDMP_NO_MEM_ERR;
 592                         break;
 593                 }
 594                 (void) snprintf(fsip->fs_type, MNTTYPE_LEN, "%s",
 595                     fs->mnt_fstype);
 596                 (void) snprintf(fsip->fs_logical_device, log_dev_len, "%s",
 597                     fs->mnt_mountp);
 598                 fsip->invalid = 0;
 599 
 600                 if (statvfs64(fs->mnt_mountp, &stat_buf) < 0) {
 601                         syslog(LOG_ERR,
 602                             "statvfs(%s) error.", fs->mnt_mountp);
 603                         fsip->fs_status =
 604                             "statvfs error: unable to determine filesystem"
 605                             " attributes";
 606                 } else {
 607                         fsip->invalid = 0;
 608                         fsip->total_size =
 609                             long_long_to_quad((u_longlong_t)stat_buf.f_frsize *
 610                             (u_longlong_t)stat_buf.f_blocks);
 611                         fsip->used_size =
 612                             long_long_to_quad((u_longlong_t)stat_buf.f_frsize *
 613                             (u_longlong_t)(stat_buf.f_blocks-stat_buf.f_bfree));
 614 
 615                         fsip->avail_size =
 616                             long_long_to_quad((u_longlong_t)stat_buf.f_frsize *
 617                             (u_longlong_t)stat_buf.f_bfree);
 618                         fsip->total_inodes =
 619                             long_long_to_quad((u_longlong_t)stat_buf.f_files);
 620                         fsip->used_inodes =
 621                             long_long_to_quad((u_longlong_t)(stat_buf.f_files -


 705                 free(envp_save);
 706                 reply.error = NDMP_NO_MEM_ERR;
 707                 ndmp_send_reply(connection, (void *)&reply,
 708                     "error sending ndmp_config_get_tape_info reply");
 709                 return;
 710         }
 711 
 712         reply.error = NDMP_NO_ERR;
 713 
 714         for (i = n = 0; i < max; i++) {
 715                 if (!(sl = sasd_dev_slink(i)) || !(sd = sasd_drive(i)))
 716                         continue;
 717                 if (sl->sl_type != DTYPE_SEQUENTIAL)
 718                         continue;
 719                 /*
 720                  * Don't report dead links.
 721                  */
 722                 if ((access(sd->sd_name, F_OK) == -1) && (errno == ENOENT))
 723                         continue;
 724 
 725                 syslog(LOG_DEBUG,
 726                     "model \"%s\" dev \"%s\"", sd->sd_id, sd->sd_name);
 727 
 728                 envp_head = envp;
 729                 NDMP_SETENV(envp, "EXECUTE_CDB", "b");
 730                 NDMP_SETENV(envp, "SERIAL_NUMBER", sd->sd_serial);
 731                 NDMP_SETENV(envp, "WORLD_WIDE_NAME", sd->sd_wwn);
 732 
 733                 tip->model = sd->sd_id; /* like "DLT7000   " */
 734                 tip->caplist.caplist_len = 1;
 735                 tip->caplist.caplist_val = dcp;
 736                 dcp->device = sd->sd_name; /* like "isp1t060" */
 737                 dcp->attr = 0;
 738                 dcp->capability.capability_len = 3;
 739                 dcp->capability.capability_val = envp_head;
 740                 tip++;
 741                 dcp++;
 742                 n++;
 743         }
 744 


 745         /*
 746          * We should not receive the get_tape_info when three-way backup is
 747          * running and we are acting as just data, but some clients try
 748          * to get the Tape information anyway.
 749          */
 750         if (n == 0 || max <= 0) {
 751                 reply.error = NDMP_NO_DEVICE_ERR;
 752                 ndmp_send_reply(connection, (void *)&reply,
 753                     "error sending ndmp_config_get_tape_info reply");
 754                 free(tip_save); free(dcp_save); free(envp_save);
 755                 return;
 756         }
 757 
 758 
 759         reply.tape_info.tape_info_len = n;
 760         reply.tape_info.tape_info_val = tip_save;
 761 
 762         ndmp_send_reply(connection, (void *)&reply,
 763             "error sending ndmp_config_get_tape_info reply");
 764 


 805                 free(dcp_save);
 806                 free(envp_save);
 807                 reply.error = NDMP_NO_MEM_ERR;
 808                 ndmp_send_reply(connection, (void *)&reply,
 809                     "error sending ndmp_config_get_scsi_info reply");
 810                 return;
 811         }
 812 
 813         reply.error = NDMP_NO_ERR;
 814         for (i = n = 0; i < max; i++) {
 815                 if (!(sl = sasd_dev_slink(i)) || !(sd = sasd_drive(i)))
 816                         continue;
 817                 if (sl->sl_type != DTYPE_CHANGER)
 818                         continue;
 819                 /*
 820                  * Don't report dead links.
 821                  */
 822                 if ((access(sd->sd_name, F_OK) == -1) && (errno == ENOENT))
 823                         continue;
 824 
 825                 syslog(LOG_DEBUG,
 826                     "model \"%s\" dev \"%s\"", sd->sd_id, sd->sd_name);
 827 
 828                 envp_head = envp;
 829                 NDMP_SETENV(envp, "SERIAL_NUMBER", sd->sd_serial);
 830                 NDMP_SETENV(envp, "WORLD_WIDE_NAME", sd->sd_wwn);
 831 
 832                 sip->model = sd->sd_id; /* like "Powerstor L200  " */
 833                 sip->caplist.caplist_len = 1;
 834                 sip->caplist.caplist_val = dcp;
 835                 dcp->device = sd->sd_name; /* like "isp1m000" */
 836 
 837                 dcp->attr = 0;
 838                 dcp->capability.capability_len = 2;
 839                 dcp->capability.capability_val = envp_head;
 840                 sip++;
 841                 dcp++;
 842                 n++;
 843         }
 844 


 845         reply.scsi_info.scsi_info_len = n;
 846         reply.scsi_info.scsi_info_val = sip_save;
 847 
 848         ndmp_send_reply(connection, (void *)&reply,
 849             "error sending ndmp_config_get_scsi_info reply");
 850 
 851         free(sip_save);
 852         free(dcp_save);
 853         free(envp_save);
 854 }
 855 
 856 
 857 /*
 858  * ndmpd_config_get_server_info_v3
 859  *
 860  * This handler handles the ndmp_config_get_server_info request.
 861  * Host specific information is returned.
 862  *
 863  * Parameters:
 864  *   connection (input) - connection handle.
 865  *   body       (input) - request message body.
 866  *
 867  * Returns:
 868  *   void
 869  */
 870 /*ARGSUSED*/
 871 void
 872 ndmpd_config_get_server_info_v3(ndmp_connection_t *connection, void *body)
 873 {
 874         ndmp_config_get_server_info_reply_v3 reply;
 875         ndmp_auth_type auth_types[2];
 876         char rev_number[10];
 877         ndmpd_session_t *session = ndmp_get_client_data(connection);
 878         char *vendor;
 879         char *product;
 880 
 881         (void) memset((void*)&reply, 0, sizeof (reply));
 882         reply.error = NDMP_NO_ERR;
 883 
 884         if (connection->conn_authorized ||
 885             session->ns_protocol_version != NDMPV4) {
 886                 if ((vendor = ndmpd_get_prop(NDMP_VENDOR_NAME)) == NULL ||
 887                     *vendor == 0) {
 888                         reply.vendor_name = VENDOR_NAME;
 889                 } else {
 890                         reply.vendor_name = vendor;
 891                 }
 892                 if ((product = ndmpd_get_prop(NDMP_PRODUCT_NAME)) == NULL ||
 893                     *product == 0) {
 894                         reply.product_name = PRODUCT_NAME;
 895                 } else {
 896                         reply.product_name = product;
 897                 }
 898                 (void) snprintf(rev_number, sizeof (rev_number), "%d",
 899                     ndmp_ver);
 900                 reply.revision_number = rev_number;
 901         } else {
 902                 reply.vendor_name = "\0";
 903                 reply.product_name = "\0";
 904                 reply.revision_number = "\0";
 905         }
 906 




 907         auth_types[0] = NDMP_AUTH_TEXT;
 908         auth_types[1] = NDMP_AUTH_MD5;
 909         reply.auth_type.auth_type_len = ARRAY_LEN(auth_types, ndmp_auth_type);
 910         reply.auth_type.auth_type_val = auth_types;
 911 
 912         ndmp_send_reply(connection, (void *)&reply,
 913             "error sending ndmp_config_get_server_info reply");
 914 }
 915 
 916 
 917 
 918 /*
 919  * ************************************************************************
 920  * NDMP V4 HANDLERS
 921  * ************************************************************************
 922  */
 923 
 924 /*
 925  * ndmpd_config_get_butype_info_v4
 926  *


1043  * Parameters:
1044  *   connection (input) - connection handle.
1045  *   body       (input) - request message body.
1046  *
1047  * Returns:
1048  *   void
1049  */
1050 /*ARGSUSED*/
1051 void
1052 ndmpd_config_get_ext_list_v4(ndmp_connection_t *connection, void *body)
1053 {
1054         ndmp_config_get_ext_list_reply_v4 reply;
1055         ndmpd_session_t *session = ndmp_get_client_data(connection);
1056 
1057         (void) memset((void*)&reply, 0, sizeof (reply));
1058 
1059         if (session->ns_set_ext_list) {
1060                 /*
1061                  * Illegal request if extensions have already been selected.
1062                  */
1063                 syslog(LOG_ERR, "Extensions have already been selected.");
1064                 reply.error = NDMP_EXT_DANDN_ILLEGAL_ERR;
1065         } else {
1066                 /*
1067                  * Reply with an empty set of extensions.
1068                  */
1069                 session->ns_get_ext_list = B_TRUE;
1070                 reply.error = NDMP_NO_ERR;
1071         }
1072 
1073         reply.class_list.class_list_val = NULL;
1074         reply.class_list.class_list_len = 0;
1075 
1076         ndmp_send_reply(connection, (void *)&reply,
1077             "error sending ndmp_config_get_ext_list reply");
1078 }
1079 
1080 /*
1081  * ndmpd_config_set_ext_list_v4
1082  *
1083  * This handler handles the ndmpd_config_get_ext_list_v4 request.


1088  *
1089  * Returns:
1090  *   void
1091  */
1092 void
1093 ndmpd_config_set_ext_list_v4(ndmp_connection_t *connection, void *body)
1094 {
1095         ndmp_config_set_ext_list_reply_v4 reply;
1096         ndmp_config_set_ext_list_request_v4 *request;
1097         ndmpd_session_t *session = ndmp_get_client_data(connection);
1098 
1099         request = (ndmp_config_set_ext_list_request_v4 *)body;
1100 
1101         (void) memset((void*)&reply, 0, sizeof (reply));
1102 
1103         if (!session->ns_get_ext_list) {
1104                 /*
1105                  * The DMA is required to issue a NDMP_GET_EXT_LIST request
1106                  * prior sending a NDMP_SET_EXT_LIST request.
1107                  */
1108                 syslog(LOG_ERR, "No prior ndmp_config_get_ext_list issued.");
1109                 reply.error = NDMP_PRECONDITION_ERR;
1110         } else if (session->ns_set_ext_list) {
1111                 /*
1112                  * Illegal request if extensions have already been selected.
1113                  */
1114                 syslog(LOG_ERR, "Extensions have already been selected.");
1115                 reply.error = NDMP_EXT_DANDN_ILLEGAL_ERR;
1116         } else {
1117                 /*
1118                  * We currently do not support any extensions, but the DMA
1119                  * may test NDMP_CONFIG_SET_EXT_LIST with an empty list.
1120                  */
1121                 if (request->ndmp_selected_ext.ndmp_selected_ext_len != 0) {
1122                         reply.error = NDMP_CLASS_NOT_SUPPORTED_ERR;
1123                 } else {
1124                         session->ns_set_ext_list = B_TRUE;
1125                         reply.error = NDMP_NO_ERR;
1126                 }
1127         }
1128 
1129         ndmp_send_reply(connection, (void *)&reply,
1130             "error sending ndmp_config_set_ext_list reply");
1131 }
1132 
1133 
1134