xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_config.c (revision 2e0fe3efe5f9d579d4e44b3532d8e342c68b40ca)
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_INCREMENTAL;
499 
500 	/* zfs backup type */
501 	info[2].butype_name = "zfs";
502 	info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval);
503 	info[2].default_env.default_env_val = zfs_envs;
504 	info[2].attrs = zfs_attrs;
505 
506 	reply.error = NDMP_NO_ERR;
507 	reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info);
508 	reply.butype_info.butype_info_val = info;
509 
510 	ndmp_send_reply(connection, (void *)&reply,
511 	    "sending ndmp_config_get_butype_info reply");
512 }
513 
514 /*
515  * ndmpd_config_get_fs_info_v3
516  *
517  * This handler handles the ndmp_config_get_fs_info_request.
518  * Information about all mounted file systems is returned.
519  *
520  * Parameters:
521  *   connection (input) - connection handle.
522  *   body       (input) - request message body.
523  *
524  * Returns:
525  *   void
526  */
527 /*ARGSUSED*/
528 void
529 ndmpd_config_get_fs_info_v3(ndmp_connection_t *connection, void *body)
530 {
531 	ndmp_config_get_fs_info_reply_v3 reply;
532 	ndmp_fs_info_v3 *fsip, *fsip_save; /* FS info pointer */
533 	int i, nmnt, fd;
534 	int log_dev_len;
535 	FILE *fp = NULL;
536 	struct mnttab mt, *fs;
537 	struct statvfs64 stat_buf;
538 	ndmp_pval *envp, *save;
539 
540 	(void) memset((void*)&reply, 0, sizeof (reply));
541 	reply.error = NDMP_NO_ERR;
542 
543 	if ((fd = open(MNTTAB, O_RDONLY)) == -1) {
544 		NDMP_LOG(LOG_ERR, "File mnttab open error: %m.");
545 		reply.error = NDMP_UNDEFINED_ERR;
546 		ndmp_send_reply(connection, (void *)&reply,
547 		    "sending ndmp_config_get_fs_info reply");
548 		return;
549 	}
550 
551 	/* nothing was found, send an empty reply */
552 	if (ioctl(fd, MNTIOC_NMNTS, &nmnt) != 0 || nmnt <= 0) {
553 		NDMP_LOG(LOG_ERR, "No file system found.");
554 		ndmp_send_reply(connection, (void *)&reply,
555 		    "sending ndmp_config_get_fs_info reply");
556 		return;
557 	}
558 
559 	fp = fopen(MNTTAB, "r");
560 	if (!fp) {
561 		NDMP_LOG(LOG_ERR, "File mnttab open error: %m.");
562 		reply.error = NDMP_UNDEFINED_ERR;
563 		ndmp_send_reply(connection, (void *)&reply,
564 		    "sending ndmp_config_get_fs_info reply");
565 		return;
566 	}
567 
568 	fsip_save = fsip = ndmp_malloc(sizeof (ndmp_fs_info_v3) * nmnt);
569 	if (!fsip) {
570 		(void) fclose(fp);
571 		reply.error = NDMP_NO_MEM_ERR;
572 		ndmp_send_reply(connection, (void *)&reply,
573 		    "error sending ndmp_config_get_fs_info reply");
574 		return;
575 	}
576 
577 	/*
578 	 * Re-read the directory and set up file system information.
579 	 */
580 	i = 0;
581 	rewind(fp);
582 	while (i < nmnt && (getmntent(fp, &mt) == 0))
583 
584 	{
585 		fs = &mt;
586 		log_dev_len = strlen(mt.mnt_mountp)+2;
587 		if (!IS_VALID_FS(fs))
588 			continue;
589 
590 		fsip->fs_logical_device = ndmp_malloc(log_dev_len);
591 		fsip->fs_type = ndmp_malloc(MNTTYPE_LEN);
592 		if (!fsip->fs_logical_device || !fsip->fs_type) {
593 			reply.error = NDMP_NO_MEM_ERR;
594 			free(fsip->fs_logical_device);
595 			free(fsip->fs_type);
596 			break;
597 		}
598 		(void) snprintf(fsip->fs_type, MNTTYPE_LEN, "%s",
599 		    fs->mnt_fstype);
600 		(void) snprintf(fsip->fs_logical_device, log_dev_len, "%s",
601 		    fs->mnt_mountp);
602 		fsip->invalid = 0;
603 
604 		if (statvfs64(fs->mnt_mountp, &stat_buf) < 0) {
605 			NDMP_LOG(LOG_DEBUG,
606 			    "statvfs(%s) error.", fs->mnt_mountp);
607 			fsip->fs_status =
608 			    "statvfs error: unable to determine filesystem"
609 			    " attributes";
610 		} else {
611 			fsip->invalid = 0;
612 			fsip->total_size =
613 			    long_long_to_quad((u_longlong_t)stat_buf.f_frsize *
614 			    (u_longlong_t)stat_buf.f_blocks);
615 			fsip->used_size =
616 			    long_long_to_quad((u_longlong_t)stat_buf.f_frsize *
617 			    (u_longlong_t)(stat_buf.f_blocks-stat_buf.f_bfree));
618 
619 			fsip->avail_size =
620 			    long_long_to_quad((u_longlong_t)stat_buf.f_frsize *
621 			    (u_longlong_t)stat_buf.f_bfree);
622 			fsip->total_inodes =
623 			    long_long_to_quad((u_longlong_t)stat_buf.f_files);
624 			fsip->used_inodes =
625 			    long_long_to_quad((u_longlong_t)(stat_buf.f_files -
626 			    stat_buf.f_ffree));
627 			fsip->fs_status = "";
628 		}
629 		save = envp = ndmp_malloc(sizeof (ndmp_pval) * V3_N_FS_ENVS);
630 		if (!envp) {
631 			reply.error = NDMP_NO_MEM_ERR;
632 			break;
633 		}
634 		(void) memset((void*)save, 0,
635 		    V3_N_FS_ENVS * sizeof (ndmp_pval));
636 
637 		fsip->fs_env.fs_env_val = envp;
638 		NDMP_SETENV(envp, "LOCAL", "y");
639 		NDMP_SETENV(envp, "TYPE", fsip->fs_type);
640 		NDMP_SETENV(envp, "AVAILABLE_BACKUP", "tar,dump");
641 
642 		if (FS_READONLY(fs) == 0) {
643 			NDMP_SETENV(envp, "AVAILABLE_RECOVERY", "tar,dump");
644 		}
645 
646 		fsip->fs_env.fs_env_len = envp - save;
647 		i++;
648 		fsip++;
649 	}
650 	(void) fclose(fp);
651 	if (reply.error == NDMP_NO_ERR) {
652 		reply.fs_info.fs_info_len = i;
653 		reply.fs_info.fs_info_val = fsip_save;
654 	} else {
655 		reply.fs_info.fs_info_len = 0;
656 		reply.fs_info.fs_info_val = NULL;
657 	}
658 	ndmp_send_reply(connection, (void *)&reply,
659 	    "error sending ndmp_config_get_fs_info reply");
660 
661 	fsip = fsip_save;
662 	while (--i >= 0) {
663 		free(fsip->fs_logical_device);
664 		free(fsip->fs_env.fs_env_val);
665 		free(fsip->fs_type);
666 		fsip++;
667 	}
668 
669 	free(fsip_save);
670 }
671 
672 
673 /*
674  * ndmpd_config_get_tape_info_v3
675  *
676  * This handler handles the ndmp_config_get_tape_info_request.
677  * Information about all connected tape drives is returned.
678  *
679  * Parameters:
680  *   connection (input) - connection handle.
681  *   body       (input) - request message body.
682  *
683  * Returns:
684  *   void
685  */
686 /*ARGSUSED*/
687 void
688 ndmpd_config_get_tape_info_v3(ndmp_connection_t *connection, void *body)
689 {
690 	ndmp_config_get_tape_info_reply_v3 reply;
691 	ndmp_device_info_v3 *tip, *tip_save = NULL; /* tape info pointer */
692 	ndmp_device_capability_v3 *dcp;
693 	ndmp_device_capability_v3 *dcp_save = NULL; /* dev capability pointer */
694 	int i, n, max;
695 	sasd_drive_t *sd;
696 	scsi_link_t *sl;
697 	ndmp_pval *envp, *envp_save = NULL;
698 	ndmp_pval *envp_head;
699 
700 	(void) memset((void*)&reply, 0, sizeof (reply));
701 	max = sasd_dev_count();
702 
703 	tip_save = tip = ndmp_malloc(sizeof (ndmp_device_info_v3) * max);
704 	dcp_save = dcp = ndmp_malloc(sizeof (ndmp_device_capability_v3) * max);
705 	envp_save = envp = ndmp_malloc(sizeof (ndmp_pval) * max * 3);
706 	if (!tip_save || !dcp_save || !envp_save) {
707 		free(tip_save);
708 		free(dcp_save);
709 		free(envp_save);
710 		reply.error = NDMP_NO_MEM_ERR;
711 		ndmp_send_reply(connection, (void *)&reply,
712 		    "error sending ndmp_config_get_tape_info reply");
713 		return;
714 	}
715 
716 	reply.error = NDMP_NO_ERR;
717 
718 	for (i = n = 0; i < max; i++) {
719 		if (!(sl = sasd_dev_slink(i)) || !(sd = sasd_drive(i)))
720 			continue;
721 		if (sl->sl_type != DTYPE_SEQUENTIAL)
722 			continue;
723 
724 		NDMP_LOG(LOG_DEBUG,
725 		    "model \"%s\" dev \"%s\"", sd->sd_id, sd->sd_name);
726 
727 		envp_head = envp;
728 		NDMP_SETENV(envp, "EXECUTE_CDB", "b");
729 		NDMP_SETENV(envp, "SERIAL_NUMBER", sd->sd_serial);
730 		NDMP_SETENV(envp, "WORLD_WIDE_NAME", sd->sd_wwn);
731 
732 		tip->model = sd->sd_id; /* like "DLT7000	 " */
733 		tip->caplist.caplist_len = 1;
734 		tip->caplist.caplist_val = dcp;
735 		dcp->device = sd->sd_name; /* like "isp1t060" */
736 		dcp->attr = 0;
737 		dcp->capability.capability_len = 3;
738 		dcp->capability.capability_val = envp_head;
739 		tip++;
740 		dcp++;
741 		n++;
742 	}
743 
744 	NDMP_LOG(LOG_DEBUG, "n %d", n);
745 
746 	/*
747 	 * We should not receive the get_tape_info when three-way backup is
748 	 * running and we are acting as just data, but some clients try
749 	 * to get the Tape information anyway.
750 	 */
751 	if (n == 0 || max <= 0) {
752 		reply.error = NDMP_NO_DEVICE_ERR;
753 		ndmp_send_reply(connection, (void *)&reply,
754 		    "error sending ndmp_config_get_tape_info reply");
755 		free(tip_save); free(dcp_save); free(envp_save);
756 		return;
757 	}
758 
759 
760 	reply.tape_info.tape_info_len = n;
761 	reply.tape_info.tape_info_val = tip_save;
762 
763 	ndmp_send_reply(connection, (void *)&reply,
764 	    "error sending ndmp_config_get_tape_info reply");
765 
766 	free(tip_save);
767 	free(dcp_save);
768 	free(envp_save);
769 }
770 
771 
772 /*
773  * ndmpd_config_get_scsi_info_v3
774  *
775  * This handler handles the ndmp_config_get_tape_scsi_request.
776  * Information about all connected scsi tape stacker and jukeboxes
777  * is returned.
778  *
779  * Parameters:
780  *   connection (input) - connection handle.
781  *   body       (input) - request message body.
782  *
783  * Returns:
784  *   void
785  */
786 /*ARGSUSED*/
787 void
788 ndmpd_config_get_scsi_info_v3(ndmp_connection_t *connection, void *body)
789 {
790 	ndmp_config_get_scsi_info_reply_v3 reply;
791 	ndmp_device_info_v3 *sip, *sip_save;
792 	ndmp_device_capability_v3 *dcp, *dcp_save;
793 	int i, n, max;
794 	sasd_drive_t *sd;
795 	scsi_link_t *sl;
796 	ndmp_pval *envp, *envp_save = NULL;
797 	ndmp_pval *envp_head;
798 
799 	(void) memset((void*)&reply, 0, sizeof (reply));
800 	max = sasd_dev_count();
801 	sip_save = sip = ndmp_malloc(sizeof (ndmp_device_info_v3) * max);
802 	dcp_save = dcp = ndmp_malloc(sizeof (ndmp_device_capability_v3) * max);
803 	envp_save = envp = ndmp_malloc(sizeof (ndmp_pval) * max * 2);
804 	if (!sip_save || !dcp_save || !envp_save) {
805 		free(sip_save);
806 		free(dcp_save);
807 		free(envp_save);
808 		reply.error = NDMP_NO_MEM_ERR;
809 		ndmp_send_reply(connection, (void *)&reply,
810 		    "error sending ndmp_config_get_scsi_info reply");
811 		return;
812 	}
813 
814 	reply.error = NDMP_NO_ERR;
815 	for (i = n = 0; i < max; i++) {
816 		if (!(sl = sasd_dev_slink(i)) || !(sd = sasd_drive(i)))
817 			continue;
818 		if (sl->sl_type != DTYPE_CHANGER)
819 			continue;
820 
821 		NDMP_LOG(LOG_DEBUG,
822 		    "model \"%s\" dev \"%s\"", sd->sd_id, sd->sd_name);
823 
824 		envp_head = envp;
825 		NDMP_SETENV(envp, "SERIAL_NUMBER", sd->sd_serial);
826 		NDMP_SETENV(envp, "WORLD_WIDE_NAME", sd->sd_wwn);
827 
828 		sip->model = sd->sd_id; /* like "Powerstor L200  " */
829 		sip->caplist.caplist_len = 1;
830 		sip->caplist.caplist_val = dcp;
831 		dcp->device = sd->sd_name; /* like "isp1m000" */
832 
833 		dcp->attr = 0;
834 		dcp->capability.capability_len = 2;
835 		dcp->capability.capability_val = envp_head;
836 		sip++;
837 		dcp++;
838 		n++;
839 	}
840 
841 	NDMP_LOG(LOG_DEBUG, "n %d", n);
842 
843 	reply.scsi_info.scsi_info_len = n;
844 	reply.scsi_info.scsi_info_val = sip_save;
845 
846 	ndmp_send_reply(connection, (void *)&reply,
847 	    "error sending ndmp_config_get_scsi_info reply");
848 
849 	free(sip_save);
850 	free(dcp_save);
851 	free(envp_save);
852 }
853 
854 
855 /*
856  * ndmpd_config_get_server_info_v3
857  *
858  * This handler handles the ndmp_config_get_server_info request.
859  * Host specific information is returned.
860  *
861  * Parameters:
862  *   connection (input) - connection handle.
863  *   body       (input) - request message body.
864  *
865  * Returns:
866  *   void
867  */
868 /*ARGSUSED*/
869 void
870 ndmpd_config_get_server_info_v3(ndmp_connection_t *connection, void *body)
871 {
872 	ndmp_config_get_server_info_reply_v3 reply;
873 	ndmp_auth_type auth_types[2];
874 	char rev_number[10];
875 	ndmpd_session_t *session = ndmp_get_client_data(connection);
876 
877 	(void) memset((void*)&reply, 0, sizeof (reply));
878 	reply.error = NDMP_NO_ERR;
879 
880 	if (connection->conn_authorized ||
881 	    session->ns_protocol_version != NDMPV4) {
882 		reply.vendor_name = VENDOR_NAME;
883 		reply.product_name = PRODUCT_NAME;
884 		(void) snprintf(rev_number, sizeof (rev_number), "%d",
885 		    ndmp_ver);
886 		reply.revision_number = rev_number;
887 	} else {
888 		reply.vendor_name = "\0";
889 		reply.product_name = "\0";
890 		reply.revision_number = "\0";
891 	}
892 
893 	NDMP_LOG(LOG_DEBUG,
894 	    "vendor \"%s\", product \"%s\" rev \"%s\"",
895 	    reply.vendor_name, reply.product_name, reply.revision_number);
896 
897 	auth_types[0] = NDMP_AUTH_TEXT;
898 	auth_types[1] = NDMP_AUTH_MD5;
899 	reply.auth_type.auth_type_len = ARRAY_LEN(auth_types, ndmp_auth_type);
900 	reply.auth_type.auth_type_val = auth_types;
901 
902 	ndmp_send_reply(connection, (void *)&reply,
903 	    "error sending ndmp_config_get_server_info reply");
904 }
905 
906 
907 
908 /*
909  * ************************************************************************
910  * NDMP V4 HANDLERS
911  * ************************************************************************
912  */
913 
914 /*
915  * ndmpd_config_get_butype_info_v4
916  *
917  * This handler handles the ndmp_config_get_butype_info_request.
918  * Information about all supported backup types are returned.
919  *
920  * Parameters:
921  *   connection (input) - connection handle.
922  *   body       (input) - request message body.
923  *
924  * Returns:
925  *   void
926  */
927 /*ARGSUSED*/
928 void
929 ndmpd_config_get_butype_info_v4(ndmp_connection_t *connection, void *body)
930 {
931 	ndmp_config_get_butype_info_reply_v4 reply;
932 	ndmp_butype_info info[3];
933 
934 	ndmp_pval envs[12];
935 	ulong_t attrs;
936 	ndmp_pval *envp = envs;
937 
938 	ndmp_pval zfs_envs[11];
939 	ulong_t zfs_attrs;
940 	ndmp_pval *zfs_envp = zfs_envs;
941 
942 
943 	(void) memset((void*)&reply, 0, sizeof (reply));
944 
945 	/*
946 	 * Supported environment variables and their default values
947 	 * for dump and tar.
948 	 *
949 	 * The environment variables for dump and tar format are the
950 	 * same, because we use the same backup engine for both.
951 	 */
952 	NDMP_SETENV(envp, "FILESYSTEM", "");
953 	NDMP_SETENV(envp, "DIRECT", "n");
954 	NDMP_SETENV(envp, "RECURSIVE", "n");
955 	NDMP_SETENV(envp, "TYPE", "");
956 	NDMP_SETENV(envp, "USER", "");
957 	NDMP_SETENV(envp, "HIST", "n");
958 	NDMP_SETENV(envp, "PATHNAME_SEPARATOR", "/");
959 	NDMP_SETENV(envp, "LEVEL", "0");
960 	NDMP_SETENV(envp, "EXTRACT", "y");
961 	NDMP_SETENV(envp, "UPDATE", "y");
962 	NDMP_SETENV(envp, "CMD", "");
963 	NDMP_SETENV(envp, "BASE_DATE", "");
964 
965 	attrs = NDMP_BUTYPE_RECOVER_FILELIST |
966 	    NDMP_BUTYPE_BACKUP_DIRECT |
967 	    NDMP_BUTYPE_BACKUP_INCREMENTAL |
968 	    NDMP_BUTYPE_BACKUP_UTF8 |
969 	    NDMP_BUTYPE_RECOVER_UTF8 |
970 	    NDMP_BUTYPE_BACKUP_FH_FILE |
971 	    NDMP_BUTYPE_BACKUP_FH_DIR |
972 	    NDMP_BUTYPE_RECOVER_FH_FILE |
973 	    NDMP_BUTYPE_RECOVER_FH_DIR;
974 
975 	/* If DAR supported */
976 	if (ndmp_dar_support)
977 		attrs |= NDMP_BUTYPE_RECOVER_DIRECT;
978 
979 	/* tar backup type */
980 	info[0].butype_name = "tar";
981 	info[0].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
982 	info[0].default_env.default_env_val = envs;
983 	info[0].attrs = attrs;
984 
985 	/* dump backup type */
986 	info[1].butype_name = "dump";
987 	info[1].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
988 	info[1].default_env.default_env_val = envs;
989 	info[1].attrs = attrs;
990 
991 	/*
992 	 * Supported environment variables and their default values
993 	 * for type "zfs."
994 	 */
995 
996 	NDMP_SETENV(zfs_envp, "USER", "");
997 	NDMP_SETENV(zfs_envp, "CMD", "");
998 	NDMP_SETENV(zfs_envp, "FILESYSTEM", "");
999 	NDMP_SETENV(zfs_envp, "PATHNAME_SEPARATOR", "/");
1000 	NDMP_SETENV(zfs_envp, "TYPE", "zfs");
1001 	NDMP_SETENV(zfs_envp, "HIST", "n");
1002 	NDMP_SETENV(zfs_envp, "LEVEL", "0");
1003 	NDMP_SETENV(zfs_envp, "ZFS_MODE", "recursive");
1004 	NDMP_SETENV(zfs_envp, "ZFS_FORCE", "n");
1005 	NDMP_SETENV(zfs_envp, "UPDATE", "y");
1006 	NDMP_SETENV(zfs_envp, "DMP_NAME", "level");
1007 
1008 	zfs_attrs = NDMP_BUTYPE_BACKUP_UTF8 |
1009 	    NDMP_BUTYPE_RECOVER_UTF8 |
1010 	    NDMP_BUTYPE_BACKUP_INCREMENTAL;
1011 
1012 	/* zfs backup type */
1013 	info[2].butype_name = "zfs";
1014 	info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval);
1015 	info[2].default_env.default_env_val = zfs_envs;
1016 	info[2].attrs = zfs_attrs;
1017 
1018 	reply.error = NDMP_NO_ERR;
1019 	reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info);
1020 	reply.butype_info.butype_info_val = info;
1021 
1022 	ndmp_send_reply(connection, (void *)&reply,
1023 	    "sending ndmp_config_get_butype_info reply");
1024 }
1025 
1026 
1027 /*
1028  * ndmpd_config_get_ext_list_v4
1029  *
1030  * This handler handles the ndmpd_config_get_ext_list_v4 request.
1031  *
1032  * Parameters:
1033  *   connection (input) - connection handle.
1034  *   body       (input) - request message body.
1035  *
1036  * Returns:
1037  *   void
1038  */
1039 /*ARGSUSED*/
1040 void
1041 ndmpd_config_get_ext_list_v4(ndmp_connection_t *connection, void *body)
1042 {
1043 	ndmp_config_get_ext_list_reply_v4 reply;
1044 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1045 
1046 	(void) memset((void*)&reply, 0, sizeof (reply));
1047 
1048 	if (session->ns_set_ext_list == FALSE)
1049 		reply.error = NDMP_EXT_DANDN_ILLEGAL_ERR;
1050 	else
1051 		reply.error = NDMP_NO_ERR;
1052 
1053 	reply.class_list.class_list_val = NULL;
1054 	reply.class_list.class_list_len = 0;
1055 
1056 
1057 	ndmp_send_reply(connection, (void *)&reply,
1058 	    "error sending ndmp_config_get_ext_list reply");
1059 }
1060 
1061 /*
1062  * ndmpd_config_set_ext_list_v4
1063  *
1064  * This handler handles the ndmpd_config_get_ext_list_v4 request.
1065  *
1066  * Parameters:
1067  *   connection (input) - connection handle.
1068  *   body       (input) - request message body.
1069  *
1070  * Returns:
1071  *   void
1072  */
1073 /*ARGSUSED*/
1074 void
1075 ndmpd_config_set_ext_list_v4(ndmp_connection_t *connection, void *body)
1076 {
1077 	ndmp_config_set_ext_list_reply_v4 reply;
1078 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1079 
1080 	(void) memset((void*)&reply, 0, sizeof (reply));
1081 	if (session->ns_set_ext_list == TRUE) {
1082 		reply.error = NDMP_EXT_DANDN_ILLEGAL_ERR;
1083 	} else {
1084 		session->ns_set_ext_list = TRUE;
1085 		/*
1086 		 * NOTE: for now we are not supporting any extension list,
1087 		 * hence this error, when we start to support extensions,
1088 		 * this should be validated
1089 		 */
1090 
1091 		reply.error = NDMP_VERSION_NOT_SUPPORTED_ERR;
1092 	}
1093 
1094 	ndmp_send_reply(connection, (void *)&reply,
1095 	    "error sending ndmp_config_set_ext_list reply");
1096 }
1097 
1098 
1099 
1100 /*
1101  * ************************************************************************
1102  * LOCALS
1103  * ************************************************************************
1104  */
1105 
1106 /*
1107  * simple_get_attrs
1108  *
1109  * Set the default attrs for dump mode
1110  *
1111  * Parameters:
1112  *   attributes (output) - the attributes for dump mode
1113  *
1114  * Returns:
1115  *   void
1116  */
1117 static void
1118 simple_get_attrs(ulong_t *attributes)
1119 {
1120 	*attributes = NDMP_NO_RECOVER_FHINFO;
1121 }
1122