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 } 1152