xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_config.c (revision f970887035084ffc66d633763104257174c8c502)
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 		NDMP_LOG(LOG_DEBUG,
728 		    "model \"%s\" dev \"%s\"", sd->sd_id, sd->sd_name);
729 
730 		envp_head = envp;
731 		NDMP_SETENV(envp, "EXECUTE_CDB", "b");
732 		NDMP_SETENV(envp, "SERIAL_NUMBER", sd->sd_serial);
733 		NDMP_SETENV(envp, "WORLD_WIDE_NAME", sd->sd_wwn);
734 
735 		tip->model = sd->sd_id; /* like "DLT7000	 " */
736 		tip->caplist.caplist_len = 1;
737 		tip->caplist.caplist_val = dcp;
738 		dcp->device = sd->sd_name; /* like "isp1t060" */
739 		dcp->attr = 0;
740 		dcp->capability.capability_len = 3;
741 		dcp->capability.capability_val = envp_head;
742 		tip++;
743 		dcp++;
744 		n++;
745 	}
746 
747 	NDMP_LOG(LOG_DEBUG, "n %d", n);
748 
749 	/*
750 	 * We should not receive the get_tape_info when three-way backup is
751 	 * running and we are acting as just data, but some clients try
752 	 * to get the Tape information anyway.
753 	 */
754 	if (n == 0 || max <= 0) {
755 		reply.error = NDMP_NO_DEVICE_ERR;
756 		ndmp_send_reply(connection, (void *)&reply,
757 		    "error sending ndmp_config_get_tape_info reply");
758 		free(tip_save); free(dcp_save); free(envp_save);
759 		return;
760 	}
761 
762 
763 	reply.tape_info.tape_info_len = n;
764 	reply.tape_info.tape_info_val = tip_save;
765 
766 	ndmp_send_reply(connection, (void *)&reply,
767 	    "error sending ndmp_config_get_tape_info reply");
768 
769 	free(tip_save);
770 	free(dcp_save);
771 	free(envp_save);
772 }
773 
774 
775 /*
776  * ndmpd_config_get_scsi_info_v3
777  *
778  * This handler handles the ndmp_config_get_tape_scsi_request.
779  * Information about all connected scsi tape stacker and jukeboxes
780  * is returned.
781  *
782  * Parameters:
783  *   connection (input) - connection handle.
784  *   body       (input) - request message body.
785  *
786  * Returns:
787  *   void
788  */
789 /*ARGSUSED*/
790 void
791 ndmpd_config_get_scsi_info_v3(ndmp_connection_t *connection, void *body)
792 {
793 	ndmp_config_get_scsi_info_reply_v3 reply;
794 	ndmp_device_info_v3 *sip, *sip_save;
795 	ndmp_device_capability_v3 *dcp, *dcp_save;
796 	int i, n, max;
797 	sasd_drive_t *sd;
798 	scsi_link_t *sl;
799 	ndmp_pval *envp, *envp_save = NULL;
800 	ndmp_pval *envp_head;
801 
802 	(void) memset((void*)&reply, 0, sizeof (reply));
803 	max = sasd_dev_count();
804 	sip_save = sip = ndmp_malloc(sizeof (ndmp_device_info_v3) * max);
805 	dcp_save = dcp = ndmp_malloc(sizeof (ndmp_device_capability_v3) * max);
806 	envp_save = envp = ndmp_malloc(sizeof (ndmp_pval) * max * 2);
807 	if (!sip_save || !dcp_save || !envp_save) {
808 		free(sip_save);
809 		free(dcp_save);
810 		free(envp_save);
811 		reply.error = NDMP_NO_MEM_ERR;
812 		ndmp_send_reply(connection, (void *)&reply,
813 		    "error sending ndmp_config_get_scsi_info reply");
814 		return;
815 	}
816 
817 	reply.error = NDMP_NO_ERR;
818 	for (i = n = 0; i < max; i++) {
819 		if (!(sl = sasd_dev_slink(i)) || !(sd = sasd_drive(i)))
820 			continue;
821 		if (sl->sl_type != DTYPE_CHANGER)
822 			continue;
823 
824 		NDMP_LOG(LOG_DEBUG,
825 		    "model \"%s\" dev \"%s\"", sd->sd_id, sd->sd_name);
826 
827 		envp_head = envp;
828 		NDMP_SETENV(envp, "SERIAL_NUMBER", sd->sd_serial);
829 		NDMP_SETENV(envp, "WORLD_WIDE_NAME", sd->sd_wwn);
830 
831 		sip->model = sd->sd_id; /* like "Powerstor L200  " */
832 		sip->caplist.caplist_len = 1;
833 		sip->caplist.caplist_val = dcp;
834 		dcp->device = sd->sd_name; /* like "isp1m000" */
835 
836 		dcp->attr = 0;
837 		dcp->capability.capability_len = 2;
838 		dcp->capability.capability_val = envp_head;
839 		sip++;
840 		dcp++;
841 		n++;
842 	}
843 
844 	NDMP_LOG(LOG_DEBUG, "n %d", n);
845 
846 	reply.scsi_info.scsi_info_len = n;
847 	reply.scsi_info.scsi_info_val = sip_save;
848 
849 	ndmp_send_reply(connection, (void *)&reply,
850 	    "error sending ndmp_config_get_scsi_info reply");
851 
852 	free(sip_save);
853 	free(dcp_save);
854 	free(envp_save);
855 }
856 
857 
858 /*
859  * ndmpd_config_get_server_info_v3
860  *
861  * This handler handles the ndmp_config_get_server_info request.
862  * Host specific information is returned.
863  *
864  * Parameters:
865  *   connection (input) - connection handle.
866  *   body       (input) - request message body.
867  *
868  * Returns:
869  *   void
870  */
871 /*ARGSUSED*/
872 void
873 ndmpd_config_get_server_info_v3(ndmp_connection_t *connection, void *body)
874 {
875 	ndmp_config_get_server_info_reply_v3 reply;
876 	ndmp_auth_type auth_types[2];
877 	char rev_number[10];
878 	ndmpd_session_t *session = ndmp_get_client_data(connection);
879 
880 	(void) memset((void*)&reply, 0, sizeof (reply));
881 	reply.error = NDMP_NO_ERR;
882 
883 	if (connection->conn_authorized ||
884 	    session->ns_protocol_version != NDMPV4) {
885 		reply.vendor_name = VENDOR_NAME;
886 		reply.product_name = PRODUCT_NAME;
887 		(void) snprintf(rev_number, sizeof (rev_number), "%d",
888 		    ndmp_ver);
889 		reply.revision_number = rev_number;
890 	} else {
891 		reply.vendor_name = "\0";
892 		reply.product_name = "\0";
893 		reply.revision_number = "\0";
894 	}
895 
896 	NDMP_LOG(LOG_DEBUG,
897 	    "vendor \"%s\", product \"%s\" rev \"%s\"",
898 	    reply.vendor_name, reply.product_name, reply.revision_number);
899 
900 	auth_types[0] = NDMP_AUTH_TEXT;
901 	auth_types[1] = NDMP_AUTH_MD5;
902 	reply.auth_type.auth_type_len = ARRAY_LEN(auth_types, ndmp_auth_type);
903 	reply.auth_type.auth_type_val = auth_types;
904 
905 	ndmp_send_reply(connection, (void *)&reply,
906 	    "error sending ndmp_config_get_server_info reply");
907 }
908 
909 
910 
911 /*
912  * ************************************************************************
913  * NDMP V4 HANDLERS
914  * ************************************************************************
915  */
916 
917 /*
918  * ndmpd_config_get_butype_info_v4
919  *
920  * This handler handles the ndmp_config_get_butype_info_request.
921  * Information about all supported backup types are returned.
922  *
923  * Parameters:
924  *   connection (input) - connection handle.
925  *   body       (input) - request message body.
926  *
927  * Returns:
928  *   void
929  */
930 /*ARGSUSED*/
931 void
932 ndmpd_config_get_butype_info_v4(ndmp_connection_t *connection, void *body)
933 {
934 	ndmp_config_get_butype_info_reply_v4 reply;
935 	ndmp_butype_info info[3];
936 
937 	ndmp_pval envs[12];
938 	ulong_t attrs;
939 	ndmp_pval *envp = envs;
940 
941 	ndmp_pval zfs_envs[11];
942 	ulong_t zfs_attrs;
943 	ndmp_pval *zfs_envp = zfs_envs;
944 
945 
946 	(void) memset((void*)&reply, 0, sizeof (reply));
947 
948 	/*
949 	 * Supported environment variables and their default values
950 	 * for dump and tar.
951 	 *
952 	 * The environment variables for dump and tar format are the
953 	 * same, because we use the same backup engine for both.
954 	 */
955 	NDMP_SETENV(envp, "FILESYSTEM", "");
956 	NDMP_SETENV(envp, "DIRECT", "n");
957 	NDMP_SETENV(envp, "RECURSIVE", "n");
958 	NDMP_SETENV(envp, "TYPE", "");
959 	NDMP_SETENV(envp, "USER", "");
960 	NDMP_SETENV(envp, "HIST", "n");
961 	NDMP_SETENV(envp, "PATHNAME_SEPARATOR", "/");
962 	NDMP_SETENV(envp, "LEVEL", "0");
963 	NDMP_SETENV(envp, "EXTRACT", "y");
964 	NDMP_SETENV(envp, "UPDATE", "y");
965 	NDMP_SETENV(envp, "CMD", "");
966 	NDMP_SETENV(envp, "BASE_DATE", "");
967 
968 	attrs = NDMP_BUTYPE_RECOVER_FILELIST |
969 	    NDMP_BUTYPE_BACKUP_DIRECT |
970 	    NDMP_BUTYPE_BACKUP_INCREMENTAL |
971 	    NDMP_BUTYPE_BACKUP_UTF8 |
972 	    NDMP_BUTYPE_RECOVER_UTF8 |
973 	    NDMP_BUTYPE_BACKUP_FH_FILE |
974 	    NDMP_BUTYPE_BACKUP_FH_DIR |
975 	    NDMP_BUTYPE_RECOVER_FH_FILE |
976 	    NDMP_BUTYPE_RECOVER_FH_DIR;
977 
978 	/* If DAR supported */
979 	if (ndmp_dar_support)
980 		attrs |= NDMP_BUTYPE_RECOVER_DIRECT;
981 
982 	/* tar backup type */
983 	info[0].butype_name = "tar";
984 	info[0].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
985 	info[0].default_env.default_env_val = envs;
986 	info[0].attrs = attrs;
987 
988 	/* dump backup type */
989 	info[1].butype_name = "dump";
990 	info[1].default_env.default_env_len = ARRAY_LEN(envs, ndmp_pval);
991 	info[1].default_env.default_env_val = envs;
992 	info[1].attrs = attrs;
993 
994 	/*
995 	 * Supported environment variables and their default values
996 	 * for type "zfs."
997 	 */
998 
999 	NDMP_SETENV(zfs_envp, "USER", "");
1000 	NDMP_SETENV(zfs_envp, "CMD", "");
1001 	NDMP_SETENV(zfs_envp, "FILESYSTEM", "");
1002 	NDMP_SETENV(zfs_envp, "PATHNAME_SEPARATOR", "/");
1003 	NDMP_SETENV(zfs_envp, "TYPE", "zfs");
1004 	NDMP_SETENV(zfs_envp, "HIST", "n");
1005 	NDMP_SETENV(zfs_envp, "LEVEL", "0");
1006 	NDMP_SETENV(zfs_envp, "ZFS_MODE", "recursive");
1007 	NDMP_SETENV(zfs_envp, "ZFS_FORCE", "n");
1008 	NDMP_SETENV(zfs_envp, "UPDATE", "y");
1009 	NDMP_SETENV(zfs_envp, "DMP_NAME", "level");
1010 
1011 	zfs_attrs = NDMP_BUTYPE_BACKUP_UTF8 |
1012 	    NDMP_BUTYPE_RECOVER_UTF8 |
1013 	    NDMP_BUTYPE_BACKUP_DIRECT |
1014 	    NDMP_BUTYPE_BACKUP_INCREMENTAL;
1015 
1016 	/* zfs backup type */
1017 	info[2].butype_name = "zfs";
1018 	info[2].default_env.default_env_len = ARRAY_LEN(zfs_envs, ndmp_pval);
1019 	info[2].default_env.default_env_val = zfs_envs;
1020 	info[2].attrs = zfs_attrs;
1021 
1022 	reply.error = NDMP_NO_ERR;
1023 	reply.butype_info.butype_info_len = ARRAY_LEN(info, ndmp_butype_info);
1024 	reply.butype_info.butype_info_val = info;
1025 
1026 	ndmp_send_reply(connection, (void *)&reply,
1027 	    "sending ndmp_config_get_butype_info reply");
1028 }
1029 
1030 
1031 /*
1032  * ndmpd_config_get_ext_list_v4
1033  *
1034  * This handler handles the ndmpd_config_get_ext_list_v4 request.
1035  *
1036  * Parameters:
1037  *   connection (input) - connection handle.
1038  *   body       (input) - request message body.
1039  *
1040  * Returns:
1041  *   void
1042  */
1043 /*ARGSUSED*/
1044 void
1045 ndmpd_config_get_ext_list_v4(ndmp_connection_t *connection, void *body)
1046 {
1047 	ndmp_config_get_ext_list_reply_v4 reply;
1048 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1049 
1050 	(void) memset((void*)&reply, 0, sizeof (reply));
1051 
1052 	if (session->ns_set_ext_list == FALSE)
1053 		reply.error = NDMP_EXT_DANDN_ILLEGAL_ERR;
1054 	else
1055 		reply.error = NDMP_NO_ERR;
1056 
1057 	reply.class_list.class_list_val = NULL;
1058 	reply.class_list.class_list_len = 0;
1059 
1060 
1061 	ndmp_send_reply(connection, (void *)&reply,
1062 	    "error sending ndmp_config_get_ext_list reply");
1063 }
1064 
1065 /*
1066  * ndmpd_config_set_ext_list_v4
1067  *
1068  * This handler handles the ndmpd_config_get_ext_list_v4 request.
1069  *
1070  * Parameters:
1071  *   connection (input) - connection handle.
1072  *   body       (input) - request message body.
1073  *
1074  * Returns:
1075  *   void
1076  */
1077 /*ARGSUSED*/
1078 void
1079 ndmpd_config_set_ext_list_v4(ndmp_connection_t *connection, void *body)
1080 {
1081 	ndmp_config_set_ext_list_reply_v4 reply;
1082 	ndmpd_session_t *session = ndmp_get_client_data(connection);
1083 
1084 	(void) memset((void*)&reply, 0, sizeof (reply));
1085 	if (session->ns_set_ext_list == TRUE) {
1086 		reply.error = NDMP_EXT_DANDN_ILLEGAL_ERR;
1087 	} else {
1088 		session->ns_set_ext_list = TRUE;
1089 		/*
1090 		 * NOTE: for now we are not supporting any extension list,
1091 		 * hence this error, when we start to support extensions,
1092 		 * this should be validated
1093 		 */
1094 
1095 		reply.error = NDMP_VERSION_NOT_SUPPORTED_ERR;
1096 	}
1097 
1098 	ndmp_send_reply(connection, (void *)&reply,
1099 	    "error sending ndmp_config_set_ext_list reply");
1100 }
1101 
1102 
1103 
1104 /*
1105  * ************************************************************************
1106  * LOCALS
1107  * ************************************************************************
1108  */
1109 
1110 /*
1111  * simple_get_attrs
1112  *
1113  * Set the default attrs for dump mode
1114  *
1115  * Parameters:
1116  *   attributes (output) - the attributes for dump mode
1117  *
1118  * Returns:
1119  *   void
1120  */
1121 static void
1122 simple_get_attrs(ulong_t *attributes)
1123 {
1124 	*attributes = NDMP_NO_RECOVER_FHINFO;
1125 }
1126