1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 
   5 /*
   6  * BSD 3 Clause License
   7  *
   8  * Copyright (c) 2007, The Storage Networking Industry Association.
   9  *
  10  * Redistribution and use in source and binary forms, with or without
  11  * modification, are permitted provided that the following conditions
  12  * are met:
  13  *      - Redistributions of source code must retain the above copyright
  14  *        notice, this list of conditions and the following disclaimer.
  15  *
  16  *      - Redistributions in binary form must reproduce the above copyright
  17  *        notice, this list of conditions and the following disclaimer in
  18  *        the documentation and/or other materials provided with the
  19  *        distribution.
  20  *
  21  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  22  *        nor the names of its contributors may be used to endorse or promote
  23  *        products derived from this software without specific prior written
  24  *        permission.
  25  *
  26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36  * POSSIBILITY OF SUCH DAMAGE.
  37  */
  38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
  39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
  40 /* Copyright 2014 Nexenta Systems, Inc.  All rights reserved. */
  41 
  42 #include <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 
  67 /*
  68  * Is the file system a valid one to be reported to the
  69  * clients?
  70  */
  71 #define IS_VALID_FS(fs) (fs && ( \
  72         strcasecmp(fs->mnt_fstype, MNTTYPE_UFS) == 0 || \
  73         strcasecmp(fs->mnt_fstype, MNTTYPE_ZFS) == 0 || \
  74         strcasecmp(fs->mnt_fstype, MNTTYPE_NFS) == 0 || \
  75         strcasecmp(fs->mnt_fstype, MNTTYPE_NFS3) == 0 || \
  76         strcasecmp(fs->mnt_fstype, MNTTYPE_NFS4) == 0))
  77 
  78 #define MNTTYPE_LEN     10
  79 
  80 extern struct fs_ops sfs2_ops;
  81 extern struct fs_ops sfs2cpv_ops;
  82 
  83 
  84 /*
  85  * ************************************************************************
  86  * NDMP V2 HANDLERS
  87  * ************************************************************************
  88  */
  89 
  90 /*
  91  * ndmpd_config_get_host_info_v2
  92  *
  93  * This handler handles the ndmp_config_get_host_info request.
  94  * Host specific information is returned.
  95  *
  96  * Parameters:
  97  *   connection (input) - connection handle.
  98  *   body       (input) - request message body.
  99  *
 100  * Returns:
 101  *   void
 102  */
 103 /*ARGSUSED*/
 104 void
 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 
 146 /*
 147  * ndmpd_config_get_butype_attr_v2
 148  *
 149  * This handler handles the ndmp_config_get_butype_attr request.
 150  * Information about the specified backup type is returned.
 151  *
 152  * Parameters:
 153  *   connection (input) - connection handle.
 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:
 196  *   void
 197  */
 198 /*ARGSUSED*/
 199 void
 200 ndmpd_config_get_mover_type_v2(ndmp_connection_t *connection, void *body)
 201 {
 202         ndmp_config_get_mover_type_reply reply;
 203         ndmp_addr_type types[2];
 204 
 205         types[0] = NDMP_ADDR_LOCAL;
 206         types[1] = NDMP_ADDR_TCP;
 207 
 208         reply.error = NDMP_NO_ERR;
 209         reply.methods.methods_len = 2;
 210         reply.methods.methods_val = types;
 211 
 212         ndmp_send_reply(connection, (void *) &reply,
 213             "sending ndmp_config_get_mover_type reply");
 214 }
 215 
 216 
 217 
 218 /*
 219  * ndmpd_config_get_auth_attr_v2
 220  *
 221  * This handler handles the ndmp_config_get_auth_attr request.
 222  * Authorization type specific information is returned.
 223  *
 224  * Parameters:
 225  *   connection (input) - connection handle.
 226  *   body       (input) - request message body.
 227  *
 228  * Returns:
 229  *   void
 230  */
 231 void
 232 ndmpd_config_get_auth_attr_v2(ndmp_connection_t *connection, void *body)
 233 {
 234         ndmp_config_get_auth_attr_request *request;
 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.
 278  * Host specific information is returned.
 279  *
 280  * Parameters:
 281  *   connection (input) - connection handle.
 282  *   body       (input) - request message body.
 283  *
 284  * Returns:
 285  *   void
 286  */
 287 /*ARGSUSED*/
 288 void
 289 ndmpd_config_get_host_info_v3(ndmp_connection_t *connection, void *body)
 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.
 331  * A list of supported data connection types is returned.
 332  *
 333  * Parameters:
 334  *   connection (input) - connection handle.
 335  *   body       (input) - request message body.
 336  *
 337  * Returns:
 338  *   void
 339  */
 340 /*ARGSUSED*/
 341 void
 342 ndmpd_config_get_connection_type_v3(ndmp_connection_t *connection,
 343     void *body)
 344 {
 345         ndmp_config_get_connection_type_reply_v3 reply;
 346         ndmp_addr_type addr_types[2];
 347 
 348         (void) memset((void*)&reply, 0, sizeof (reply));
 349 
 350         reply.error = NDMP_NO_ERR;
 351 
 352         addr_types[0] = NDMP_ADDR_LOCAL;
 353         addr_types[1] = NDMP_ADDR_TCP;
 354         reply.addr_types.addr_types_len = 2;
 355         reply.addr_types.addr_types_val = addr_types;
 356 
 357         ndmp_send_reply(connection, (void *) &reply,
 358             "sending config_get_connection_type_v3 reply");
 359 }
 360 
 361 
 362 
 363 /*
 364  * ndmpd_config_get_auth_attr_v3
 365  *
 366  * This handler handles the ndmp_config_get_auth_attr request.
 367  * Authorization type specific information is returned.
 368  *
 369  * Parameters:
 370  *   connection (input) - connection handle.
 371  *   body       (input) - request message body.
 372  *
 373  * Returns:
 374  *   void
 375  */
 376 void
 377 ndmpd_config_get_auth_attr_v3(ndmp_connection_t *connection, void *body)
 378 {
 379         ndmp_config_get_auth_attr_request *request;
 380         ndmp_config_get_auth_attr_reply reply;
 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  *
 424  * Returns:
 425  *   void
 426  */
 427 /*ARGSUSED*/
 428 void
 429 ndmpd_config_get_butype_info_v3(ndmp_connection_t *connection, void *body)
 430 {
 431         ndmp_config_get_butype_info_reply_v3 reply;
 432         ndmp_butype_info info[3];
 433         ndmp_pval envs[8];
 434         ulong_t attrs;
 435         ndmp_pval *envp = envs;
 436 
 437         ndmp_pval zfs_envs[9];
 438         ulong_t zfs_attrs;
 439         ndmp_pval *zfs_envp = zfs_envs;
 440 
 441         (void) memset((void*)&reply, 0, sizeof (reply));
 442 
 443         /*
 444          * Supported environment variables and their default values
 445          * for dump and tar.
 446          *
 447          * The environment variables for dump and tar format are the
 448          * same, because we use the same backup engine for both.
 449          */
 450         NDMP_SETENV(envp, "PREFIX", "");
 451         NDMP_SETENV(envp, "TYPE", "");
 452         NDMP_SETENV(envp, "DIRECT", "n");
 453         NDMP_SETENV(envp, "HIST", "n");
 454         NDMP_SETENV(envp, "FILESYSTEM", "");
 455         NDMP_SETENV(envp, "LEVEL", "0");
 456         NDMP_SETENV(envp, "UPDATE", "TRUE");
 457         NDMP_SETENV(envp, "BASE_DATE", "");
 458 
 459         attrs = NDMP_BUTYPE_BACKUP_FILE_HISTORY |
 460             NDMP_BUTYPE_RECOVER_FILELIST |
 461             NDMP_BUTYPE_BACKUP_DIRECT |
 462             NDMP_BUTYPE_BACKUP_INCREMENTAL |
 463             NDMP_BUTYPE_BACKUP_UTF8 |
 464             NDMP_BUTYPE_RECOVER_UTF8;
 465 
 466         /* If DAR supported */
 467         if (ndmp_dar_support)
 468                 attrs |= NDMP_BUTYPE_RECOVER_DIRECT;
 469 
 470         /* tar backup type */
 471         info[0].butype_name = "tar";
 472         info[0].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
 473         info[0].default_env.default_env_val = envs;
 474         info[0].attrs = attrs;
 475 
 476         /* dump backup type */
 477         info[1].butype_name = "dump";
 478         info[1].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
 479         info[1].default_env.default_env_val = envs;
 480         info[1].attrs = attrs;
 481 
 482         /*
 483          * Supported environment variables and their default values
 484          * for type "zfs."
 485          */
 486 
 487         NDMP_SETENV(zfs_envp, "PREFIX", "");
 488         NDMP_SETENV(zfs_envp, "FILESYSTEM", "");
 489         NDMP_SETENV(zfs_envp, "TYPE", "zfs");
 490         NDMP_SETENV(zfs_envp, "HIST", "n");
 491         NDMP_SETENV(zfs_envp, "LEVEL", "0");
 492         NDMP_SETENV(zfs_envp, "ZFS_MODE", "recursive");
 493         NDMP_SETENV(zfs_envp, "ZFS_FORCE", "FALSE");
 494         NDMP_SETENV(zfs_envp, "UPDATE", "TRUE");
 495         NDMP_SETENV(zfs_envp, "DMP_NAME", "level");
 496 
 497         zfs_attrs = NDMP_BUTYPE_BACKUP_UTF8 |
 498             NDMP_BUTYPE_RECOVER_UTF8 |
 499             NDMP_BUTYPE_BACKUP_DIRECT |
 500             NDMP_BUTYPE_BACKUP_INCREMENTAL;
 501 
 502         /* zfs backup type */
 503         info[2].butype_name = "zfs";
 504         info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval);
 505         info[2].default_env.default_env_val = zfs_envs;
 506         info[2].attrs = zfs_attrs;
 507 
 508         reply.error = NDMP_NO_ERR;
 509         reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info);
 510         reply.butype_info.butype_info_val = info;
 511 
 512         ndmp_send_reply(connection, (void *)&reply,
 513             "sending ndmp_config_get_butype_info reply");
 514 }
 515 
 516 /*
 517  * ndmpd_config_get_fs_info_v3
 518  *
 519  * This handler handles the ndmp_config_get_fs_info_request.
 520  * Information about all mounted file systems is returned.
 521  *
 522  * Parameters:
 523  *   connection (input) - connection handle.
 524  *   body       (input) - request message body.
 525  *
 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 -
 621                             stat_buf.f_ffree));
 622                         fsip->fs_status = "";
 623                 }
 624                 save = envp = ndmp_malloc(sizeof (ndmp_pval) * V3_N_FS_ENVS);
 625                 if (!envp) {
 626                         free(fsip->fs_logical_device);
 627                         free(fsip->fs_type);
 628                         reply.error = NDMP_NO_MEM_ERR;
 629                         break;
 630                 }
 631                 (void) memset((void*)save, 0,
 632                     V3_N_FS_ENVS * sizeof (ndmp_pval));
 633 
 634                 fsip->fs_env.fs_env_val = envp;
 635                 NDMP_SETENV(envp, "LOCAL", "y");
 636                 NDMP_SETENV(envp, "TYPE", fsip->fs_type);
 637                 NDMP_SETENV(envp, "AVAILABLE_BACKUP", "tar,dump");
 638 
 639                 if (FS_READONLY(fs) == 0) {
 640                         NDMP_SETENV(envp, "AVAILABLE_RECOVERY", "tar,dump");
 641                 }
 642 
 643                 fsip->fs_env.fs_env_len = envp - save;
 644                 len++;
 645                 fsip++;
 646         }
 647         (void) fclose(fp);
 648 
 649 send_reply:
 650         if (reply.error == NDMP_NO_ERR) {
 651                 reply.fs_info.fs_info_len = len;
 652                 reply.fs_info.fs_info_val = fsip_save;
 653         }
 654         ndmp_send_reply(connection, (void *)&reply,
 655             "error sending ndmp_config_get_fs_info reply");
 656 
 657         while (fsip > fsip_save) {
 658                 fsip--;
 659                 free(fsip->fs_logical_device);
 660                 free(fsip->fs_env.fs_env_val);
 661                 free(fsip->fs_type);
 662         }
 663 
 664         free(fsip);
 665 }
 666 
 667 
 668 /*
 669  * ndmpd_config_get_tape_info_v3
 670  *
 671  * This handler handles the ndmp_config_get_tape_info_request.
 672  * Information about all connected tape drives is returned.
 673  *
 674  * Parameters:
 675  *   connection (input) - connection handle.
 676  *   body       (input) - request message body.
 677  *
 678  * Returns:
 679  *   void
 680  */
 681 /*ARGSUSED*/
 682 void
 683 ndmpd_config_get_tape_info_v3(ndmp_connection_t *connection, void *body)
 684 {
 685         ndmp_config_get_tape_info_reply_v3 reply;
 686         ndmp_device_info_v3 *tip, *tip_save = NULL; /* tape info pointer */
 687         ndmp_device_capability_v3 *dcp;
 688         ndmp_device_capability_v3 *dcp_save = NULL; /* dev capability pointer */
 689         int i, n, max;
 690         sasd_drive_t *sd;
 691         scsi_link_t *sl;
 692         ndmp_pval *envp, *envp_save = NULL;
 693         ndmp_pval *envp_head;
 694 
 695         (void) memset((void*)&reply, 0, sizeof (reply));
 696         max = sasd_dev_count();
 697 
 698         tip_save = tip = ndmp_malloc(sizeof (ndmp_device_info_v3) * max);
 699         dcp_save = dcp = ndmp_malloc(sizeof (ndmp_device_capability_v3) * max);
 700         envp_save = envp = ndmp_malloc(sizeof (ndmp_pval) * max * 3);
 701         if (!tip_save || !dcp_save || !envp_save) {
 702                 free(tip_save);
 703                 free(dcp_save);
 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 
 766         free(tip_save);
 767         free(dcp_save);
 768         free(envp_save);
 769 }
 770 
 771 
 772 /*
 773  * ndmpd_config_get_scsi_info_v3
 774  *
 775  * This handler handles the ndmp_config_get_tape_scsi_request.
 776  * Information about all connected scsi tape stacker and jukeboxes
 777  * is returned.
 778  *
 779  * Parameters:
 780  *   connection (input) - connection handle.
 781  *   body       (input) - request message body.
 782  *
 783  * Returns:
 784  *   void
 785  */
 786 /*ARGSUSED*/
 787 void
 788 ndmpd_config_get_scsi_info_v3(ndmp_connection_t *connection, void *body)
 789 {
 790         ndmp_config_get_scsi_info_reply_v3 reply;
 791         ndmp_device_info_v3 *sip, *sip_save;
 792         ndmp_device_capability_v3 *dcp, *dcp_save;
 793         int i, n, max;
 794         sasd_drive_t *sd;
 795         scsi_link_t *sl;
 796         ndmp_pval *envp, *envp_save = NULL;
 797         ndmp_pval *envp_head;
 798 
 799         (void) memset((void*)&reply, 0, sizeof (reply));
 800         max = sasd_dev_count();
 801         sip_save = sip = ndmp_malloc(sizeof (ndmp_device_info_v3) * max);
 802         dcp_save = dcp = ndmp_malloc(sizeof (ndmp_device_capability_v3) * max);
 803         envp_save = envp = ndmp_malloc(sizeof (ndmp_pval) * max * 2);
 804         if (!sip_save || !dcp_save || !envp_save) {
 805                 free(sip_save);
 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  *
 922  * This handler handles the ndmp_config_get_butype_info_request.
 923  * Information about all supported backup types are returned.
 924  *
 925  * Parameters:
 926  *   connection (input) - connection handle.
 927  *   body       (input) - request message body.
 928  *
 929  * Returns:
 930  *   void
 931  */
 932 /*ARGSUSED*/
 933 void
 934 ndmpd_config_get_butype_info_v4(ndmp_connection_t *connection, void *body)
 935 {
 936         ndmp_config_get_butype_info_reply_v4 reply;
 937         ndmp_butype_info info[3];
 938 
 939         ndmp_pval envs[12];
 940         ulong_t attrs;
 941         ndmp_pval *envp = envs;
 942 
 943         ndmp_pval zfs_envs[11];
 944         ulong_t zfs_attrs;
 945         ndmp_pval *zfs_envp = zfs_envs;
 946 
 947 
 948         (void) memset((void*)&reply, 0, sizeof (reply));
 949 
 950         /*
 951          * Supported environment variables and their default values
 952          * for dump and tar.
 953          *
 954          * The environment variables for dump and tar format are the
 955          * same, because we use the same backup engine for both.
 956          */
 957         NDMP_SETENV(envp, "FILESYSTEM", "");
 958         NDMP_SETENV(envp, "DIRECT", "n");
 959         NDMP_SETENV(envp, "RECURSIVE", "n");
 960         NDMP_SETENV(envp, "TYPE", "");
 961         NDMP_SETENV(envp, "USER", "");
 962         NDMP_SETENV(envp, "HIST", "n");
 963         NDMP_SETENV(envp, "PATHNAME_SEPARATOR", "/");
 964         NDMP_SETENV(envp, "LEVEL", "0");
 965         NDMP_SETENV(envp, "EXTRACT", "y");
 966         NDMP_SETENV(envp, "UPDATE", "y");
 967         NDMP_SETENV(envp, "CMD", "");
 968         NDMP_SETENV(envp, "BASE_DATE", "");
 969 
 970         attrs = NDMP_BUTYPE_RECOVER_FILELIST |
 971             NDMP_BUTYPE_BACKUP_DIRECT |
 972             NDMP_BUTYPE_BACKUP_INCREMENTAL |
 973             NDMP_BUTYPE_BACKUP_UTF8 |
 974             NDMP_BUTYPE_RECOVER_UTF8 |
 975             NDMP_BUTYPE_BACKUP_FH_FILE |
 976             NDMP_BUTYPE_BACKUP_FH_DIR |
 977             NDMP_BUTYPE_RECOVER_FH_FILE |
 978             NDMP_BUTYPE_RECOVER_FH_DIR;
 979 
 980         /* If DAR supported */
 981         if (ndmp_dar_support)
 982                 attrs |= NDMP_BUTYPE_RECOVER_DIRECT;
 983 
 984         /* tar backup type */
 985         info[0].butype_name = "tar";
 986         info[0].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
 987         info[0].default_env.default_env_val = envs;
 988         info[0].attrs = attrs;
 989 
 990         /* dump backup type */
 991         info[1].butype_name = "dump";
 992         info[1].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
 993         info[1].default_env.default_env_val = envs;
 994         info[1].attrs = attrs;
 995 
 996         /*
 997          * Supported environment variables and their default values
 998          * for type "zfs."
 999          */
1000 
1001         NDMP_SETENV(zfs_envp, "USER", "");
1002         NDMP_SETENV(zfs_envp, "CMD", "");
1003         NDMP_SETENV(zfs_envp, "FILESYSTEM", "");
1004         NDMP_SETENV(zfs_envp, "PATHNAME_SEPARATOR", "/");
1005         NDMP_SETENV(zfs_envp, "TYPE", "zfs");
1006         NDMP_SETENV(zfs_envp, "HIST", "n");
1007         NDMP_SETENV(zfs_envp, "LEVEL", "0");
1008         NDMP_SETENV(zfs_envp, "ZFS_MODE", "recursive");
1009         NDMP_SETENV(zfs_envp, "ZFS_FORCE", "n");
1010         NDMP_SETENV(zfs_envp, "UPDATE", "y");
1011         NDMP_SETENV(zfs_envp, "DMP_NAME", "level");
1012 
1013         zfs_attrs = NDMP_BUTYPE_BACKUP_UTF8 |
1014             NDMP_BUTYPE_RECOVER_UTF8 |
1015             NDMP_BUTYPE_BACKUP_DIRECT |
1016             NDMP_BUTYPE_BACKUP_INCREMENTAL;
1017 
1018         /* zfs backup type */
1019         info[2].butype_name = "zfs";
1020         info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval);
1021         info[2].default_env.default_env_val = zfs_envs;
1022         info[2].attrs = zfs_attrs;
1023 
1024         reply.error = NDMP_NO_ERR;
1025         reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info);
1026         reply.butype_info.butype_info_val = info;
1027 
1028         ndmp_send_reply(connection, (void *)&reply,
1029             "sending ndmp_config_get_butype_info reply");
1030 }
1031 
1032 
1033 /*
1034  * ndmpd_config_get_ext_list_v4
1035  *
1036  * This handler handles the ndmpd_config_get_ext_list_v4 request.
1037  *
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.
1079  *
1080  * Parameters:
1081  *   connection (input) - connection handle.
1082  *   body       (input) - request message body.
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 
1130 /*
1131  * ************************************************************************
1132  * LOCALS
1133  * ************************************************************************
1134  */
1135 
1136 /*
1137  * simple_get_attrs
1138  *
1139  * Set the default attrs for dump mode
1140  *
1141  * Parameters:
1142  *   attributes (output) - the attributes for dump mode
1143  *
1144  * Returns:
1145  *   void
1146  */
1147 static void
1148 simple_get_attrs(ulong_t *attributes)
1149 {
1150         *attributes = NDMP_NO_RECOVER_FHINFO;
1151 }