xref: /titanic_50/usr/src/cmd/ndmpd/ndmp/ndmpd_config.c (revision 0a1278f26ea4b7c8c0285d4f2d6c5b680904aa01)
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