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