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