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