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 41 #include <dirent.h> 42 #include <errno.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <sys/stat.h> 47 #include <sys/mnttab.h> 48 #include <sys/mntent.h> 49 #include <sys/mntio.h> 50 #include <sys/statvfs.h> 51 #include <sys/utsname.h> 52 #include <sys/scsi/scsi.h> 53 #include <unistd.h> 54 #include <sys/systeminfo.h> 55 #include "ndmpd_common.h" 56 #include "ndmpd.h" 57 58 static void simple_get_attrs(ulong_t *attributes); 59 60 /* 61 * Number of environment variable for the file system 62 * info in V3 net_fs_info. 63 */ 64 #define V3_N_FS_ENVS 4 65 66 /* 67 * Is the file system a valid one to be reported to the 68 * clients? 69 */ 70 #define IS_VALID_FS(fs) (fs && ( \ 71 strcasecmp(fs->mnt_fstype, MNTTYPE_UFS) == 0 || \ 72 strcasecmp(fs->mnt_fstype, MNTTYPE_ZFS) == 0 || \ 73 strcasecmp(fs->mnt_fstype, MNTTYPE_NFS) == 0 || \ 74 strcasecmp(fs->mnt_fstype, MNTTYPE_NFS3) == 0 || \ 75 strcasecmp(fs->mnt_fstype, MNTTYPE_NFS4) == 0)) 76 77 #define MNTTYPE_LEN 10 78 79 extern struct fs_ops sfs2_ops; 80 extern struct fs_ops sfs2cpv_ops; 81 82 83 /* 84 * ************************************************************************ 85 * NDMP V2 HANDLERS 86 * ************************************************************************ 87 */ 88 89 /* 90 * ndmpd_config_get_host_info_v2 91 * 92 * This handler handles the ndmp_config_get_host_info request. 93 * Host specific information is returned. 94 * 95 * Parameters: 96 * connection (input) - connection handle. 97 * body (input) - request message body. 98 * 99 * Returns: 100 * void 101 */ 102 /*ARGSUSED*/ 103 void 104 ndmpd_config_get_host_info_v2(ndmp_connection_t *connection, void *body) 105 { 106 ndmp_config_get_host_info_reply_v2 reply; 107 ndmp_auth_type auth_types[2]; 108 char buf[HOSTNAMELEN + 1]; 109 struct utsname uts; 110 char hostidstr[16]; 111 ulong_t hostid; 112 113 (void) memset((void*)&reply, 0, sizeof (reply)); 114 (void) memset(buf, 0, sizeof (buf)); 115 (void) gethostname(buf, sizeof (buf)); 116 117 reply.error = NDMP_NO_ERR; 118 reply.hostname = buf; 119 (void) uname(&uts); 120 reply.os_type = uts.sysname; 121 reply.os_vers = uts.release; 122 123 if (sysinfo(SI_HW_SERIAL, hostidstr, sizeof (hostidstr)) < 0) { 124 NDMP_LOG(LOG_DEBUG, "sysinfo error: %m."); 125 reply.error = NDMP_UNDEFINED_ERR; 126 } 127 128 /* 129 * Convert the hostid to hex. The returned string must match 130 * the string returned by hostid(1). 131 */ 132 hostid = strtoul(hostidstr, 0, 0); 133 (void) snprintf(hostidstr, sizeof (hostidstr), "%lx", hostid); 134 reply.hostid = hostidstr; 135 136 auth_types[0] = NDMP_AUTH_TEXT; 137 reply.auth_type.auth_type_len = 1; 138 reply.auth_type.auth_type_val = auth_types; 139 140 ndmp_send_reply(connection, (void *) &reply, 141 "sending ndmp_config_get_host_info reply"); 142 } 143 144 145 /* 146 * ndmpd_config_get_butype_attr_v2 147 * 148 * This handler handles the ndmp_config_get_butype_attr request. 149 * Information about the specified backup type is returned. 150 * 151 * Parameters: 152 * connection (input) - connection handle. 153 * body (input) - request message body. 154 * 155 * Returns: 156 * void 157 */ 158 void 159 ndmpd_config_get_butype_attr_v2(ndmp_connection_t *connection, void *body) 160 { 161 ndmp_config_get_butype_attr_request *request; 162 ndmp_config_get_butype_attr_reply reply; 163 164 request = (ndmp_config_get_butype_attr_request *)body; 165 166 reply.error = NDMP_NO_ERR; 167 168 if (strcmp(request->name, "dump") == 0) { 169 (void) simple_get_attrs(&reply.attrs); 170 } else if (strcmp(request->name, "tar") == 0) { 171 reply.attrs = NDMP_NO_BACKUP_FILELIST; 172 } else { 173 NDMP_LOG(LOG_ERR, "Invalid backup type: %s.", request->name); 174 NDMP_LOG(LOG_ERR, 175 "Supported backup types are 'dump' and 'tar' only."); 176 reply.error = NDMP_ILLEGAL_ARGS_ERR; 177 } 178 179 ndmp_send_reply(connection, (void *) &reply, 180 "sending ndmp_config_get_butype_attr reply"); 181 } 182 183 184 /* 185 * ndmpd_config_get_mover_type_v2 186 * 187 * This handler handles the ndmp_config_get_mover_type request. 188 * Information about the supported mover types is returned. 189 * 190 * Parameters: 191 * connection (input) - connection handle. 192 * body (input) - request message body. 193 * 194 * Returns: 195 * void 196 */ 197 /*ARGSUSED*/ 198 void 199 ndmpd_config_get_mover_type_v2(ndmp_connection_t *connection, void *body) 200 { 201 ndmp_config_get_mover_type_reply reply; 202 ndmp_addr_type types[2]; 203 204 types[0] = NDMP_ADDR_LOCAL; 205 types[1] = NDMP_ADDR_TCP; 206 207 reply.error = NDMP_NO_ERR; 208 reply.methods.methods_len = 2; 209 reply.methods.methods_val = types; 210 211 ndmp_send_reply(connection, (void *) &reply, 212 "sending ndmp_config_get_mover_type reply"); 213 } 214 215 216 217 /* 218 * ndmpd_config_get_auth_attr_v2 219 * 220 * This handler handles the ndmp_config_get_auth_attr request. 221 * Authorization type specific information is returned. 222 * 223 * Parameters: 224 * connection (input) - connection handle. 225 * body (input) - request message body. 226 * 227 * Returns: 228 * void 229 */ 230 void 231 ndmpd_config_get_auth_attr_v2(ndmp_connection_t *connection, void *body) 232 { 233 ndmp_config_get_auth_attr_request *request; 234 ndmp_config_get_auth_attr_reply reply; 235 ndmpd_session_t *session = ndmp_get_client_data(connection); 236 237 request = (ndmp_config_get_auth_attr_request *)body; 238 239 reply.error = NDMP_NO_ERR; 240 reply.server_attr.auth_type = request->auth_type; 241 242 switch (request->auth_type) { 243 case NDMP_AUTH_TEXT: 244 break; 245 case NDMP_AUTH_MD5: 246 /* Create a 64 byte random session challenge */ 247 randomize(session->ns_challenge, MD5_CHALLENGE_SIZE); 248 (void) memcpy(reply.server_attr.ndmp_auth_attr_u.challenge, 249 session->ns_challenge, MD5_CHALLENGE_SIZE); 250 break; 251 case NDMP_AUTH_NONE: 252 /* FALL THROUGH */ 253 default: 254 NDMP_LOG(LOG_ERR, "Invalid authentication type: %d.", 255 request->auth_type); 256 NDMP_LOG(LOG_ERR, 257 "Supported authentication types are md5 and cleartext."); 258 reply.error = NDMP_ILLEGAL_ARGS_ERR; 259 break; 260 } 261 262 ndmp_send_reply(connection, (void *) &reply, 263 "sending ndmp_config_get_auth_attr reply"); 264 } 265 266 267 /* 268 * ************************************************************************ 269 * NDMP V3 HANDLERS 270 * ************************************************************************ 271 */ 272 273 /* 274 * ndmpd_config_get_host_info_v3 275 * 276 * This handler handles the ndmp_config_get_host_info request. 277 * Host specific information is returned. 278 * 279 * Parameters: 280 * connection (input) - connection handle. 281 * body (input) - request message body. 282 * 283 * Returns: 284 * void 285 */ 286 /*ARGSUSED*/ 287 void 288 ndmpd_config_get_host_info_v3(ndmp_connection_t *connection, void *body) 289 { 290 ndmp_config_get_host_info_reply_v3 reply; 291 char buf[HOSTNAMELEN+1]; 292 struct utsname uts; 293 char hostidstr[16]; 294 ulong_t hostid; 295 296 (void) memset((void*)&reply, 0, sizeof (reply)); 297 (void) memset(buf, 0, sizeof (buf)); 298 (void) gethostname(buf, sizeof (buf)); 299 300 301 reply.error = NDMP_NO_ERR; 302 reply.hostname = buf; 303 (void) uname(&uts); 304 reply.os_type = uts.sysname; 305 reply.os_vers = uts.release; 306 307 if (sysinfo(SI_HW_SERIAL, hostidstr, sizeof (hostidstr)) < 0) { 308 309 NDMP_LOG(LOG_DEBUG, "sysinfo error: %m."); 310 reply.error = NDMP_UNDEFINED_ERR; 311 } 312 313 /* 314 * Convert the hostid to hex. The returned string must match 315 * the string returned by hostid(1). 316 */ 317 hostid = strtoul(hostidstr, 0, 0); 318 (void) snprintf(hostidstr, sizeof (hostidstr), "%lx", hostid); 319 reply.hostid = hostidstr; 320 321 ndmp_send_reply(connection, (void *) &reply, 322 "sending ndmp_config_get_host_info reply"); 323 } 324 325 326 /* 327 * ndmpd_config_get_connection_type_v3 328 * 329 * This handler handles the ndmp_config_get_connection_type_request. 330 * A list of supported data connection types is returned. 331 * 332 * Parameters: 333 * connection (input) - connection handle. 334 * body (input) - request message body. 335 * 336 * Returns: 337 * void 338 */ 339 /*ARGSUSED*/ 340 void 341 ndmpd_config_get_connection_type_v3(ndmp_connection_t *connection, 342 void *body) 343 { 344 ndmp_config_get_connection_type_reply_v3 reply; 345 ndmp_addr_type addr_types[2]; 346 347 (void) memset((void*)&reply, 0, sizeof (reply)); 348 349 reply.error = NDMP_NO_ERR; 350 351 addr_types[0] = NDMP_ADDR_LOCAL; 352 addr_types[1] = NDMP_ADDR_TCP; 353 reply.addr_types.addr_types_len = 2; 354 reply.addr_types.addr_types_val = addr_types; 355 356 ndmp_send_reply(connection, (void *) &reply, 357 "sending config_get_connection_type_v3 reply"); 358 } 359 360 361 362 /* 363 * ndmpd_config_get_auth_attr_v3 364 * 365 * This handler handles the ndmp_config_get_auth_attr request. 366 * Authorization type specific information is returned. 367 * 368 * Parameters: 369 * connection (input) - connection handle. 370 * body (input) - request message body. 371 * 372 * Returns: 373 * void 374 */ 375 void 376 ndmpd_config_get_auth_attr_v3(ndmp_connection_t *connection, void *body) 377 { 378 ndmp_config_get_auth_attr_request *request; 379 ndmp_config_get_auth_attr_reply reply; 380 ndmpd_session_t *session = ndmp_get_client_data(connection); 381 382 request = (ndmp_config_get_auth_attr_request *)body; 383 384 (void) memset((void*)&reply, 0, sizeof (reply)); 385 reply.error = NDMP_NO_ERR; 386 reply.server_attr.auth_type = request->auth_type; 387 388 switch (request->auth_type) { 389 case NDMP_AUTH_TEXT: 390 break; 391 case NDMP_AUTH_MD5: 392 /* Create a 64 bytes random session challenge */ 393 randomize(session->ns_challenge, MD5_CHALLENGE_SIZE); 394 (void) memcpy(reply.server_attr.ndmp_auth_attr_u.challenge, 395 session->ns_challenge, MD5_CHALLENGE_SIZE); 396 break; 397 case NDMP_AUTH_NONE: 398 /* FALL THROUGH */ 399 default: 400 NDMP_LOG(LOG_ERR, "Invalid authentication type: %d.", 401 request->auth_type); 402 NDMP_LOG(LOG_ERR, 403 "Supported authentication types are md5 and cleartext."); 404 reply.error = NDMP_ILLEGAL_ARGS_ERR; 405 break; 406 } 407 408 ndmp_send_reply(connection, (void *) &reply, 409 "sending ndmp_config_get_auth_attr_v3 reply"); 410 } 411 412 413 /* 414 * ndmpd_config_get_butype_info_v3 415 * 416 * This handler handles the ndmp_config_get_butype_info_request. 417 * Information about all supported backup types are returned. 418 * 419 * Parameters: 420 * connection (input) - connection handle. 421 * body (input) - request message body. 422 * 423 * Returns: 424 * void 425 */ 426 /*ARGSUSED*/ 427 void 428 ndmpd_config_get_butype_info_v3(ndmp_connection_t *connection, void *body) 429 { 430 ndmp_config_get_butype_info_reply_v3 reply; 431 ndmp_butype_info info[3]; 432 ndmp_pval envs[8]; 433 ulong_t attrs; 434 ndmp_pval *envp = envs; 435 436 ndmp_pval zfs_envs[9]; 437 ulong_t zfs_attrs; 438 ndmp_pval *zfs_envp = zfs_envs; 439 440 (void) memset((void*)&reply, 0, sizeof (reply)); 441 442 /* 443 * Supported environment variables and their default values 444 * for dump and tar. 445 * 446 * The environment variables for dump and tar format are the 447 * same, because we use the same backup engine for both. 448 */ 449 NDMP_SETENV(envp, "PREFIX", ""); 450 NDMP_SETENV(envp, "TYPE", ""); 451 NDMP_SETENV(envp, "DIRECT", "n"); 452 NDMP_SETENV(envp, "HIST", "n"); 453 NDMP_SETENV(envp, "FILESYSTEM", ""); 454 NDMP_SETENV(envp, "LEVEL", "0"); 455 NDMP_SETENV(envp, "UPDATE", "TRUE"); 456 NDMP_SETENV(envp, "BASE_DATE", ""); 457 458 attrs = NDMP_BUTYPE_BACKUP_FILE_HISTORY | 459 NDMP_BUTYPE_RECOVER_FILELIST | 460 NDMP_BUTYPE_BACKUP_DIRECT | 461 NDMP_BUTYPE_BACKUP_INCREMENTAL | 462 NDMP_BUTYPE_BACKUP_UTF8 | 463 NDMP_BUTYPE_RECOVER_UTF8; 464 465 /* If DAR supported */ 466 if (ndmp_dar_support) 467 attrs |= NDMP_BUTYPE_RECOVER_DIRECT; 468 469 /* tar backup type */ 470 info[0].butype_name = "tar"; 471 info[0].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval); 472 info[0].default_env.default_env_val = envs; 473 info[0].attrs = attrs; 474 475 /* dump backup type */ 476 info[1].butype_name = "dump"; 477 info[1].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval); 478 info[1].default_env.default_env_val = envs; 479 info[1].attrs = attrs; 480 481 /* 482 * Supported environment variables and their default values 483 * for type "zfs." 484 */ 485 486 NDMP_SETENV(zfs_envp, "PREFIX", ""); 487 NDMP_SETENV(zfs_envp, "FILESYSTEM", ""); 488 NDMP_SETENV(zfs_envp, "TYPE", "zfs"); 489 NDMP_SETENV(zfs_envp, "HIST", "n"); 490 NDMP_SETENV(zfs_envp, "LEVEL", "0"); 491 NDMP_SETENV(zfs_envp, "ZFS_MODE", "recursive"); 492 NDMP_SETENV(zfs_envp, "ZFS_FORCE", "FALSE"); 493 NDMP_SETENV(zfs_envp, "UPDATE", "TRUE"); 494 NDMP_SETENV(zfs_envp, "DMP_NAME", "level"); 495 496 zfs_attrs = NDMP_BUTYPE_BACKUP_UTF8 | 497 NDMP_BUTYPE_RECOVER_UTF8 | 498 NDMP_BUTYPE_BACKUP_DIRECT | 499 NDMP_BUTYPE_BACKUP_INCREMENTAL; 500 501 /* zfs backup type */ 502 info[2].butype_name = "zfs"; 503 info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval); 504 info[2].default_env.default_env_val = zfs_envs; 505 info[2].attrs = zfs_attrs; 506 507 reply.error = NDMP_NO_ERR; 508 reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info); 509 reply.butype_info.butype_info_val = info; 510 511 ndmp_send_reply(connection, (void *)&reply, 512 "sending ndmp_config_get_butype_info reply"); 513 } 514 515 /* 516 * ndmpd_config_get_fs_info_v3 517 * 518 * This handler handles the ndmp_config_get_fs_info_request. 519 * Information about all mounted file systems is returned. 520 * 521 * Parameters: 522 * connection (input) - connection handle. 523 * body (input) - request message body. 524 * 525 * Returns: 526 * void 527 */ 528 /*ARGSUSED*/ 529 void 530 ndmpd_config_get_fs_info_v3(ndmp_connection_t *connection, void *body) 531 { 532 ndmp_config_get_fs_info_reply_v3 reply; 533 ndmp_fs_info_v3 *fsip, *fsip_save; /* FS info pointer */ 534 int i, nmnt, fd; 535 int log_dev_len; 536 FILE *fp = NULL; 537 struct mnttab mt, *fs; 538 struct statvfs64 stat_buf; 539 ndmp_pval *envp, *save; 540 541 (void) memset((void*)&reply, 0, sizeof (reply)); 542 reply.error = NDMP_NO_ERR; 543 544 if ((fd = open(MNTTAB, O_RDONLY)) == -1) { 545 NDMP_LOG(LOG_ERR, "File mnttab open error: %m."); 546 reply.error = NDMP_UNDEFINED_ERR; 547 ndmp_send_reply(connection, (void *)&reply, 548 "sending ndmp_config_get_fs_info reply"); 549 return; 550 } 551 552 /* nothing was found, send an empty reply */ 553 if (ioctl(fd, MNTIOC_NMNTS, &nmnt) != 0 || nmnt <= 0) { 554 NDMP_LOG(LOG_ERR, "No file system found."); 555 ndmp_send_reply(connection, (void *)&reply, 556 "sending ndmp_config_get_fs_info reply"); 557 (void) close(fd); 558 return; 559 } 560 (void) close(fd); 561 562 fp = fopen(MNTTAB, "r"); 563 if (!fp) { 564 NDMP_LOG(LOG_ERR, "File mnttab open error: %m."); 565 reply.error = NDMP_UNDEFINED_ERR; 566 ndmp_send_reply(connection, (void *)&reply, 567 "sending ndmp_config_get_fs_info reply"); 568 return; 569 } 570 571 fsip_save = fsip = ndmp_malloc(sizeof (ndmp_fs_info_v3) * nmnt); 572 if (!fsip) { 573 (void) fclose(fp); 574 reply.error = NDMP_NO_MEM_ERR; 575 ndmp_send_reply(connection, (void *)&reply, 576 "error sending ndmp_config_get_fs_info reply"); 577 return; 578 } 579 580 /* 581 * Re-read the directory and set up file system information. 582 */ 583 i = 0; 584 rewind(fp); 585 while (i < nmnt && (getmntent(fp, &mt) == 0)) 586 587 { 588 fs = &mt; 589 log_dev_len = strlen(mt.mnt_mountp)+2; 590 if (!IS_VALID_FS(fs)) 591 continue; 592 593 fsip->fs_logical_device = ndmp_malloc(log_dev_len); 594 fsip->fs_type = ndmp_malloc(MNTTYPE_LEN); 595 if (!fsip->fs_logical_device || !fsip->fs_type) { 596 reply.error = NDMP_NO_MEM_ERR; 597 free(fsip->fs_logical_device); 598 free(fsip->fs_type); 599 break; 600 } 601 (void) snprintf(fsip->fs_type, MNTTYPE_LEN, "%s", 602 fs->mnt_fstype); 603 (void) snprintf(fsip->fs_logical_device, log_dev_len, "%s", 604 fs->mnt_mountp); 605 fsip->invalid = 0; 606 607 if (statvfs64(fs->mnt_mountp, &stat_buf) < 0) { 608 NDMP_LOG(LOG_DEBUG, 609 "statvfs(%s) error.", fs->mnt_mountp); 610 fsip->fs_status = 611 "statvfs error: unable to determine filesystem" 612 " attributes"; 613 } else { 614 fsip->invalid = 0; 615 fsip->total_size = 616 long_long_to_quad((u_longlong_t)stat_buf.f_frsize * 617 (u_longlong_t)stat_buf.f_blocks); 618 fsip->used_size = 619 long_long_to_quad((u_longlong_t)stat_buf.f_frsize * 620 (u_longlong_t)(stat_buf.f_blocks-stat_buf.f_bfree)); 621 622 fsip->avail_size = 623 long_long_to_quad((u_longlong_t)stat_buf.f_frsize * 624 (u_longlong_t)stat_buf.f_bfree); 625 fsip->total_inodes = 626 long_long_to_quad((u_longlong_t)stat_buf.f_files); 627 fsip->used_inodes = 628 long_long_to_quad((u_longlong_t)(stat_buf.f_files - 629 stat_buf.f_ffree)); 630 fsip->fs_status = ""; 631 } 632 save = envp = ndmp_malloc(sizeof (ndmp_pval) * V3_N_FS_ENVS); 633 if (!envp) { 634 reply.error = NDMP_NO_MEM_ERR; 635 break; 636 } 637 (void) memset((void*)save, 0, 638 V3_N_FS_ENVS * sizeof (ndmp_pval)); 639 640 fsip->fs_env.fs_env_val = envp; 641 NDMP_SETENV(envp, "LOCAL", "y"); 642 NDMP_SETENV(envp, "TYPE", fsip->fs_type); 643 NDMP_SETENV(envp, "AVAILABLE_BACKUP", "tar,dump"); 644 645 if (FS_READONLY(fs) == 0) { 646 NDMP_SETENV(envp, "AVAILABLE_RECOVERY", "tar,dump"); 647 } 648 649 fsip->fs_env.fs_env_len = envp - save; 650 i++; 651 fsip++; 652 } 653 (void) fclose(fp); 654 if (reply.error == NDMP_NO_ERR) { 655 reply.fs_info.fs_info_len = i; 656 reply.fs_info.fs_info_val = fsip_save; 657 } else { 658 reply.fs_info.fs_info_len = 0; 659 reply.fs_info.fs_info_val = NULL; 660 } 661 ndmp_send_reply(connection, (void *)&reply, 662 "error sending ndmp_config_get_fs_info reply"); 663 664 fsip = fsip_save; 665 while (--i >= 0) { 666 free(fsip->fs_logical_device); 667 free(fsip->fs_env.fs_env_val); 668 free(fsip->fs_type); 669 fsip++; 670 } 671 672 free(fsip_save); 673 } 674 675 676 /* 677 * ndmpd_config_get_tape_info_v3 678 * 679 * This handler handles the ndmp_config_get_tape_info_request. 680 * Information about all connected tape drives is returned. 681 * 682 * Parameters: 683 * connection (input) - connection handle. 684 * body (input) - request message body. 685 * 686 * Returns: 687 * void 688 */ 689 /*ARGSUSED*/ 690 void 691 ndmpd_config_get_tape_info_v3(ndmp_connection_t *connection, void *body) 692 { 693 ndmp_config_get_tape_info_reply_v3 reply; 694 ndmp_device_info_v3 *tip, *tip_save = NULL; /* tape info pointer */ 695 ndmp_device_capability_v3 *dcp; 696 ndmp_device_capability_v3 *dcp_save = NULL; /* dev capability pointer */ 697 int i, n, max; 698 sasd_drive_t *sd; 699 scsi_link_t *sl; 700 ndmp_pval *envp, *envp_save = NULL; 701 ndmp_pval *envp_head; 702 703 (void) memset((void*)&reply, 0, sizeof (reply)); 704 max = sasd_dev_count(); 705 706 tip_save = tip = ndmp_malloc(sizeof (ndmp_device_info_v3) * max); 707 dcp_save = dcp = ndmp_malloc(sizeof (ndmp_device_capability_v3) * max); 708 envp_save = envp = ndmp_malloc(sizeof (ndmp_pval) * max * 3); 709 if (!tip_save || !dcp_save || !envp_save) { 710 free(tip_save); 711 free(dcp_save); 712 free(envp_save); 713 reply.error = NDMP_NO_MEM_ERR; 714 ndmp_send_reply(connection, (void *)&reply, 715 "error sending ndmp_config_get_tape_info reply"); 716 return; 717 } 718 719 reply.error = NDMP_NO_ERR; 720 721 for (i = n = 0; i < max; i++) { 722 if (!(sl = sasd_dev_slink(i)) || !(sd = sasd_drive(i))) 723 continue; 724 if (sl->sl_type != DTYPE_SEQUENTIAL) 725 continue; 726 /* 727 * Don't report dead links. 728 */ 729 if ((access(sd->sd_name, F_OK) == -1) && (errno == ENOENT)) 730 continue; 731 732 NDMP_LOG(LOG_DEBUG, 733 "model \"%s\" dev \"%s\"", sd->sd_id, sd->sd_name); 734 735 envp_head = envp; 736 NDMP_SETENV(envp, "EXECUTE_CDB", "b"); 737 NDMP_SETENV(envp, "SERIAL_NUMBER", sd->sd_serial); 738 NDMP_SETENV(envp, "WORLD_WIDE_NAME", sd->sd_wwn); 739 740 tip->model = sd->sd_id; /* like "DLT7000 " */ 741 tip->caplist.caplist_len = 1; 742 tip->caplist.caplist_val = dcp; 743 dcp->device = sd->sd_name; /* like "isp1t060" */ 744 dcp->attr = 0; 745 dcp->capability.capability_len = 3; 746 dcp->capability.capability_val = envp_head; 747 tip++; 748 dcp++; 749 n++; 750 } 751 752 NDMP_LOG(LOG_DEBUG, "n %d", n); 753 754 /* 755 * We should not receive the get_tape_info when three-way backup is 756 * running and we are acting as just data, but some clients try 757 * to get the Tape information anyway. 758 */ 759 if (n == 0 || max <= 0) { 760 reply.error = NDMP_NO_DEVICE_ERR; 761 ndmp_send_reply(connection, (void *)&reply, 762 "error sending ndmp_config_get_tape_info reply"); 763 free(tip_save); free(dcp_save); free(envp_save); 764 return; 765 } 766 767 768 reply.tape_info.tape_info_len = n; 769 reply.tape_info.tape_info_val = tip_save; 770 771 ndmp_send_reply(connection, (void *)&reply, 772 "error sending ndmp_config_get_tape_info reply"); 773 774 free(tip_save); 775 free(dcp_save); 776 free(envp_save); 777 } 778 779 780 /* 781 * ndmpd_config_get_scsi_info_v3 782 * 783 * This handler handles the ndmp_config_get_tape_scsi_request. 784 * Information about all connected scsi tape stacker and jukeboxes 785 * is returned. 786 * 787 * Parameters: 788 * connection (input) - connection handle. 789 * body (input) - request message body. 790 * 791 * Returns: 792 * void 793 */ 794 /*ARGSUSED*/ 795 void 796 ndmpd_config_get_scsi_info_v3(ndmp_connection_t *connection, void *body) 797 { 798 ndmp_config_get_scsi_info_reply_v3 reply; 799 ndmp_device_info_v3 *sip, *sip_save; 800 ndmp_device_capability_v3 *dcp, *dcp_save; 801 int i, n, max; 802 sasd_drive_t *sd; 803 scsi_link_t *sl; 804 ndmp_pval *envp, *envp_save = NULL; 805 ndmp_pval *envp_head; 806 807 (void) memset((void*)&reply, 0, sizeof (reply)); 808 max = sasd_dev_count(); 809 sip_save = sip = ndmp_malloc(sizeof (ndmp_device_info_v3) * max); 810 dcp_save = dcp = ndmp_malloc(sizeof (ndmp_device_capability_v3) * max); 811 envp_save = envp = ndmp_malloc(sizeof (ndmp_pval) * max * 2); 812 if (!sip_save || !dcp_save || !envp_save) { 813 free(sip_save); 814 free(dcp_save); 815 free(envp_save); 816 reply.error = NDMP_NO_MEM_ERR; 817 ndmp_send_reply(connection, (void *)&reply, 818 "error sending ndmp_config_get_scsi_info reply"); 819 return; 820 } 821 822 reply.error = NDMP_NO_ERR; 823 for (i = n = 0; i < max; i++) { 824 if (!(sl = sasd_dev_slink(i)) || !(sd = sasd_drive(i))) 825 continue; 826 if (sl->sl_type != DTYPE_CHANGER) 827 continue; 828 /* 829 * Don't report dead links. 830 */ 831 if ((access(sd->sd_name, F_OK) == -1) && (errno == ENOENT)) 832 continue; 833 834 NDMP_LOG(LOG_DEBUG, 835 "model \"%s\" dev \"%s\"", sd->sd_id, sd->sd_name); 836 837 envp_head = envp; 838 NDMP_SETENV(envp, "SERIAL_NUMBER", sd->sd_serial); 839 NDMP_SETENV(envp, "WORLD_WIDE_NAME", sd->sd_wwn); 840 841 sip->model = sd->sd_id; /* like "Powerstor L200 " */ 842 sip->caplist.caplist_len = 1; 843 sip->caplist.caplist_val = dcp; 844 dcp->device = sd->sd_name; /* like "isp1m000" */ 845 846 dcp->attr = 0; 847 dcp->capability.capability_len = 2; 848 dcp->capability.capability_val = envp_head; 849 sip++; 850 dcp++; 851 n++; 852 } 853 854 NDMP_LOG(LOG_DEBUG, "n %d", n); 855 856 reply.scsi_info.scsi_info_len = n; 857 reply.scsi_info.scsi_info_val = sip_save; 858 859 ndmp_send_reply(connection, (void *)&reply, 860 "error sending ndmp_config_get_scsi_info reply"); 861 862 free(sip_save); 863 free(dcp_save); 864 free(envp_save); 865 } 866 867 868 /* 869 * ndmpd_config_get_server_info_v3 870 * 871 * This handler handles the ndmp_config_get_server_info request. 872 * Host specific information is returned. 873 * 874 * Parameters: 875 * connection (input) - connection handle. 876 * body (input) - request message body. 877 * 878 * Returns: 879 * void 880 */ 881 /*ARGSUSED*/ 882 void 883 ndmpd_config_get_server_info_v3(ndmp_connection_t *connection, void *body) 884 { 885 ndmp_config_get_server_info_reply_v3 reply; 886 ndmp_auth_type auth_types[2]; 887 char rev_number[10]; 888 ndmpd_session_t *session = ndmp_get_client_data(connection); 889 890 (void) memset((void*)&reply, 0, sizeof (reply)); 891 reply.error = NDMP_NO_ERR; 892 893 if (connection->conn_authorized || 894 session->ns_protocol_version != NDMPV4) { 895 reply.vendor_name = VENDOR_NAME; 896 reply.product_name = PRODUCT_NAME; 897 (void) snprintf(rev_number, sizeof (rev_number), "%d", 898 ndmp_ver); 899 reply.revision_number = rev_number; 900 } else { 901 reply.vendor_name = "\0"; 902 reply.product_name = "\0"; 903 reply.revision_number = "\0"; 904 } 905 906 NDMP_LOG(LOG_DEBUG, 907 "vendor \"%s\", product \"%s\" rev \"%s\"", 908 reply.vendor_name, reply.product_name, reply.revision_number); 909 910 auth_types[0] = NDMP_AUTH_TEXT; 911 auth_types[1] = NDMP_AUTH_MD5; 912 reply.auth_type.auth_type_len = ARRAY_LEN(auth_types, ndmp_auth_type); 913 reply.auth_type.auth_type_val = auth_types; 914 915 ndmp_send_reply(connection, (void *)&reply, 916 "error sending ndmp_config_get_server_info reply"); 917 } 918 919 920 921 /* 922 * ************************************************************************ 923 * NDMP V4 HANDLERS 924 * ************************************************************************ 925 */ 926 927 /* 928 * ndmpd_config_get_butype_info_v4 929 * 930 * This handler handles the ndmp_config_get_butype_info_request. 931 * Information about all supported backup types are returned. 932 * 933 * Parameters: 934 * connection (input) - connection handle. 935 * body (input) - request message body. 936 * 937 * Returns: 938 * void 939 */ 940 /*ARGSUSED*/ 941 void 942 ndmpd_config_get_butype_info_v4(ndmp_connection_t *connection, void *body) 943 { 944 ndmp_config_get_butype_info_reply_v4 reply; 945 ndmp_butype_info info[3]; 946 947 ndmp_pval envs[12]; 948 ulong_t attrs; 949 ndmp_pval *envp = envs; 950 951 ndmp_pval zfs_envs[11]; 952 ulong_t zfs_attrs; 953 ndmp_pval *zfs_envp = zfs_envs; 954 955 956 (void) memset((void*)&reply, 0, sizeof (reply)); 957 958 /* 959 * Supported environment variables and their default values 960 * for dump and tar. 961 * 962 * The environment variables for dump and tar format are the 963 * same, because we use the same backup engine for both. 964 */ 965 NDMP_SETENV(envp, "FILESYSTEM", ""); 966 NDMP_SETENV(envp, "DIRECT", "n"); 967 NDMP_SETENV(envp, "RECURSIVE", "n"); 968 NDMP_SETENV(envp, "TYPE", ""); 969 NDMP_SETENV(envp, "USER", ""); 970 NDMP_SETENV(envp, "HIST", "n"); 971 NDMP_SETENV(envp, "PATHNAME_SEPARATOR", "/"); 972 NDMP_SETENV(envp, "LEVEL", "0"); 973 NDMP_SETENV(envp, "EXTRACT", "y"); 974 NDMP_SETENV(envp, "UPDATE", "y"); 975 NDMP_SETENV(envp, "CMD", ""); 976 NDMP_SETENV(envp, "BASE_DATE", ""); 977 978 attrs = NDMP_BUTYPE_RECOVER_FILELIST | 979 NDMP_BUTYPE_BACKUP_DIRECT | 980 NDMP_BUTYPE_BACKUP_INCREMENTAL | 981 NDMP_BUTYPE_BACKUP_UTF8 | 982 NDMP_BUTYPE_RECOVER_UTF8 | 983 NDMP_BUTYPE_BACKUP_FH_FILE | 984 NDMP_BUTYPE_BACKUP_FH_DIR | 985 NDMP_BUTYPE_RECOVER_FH_FILE | 986 NDMP_BUTYPE_RECOVER_FH_DIR; 987 988 /* If DAR supported */ 989 if (ndmp_dar_support) 990 attrs |= NDMP_BUTYPE_RECOVER_DIRECT; 991 992 /* tar backup type */ 993 info[0].butype_name = "tar"; 994 info[0].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval); 995 info[0].default_env.default_env_val = envs; 996 info[0].attrs = attrs; 997 998 /* dump backup type */ 999 info[1].butype_name = "dump"; 1000 info[1].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval); 1001 info[1].default_env.default_env_val = envs; 1002 info[1].attrs = attrs; 1003 1004 /* 1005 * Supported environment variables and their default values 1006 * for type "zfs." 1007 */ 1008 1009 NDMP_SETENV(zfs_envp, "USER", ""); 1010 NDMP_SETENV(zfs_envp, "CMD", ""); 1011 NDMP_SETENV(zfs_envp, "FILESYSTEM", ""); 1012 NDMP_SETENV(zfs_envp, "PATHNAME_SEPARATOR", "/"); 1013 NDMP_SETENV(zfs_envp, "TYPE", "zfs"); 1014 NDMP_SETENV(zfs_envp, "HIST", "n"); 1015 NDMP_SETENV(zfs_envp, "LEVEL", "0"); 1016 NDMP_SETENV(zfs_envp, "ZFS_MODE", "recursive"); 1017 NDMP_SETENV(zfs_envp, "ZFS_FORCE", "n"); 1018 NDMP_SETENV(zfs_envp, "UPDATE", "y"); 1019 NDMP_SETENV(zfs_envp, "DMP_NAME", "level"); 1020 1021 zfs_attrs = NDMP_BUTYPE_BACKUP_UTF8 | 1022 NDMP_BUTYPE_RECOVER_UTF8 | 1023 NDMP_BUTYPE_BACKUP_DIRECT | 1024 NDMP_BUTYPE_BACKUP_INCREMENTAL; 1025 1026 /* zfs backup type */ 1027 info[2].butype_name = "zfs"; 1028 info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval); 1029 info[2].default_env.default_env_val = zfs_envs; 1030 info[2].attrs = zfs_attrs; 1031 1032 reply.error = NDMP_NO_ERR; 1033 reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info); 1034 reply.butype_info.butype_info_val = info; 1035 1036 ndmp_send_reply(connection, (void *)&reply, 1037 "sending ndmp_config_get_butype_info reply"); 1038 } 1039 1040 1041 /* 1042 * ndmpd_config_get_ext_list_v4 1043 * 1044 * This handler handles the ndmpd_config_get_ext_list_v4 request. 1045 * 1046 * Parameters: 1047 * connection (input) - connection handle. 1048 * body (input) - request message body. 1049 * 1050 * Returns: 1051 * void 1052 */ 1053 /*ARGSUSED*/ 1054 void 1055 ndmpd_config_get_ext_list_v4(ndmp_connection_t *connection, void *body) 1056 { 1057 ndmp_config_get_ext_list_reply_v4 reply; 1058 ndmpd_session_t *session = ndmp_get_client_data(connection); 1059 1060 (void) memset((void*)&reply, 0, sizeof (reply)); 1061 1062 if (session->ns_set_ext_list == FALSE) 1063 reply.error = NDMP_EXT_DANDN_ILLEGAL_ERR; 1064 else 1065 reply.error = NDMP_NO_ERR; 1066 1067 reply.class_list.class_list_val = NULL; 1068 reply.class_list.class_list_len = 0; 1069 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 /*ARGSUSED*/ 1088 void 1089 ndmpd_config_set_ext_list_v4(ndmp_connection_t *connection, void *body) 1090 { 1091 ndmp_config_set_ext_list_reply_v4 reply; 1092 ndmpd_session_t *session = ndmp_get_client_data(connection); 1093 1094 (void) memset((void*)&reply, 0, sizeof (reply)); 1095 if (session->ns_set_ext_list == TRUE) { 1096 reply.error = NDMP_EXT_DANDN_ILLEGAL_ERR; 1097 } else { 1098 session->ns_set_ext_list = TRUE; 1099 /* 1100 * NOTE: for now we are not supporting any extension list, 1101 * hence this error, when we start to support extensions, 1102 * this should be validated 1103 */ 1104 1105 reply.error = NDMP_VERSION_NOT_SUPPORTED_ERR; 1106 } 1107 1108 ndmp_send_reply(connection, (void *)&reply, 1109 "error sending ndmp_config_set_ext_list reply"); 1110 } 1111 1112 1113 1114 /* 1115 * ************************************************************************ 1116 * LOCALS 1117 * ************************************************************************ 1118 */ 1119 1120 /* 1121 * simple_get_attrs 1122 * 1123 * Set the default attrs for dump mode 1124 * 1125 * Parameters: 1126 * attributes (output) - the attributes for dump mode 1127 * 1128 * Returns: 1129 * void 1130 */ 1131 static void 1132 simple_get_attrs(ulong_t *attributes) 1133 { 1134 *attributes = NDMP_NO_RECOVER_FHINFO; 1135 } 1136