Home | History | Annotate | Download | only in ndmp
      1 /*
      2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 /*
      7  * BSD 3 Clause License
      8  *
      9  * Copyright (c) 2007, The Storage Networking Industry Association.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 	- Redistributions of source code must retain the above copyright
     15  *	  notice, this list of conditions and the following disclaimer.
     16  *
     17  * 	- Redistributions in binary form must reproduce the above copyright
     18  *	  notice, this list of conditions and the following disclaimer in
     19  *	  the documentation and/or other materials provided with the
     20  *	  distribution.
     21  *
     22  *	- Neither the name of The Storage Networking Industry Association (SNIA)
     23  *	  nor the names of its contributors may be used to endorse or promote
     24  *	  products derived from this software without specific prior written
     25  *	  permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37  * POSSIBILITY OF SUCH DAMAGE.
     38  */
     39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
     40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. 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[2];
    433 	ndmp_pval envs[8];
    434 	ulong_t attrs;
    435 	ndmp_pval *envp = envs;
    436 
    437 	(void) memset((void*)&reply, 0, sizeof (reply));
    438 
    439 	/*
    440 	 * Supported environment variables and their default values.
    441 	 * The environment variables for dump and tar format are the
    442 	 * same, because we use the same backup engine for both.
    443 	 */
    444 	NDMP_SETENV(envp, "PREFIX", "");
    445 	NDMP_SETENV(envp, "TYPE", "");
    446 	NDMP_SETENV(envp, "DIRECT", "n");
    447 	NDMP_SETENV(envp, "HIST", "n");
    448 	NDMP_SETENV(envp, "FILESYSTEM", "");
    449 	NDMP_SETENV(envp, "LEVEL", "0");
    450 	NDMP_SETENV(envp, "UPDATE", "TRUE");
    451 	NDMP_SETENV(envp, "BASE_DATE", "");
    452 
    453 	attrs = NDMP_BUTYPE_BACKUP_FILE_HISTORY |
    454 	    NDMP_BUTYPE_RECOVER_FILELIST |
    455 	    NDMP_BUTYPE_BACKUP_DIRECT |
    456 	    NDMP_BUTYPE_BACKUP_INCREMENTAL |
    457 	    NDMP_BUTYPE_BACKUP_UTF8 |
    458 	    NDMP_BUTYPE_RECOVER_UTF8;
    459 
    460 	/* If DAR supported */
    461 	if (ndmp_dar_support)
    462 		attrs |= NDMP_BUTYPE_RECOVER_DIRECT;
    463 
    464 	/* tar backup type */
    465 	info[0].butype_name = "tar";
    466 	info[0].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
    467 	info[0].default_env.default_env_val = envs;
    468 	info[0].attrs = attrs;
    469 
    470 	/* dump backup type */
    471 	info[1].butype_name = "dump";
    472 	info[1].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
    473 	info[1].default_env.default_env_val = envs;
    474 	info[1].attrs = attrs;
    475 
    476 	reply.error = NDMP_NO_ERR;
    477 	reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info);
    478 	reply.butype_info.butype_info_val = info;
    479 
    480 	ndmp_send_reply(connection, (void *)&reply,
    481 	    "sending ndmp_config_get_butype_info reply");
    482 }
    483 
    484 /*
    485  * ndmpd_config_get_fs_info_v3
    486  *
    487  * This handler handles the ndmp_config_get_fs_info_request.
    488  * Information about all mounted file systems is returned.
    489  *
    490  * Parameters:
    491  *   connection (input) - connection handle.
    492  *   body       (input) - request message body.
    493  *
    494  * Returns:
    495  *   void
    496  */
    497 /*ARGSUSED*/
    498 void
    499 ndmpd_config_get_fs_info_v3(ndmp_connection_t *connection, void *body)
    500 {
    501 	ndmp_config_get_fs_info_reply_v3 reply;
    502 	ndmp_fs_info_v3 *fsip, *fsip_save; /* FS info pointer */
    503 	int i, nmnt, fd;
    504 	int log_dev_len;
    505 	FILE *fp = NULL;
    506 	struct mnttab mt, *fs;
    507 	struct statvfs64 stat_buf;
    508 	ndmp_pval *envp, *save;
    509 
    510 	(void) memset((void*)&reply, 0, sizeof (reply));
    511 	reply.error = NDMP_NO_ERR;
    512 
    513 	if ((fd = open(MNTTAB, O_RDONLY)) == -1) {
    514 		NDMP_LOG(LOG_ERR, "File mnttab open error: %m.");
    515 		reply.error = NDMP_UNDEFINED_ERR;
    516 		ndmp_send_reply(connection, (void *)&reply,
    517 		    "sending ndmp_config_get_fs_info reply");
    518 		return;
    519 	}
    520 
    521 	/* nothing was found, send an empty reply */
    522 	if (ioctl(fd, MNTIOC_NMNTS, &nmnt) != 0 || nmnt <= 0) {
    523 		NDMP_LOG(LOG_ERR, "No file system found.");
    524 		ndmp_send_reply(connection, (void *)&reply,
    525 		    "sending ndmp_config_get_fs_info reply");
    526 		return;
    527 	}
    528 
    529 	fp = fopen(MNTTAB, "r");
    530 	if (!fp) {
    531 		NDMP_LOG(LOG_ERR, "File mnttab open error: %m.");
    532 		reply.error = NDMP_UNDEFINED_ERR;
    533 		ndmp_send_reply(connection, (void *)&reply,
    534 		    "sending ndmp_config_get_fs_info reply");
    535 		return;
    536 	}
    537 
    538 	fsip_save = fsip = ndmp_malloc(sizeof (ndmp_fs_info_v3) * nmnt);
    539 	if (!fsip) {
    540 		(void) fclose(fp);
    541 		reply.error = NDMP_NO_MEM_ERR;
    542 		ndmp_send_reply(connection, (void *)&reply,
    543 		    "error sending ndmp_config_get_fs_info reply");
    544 		return;
    545 	}
    546 
    547 	/*
    548 	 * Re-read the directory and set up file system information.
    549 	 */
    550 	i = 0;
    551 	rewind(fp);
    552 	while (i < nmnt && (getmntent(fp, &mt) == 0))
    553 
    554 	{
    555 		fs = &mt;
    556 		log_dev_len = strlen(mt.mnt_mountp)+2;
    557 		if (!IS_VALID_FS(fs))
    558 			continue;
    559 
    560 		fsip->fs_logical_device = ndmp_malloc(log_dev_len);
    561 		fsip->fs_type = ndmp_malloc(MNTTYPE_LEN);
    562 		if (!fsip->fs_logical_device || !fsip->fs_type) {
    563 			reply.error = NDMP_NO_MEM_ERR;
    564 			free(fsip->fs_logical_device);
    565 			free(fsip->fs_type);
    566 			break;
    567 		}
    568 		(void) snprintf(fsip->fs_type, MNTTYPE_LEN, "%s",
    569 		    fs->mnt_fstype);
    570 		(void) snprintf(fsip->fs_logical_device, log_dev_len, "%s",
    571 		    fs->mnt_mountp);
    572 		fsip->invalid = 0;
    573 
    574 		if (statvfs64(fs->mnt_mountp, &stat_buf) < 0) {
    575 			NDMP_LOG(LOG_DEBUG,
    576 			    "statvfs(%s) error.", fs->mnt_mountp);
    577 			fsip->fs_status =
    578 			    "statvfs error: unable to determine filesystem"
    579 			    " attributes";
    580 		} else {
    581 			fsip->invalid = 0;
    582 			fsip->total_size =
    583 			    long_long_to_quad((u_longlong_t)stat_buf.f_frsize *
    584 			    (u_longlong_t)stat_buf.f_blocks);
    585 			fsip->used_size =
    586 			    long_long_to_quad((u_longlong_t)stat_buf.f_frsize *
    587 			    (u_longlong_t)(stat_buf.f_blocks-stat_buf.f_bfree));
    588 
    589 			fsip->avail_size =
    590 			    long_long_to_quad((u_longlong_t)stat_buf.f_frsize *
    591 			    (u_longlong_t)stat_buf.f_bfree);
    592 			fsip->total_inodes =
    593 			    long_long_to_quad((u_longlong_t)stat_buf.f_files);
    594 			fsip->used_inodes =
    595 			    long_long_to_quad((u_longlong_t)(stat_buf.f_files -
    596 			    stat_buf.f_ffree));
    597 			fsip->fs_status = "";
    598 		}
    599 		save = envp = ndmp_malloc(sizeof (ndmp_pval) * V3_N_FS_ENVS);
    600 		if (!envp) {
    601 			reply.error = NDMP_NO_MEM_ERR;
    602 			break;
    603 		}
    604 		(void) memset((void*)save, 0,
    605 		    V3_N_FS_ENVS * sizeof (ndmp_pval));
    606 
    607 		fsip->fs_env.fs_env_val = envp;
    608 		NDMP_SETENV(envp, "LOCAL", "y");
    609 		NDMP_SETENV(envp, "TYPE", fsip->fs_type);
    610 		NDMP_SETENV(envp, "AVAILABLE_BACKUP", "tar,dump");
    611 
    612 		if (FS_READONLY(fs) == 0) {
    613 			NDMP_SETENV(envp, "AVAILABLE_RECOVERY", "tar,dump");
    614 		}
    615 
    616 		fsip->fs_env.fs_env_len = envp - save;
    617 		i++;
    618 		fsip++;
    619 	}
    620 	(void) fclose(fp);
    621 	if (reply.error == NDMP_NO_ERR) {
    622 		reply.fs_info.fs_info_len = i;
    623 		reply.fs_info.fs_info_val = fsip_save;
    624 	} else {
    625 		reply.fs_info.fs_info_len = 0;
    626 		reply.fs_info.fs_info_val = NULL;
    627 	}
    628 	ndmp_send_reply(connection, (void *)&reply,
    629 	    "error sending ndmp_config_get_fs_info reply");
    630 
    631 	fsip = fsip_save;
    632 	while (--i >= 0) {
    633 		free(fsip->fs_logical_device);
    634 		free(fsip->fs_env.fs_env_val);
    635 		free(fsip->fs_type);
    636 		fsip++;
    637 	}
    638 
    639 	free(fsip_save);
    640 }
    641 
    642 
    643 /*
    644  * ndmpd_config_get_tape_info_v3
    645  *
    646  * This handler handles the ndmp_config_get_tape_info_request.
    647  * Information about all connected tape drives is returned.
    648  *
    649  * Parameters:
    650  *   connection (input) - connection handle.
    651  *   body       (input) - request message body.
    652  *
    653  * Returns:
    654  *   void
    655  */
    656 /*ARGSUSED*/
    657 void
    658 ndmpd_config_get_tape_info_v3(ndmp_connection_t *connection, void *body)
    659 {
    660 	ndmp_config_get_tape_info_reply_v3 reply;
    661 	ndmp_device_info_v3 *tip, *tip_save = NULL; /* tape info pointer */
    662 	ndmp_device_capability_v3 *dcp;
    663 	ndmp_device_capability_v3 *dcp_save = NULL; /* dev capability pointer */
    664 	int i, n, max;
    665 	sasd_drive_t *sd;
    666 	scsi_link_t *sl;
    667 	ndmp_pval *envp, *envp_save = NULL;
    668 	ndmp_pval *envp_head;
    669 
    670 	(void) memset((void*)&reply, 0, sizeof (reply));
    671 	max = sasd_dev_count();
    672 
    673 	tip_save = tip = ndmp_malloc(sizeof (ndmp_device_info_v3) * max);
    674 	dcp_save = dcp = ndmp_malloc(sizeof (ndmp_device_capability_v3) * max);
    675 	envp_save = envp = ndmp_malloc(sizeof (ndmp_pval) * max * 3);
    676 	if (!tip_save || !dcp_save || !envp_save) {
    677 		free(tip_save);
    678 		free(dcp_save);
    679 		free(envp_save);
    680 		reply.error = NDMP_NO_MEM_ERR;
    681 		ndmp_send_reply(connection, (void *)&reply,
    682 		    "error sending ndmp_config_get_tape_info reply");
    683 		return;
    684 	}
    685 
    686 	reply.error = NDMP_NO_ERR;
    687 
    688 	for (i = n = 0; i < max; i++) {
    689 		if (!(sl = sasd_dev_slink(i)) || !(sd = sasd_drive(i)))
    690 			continue;
    691 		if (sl->sl_type != DTYPE_SEQUENTIAL)
    692 			continue;
    693 
    694 		NDMP_LOG(LOG_DEBUG,
    695 		    "model \"%s\" dev \"%s\"", sd->sd_id, sd->sd_name);
    696 
    697 		envp_head = envp;
    698 		NDMP_SETENV(envp, "EXECUTE_CDB", "b");
    699 		NDMP_SETENV(envp, "SERIAL_NUMBER", sd->sd_serial);
    700 		NDMP_SETENV(envp, "WORLD_WIDE_NAME", sd->sd_wwn);
    701 
    702 		tip->model = sd->sd_id; /* like "DLT7000	 " */
    703 		tip->caplist.caplist_len = 1;
    704 		tip->caplist.caplist_val = dcp;
    705 		dcp->device = sd->sd_name; /* like "isp1t060" */
    706 		dcp->attr = 0;
    707 		dcp->capability.capability_len = 3;
    708 		dcp->capability.capability_val = envp_head;
    709 		tip++;
    710 		dcp++;
    711 		n++;
    712 	}
    713 
    714 	NDMP_LOG(LOG_DEBUG, "n %d", n);
    715 
    716 	/*
    717 	 * We should not receive the get_tape_info when three-way backup is
    718 	 * running and we are acting as just data, but some clients try
    719 	 * to get the Tape information anyway.
    720 	 */
    721 	if (n == 0 || max <= 0) {
    722 		reply.error = NDMP_NO_DEVICE_ERR;
    723 		ndmp_send_reply(connection, (void *)&reply,
    724 		    "error sending ndmp_config_get_tape_info reply");
    725 		free(tip_save); free(dcp_save); free(envp_save);
    726 		return;
    727 	}
    728 
    729 
    730 	reply.tape_info.tape_info_len = n;
    731 	reply.tape_info.tape_info_val = tip_save;
    732 
    733 	ndmp_send_reply(connection, (void *)&reply,
    734 	    "error sending ndmp_config_get_tape_info reply");
    735 
    736 	free(tip_save);
    737 	free(dcp_save);
    738 	free(envp_save);
    739 }
    740 
    741 
    742 /*
    743  * ndmpd_config_get_scsi_info_v3
    744  *
    745  * This handler handles the ndmp_config_get_tape_scsi_request.
    746  * Information about all connected scsi tape stacker and jukeboxes
    747  * is returned.
    748  *
    749  * Parameters:
    750  *   connection (input) - connection handle.
    751  *   body       (input) - request message body.
    752  *
    753  * Returns:
    754  *   void
    755  */
    756 /*ARGSUSED*/
    757 void
    758 ndmpd_config_get_scsi_info_v3(ndmp_connection_t *connection, void *body)
    759 {
    760 	ndmp_config_get_scsi_info_reply_v3 reply;
    761 	ndmp_device_info_v3 *sip, *sip_save;
    762 	ndmp_device_capability_v3 *dcp, *dcp_save;
    763 	int i, n, max;
    764 	sasd_drive_t *sd;
    765 	scsi_link_t *sl;
    766 	ndmp_pval *envp, *envp_save = NULL;
    767 	ndmp_pval *envp_head;
    768 
    769 	(void) memset((void*)&reply, 0, sizeof (reply));
    770 	max = sasd_dev_count();
    771 	sip_save = sip = ndmp_malloc(sizeof (ndmp_device_info_v3) * max);
    772 	dcp_save = dcp = ndmp_malloc(sizeof (ndmp_device_capability_v3) * max);
    773 	envp_save = envp = ndmp_malloc(sizeof (ndmp_pval) * max * 2);
    774 	if (!sip_save || !dcp_save || !envp_save) {
    775 		free(sip_save);
    776 		free(dcp_save);
    777 		free(envp_save);
    778 		reply.error = NDMP_NO_MEM_ERR;
    779 		ndmp_send_reply(connection, (void *)&reply,
    780 		    "error sending ndmp_config_get_scsi_info reply");
    781 		return;
    782 	}
    783 
    784 	reply.error = NDMP_NO_ERR;
    785 	for (i = n = 0; i < max; i++) {
    786 		if (!(sl = sasd_dev_slink(i)) || !(sd = sasd_drive(i)))
    787 			continue;
    788 		if (sl->sl_type != DTYPE_CHANGER)
    789 			continue;
    790 
    791 		NDMP_LOG(LOG_DEBUG,
    792 		    "model \"%s\" dev \"%s\"", sd->sd_id, sd->sd_name);
    793 
    794 		envp_head = envp;
    795 		NDMP_SETENV(envp, "SERIAL_NUMBER", sd->sd_serial);
    796 		NDMP_SETENV(envp, "WORLD_WIDE_NAME", sd->sd_wwn);
    797 
    798 		sip->model = sd->sd_id; /* like "Powerstor L200  " */
    799 		sip->caplist.caplist_len = 1;
    800 		sip->caplist.caplist_val = dcp;
    801 		dcp->device = sd->sd_name; /* like "isp1m000" */
    802 
    803 		dcp->attr = 0;
    804 		dcp->capability.capability_len = 2;
    805 		dcp->capability.capability_val = envp_head;
    806 		sip++;
    807 		dcp++;
    808 		n++;
    809 	}
    810 
    811 	NDMP_LOG(LOG_DEBUG, "n %d", n);
    812 
    813 	reply.scsi_info.scsi_info_len = n;
    814 	reply.scsi_info.scsi_info_val = sip_save;
    815 
    816 	ndmp_send_reply(connection, (void *)&reply,
    817 	    "error sending ndmp_config_get_scsi_info reply");
    818 
    819 	free(sip_save);
    820 	free(dcp_save);
    821 	free(envp_save);
    822 }
    823 
    824 
    825 /*
    826  * ndmpd_config_get_server_info_v3
    827  *
    828  * This handler handles the ndmp_config_get_server_info request.
    829  * Host specific information is returned.
    830  *
    831  * Parameters:
    832  *   connection (input) - connection handle.
    833  *   body       (input) - request message body.
    834  *
    835  * Returns:
    836  *   void
    837  */
    838 /*ARGSUSED*/
    839 void
    840 ndmpd_config_get_server_info_v3(ndmp_connection_t *connection, void *body)
    841 {
    842 	ndmp_config_get_server_info_reply_v3 reply;
    843 	ndmp_auth_type auth_types[2];
    844 	char rev_number[10];
    845 	ndmpd_session_t *session = ndmp_get_client_data(connection);
    846 
    847 	(void) memset((void*)&reply, 0, sizeof (reply));
    848 	reply.error = NDMP_NO_ERR;
    849 
    850 	if (connection->conn_authorized ||
    851 	    session->ns_protocol_version != NDMPV4) {
    852 		reply.vendor_name = VENDOR_NAME;
    853 		reply.product_name = PRODUCT_NAME;
    854 		(void) snprintf(rev_number, sizeof (rev_number), "%d",
    855 		    ndmp_ver);
    856 		reply.revision_number = rev_number;
    857 	} else {
    858 		reply.vendor_name = "\0";
    859 		reply.product_name = "\0";
    860 		reply.revision_number = "\0";
    861 	}
    862 
    863 	NDMP_LOG(LOG_DEBUG,
    864 	    "vendor \"%s\", product \"%s\" rev \"%s\"",
    865 	    reply.vendor_name, reply.product_name, reply.revision_number);
    866 
    867 	auth_types[0] = NDMP_AUTH_TEXT;
    868 	auth_types[1] = NDMP_AUTH_MD5;
    869 	reply.auth_type.auth_type_len = ARRAY_LEN(auth_types, ndmp_auth_type);
    870 	reply.auth_type.auth_type_val = auth_types;
    871 
    872 	ndmp_send_reply(connection, (void *)&reply,
    873 	    "error sending ndmp_config_get_server_info reply");
    874 }
    875 
    876 
    877 
    878 /*
    879  * ************************************************************************
    880  * NDMP V4 HANDLERS
    881  * ************************************************************************
    882  */
    883 
    884 /*
    885  * ndmpd_config_get_butype_info_v4
    886  *
    887  * This handler handles the ndmp_config_get_butype_info_request.
    888  * Information about all supported backup types are returned.
    889  *
    890  * Parameters:
    891  *   connection (input) - connection handle.
    892  *   body       (input) - request message body.
    893  *
    894  * Returns:
    895  *   void
    896  */
    897 /*ARGSUSED*/
    898 void
    899 ndmpd_config_get_butype_info_v4(ndmp_connection_t *connection, void *body)
    900 {
    901 	ndmp_config_get_butype_info_reply_v4 reply;
    902 	ndmp_butype_info info[2];
    903 	ndmp_pval envs[12];
    904 	ulong_t attrs;
    905 	ndmp_pval *envp = envs;
    906 
    907 	(void) memset((void*)&reply, 0, sizeof (reply));
    908 
    909 	/*
    910 	 * Supported environment variables and their default values.
    911 	 * The environment variables for dump and tar format are the
    912 	 * same, because we use the same backup engine for both.
    913 	 */
    914 	NDMP_SETENV(envp, "FILESYSTEM", "");
    915 	NDMP_SETENV(envp, "DIRECT", "n");
    916 	NDMP_SETENV(envp, "RECURSIVE", "n");
    917 	NDMP_SETENV(envp, "TYPE", "");
    918 	NDMP_SETENV(envp, "USER", "");
    919 	NDMP_SETENV(envp, "HIST", "n");
    920 	NDMP_SETENV(envp, "PATHNAME_SEPARATOR", "/");
    921 	NDMP_SETENV(envp, "LEVEL", "0");
    922 	NDMP_SETENV(envp, "EXTRACT", "y");
    923 	NDMP_SETENV(envp, "UPDATE", "y");
    924 	NDMP_SETENV(envp, "CMD", "");
    925 	NDMP_SETENV(envp, "BASE_DATE", "");
    926 
    927 	attrs = NDMP_BUTYPE_RECOVER_FILELIST |
    928 	    NDMP_BUTYPE_BACKUP_DIRECT |
    929 	    NDMP_BUTYPE_BACKUP_INCREMENTAL |
    930 	    NDMP_BUTYPE_BACKUP_UTF8 |
    931 	    NDMP_BUTYPE_RECOVER_UTF8 |
    932 	    NDMP_BUTYPE_BACKUP_FH_FILE |
    933 	    NDMP_BUTYPE_BACKUP_FH_DIR |
    934 	    NDMP_BUTYPE_RECOVER_FH_FILE |
    935 	    NDMP_BUTYPE_RECOVER_FH_DIR;
    936 
    937 	/* If DAR supported */
    938 	if (ndmp_dar_support)
    939 		attrs |= NDMP_BUTYPE_RECOVER_DIRECT;
    940 
    941 	/* tar backup type */
    942 	info[0].butype_name = "tar";
    943 	info[0].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
    944 	info[0].default_env.default_env_val = envs;
    945 	info[0].attrs = attrs;
    946 
    947 	/* dump backup type */
    948 	info[1].butype_name = "dump";
    949 	info[1].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
    950 	info[1].default_env.default_env_val = envs;
    951 	info[1].attrs = attrs;
    952 
    953 	reply.error = NDMP_NO_ERR;
    954 	reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info);
    955 	reply.butype_info.butype_info_val = info;
    956 
    957 	ndmp_send_reply(connection, (void *)&reply,
    958 	    "sending ndmp_config_get_butype_info reply");
    959 }
    960 
    961 
    962 /*
    963  * ndmpd_config_get_ext_list_v4
    964  *
    965  * This handler handles the ndmpd_config_get_ext_list_v4 request.
    966  *
    967  * Parameters:
    968  *   connection (input) - connection handle.
    969  *   body       (input) - request message body.
    970  *
    971  * Returns:
    972  *   void
    973  */
    974 /*ARGSUSED*/
    975 void
    976 ndmpd_config_get_ext_list_v4(ndmp_connection_t *connection, void *body)
    977 {
    978 	ndmp_config_get_ext_list_reply_v4 reply;
    979 	ndmpd_session_t *session = ndmp_get_client_data(connection);
    980 
    981 	(void) memset((void*)&reply, 0, sizeof (reply));
    982 
    983 	if (session->ns_set_ext_list == FALSE)
    984 		reply.error = NDMP_EXT_DANDN_ILLEGAL_ERR;
    985 	else
    986 		reply.error = NDMP_NO_ERR;
    987 
    988 	reply.class_list.class_list_val = NULL;
    989 	reply.class_list.class_list_len = 0;
    990 
    991 
    992 	ndmp_send_reply(connection, (void *)&reply,
    993 	    "error sending ndmp_config_get_ext_list reply");
    994 }
    995 
    996 /*
    997  * ndmpd_config_set_ext_list_v4
    998  *
    999  * This handler handles the ndmpd_config_get_ext_list_v4 request.
   1000  *
   1001  * Parameters:
   1002  *   connection (input) - connection handle.
   1003  *   body       (input) - request message body.
   1004  *
   1005  * Returns:
   1006  *   void
   1007  */
   1008 /*ARGSUSED*/
   1009 void
   1010 ndmpd_config_set_ext_list_v4(ndmp_connection_t *connection, void *body)
   1011 {
   1012 	ndmp_config_set_ext_list_reply_v4 reply;
   1013 	ndmpd_session_t *session = ndmp_get_client_data(connection);
   1014 
   1015 	(void) memset((void*)&reply, 0, sizeof (reply));
   1016 	if (session->ns_set_ext_list == TRUE) {
   1017 		reply.error = NDMP_EXT_DANDN_ILLEGAL_ERR;
   1018 	} else {
   1019 		session->ns_set_ext_list = TRUE;
   1020 		/*
   1021 		 * NOTE: for now we are not supporting any extension list,
   1022 		 * hence this error, when we start to support extensions,
   1023 		 * this should be validated
   1024 		 */
   1025 
   1026 		reply.error = NDMP_VERSION_NOT_SUPPORTED_ERR;
   1027 	}
   1028 
   1029 	ndmp_send_reply(connection, (void *)&reply,
   1030 	    "error sending ndmp_config_set_ext_list reply");
   1031 }
   1032 
   1033 
   1034 
   1035 /*
   1036  * ************************************************************************
   1037  * LOCALS
   1038  * ************************************************************************
   1039  */
   1040 
   1041 /*
   1042  * simple_get_attrs
   1043  *
   1044  * Set the default attrs for dump mode
   1045  *
   1046  * Parameters:
   1047  *   attributes (output) - the attributes for dump mode
   1048  *
   1049  * Returns:
   1050  *   void
   1051  */
   1052 static void
   1053 simple_get_attrs(ulong_t *attributes)
   1054 {
   1055 	*attributes = NDMP_NO_RECOVER_FHINFO;
   1056 }
   1057