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 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 
  68 /*
  69  * Is the file system a valid one to be reported to the
  70  * clients?
  71  */
  72 #define IS_VALID_FS(fs) (fs && ( \
  73         strcasecmp(fs->mnt_fstype, MNTTYPE_UFS) == 0 || \
  74         strcasecmp(fs->mnt_fstype, MNTTYPE_ZFS) == 0 || \
  75         strcasecmp(fs->mnt_fstype, MNTTYPE_NFS) == 0 || \
  76         strcasecmp(fs->mnt_fstype, MNTTYPE_NFS3) == 0 || \
  77         strcasecmp(fs->mnt_fstype, MNTTYPE_NFS4) == 0))
  78 
  79 #define MNTTYPE_LEN     10
  80 
  81 extern struct fs_ops sfs2_ops;
  82 extern struct fs_ops sfs2cpv_ops;
  83 
  84 
  85 /*
  86  * ************************************************************************
  87  * NDMP V2 HANDLERS
  88  * ************************************************************************
  89  */
  90 
  91 /*
  92  * ndmpd_config_get_host_info_v2
  93  *
  94  * This handler handles the ndmp_config_get_host_info request.
  95  * Host specific information is returned.
  96  *
  97  * Parameters:
  98  *   connection (input) - connection handle.
  99  *   body       (input) - request message body.
 100  *
 101  * Returns:
 102  *   void
 103  */
 104 /*ARGSUSED*/
 105 void
 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 
 147 /*
 148  * ndmpd_config_get_butype_attr_v2
 149  *
 150  * This handler handles the ndmp_config_get_butype_attr request.
 151  * Information about the specified backup type is returned.
 152  *
 153  * Parameters:
 154  *   connection (input) - connection handle.
 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:
 197  *   void
 198  */
 199 /*ARGSUSED*/
 200 void
 201 ndmpd_config_get_mover_type_v2(ndmp_connection_t *connection, void *body)
 202 {
 203         ndmp_config_get_mover_type_reply reply;
 204         ndmp_addr_type types[2];
 205 
 206         types[0] = NDMP_ADDR_LOCAL;
 207         types[1] = NDMP_ADDR_TCP;
 208 
 209         reply.error = NDMP_NO_ERR;
 210         reply.methods.methods_len = 2;
 211         reply.methods.methods_val = types;
 212 
 213         ndmp_send_reply(connection, (void *) &reply,
 214             "sending ndmp_config_get_mover_type reply");
 215 }
 216 
 217 
 218 
 219 /*
 220  * ndmpd_config_get_auth_attr_v2
 221  *
 222  * This handler handles the ndmp_config_get_auth_attr request.
 223  * Authorization type specific information is returned.
 224  *
 225  * Parameters:
 226  *   connection (input) - connection handle.
 227  *   body       (input) - request message body.
 228  *
 229  * Returns:
 230  *   void
 231  */
 232 void
 233 ndmpd_config_get_auth_attr_v2(ndmp_connection_t *connection, void *body)
 234 {
 235         ndmp_config_get_auth_attr_request *request;
 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.
 279  * Host specific information is returned.
 280  *
 281  * Parameters:
 282  *   connection (input) - connection handle.
 283  *   body       (input) - request message body.
 284  *
 285  * Returns:
 286  *   void
 287  */
 288 /*ARGSUSED*/
 289 void
 290 ndmpd_config_get_host_info_v3(ndmp_connection_t *connection, void *body)
 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.
 332  * A list of supported data connection types is returned.
 333  *
 334  * Parameters:
 335  *   connection (input) - connection handle.
 336  *   body       (input) - request message body.
 337  *
 338  * Returns:
 339  *   void
 340  */
 341 /*ARGSUSED*/
 342 void
 343 ndmpd_config_get_connection_type_v3(ndmp_connection_t *connection,
 344     void *body)
 345 {
 346         ndmp_config_get_connection_type_reply_v3 reply;
 347         ndmp_addr_type addr_types[2];
 348 
 349         (void) memset((void*)&reply, 0, sizeof (reply));
 350 
 351         reply.error = NDMP_NO_ERR;
 352 
 353         addr_types[0] = NDMP_ADDR_LOCAL;
 354         addr_types[1] = NDMP_ADDR_TCP;
 355         reply.addr_types.addr_types_len = 2;
 356         reply.addr_types.addr_types_val = addr_types;
 357 
 358         ndmp_send_reply(connection, (void *) &reply,
 359             "sending config_get_connection_type_v3 reply");
 360 }
 361 
 362 
 363 
 364 /*
 365  * ndmpd_config_get_auth_attr_v3
 366  *
 367  * This handler handles the ndmp_config_get_auth_attr request.
 368  * Authorization type specific information is returned.
 369  *
 370  * Parameters:
 371  *   connection (input) - connection handle.
 372  *   body       (input) - request message body.
 373  *
 374  * Returns:
 375  *   void
 376  */
 377 void
 378 ndmpd_config_get_auth_attr_v3(ndmp_connection_t *connection, void *body)
 379 {
 380         ndmp_config_get_auth_attr_request *request;
 381         ndmp_config_get_auth_attr_reply reply;
 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  *
 425  * Returns:
 426  *   void
 427  */
 428 /*ARGSUSED*/
 429 void
 430 ndmpd_config_get_butype_info_v3(ndmp_connection_t *connection, void *body)
 431 {
 432         ndmp_config_get_butype_info_reply_v3 reply;
 433         ndmp_butype_info info[3];
 434         ndmp_pval envs[8];
 435         ulong_t attrs;
 436         ndmp_pval *envp = envs;
 437 
 438         ndmp_pval zfs_envs[9];
 439         ulong_t zfs_attrs;
 440         ndmp_pval *zfs_envp = zfs_envs;
 441 
 442         (void) memset((void*)&reply, 0, sizeof (reply));
 443 
 444         /*
 445          * Supported environment variables and their default values
 446          * for dump and tar.
 447          *
 448          * The environment variables for dump and tar format are the
 449          * same, because we use the same backup engine for both.
 450          */
 451         NDMP_SETENV(envp, "PREFIX", "");
 452         NDMP_SETENV(envp, "TYPE", "");
 453         NDMP_SETENV(envp, "DIRECT", "n");
 454         NDMP_SETENV(envp, "HIST", "n");
 455         NDMP_SETENV(envp, "FILESYSTEM", "");
 456         NDMP_SETENV(envp, "LEVEL", "0");
 457         NDMP_SETENV(envp, "UPDATE", "TRUE");
 458         NDMP_SETENV(envp, "BASE_DATE", "");
 459 
 460         attrs = NDMP_BUTYPE_BACKUP_FILE_HISTORY |
 461             NDMP_BUTYPE_RECOVER_FILELIST |
 462             NDMP_BUTYPE_BACKUP_DIRECT |
 463             NDMP_BUTYPE_BACKUP_INCREMENTAL |
 464             NDMP_BUTYPE_BACKUP_UTF8 |
 465             NDMP_BUTYPE_RECOVER_UTF8;
 466 
 467         /* If DAR supported */
 468         if (ndmp_dar_support)
 469                 attrs |= NDMP_BUTYPE_RECOVER_DIRECT;
 470 
 471         /* tar backup type */
 472         info[0].butype_name = "tar";
 473         info[0].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
 474         info[0].default_env.default_env_val = envs;
 475         info[0].attrs = attrs;
 476 
 477         /* dump backup type */
 478         info[1].butype_name = "dump";
 479         info[1].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
 480         info[1].default_env.default_env_val = envs;
 481         info[1].attrs = attrs;
 482 
 483         /*
 484          * Supported environment variables and their default values
 485          * for type "zfs."
 486          */
 487 
 488         NDMP_SETENV(zfs_envp, "PREFIX", "");
 489         NDMP_SETENV(zfs_envp, "FILESYSTEM", "");
 490         NDMP_SETENV(zfs_envp, "TYPE", "zfs");
 491         NDMP_SETENV(zfs_envp, "HIST", "n");
 492         NDMP_SETENV(zfs_envp, "LEVEL", "0");
 493         NDMP_SETENV(zfs_envp, "ZFS_MODE", "recursive");
 494         NDMP_SETENV(zfs_envp, "ZFS_FORCE", "FALSE");
 495         NDMP_SETENV(zfs_envp, "UPDATE", "TRUE");
 496         NDMP_SETENV(zfs_envp, "DMP_NAME", "level");
 497 
 498         zfs_attrs = NDMP_BUTYPE_BACKUP_UTF8 |
 499             NDMP_BUTYPE_RECOVER_UTF8 |
 500             NDMP_BUTYPE_BACKUP_DIRECT |
 501             NDMP_BUTYPE_BACKUP_INCREMENTAL;
 502 
 503         /* zfs backup type */
 504         info[2].butype_name = "zfs";
 505         info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval);
 506         info[2].default_env.default_env_val = zfs_envs;
 507         info[2].attrs = zfs_attrs;
 508 
 509         reply.error = NDMP_NO_ERR;
 510         reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info);
 511         reply.butype_info.butype_info_val = info;
 512 
 513         ndmp_send_reply(connection, (void *)&reply,
 514             "sending ndmp_config_get_butype_info reply");
 515 }
 516 
 517 /*
 518  * ndmpd_config_get_fs_info_v3
 519  *
 520  * This handler handles the ndmp_config_get_fs_info_request.
 521  * Information about all mounted file systems is returned.
 522  *
 523  * Parameters:
 524  *   connection (input) - connection handle.
 525  *   body       (input) - request message body.
 526  *
 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 -
 622                             stat_buf.f_ffree));
 623                         fsip->fs_status = "";
 624                 }
 625                 save = envp = ndmp_malloc(sizeof (ndmp_pval) * V3_N_FS_ENVS);
 626                 if (!envp) {
 627                         free(fsip->fs_logical_device);
 628                         free(fsip->fs_type);
 629                         reply.error = NDMP_NO_MEM_ERR;
 630                         break;
 631                 }
 632                 (void) memset((void*)save, 0,
 633                     V3_N_FS_ENVS * sizeof (ndmp_pval));
 634 
 635                 fsip->fs_env.fs_env_val = envp;
 636                 NDMP_SETENV(envp, "LOCAL", "y");
 637                 NDMP_SETENV(envp, "TYPE", fsip->fs_type);
 638                 NDMP_SETENV(envp, "AVAILABLE_BACKUP", "tar,dump");
 639 
 640                 if (FS_READONLY(fs) == 0) {
 641                         NDMP_SETENV(envp, "AVAILABLE_RECOVERY", "tar,dump");
 642                 }
 643 
 644                 fsip->fs_env.fs_env_len = envp - save;
 645                 len++;
 646                 fsip++;
 647         }
 648         (void) fclose(fp);
 649 
 650 send_reply:
 651         if (reply.error == NDMP_NO_ERR) {
 652                 reply.fs_info.fs_info_len = len;
 653                 reply.fs_info.fs_info_val = fsip_save;
 654         }
 655         ndmp_send_reply(connection, (void *)&reply,
 656             "error sending ndmp_config_get_fs_info reply");
 657 
 658         while (fsip > fsip_save) {
 659                 fsip--;
 660                 free(fsip->fs_logical_device);
 661                 free(fsip->fs_env.fs_env_val);
 662                 free(fsip->fs_type);
 663         }
 664 
 665         free(fsip);
 666 }
 667 
 668 
 669 /*
 670  * ndmpd_config_get_tape_info_v3
 671  *
 672  * This handler handles the ndmp_config_get_tape_info_request.
 673  * Information about all connected tape drives is returned.
 674  *
 675  * Parameters:
 676  *   connection (input) - connection handle.
 677  *   body       (input) - request message body.
 678  *
 679  * Returns:
 680  *   void
 681  */
 682 /*ARGSUSED*/
 683 void
 684 ndmpd_config_get_tape_info_v3(ndmp_connection_t *connection, void *body)
 685 {
 686         ndmp_config_get_tape_info_reply_v3 reply;
 687         ndmp_device_info_v3 *tip, *tip_save = NULL; /* tape info pointer */
 688         ndmp_device_capability_v3 *dcp;
 689         ndmp_device_capability_v3 *dcp_save = NULL; /* dev capability pointer */
 690         int i, n, max;
 691         sasd_drive_t *sd;
 692         scsi_link_t *sl;
 693         ndmp_pval *envp, *envp_save = NULL;
 694         ndmp_pval *envp_head;
 695 
 696         (void) memset((void*)&reply, 0, sizeof (reply));
 697         max = sasd_dev_count();
 698 
 699         tip_save = tip = ndmp_malloc(sizeof (ndmp_device_info_v3) * max);
 700         dcp_save = dcp = ndmp_malloc(sizeof (ndmp_device_capability_v3) * max);
 701         envp_save = envp = ndmp_malloc(sizeof (ndmp_pval) * max * 3);
 702         if (!tip_save || !dcp_save || !envp_save) {
 703                 free(tip_save);
 704                 free(dcp_save);
 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 
 765         free(tip_save);
 766         free(dcp_save);
 767         free(envp_save);
 768 }
 769 
 770 
 771 /*
 772  * ndmpd_config_get_scsi_info_v3
 773  *
 774  * This handler handles the ndmp_config_get_tape_scsi_request.
 775  * Information about all connected scsi tape stacker and jukeboxes
 776  * is returned.
 777  *
 778  * Parameters:
 779  *   connection (input) - connection handle.
 780  *   body       (input) - request message body.
 781  *
 782  * Returns:
 783  *   void
 784  */
 785 /*ARGSUSED*/
 786 void
 787 ndmpd_config_get_scsi_info_v3(ndmp_connection_t *connection, void *body)
 788 {
 789         ndmp_config_get_scsi_info_reply_v3 reply;
 790         ndmp_device_info_v3 *sip, *sip_save;
 791         ndmp_device_capability_v3 *dcp, *dcp_save;
 792         int i, n, max;
 793         sasd_drive_t *sd;
 794         scsi_link_t *sl;
 795         ndmp_pval *envp, *envp_save = NULL;
 796         ndmp_pval *envp_head;
 797 
 798         (void) memset((void*)&reply, 0, sizeof (reply));
 799         max = sasd_dev_count();
 800         sip_save = sip = ndmp_malloc(sizeof (ndmp_device_info_v3) * max);
 801         dcp_save = dcp = ndmp_malloc(sizeof (ndmp_device_capability_v3) * max);
 802         envp_save = envp = ndmp_malloc(sizeof (ndmp_pval) * max * 2);
 803         if (!sip_save || !dcp_save || !envp_save) {
 804                 free(sip_save);
 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  *
 927  * This handler handles the ndmp_config_get_butype_info_request.
 928  * Information about all supported backup types are returned.
 929  *
 930  * Parameters:
 931  *   connection (input) - connection handle.
 932  *   body       (input) - request message body.
 933  *
 934  * Returns:
 935  *   void
 936  */
 937 /*ARGSUSED*/
 938 void
 939 ndmpd_config_get_butype_info_v4(ndmp_connection_t *connection, void *body)
 940 {
 941         ndmp_config_get_butype_info_reply_v4 reply;
 942         ndmp_butype_info info[3];
 943 
 944         ndmp_pval envs[12];
 945         ulong_t attrs;
 946         ndmp_pval *envp = envs;
 947 
 948         ndmp_pval zfs_envs[11];
 949         ulong_t zfs_attrs;
 950         ndmp_pval *zfs_envp = zfs_envs;
 951 
 952 
 953         (void) memset((void*)&reply, 0, sizeof (reply));
 954 
 955         /*
 956          * Supported environment variables and their default values
 957          * for dump and tar.
 958          *
 959          * The environment variables for dump and tar format are the
 960          * same, because we use the same backup engine for both.
 961          */
 962         NDMP_SETENV(envp, "FILESYSTEM", "");
 963         NDMP_SETENV(envp, "DIRECT", "n");
 964         NDMP_SETENV(envp, "RECURSIVE", "n");
 965         NDMP_SETENV(envp, "TYPE", "");
 966         NDMP_SETENV(envp, "USER", "");
 967         NDMP_SETENV(envp, "HIST", "n");
 968         NDMP_SETENV(envp, "PATHNAME_SEPARATOR", "/");
 969         NDMP_SETENV(envp, "LEVEL", "0");
 970         NDMP_SETENV(envp, "EXTRACT", "y");
 971         NDMP_SETENV(envp, "UPDATE", "y");
 972         NDMP_SETENV(envp, "CMD", "");
 973         NDMP_SETENV(envp, "BASE_DATE", "");
 974 
 975         attrs = NDMP_BUTYPE_RECOVER_FILELIST |
 976             NDMP_BUTYPE_BACKUP_DIRECT |
 977             NDMP_BUTYPE_BACKUP_INCREMENTAL |
 978             NDMP_BUTYPE_BACKUP_UTF8 |
 979             NDMP_BUTYPE_RECOVER_UTF8 |
 980             NDMP_BUTYPE_BACKUP_FH_FILE |
 981             NDMP_BUTYPE_BACKUP_FH_DIR |
 982             NDMP_BUTYPE_RECOVER_FH_FILE |
 983             NDMP_BUTYPE_RECOVER_FH_DIR;
 984 
 985         /* If DAR supported */
 986         if (ndmp_dar_support)
 987                 attrs |= NDMP_BUTYPE_RECOVER_DIRECT;
 988 
 989         /* tar backup type */
 990         info[0].butype_name = "tar";
 991         info[0].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
 992         info[0].default_env.default_env_val = envs;
 993         info[0].attrs = attrs;
 994 
 995         /* dump backup type */
 996         info[1].butype_name = "dump";
 997         info[1].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
 998         info[1].default_env.default_env_val = envs;
 999         info[1].attrs = attrs;
1000 
1001         /*
1002          * Supported environment variables and their default values
1003          * for type "zfs."
1004          */
1005 
1006         NDMP_SETENV(zfs_envp, "USER", "");
1007         NDMP_SETENV(zfs_envp, "CMD", "");
1008         NDMP_SETENV(zfs_envp, "FILESYSTEM", "");
1009         NDMP_SETENV(zfs_envp, "PATHNAME_SEPARATOR", "/");
1010         NDMP_SETENV(zfs_envp, "TYPE", "zfs");
1011         NDMP_SETENV(zfs_envp, "HIST", "n");
1012         NDMP_SETENV(zfs_envp, "LEVEL", "0");
1013         NDMP_SETENV(zfs_envp, "ZFS_MODE", "recursive");
1014         NDMP_SETENV(zfs_envp, "ZFS_FORCE", "n");
1015         NDMP_SETENV(zfs_envp, "UPDATE", "y");
1016         NDMP_SETENV(zfs_envp, "DMP_NAME", "level");
1017 
1018         zfs_attrs = NDMP_BUTYPE_BACKUP_UTF8 |
1019             NDMP_BUTYPE_RECOVER_UTF8 |
1020             NDMP_BUTYPE_BACKUP_DIRECT |
1021             NDMP_BUTYPE_BACKUP_INCREMENTAL;
1022 
1023         /* zfs backup type */
1024         info[2].butype_name = "zfs";
1025         info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval);
1026         info[2].default_env.default_env_val = zfs_envs;
1027         info[2].attrs = zfs_attrs;
1028 
1029         reply.error = NDMP_NO_ERR;
1030         reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info);
1031         reply.butype_info.butype_info_val = info;
1032 
1033         ndmp_send_reply(connection, (void *)&reply,
1034             "sending ndmp_config_get_butype_info reply");
1035 }
1036 
1037 
1038 /*
1039  * ndmpd_config_get_ext_list_v4
1040  *
1041  * This handler handles the ndmpd_config_get_ext_list_v4 request.
1042  *
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.
1084  *
1085  * Parameters:
1086  *   connection (input) - connection handle.
1087  *   body       (input) - request message body.
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 
1135 /*
1136  * ************************************************************************
1137  * LOCALS
1138  * ************************************************************************
1139  */
1140 
1141 /*
1142  * simple_get_attrs
1143  *
1144  * Set the default attrs for dump mode
1145  *
1146  * Parameters:
1147  *   attributes (output) - the attributes for dump mode
1148  *
1149  * Returns:
1150  *   void
1151  */
1152 static void
1153 simple_get_attrs(ulong_t *attributes)
1154 {
1155         *attributes = NDMP_NO_RECOVER_FHINFO;
1156 }