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 2017 Nexenta Systems, Inc. All rights reserved. */
41
42 #include <sys/types.h>
43 #include <syslog.h>
44 #include <assert.h>
45 #include <ctype.h>
46 #include <errno.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <strings.h>
51 #include <time.h>
52 #include "ndmpd.h"
53 #include <bitmap.h>
54 #include <sys/queue.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <netinet/tcp.h>
58 #include <arpa/inet.h>
59 #include <sys/socketvar.h>
60 #include <net/if.h>
61 #include <netdb.h>
62 #include <sys/filio.h>
63 #include <sys/mtio.h>
64 #include <sys/scsi/impl/uscsi.h>
65 #include <sys/scsi/scsi.h>
66 #include "tlm.h"
67
68 /*
69 * Force to backup all the intermediate directories leading to an object
70 * to be backed up in 'dump' format backup.
71 */
72 boolean_t ndmp_dump_path_node = FALSE;
73
74
75 /*
76 * Force to backup all the intermediate directories leading to an object
77 * to be backed up in 'tar' format backup.
78 */
79 boolean_t ndmp_tar_path_node = FALSE;
80
81
82 /*
83 * Should the 'st_ctime' be ignored during incremental level backup?
84 */
85 boolean_t ndmp_ignore_ctime = FALSE;
86
87 /*
88 * Should the 'st_lmtime' be included during incremental level backup?
89 */
90 boolean_t ndmp_include_lmtime = FALSE;
91
92 /*
93 * Force to send the file history node entries along with the file history
94 * dir entries for all directories containing the changed files to the client
95 * for incremental backup.
96 *
97 * Note: This variable is added to support Bakbone Software's Netvault DMA
98 * which expects to get the FH ADD NODES for all upper directories which
99 * contain the changed files in incremental backup along with the FH ADD DIRS.
100 */
101 boolean_t ndmp_fhinode = FALSE;
102
103 /*
104 * Maximum permitted sequence number in the token-based backup. The
105 * value of this variable can be changed by the administrator and is
106 * saved in the NDMP configuration file.
107 */
108 static int ndmp_max_tok_seq = NDMP_MAX_TOKSEQ;
109
110 /*
111 * Force backup directories in incremental backups. If the
112 * directory is not modified itself, it's not backed up by
113 * default.
114 */
115 int ndmp_force_bk_dirs = 0;
116
117 /*
118 * Keeps track of the open SCSI (including tape and robot) devices.
119 * When a SCSI device is opened its name must be added to this list and
120 * when it's closed its name must be removed from this list. The main
121 * purpose of this list is the robot device. If the robot devices are not
122 * attached in SASD layer, Local Backup won't see them. If they are
123 * attached and we open the robot devices, then wrong commands are sent
124 * to robot by SASD since it assumes that the robot is a tape (sequential
125 * access) device.
126 */
127 struct open_list {
128 LIST_ENTRY(open_list) ol_q;
129 int ol_nref;
130 char *ol_devnm;
131 int ol_sid;
132 int ol_lun;
133 int ol_fd;
134 ndmp_connection_t *cl_conn;
135 };
136 LIST_HEAD(ol_head, open_list);
137
138
139 /*
140 * Head of the opened SCSI devices list.
141 */
142 static struct ol_head ol_head;
143
144 mutex_t ol_mutex = DEFAULTMUTEX;
145
146
147 /*
148 * List of things to be exluded from backup.
149 */
150 static char *exls[] = {
151 EXCL_PROC,
152 EXCL_TMP,
153 NULL, /* reserved for a copy of the "backup.directory" */
154 NULL
155 };
156
157 /*
158 * The counter for creating unique names with "NDMP_RCF_BASENAME.%d" format.
159 */
160 static int ndmp_job_cnt = 0;
161
162 static int scsi_test_unit_ready(int dev_id);
163 static int ndmpd_mkdir(const char *);
164
165 /*
166 * ndmpd_add_file_handler
167 *
168 * Adds a file handler to the file handler list.
169 * The file handler list is used by ndmpd_api_dispatch.
170 *
171 * Parameters:
172 * session (input) - session pointer.
173 * cookie (input) - opaque data to be passed to file hander when called.
174 * fd (input) - file descriptor.
175 * mode (input) - bitmask of the following:
176 * 1 = watch file for ready for reading
177 * 2 = watch file for ready for writing
178 * 4 = watch file for exception
179 * class (input) - handler class. (HC_CLIENT, HC_MOVER, HC_MODULE)
180 * func (input) - function to call when the file meets one of the
181 * conditions specified by mode.
182 *
183 * Returns:
184 * 0 - success.
185 * -1 - error.
186 */
187 int
188 ndmpd_add_file_handler(ndmpd_session_t *session, void *cookie, int fd,
189 ulong_t mode, ulong_t class, ndmpd_file_handler_func_t *func)
190 {
191 ndmpd_file_handler_t *new;
192
193 new = ndmp_malloc(sizeof (ndmpd_file_handler_t));
194 if (new == 0)
195 return (-1);
196
197 new->fh_cookie = cookie;
198 new->fh_fd = fd;
199 new->fh_mode = mode;
200 new->fh_class = class;
201 new->fh_func = func;
202 new->fh_next = session->ns_file_handler_list;
203 session->ns_file_handler_list = new;
204 return (0);
205 }
206
207
208 /*
209 * ndmpd_remove_file_handler
210 *
211 * Removes a file handler from the file handler list.
212 *
213 * Parameters:
214 * session (input) - session pointer.
215 * fd (input) - file descriptor.
216 *
217 * Returns:
218 * 0 - success.
219 * -1 - error.
220 */
221 int
222 ndmpd_remove_file_handler(ndmpd_session_t *session, int fd)
223 {
224 ndmpd_file_handler_t **last;
225 ndmpd_file_handler_t *handler;
226
227 last = &session->ns_file_handler_list;
228 while (*last != 0) {
229 handler = *last;
230
231 if (handler->fh_fd == fd) {
232 *last = handler->fh_next;
233 (void) free(handler);
234 return (1);
235 }
236 last = &handler->fh_next;
237 }
238
239 return (0);
240 }
241
242
243 /*
244 * ndmp_connection_closed
245 *
246 * If the connection closed or not.
247 *
248 * Parameters:
249 * fd (input) : file descriptor
250 *
251 * Returns:
252 * 0 - connection is still valid
253 * 1 - connection is not valid anymore
254 * -1 - Internal kernel error
255 */
256 int
257 ndmp_connection_closed(int fd)
258 {
259 fd_set fds;
260 int closed, ret;
261 struct timeval timeout;
262
263 if (fd < 0) /* We are not using the mover */
264 return (-1);
265
266 timeout.tv_sec = 0;
267 timeout.tv_usec = 1000;
268
269 FD_ZERO(&fds);
270 FD_SET(fd, &fds);
271 ret = select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
272
273 closed = (ret == -1 && errno == EBADF);
274
275 return (closed);
276 }
277
278 /*
279 * ndmp_check_mover_state
280 *
281 * Checks the mover connection status and sends an appropriate
282 * NDMP message to client based on that.
283 *
284 * Parameters:
285 * ndmpd_session_t *session (input) : session pointer
286 *
287 * Returns:
288 * void.
289 */
290 void
291 ndmp_check_mover_state(ndmpd_session_t *session)
292 {
293 int moverfd;
294 /*
295 * NDMPV3 Spec (Three-way restore):
296 * Once all of the files have been recovered, NDMP DATA Server closes
297 * the connection to the mover on the NDMP TAPE Server. THEN
298 * The NDMP client should receive an NDMP_NOTIFY_MOVER_HALTED message
299 * with an NDMP_MOVER_CONNECT_CLOSED reason from the NDMP TAPE Server
300 */
301 moverfd = session->ns_mover.md_sock;
302 /* If connection is closed by the peer */
303 if (moverfd >= 0 &&
304 session->ns_mover.md_mode == NDMP_MOVER_MODE_WRITE) {
305 int closed, reason;
306
307 closed = ndmp_connection_closed(moverfd);
308 if (closed) {
309 /* Connection closed or internal error */
310 if (closed > 0) {
311 syslog(LOG_DEBUG,
312 "ndmp mover: connection closed by peer");
313 reason = NDMP_MOVER_HALT_CONNECT_CLOSED;
314 } else {
315 syslog(LOG_DEBUG,
316 "ndmp mover: Internal error");
317 reason = NDMP_MOVER_HALT_INTERNAL_ERROR;
318 }
319 ndmpd_mover_error(session, reason);
320
321 }
322 }
323 }
324
325
326 /*
327 * ndmpd_select
328 *
329 * Calls select on the the set of file descriptors from the
330 * file handler list masked by the fd_class argument.
331 * Calls the file handler function for each
332 * file descriptor that is ready for I/O.
333 *
334 * Parameters:
335 * session (input) - session pointer.
336 * block (input) - if TRUE, ndmpd_select waits until at least one
337 * file descriptor is ready for I/O. Otherwise,
338 * it returns immediately if no file descriptors are
339 * ready for I/O.
340 * class_mask (input) - bit mask of handler classes to be examined.
341 * Provides for excluding some of the handlers from
342 * being called.
343 *
344 * Returns:
345 * -1 - error.
346 * 0 - no handlers were called.
347 * 1 - at least one handler was called.
348 */
349 int
350 ndmpd_select(ndmpd_session_t *session, boolean_t block, ulong_t class_mask)
351 {
352 fd_set rfds;
353 fd_set wfds;
354 fd_set efds;
355 int n;
356 ndmpd_file_handler_t *handler;
357 struct timeval timeout;
358 ndmp_lbr_params_t *nlp;
359
360 if (session->ns_file_handler_list == 0)
361 return (0);
362
363
364 /*
365 * If select should be blocked, then we poll every ten seconds.
366 * The reason is in case of three-way restore we should be able
367 * to detect if the other end closed the connection or not.
368 * NDMP client(DMA) does not send any information about the connection
369 * that was closed in the other end.
370 */
371
372 if (block == TRUE)
373 timeout.tv_sec = 10;
374 else
375 timeout.tv_sec = 0;
376 timeout.tv_usec = 0;
377
378 do {
379 /* Create the fd_sets for select. */
380 FD_ZERO(&rfds);
381 FD_ZERO(&wfds);
382 FD_ZERO(&efds);
383
384 for (handler = session->ns_file_handler_list; handler != 0;
385 handler = handler->fh_next) {
386 if ((handler->fh_class & class_mask) == 0)
387 continue;
388
389 if (handler->fh_mode & NDMPD_SELECT_MODE_READ)
390 FD_SET(handler->fh_fd, &rfds);
391 if (handler->fh_mode & NDMPD_SELECT_MODE_WRITE)
392 FD_SET(handler->fh_fd, &wfds);
393 if (handler->fh_mode & NDMPD_SELECT_MODE_EXCEPTION)
394 FD_SET(handler->fh_fd, &efds);
395 }
396 ndmp_check_mover_state(session);
397 n = select(FD_SETSIZE, &rfds, &wfds, &efds, &timeout);
398 } while (n == 0 && block == TRUE);
399
400 if (n < 0) {
401 int connection_fd = ndmp_get_fd(session->ns_connection);
402
403 if (errno == EINTR)
404 return (0);
405
406 nlp = ndmp_get_nlp(session);
407 (void) mutex_lock(&nlp->nlp_mtx);
408 for (handler = session->ns_file_handler_list; handler != 0;
409 handler = handler->fh_next) {
410 if ((handler->fh_class & class_mask) == 0)
411 continue;
412
413 if (handler->fh_mode & NDMPD_SELECT_MODE_READ) {
414 if (FD_ISSET(handler->fh_fd, &rfds) &&
415 connection_fd == handler->fh_fd)
416 session->ns_eof = TRUE;
417 }
418 if (handler->fh_mode & NDMPD_SELECT_MODE_WRITE) {
419 if (FD_ISSET(handler->fh_fd, &wfds) &&
420 connection_fd == handler->fh_fd)
421 session->ns_eof = TRUE;
422 }
423 if (handler->fh_mode & NDMPD_SELECT_MODE_EXCEPTION) {
424 if (FD_ISSET(handler->fh_fd, &efds) &&
425 connection_fd == handler->fh_fd)
426 session->ns_eof = TRUE;
427 }
428 }
429 (void) cond_broadcast(&nlp->nlp_cv);
430 (void) mutex_unlock(&nlp->nlp_mtx);
431 return (-1);
432 }
433 if (n == 0)
434 return (0);
435
436 handler = session->ns_file_handler_list;
437 while (handler != 0) {
438 ulong_t mode = 0;
439
440 if ((handler->fh_class & class_mask) == 0) {
441 handler = handler->fh_next;
442 continue;
443 }
444 if (handler->fh_mode & NDMPD_SELECT_MODE_READ) {
445 if (FD_ISSET(handler->fh_fd, &rfds)) {
446 mode |= NDMPD_SELECT_MODE_READ;
447 FD_CLR(handler->fh_fd, &rfds);
448 }
449 }
450 if (handler->fh_mode & NDMPD_SELECT_MODE_WRITE) {
451 if (FD_ISSET(handler->fh_fd, &wfds)) {
452 mode |= NDMPD_SELECT_MODE_WRITE;
453 FD_CLR(handler->fh_fd, &wfds);
454 }
455 }
456 if (handler->fh_mode & NDMPD_SELECT_MODE_EXCEPTION) {
457 if (FD_ISSET(handler->fh_fd, &efds)) {
458 mode |= NDMPD_SELECT_MODE_EXCEPTION;
459 FD_CLR(handler->fh_fd, &efds);
460 }
461 }
462 if (mode) {
463 (*handler->fh_func) (handler->fh_cookie,
464 handler->fh_fd, mode);
465
466 /*
467 * K.L. The list can be modified during the execution
468 * of handler->fh_func. Therefore, handler will start
469 * from the beginning of the handler list after
470 * each execution.
471 */
472 handler = session->ns_file_handler_list;
473 } else
474 handler = handler->fh_next;
475
476 }
477
478 return (1);
479 }
480
481
482 /*
483 * ndmpd_save_env
484 *
485 * Saves a copy of the environment variable list from the data_start_backup
486 * request or data_start_recover request.
487 *
488 * Parameters:
489 * session (input) - session pointer.
490 * env (input) - environment variable list to be saved.
491 * envlen (input) - length of variable array.
492 *
493 * Returns:
494 * error code.
495 */
496 ndmp_error
497 ndmpd_save_env(ndmpd_session_t *session, ndmp_pval *env, ulong_t envlen)
498 {
499 ulong_t i;
500 char *namebuf;
501 char *valbuf;
502
503 session->ns_data.dd_env_len = 0;
504
505 if (envlen == 0)
506 return (NDMP_NO_ERR);
507
508 session->ns_data.dd_env = ndmp_malloc(sizeof (ndmp_pval) * envlen);
509 if (session->ns_data.dd_env == 0)
510 return (NDMP_NO_MEM_ERR);
511
512 for (i = 0; i < envlen; i++) {
513 namebuf = strdup(env[i].name);
514 if (namebuf == 0)
515 return (NDMP_NO_MEM_ERR);
516
517 valbuf = strdup(env[i].value);
518 if (valbuf == 0) {
519 free(namebuf);
520 return (NDMP_NO_MEM_ERR);
521 }
522
523 syslog(LOG_DEBUG, "env(%s): \"%s\"",
524 namebuf, valbuf);
525
526 (void) mutex_lock(&session->ns_lock);
527 session->ns_data.dd_env[i].name = namebuf;
528 session->ns_data.dd_env[i].value = valbuf;
529 session->ns_data.dd_env_len++;
530 (void) mutex_unlock(&session->ns_lock);
531 }
532
533 return (NDMP_NO_ERR);
534 }
535
536
537 /*
538 * ndmpd_free_env
539 *
540 * Free the previously saved environment variable array.
541 *
542 * Parameters:
543 * session - NDMP session pointer.
544 *
545 * Returns:
546 * void.
547 */
548 void
549 ndmpd_free_env(ndmpd_session_t *session)
550 {
551 ulong_t i;
552 int count = session->ns_data.dd_env_len;
553
554 (void) mutex_lock(&session->ns_lock);
555 session->ns_data.dd_env_len = 0;
556 for (i = 0; i < count; i++) {
557 free(session->ns_data.dd_env[i].name);
558 free(session->ns_data.dd_env[i].value);
559 }
560
561 free((char *)session->ns_data.dd_env);
562 session->ns_data.dd_env = 0;
563 (void) mutex_unlock(&session->ns_lock);
564 }
565
566
567 /*
568 * ndmpd_save_nlist_v2
569 *
570 * Save a copy of list of file names to be restored.
571 *
572 * Parameters:
573 * nlist (input) - name list from data_start_recover request.
574 * nlistlen (input) - length of name list.
575 *
576 * Returns:
577 * array of file name pointers.
578 *
579 * Notes:
580 * free_nlist should be called to free the returned list.
581 * A null pointer indicates the end of the list.
582 */
583 ndmp_error
584 ndmpd_save_nlist_v2(ndmpd_session_t *session, ndmp_name *nlist,
585 ulong_t nlistlen)
586 {
587 ulong_t i;
588 char *namebuf;
589 char *destbuf;
590
591 if (nlistlen == 0)
592 return (NDMP_NO_ERR);
593
594 session->ns_data.dd_nlist_len = 0;
595 session->ns_data.dd_nlist =
596 ndmp_malloc(sizeof (ndmp_name)*(nlistlen + 1));
597 if (session->ns_data.dd_nlist == 0)
598 return (NDMP_NO_MEM_ERR);
599
600 for (i = 0; i < nlistlen; i++) {
601 namebuf = ndmp_malloc(strlen(nlist[i].name) + 1);
602 if (namebuf == 0)
603 return (NDMP_NO_MEM_ERR);
604
605 destbuf = ndmp_malloc(strlen(nlist[i].dest) + 1);
606 if (destbuf == 0) {
607 free(namebuf);
608 return (NDMP_NO_MEM_ERR);
609 }
610 (void) strlcpy(namebuf, nlist[i].name,
611 strlen(nlist[i].name) + 1);
612 (void) strlcpy(destbuf, nlist[i].dest,
613 strlen(nlist[i].dest) + 1);
614
615 session->ns_data.dd_nlist[i].name = namebuf;
616 session->ns_data.dd_nlist[i].dest = destbuf;
617 session->ns_data.dd_nlist[i].ssid = nlist[i].ssid;
618 session->ns_data.dd_nlist[i].fh_info = nlist[i].fh_info;
619 session->ns_data.dd_nlist_len++;
620 }
621
622 return (NDMP_NO_ERR);
623 }
624
625
626 /*
627 * ndmpd_free_nlist_v2
628 *
629 * Free a list created by ndmpd_save_nlist_v2.
630 *
631 * Parameters:
632 * session (input) - session pointer.
633 *
634 * Returns:
635 * void
636 */
637 void
638 ndmpd_free_nlist_v2(ndmpd_session_t *session)
639 {
640 ulong_t i;
641
642 for (i = 0; i < session->ns_data.dd_nlist_len; i++) {
643 free(session->ns_data.dd_nlist[i].name);
644 free(session->ns_data.dd_nlist[i].dest);
645 }
646
647 if (session->ns_data.dd_nlist != NULL)
648 free((char *)session->ns_data.dd_nlist);
649 session->ns_data.dd_nlist = 0;
650 session->ns_data.dd_nlist_len = 0;
651 }
652
653
654 /*
655 * ndmpd_free_nlist_v3
656 *
657 * Free a list created by ndmpd_save_nlist_v3.
658 *
659 * Parameters:
660 * session (input) - session pointer.
661 *
662 * Returns:
663 * void
664 */
665 void
666 ndmpd_free_nlist_v3(ndmpd_session_t *session)
667 {
668 ulong_t i;
669 mem_ndmp_name_v3_t *tp; /* destination entry */
670
671 tp = session->ns_data.dd_nlist_v3;
672 for (i = 0; i < session->ns_data.dd_nlist_len; tp++, i++) {
673 NDMP_FREE(tp->nm3_opath);
674 NDMP_FREE(tp->nm3_dpath);
675 NDMP_FREE(tp->nm3_newnm);
676 }
677
678 NDMP_FREE(session->ns_data.dd_nlist_v3);
679 session->ns_data.dd_nlist_len = 0;
680 }
681
682
683 /*
684 * ndmpd_save_nlist_v3
685 *
686 * Save a copy of list of file names to be restored.
687 *
688 * Parameters:
689 * nlist (input) - name list from data_start_recover request.
690 * nlistlen (input) - length of name list.
691 *
692 * Returns:
693 * array of file name pointers.
694 *
695 * Notes:
696 * free_nlist should be called to free the returned list.
697 * A null pointer indicates the end of the list.
698 */
699 ndmp_error
700 ndmpd_save_nlist_v3(ndmpd_session_t *session, ndmp_name_v3 *nlist,
701 ulong_t nlistlen)
702 {
703 ulong_t i;
704 ndmp_error rv;
705 ndmp_name_v3 *sp; /* source entry */
706 mem_ndmp_name_v3_t *tp; /* destination entry */
707
708 if (nlistlen == 0)
709 return (NDMP_ILLEGAL_ARGS_ERR);
710
711 session->ns_data.dd_nlist_len = 0;
712 tp = session->ns_data.dd_nlist_v3 =
713 ndmp_malloc(sizeof (mem_ndmp_name_v3_t) * nlistlen);
714 if (session->ns_data.dd_nlist_v3 == 0)
715 return (NDMP_NO_MEM_ERR);
716
717 rv = NDMP_NO_ERR;
718 sp = nlist;
719 for (i = 0; i < nlistlen; tp++, sp++, i++) {
720 tp->nm3_opath = strdup(sp->original_path);
721 if (!tp->nm3_opath) {
722 rv = NDMP_NO_MEM_ERR;
723 break;
724 }
725 if (!*sp->destination_dir) {
726 tp->nm3_dpath = NULL;
727 /* In V4 destination dir cannot be NULL */
728 if (session->ns_protocol_version == NDMPV4) {
729 rv = NDMP_ILLEGAL_ARGS_ERR;
730 break;
731 }
732 } else if (!(tp->nm3_dpath = strdup(sp->destination_dir))) {
733 rv = NDMP_NO_MEM_ERR;
734 break;
735 }
736 if (!*sp->new_name)
737 tp->nm3_newnm = NULL;
738 else if (!(tp->nm3_newnm = strdup(sp->new_name))) {
739 rv = NDMP_NO_MEM_ERR;
740 break;
741 }
742
743 tp->nm3_node = quad_to_long_long(sp->node);
744 tp->nm3_fh_info = quad_to_long_long(sp->fh_info);
745 tp->nm3_err = NDMP_NO_ERR;
746 session->ns_data.dd_nlist_len++;
747
748 }
749
750 if (rv != NDMP_NO_ERR)
751 ndmpd_free_nlist_v3(session);
752
753 return (rv);
754 }
755
756
757 /*
758 * ndmpd_free_nlist
759 *
760 * Free the recovery list based on the version
761 *
762 * Parameters:
763 * session (input) - session pointer.
764 *
765 * Returns:
766 * void
767 */
768 void
769 ndmpd_free_nlist(ndmpd_session_t *session)
770 {
771 switch (session->ns_protocol_version) {
772 case 1:
773 case 2:
774 ndmpd_free_nlist_v2(session);
775 break;
776 case 3:
777 case 4:
778 ndmpd_free_nlist_v3(session);
779 break;
780
781 default:
782 syslog(LOG_DEBUG, "Unknown version %d",
783 session->ns_protocol_version);
784 }
785 }
786
787
788 /*
789 * fh_cmpv3
790 *
791 * Comparison function used in sorting the Nlist based on their
792 * file history info (offset of the entry on the tape)
793 *
794 * Parameters:
795 * p (input) - pointer to P
796 * q (input) - pointer to Q
797 *
798 * Returns:
799 * -1: P < Q
800 * 0: P = Q
801 * 1: P > Q
802 */
803 static int
804 fh_cmpv3(const void *p,
805 const void *q)
806 {
807 #define FH_INFOV3(p) (((mem_ndmp_name_v3_t *)p)->nm3_fh_info)
808
809 if (FH_INFOV3(p) < FH_INFOV3(q))
810 return (-1);
811 else if (FH_INFOV3(p) == FH_INFOV3(q))
812 return (0);
813 else
814 return (1);
815
816 #undef FH_INFOV3
817 }
818
819
820 /*
821 * ndmp_sort_nlist_v3
822 *
823 * Sort the recovery list based on their offset on the tape
824 *
825 * Parameters:
826 * session (input) - session pointer.
827 *
828 * Returns:
829 * void
830 */
831 void
832 ndmp_sort_nlist_v3(ndmpd_session_t *session)
833 {
834 if (!session || session->ns_data.dd_nlist_len == 0 ||
835 !session->ns_data.dd_nlist_v3)
836 return;
837
838 (void) qsort(session->ns_data.dd_nlist_v3,
839 session->ns_data.dd_nlist_len,
840 sizeof (mem_ndmp_name_v3_t), fh_cmpv3);
841 }
842
843
844 /*
845 * ndmp_send_reply
846 *
847 * Send the reply, check for error and print the msg if any error
848 * occured when sending the reply.
849 *
850 * Parameters:
851 * connection (input) - connection pointer.
852 *
853 * Return:
854 * void
855 */
856 void
857 ndmp_send_reply(ndmp_connection_t *connection, void *reply, char *msg)
858 {
859 if (ndmp_send_response(connection, NDMP_NO_ERR, reply) < 0)
860 syslog(LOG_DEBUG, "%s", msg);
861 }
862
863
864 /*
865 * ndmp_mtioctl
866 *
867 * Performs numerous filemark operations.
868 *
869 * Parameters:
870 * fd - file descriptor of the device
871 * cmd - filemark or record command
872 * count - the number of operations to be performed
873 */
874 int
875 ndmp_mtioctl(int fd, int cmd, int count)
876 {
877 struct mtop mp;
878
879 mp.mt_op = cmd;
880 mp.mt_count = count;
881 if (ioctl(fd, MTIOCTOP, &mp) < 0) {
882 syslog(LOG_ERR, "Failed to send command to tape: %m.");
883 return (-1);
884 }
885
886 return (0);
887 }
888
889
890 /*
891 * quad_to_long_long
892 *
893 * Convert type quad to longlong_t
894 */
895 u_longlong_t
896 quad_to_long_long(ndmp_u_quad q)
897 {
898 u_longlong_t ull;
899
900 ull = ((u_longlong_t)q.high << 32) + q.low;
901 return (ull);
902 }
903
904
905 /*
906 * long_long_to_quad
907 *
908 * Convert long long to quad type
909 */
910 ndmp_u_quad
911 long_long_to_quad(u_longlong_t ull)
912 {
913 ndmp_u_quad q;
914
915 q.high = (ulong_t)(ull >> 32);
916 q.low = (ulong_t)ull;
917 return (q);
918 }
919
920 void
921 set_socket_options(int sock)
922 {
923 int val;
924
925 /* set send buffer size */
926 val = atoi((const char *)ndmpd_get_prop_default(NDMP_SOCKET_CSS, "60"));
927 if (val <= 0)
928 val = 60;
929 val <<= 10; /* convert the value from kilobytes to bytes */
930 if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)) < 0)
931 syslog(LOG_ERR, "SO_SNDBUF failed: %m");
932
933 /* set receive buffer size */
934 val = atoi((const char *)ndmpd_get_prop_default(NDMP_SOCKET_CRS, "60"));
935 if (val <= 0)
936 val = 60;
937 val <<= 10; /* convert the value from kilobytes to bytes */
938 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)) < 0)
939 syslog(LOG_ERR, "SO_RCVBUF failed: %m");
940
941 /* don't wait to group tcp data */
942 val = 1;
943 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val)) != 0)
944 syslog(LOG_ERR, "TCP_NODELAY failed: %m");
945
946 /* tcp keep-alive */
947 val = 1;
948 if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof (val)) != 0)
949 syslog(LOG_ERR, "SO_KEEPALIVE failed: %m");
950 }
951
952 /*
953 * ndmp_get_max_tok_seq
954 *
955 * Get the maximum permitted token sequence for token-based
956 * backups.
957 *
958 * Parameters:
959 * void
960 *
961 * Returns:
962 * ndmp_max_tok_seq
963 */
964 int
965 ndmp_get_max_tok_seq(void)
966 {
967 return (ndmp_max_tok_seq);
968 }
969
970 /*
971 * ndmp_buffer_get_size
972 *
973 * Return the NDMP transfer buffer size
974 *
975 * Parameters:
976 * session (input) - session pointer.
977 *
978 * Returns:
979 * buffer size
980 */
981 long
982 ndmp_buffer_get_size(ndmpd_session_t *session)
983 {
984 long xfer_size;
985
986 if (session == NULL)
987 return (0);
988
989 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
990 xfer_size = atoi(ndmpd_get_prop_default(NDMP_MOVER_RECSIZE,
991 "60"));
992 if (xfer_size > 0)
993 xfer_size *= KILOBYTE;
994 else
995 xfer_size = REMOTE_RECORD_SIZE;
996 syslog(LOG_DEBUG, "Remote operation: %d", xfer_size);
997 } else {
998 syslog(LOG_DEBUG,
999 "Local operation: %lu", session->ns_mover.md_record_size);
1000 if ((xfer_size = session->ns_mover.md_record_size) == 0)
1001 xfer_size = MAX_RECORD_SIZE;
1002 }
1003
1004 syslog(LOG_DEBUG, "xfer_size: %d", xfer_size);
1005 return (xfer_size);
1006 }
1007
1008
1009 /*
1010 * ndmp_lbr_init
1011 *
1012 * Initialize the LBR/NDMP backup parameters
1013 *
1014 * Parameters:
1015 * session (input) - session pointer.
1016 *
1017 * Returns:
1018 * 0: on success
1019 * -1: otherwise
1020 */
1021 int
1022 ndmp_lbr_init(ndmpd_session_t *session)
1023 {
1024 if (session->ns_ndmp_lbr_params != NULL) {
1025 syslog(LOG_DEBUG, "ndmp_lbr_params already allocated.");
1026 return (0);
1027 }
1028
1029 session->ns_ndmp_lbr_params = ndmp_malloc(sizeof (ndmp_lbr_params_t));
1030 if (session->ns_ndmp_lbr_params == NULL)
1031 return (-1);
1032
1033 session->ns_ndmp_lbr_params->nlp_bkmap = -1;
1034 session->ns_ndmp_lbr_params->nlp_session = session;
1035 (void) cond_init(&session->ns_ndmp_lbr_params->nlp_cv, 0, NULL);
1036 (void) mutex_init(&session->ns_ndmp_lbr_params->nlp_mtx, 0, NULL);
1037 (void) mutex_init(&session->ns_lock, 0, NULL);
1038 session->ns_nref = 0;
1039 return (0);
1040 }
1041
1042
1043 /*
1044 * ndmp_lbr_cleanup
1045 *
1046 * Deallocate and cleanup all NDMP/LBR parameters
1047 *
1048 * Parameters:
1049 * session (input) - session pointer.
1050 *
1051 * Returns:
1052 * 0: on success
1053 * -1: otherwise
1054 */
1055 void
1056 ndmp_lbr_cleanup(ndmpd_session_t *session)
1057 {
1058 ndmpd_abort_marking_v2(session);
1059 ndmp_stop_buffer_worker(session);
1060 ndmp_waitfor_op(session);
1061 ndmp_free_reader_writer_ipc(session);
1062 if (session->ns_ndmp_lbr_params) {
1063 if (session->ns_ndmp_lbr_params->nlp_bkmap != -1)
1064 (void) dbm_free(session->ns_ndmp_lbr_params->nlp_bkmap);
1065 tlm_release_list(session->ns_ndmp_lbr_params->nlp_exl);
1066 tlm_release_list(session->ns_ndmp_lbr_params->nlp_inc);
1067 (void) cond_destroy(&session->ns_ndmp_lbr_params->nlp_cv);
1068 (void) mutex_destroy(&session->ns_ndmp_lbr_params->nlp_mtx);
1069 }
1070
1071 NDMP_FREE(session->ns_ndmp_lbr_params);
1072 }
1073
1074 /*
1075 * ndmp_wait_for_mover
1076 *
1077 * Wait for a mover to become active. Waiting is interrupted if session is
1078 * aborted or mover gets to unexpected state.
1079 *
1080 * Parameters:
1081 * session (input) - session pointer.
1082 *
1083 * Returns:
1084 * 0 if success, -1 if failure.
1085 */
1086 int
1087 ndmp_wait_for_mover(ndmpd_session_t *session)
1088 {
1089 ndmp_lbr_params_t *nlp;
1090 tlm_cmd_t *lcmd;
1091
1092 if ((nlp = ndmp_get_nlp(session)) == NULL)
1093 return (-1);
1094
1095 (void) mutex_lock(&nlp->nlp_mtx);
1096 while (session->ns_mover.md_state == NDMP_MOVER_STATE_PAUSED) {
1097 if (session->ns_eof) {
1098 syslog(LOG_ERR, "EOF detected");
1099 break;
1100 }
1101 if (session->ns_data.dd_abort) {
1102 syslog(LOG_DEBUG, "Received data abort");
1103 break;
1104 }
1105 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
1106 /* remote backup/restore error */
1107 if (session->ns_mover.md_sock == -1 &&
1108 session->ns_mover.md_listen_sock == -1) {
1109 syslog(LOG_ERR,
1110 "Remote data connection terminated");
1111 break;
1112 }
1113 } else {
1114 /* local backup/restore error */
1115 if ((lcmd = nlp->nlp_cmds.tcs_command) != NULL) {
1116 if (lcmd->tc_reader == TLM_STOP ||
1117 lcmd->tc_reader == TLM_ABORT ||
1118 lcmd->tc_writer == TLM_STOP ||
1119 lcmd->tc_writer == TLM_ABORT) {
1120 syslog(LOG_ERR,
1121 "Local data connection terminated");
1122 break;
1123 }
1124 }
1125 }
1126
1127 (void) cond_wait(&nlp->nlp_cv, &nlp->nlp_mtx);
1128 }
1129 (void) mutex_unlock(&nlp->nlp_mtx);
1130
1131 return ((session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) ?
1132 0 : -1);
1133 }
1134
1135 /*
1136 * is_buffer_erroneous
1137 *
1138 * Run a sanity check on the buffer
1139 *
1140 * returns:
1141 * TRUE: if the buffer seems to have error
1142 * FALSE: if the buffer is full and has valid data.
1143 */
1144 boolean_t
1145 is_buffer_erroneous(tlm_buffer_t *buf)
1146 {
1147 boolean_t rv;
1148
1149 rv = (buf == NULL || buf->tb_eot || buf->tb_eof ||
1150 buf->tb_errno != 0);
1151 if (rv) {
1152 if (buf == NULL) {
1153 syslog(LOG_DEBUG, "buf == NULL");
1154 } else {
1155 syslog(LOG_DEBUG, "eot: %u, eof: %u, errno: %d",
1156 buf->tb_eot, buf->tb_eof, buf->tb_errno);
1157 }
1158 }
1159
1160 return (rv);
1161 }
1162
1163 /*
1164 * ndmp_execute_cdb
1165 *
1166 * Main SCSI CDB execution program, this is used by message handler
1167 * for the NDMP tape/SCSI execute CDB requests. This function uses
1168 * USCSI interface to run the CDB command and sets all the CDB parameters
1169 * in the SCSI query before calling the USCSI ioctl. The result of the
1170 * CDB is returned in two places:
1171 * cmd.uscsi_status The status of CDB execution
1172 * cmd.uscsi_rqstatus The status of sense requests
1173 * reply.error The general errno (ioctl)
1174 *
1175 * Parameters:
1176 * session (input) - session pointer
1177 * adapter_name (input) - name of SCSI adapter
1178 * sid (input) - SCSI target ID
1179 * lun (input) - LUN number
1180 * request (input) - NDMP client CDB request
1181 *
1182 * Returns:
1183 * void
1184 */
1185 /*ARGSUSED*/
1186 void
1187 ndmp_execute_cdb(ndmpd_session_t *session, char *adapter_name, int sid, int lun,
1188 ndmp_execute_cdb_request *request)
1189 {
1190 ndmp_execute_cdb_reply reply;
1191 struct uscsi_cmd cmd;
1192 int fd;
1193 struct open_list *olp;
1194 char rq_buf[255];
1195
1196 (void) memset((void *)&cmd, 0, sizeof (cmd));
1197 (void) memset((void *)&reply, 0, sizeof (reply));
1198 (void) memset((void *)rq_buf, 0, sizeof (rq_buf));
1199
1200 if (request->flags == NDMP_SCSI_DATA_IN) {
1201 cmd.uscsi_flags = USCSI_READ | USCSI_RQENABLE;
1202 if ((cmd.uscsi_bufaddr =
1203 ndmp_malloc(request->datain_len)) == 0) {
1204 reply.error = NDMP_NO_MEM_ERR;
1205 if (ndmp_send_response(session->ns_connection,
1206 NDMP_NO_ERR, (void *)&reply) < 0)
1207 syslog(LOG_DEBUG, "error sending"
1208 " scsi_execute_cdb reply.");
1209 return;
1210 }
1211
1212 cmd.uscsi_buflen = request->datain_len;
1213 } else if (request->flags == NDMP_SCSI_DATA_OUT) {
1214 cmd.uscsi_flags = USCSI_WRITE | USCSI_RQENABLE;
1215 cmd.uscsi_bufaddr = request->dataout.dataout_val;
1216 cmd.uscsi_buflen = request->dataout.dataout_len;
1217 } else {
1218 cmd.uscsi_flags = USCSI_RQENABLE;
1219 cmd.uscsi_bufaddr = 0;
1220 cmd.uscsi_buflen = 0;
1221 }
1222 cmd.uscsi_rqlen = sizeof (rq_buf);
1223 cmd.uscsi_rqbuf = rq_buf;
1224
1225 cmd.uscsi_timeout = (request->timeout < 1000) ?
1226 1 : (request->timeout / 1000);
1227
1228 cmd.uscsi_cdb = (caddr_t)request->cdb.cdb_val;
1229 cmd.uscsi_cdblen = request->cdb.cdb_len;
1230
1231 if (request->cdb.cdb_len > 12) {
1232 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1233 ndmp_send_reply(session->ns_connection, (void *) &reply,
1234 "sending execute_cdb reply");
1235 if (request->flags == NDMP_SCSI_DATA_IN)
1236 free(cmd.uscsi_bufaddr);
1237 return;
1238 }
1239
1240 reply.error = NDMP_NO_ERR;
1241
1242 if ((olp = ndmp_open_list_find(adapter_name, sid, lun)) != NULL) {
1243 fd = olp->ol_fd;
1244 } else {
1245 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1246 ndmp_send_reply(session->ns_connection, (void *) &reply,
1247 "sending execute_cdb reply");
1248 if (request->flags == NDMP_SCSI_DATA_IN)
1249 free(cmd.uscsi_bufaddr);
1250 return;
1251 }
1252
1253 if (ioctl(fd, USCSICMD, &cmd) < 0) {
1254 if (errno != EIO && errno != 0) {
1255 syslog(LOG_ERR,
1256 "Failed to send command to device: %m");
1257 }
1258 if (cmd.uscsi_status == 0)
1259 reply.error = NDMP_IO_ERR;
1260 }
1261
1262 reply.status = cmd.uscsi_status;
1263
1264 if (request->flags == NDMP_SCSI_DATA_IN) {
1265 reply.datain.datain_len = cmd.uscsi_buflen;
1266 reply.datain.datain_val = cmd.uscsi_bufaddr;
1267 } else {
1268 reply.dataout_len = request->dataout.dataout_len;
1269 }
1270
1271 reply.ext_sense.ext_sense_len = cmd.uscsi_rqlen - cmd.uscsi_rqresid;
1272 reply.ext_sense.ext_sense_val = rq_buf;
1273
1274 if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1275 (void *)&reply) < 0)
1276 syslog(LOG_DEBUG, "Error sending scsi_execute_cdb reply.");
1277
1278 if (request->flags == NDMP_SCSI_DATA_IN)
1279 free(cmd.uscsi_bufaddr);
1280 }
1281
1282
1283 /*
1284 * ndmp_stop_local_reader
1285 *
1286 * Stops a mover reader thread (for local backup only)
1287 *
1288 * Parameters:
1289 * session (input) - session pointer
1290 * cmds (input) - reader/writer command struct
1291 *
1292 * Returns:
1293 * void
1294 */
1295 void
1296 ndmp_stop_local_reader(ndmpd_session_t *session, tlm_commands_t *cmds)
1297 {
1298 ndmp_lbr_params_t *nlp;
1299
1300 if (session != NULL) {
1301 if (cmds != NULL && cmds->tcs_reader_count > 0) {
1302 if ((nlp = ndmp_get_nlp(session)) != NULL) {
1303 (void) mutex_lock(&nlp->nlp_mtx);
1304 cmds->tcs_command->tc_reader = TLM_STOP;
1305 (void) cond_broadcast(&nlp->nlp_cv);
1306 (void) mutex_unlock(&nlp->nlp_mtx);
1307 }
1308 }
1309 }
1310 }
1311
1312
1313 /*
1314 * Stops a mover reader thread (for remote backup only)
1315 *
1316 * Parameters:
1317 * session (input) - session pointer
1318 * cmds (input) - reader/writer command struct
1319 *
1320 * Returns:
1321 * void
1322 */
1323 void
1324 ndmp_stop_remote_reader(ndmpd_session_t *session)
1325 {
1326 if (session != NULL) {
1327 if (session->ns_data.dd_sock >= 0) {
1328 /*
1329 * 3-way restore.
1330 */
1331 syslog(LOG_DEBUG,
1332 "data.sock: %d", session->ns_data.dd_sock);
1333 (void) close(session->ns_data.dd_sock);
1334 session->ns_data.dd_sock = -1;
1335 }
1336 }
1337 }
1338
1339
1340 /*
1341 * ndmp_wait_for_reader
1342 *
1343 * Wait for a reader until get done (busy wait)
1344 */
1345 void
1346 ndmp_wait_for_reader(tlm_commands_t *cmds)
1347 {
1348 if (cmds != NULL) {
1349 while (cmds->tcs_reader_count > 0)
1350 (void) sleep(1);
1351 }
1352 }
1353
1354
1355 /*
1356 * ndmp_open_list_find
1357 *
1358 * Find a specific device in the open list
1359 *
1360 * Parameters:
1361 * dev (input) - device name
1362 * sid (input) - SCSI target ID
1363 * lun (input) - LUN number
1364 *
1365 * Returns:
1366 * pointer to the open list entry
1367 */
1368 struct open_list *
1369 ndmp_open_list_find(char *dev, int sid, int lun)
1370 {
1371 struct ol_head *olhp;
1372 struct open_list *olp;
1373
1374 if (dev == NULL || *dev == '\0') {
1375 return (NULL);
1376 }
1377
1378 (void) mutex_lock(&ol_mutex);
1379 olhp = &ol_head;
1380 for (olp = LIST_FIRST(olhp); olp != NULL; olp = LIST_NEXT(olp, ol_q))
1381 if (strcmp(olp->ol_devnm, dev) == 0 && olp->ol_sid == sid &&
1382 olp->ol_lun == lun) {
1383 (void) mutex_unlock(&ol_mutex);
1384 return (olp);
1385 }
1386
1387 (void) mutex_unlock(&ol_mutex);
1388 return (NULL);
1389 }
1390
1391
1392 /*
1393 * ndmp_open_list_add
1394 *
1395 * Add a specific device to the open list
1396 *
1397 * Parameters:
1398 * conn (input) - connection pointer
1399 * dev (input) - device name
1400 * sid (input) - SCSI target ID
1401 * lun (input) - LUN number
1402 * fd (input) - the device file descriptor
1403 *
1404 * Returns:
1405 * errno
1406 */
1407 int
1408 ndmp_open_list_add(ndmp_connection_t *conn, char *dev, int sid, int lun, int fd)
1409 {
1410 int err;
1411 struct ol_head *olhp;
1412 struct open_list *olp;
1413
1414 if (dev == NULL || *dev == '\0') {
1415 return (EINVAL);
1416 }
1417
1418 err = 0;
1419 olhp = &ol_head;
1420
1421 if ((olp = ndmp_open_list_find(dev, sid, lun)) != NULL) {
1422 /*
1423 * The adapter handle can be opened many times by the clients.
1424 * Only when the target is set, we must check and reject the
1425 * open request if the device is already being used by another
1426 * session.
1427 */
1428 if (sid == -1)
1429 olp->ol_nref++;
1430 else
1431 err = EBUSY;
1432 } else if ((olp = ndmp_malloc(sizeof (struct open_list))) == NULL) {
1433 err = ENOMEM;
1434 } else if ((olp->ol_devnm = strdup(dev)) == NULL) {
1435 syslog(LOG_ERR, "Out of memory.");
1436 free(olp);
1437 err = ENOMEM;
1438 } else {
1439 olp->cl_conn = conn;
1440 olp->ol_nref = 1;
1441 olp->ol_sid = sid;
1442 olp->ol_lun = lun;
1443 if (fd > 0)
1444 olp->ol_fd = fd;
1445 else
1446 olp->ol_fd = -1;
1447 (void) mutex_lock(&ol_mutex);
1448 LIST_INSERT_HEAD(olhp, olp, ol_q);
1449 (void) mutex_unlock(&ol_mutex);
1450 }
1451
1452 return (err);
1453 }
1454
1455
1456 /*
1457 * ndmp_open_list_del
1458 *
1459 * Delete a specific device from the open list
1460 *
1461 * Parameters:
1462 * dev (input) - device name
1463 * sid (input) - SCSI target ID
1464 * lun (input) - LUN number
1465 *
1466 * Returns:
1467 * errno
1468 */
1469 int
1470 ndmp_open_list_del(char *dev, int sid, int lun)
1471 {
1472 struct open_list *olp;
1473
1474 if (dev == NULL || *dev == '\0') {
1475 syslog(LOG_DEBUG, "Invalid argument");
1476 return (EINVAL);
1477 }
1478 if ((olp = ndmp_open_list_find(dev, sid, lun)) == NULL) {
1479 syslog(LOG_DEBUG, "%s not found", dev);
1480 return (ENOENT);
1481 }
1482
1483 (void) mutex_lock(&ol_mutex);
1484 if (--olp->ol_nref <= 0) {
1485 LIST_REMOVE(olp, ol_q);
1486 free(olp->ol_devnm);
1487 free(olp);
1488 }
1489 (void) mutex_unlock(&ol_mutex);
1490
1491 return (0);
1492 }
1493
1494
1495 /*
1496 * ndmp_open_list_release
1497 *
1498 * Close all the resources belonging to this connection.
1499 *
1500 * Parameters:
1501 * ndmp_connection_t *conn : connection identifier
1502 *
1503 * Returns:
1504 * void
1505 */
1506 void
1507 ndmp_open_list_release(ndmp_connection_t *conn)
1508 {
1509 struct ol_head *olhp = &ol_head;
1510 struct open_list *olp;
1511 struct open_list *next;
1512
1513 (void) mutex_lock(&ol_mutex);
1514 olp = LIST_FIRST(olhp);
1515 while (olp != NULL) {
1516 next = LIST_NEXT(olp, ol_q);
1517 if (olp->cl_conn == conn) {
1518 LIST_REMOVE(olp, ol_q);
1519 if (olp->ol_fd > 0)
1520 (void) close(olp->ol_fd);
1521 free(olp->ol_devnm);
1522 free(olp);
1523 }
1524 olp = next;
1525 }
1526 (void) mutex_unlock(&ol_mutex);
1527 }
1528
1529
1530 /*
1531 * ndmp_stop_buffer_worker
1532 *
1533 * Stop all reader and writer threads for a specific buffer.
1534 *
1535 * Parameters:
1536 * session (input) - session pointer
1537 *
1538 * Returns:
1539 * void
1540 */
1541 void
1542 ndmp_stop_buffer_worker(ndmpd_session_t *session)
1543 {
1544 ndmp_lbr_params_t *nlp;
1545 tlm_commands_t *cmds;
1546
1547 session->ns_tape.td_pos = 0;
1548 if ((nlp = ndmp_get_nlp(session)) == NULL) {
1549 syslog(LOG_DEBUG, "nlp == NULL");
1550 } else {
1551 cmds = &nlp->nlp_cmds;
1552 if (cmds->tcs_command != NULL) {
1553 cmds->tcs_reader = cmds->tcs_writer = TLM_ABORT;
1554 cmds->tcs_command->tc_reader = TLM_ABORT;
1555 cmds->tcs_command->tc_writer = TLM_ABORT;
1556 while (cmds->tcs_reader_count > 0 ||
1557 cmds->tcs_writer_count > 0) {
1558 syslog(LOG_DEBUG,
1559 "trying to stop buffer worker");
1560 (void) sleep(1);
1561 }
1562 }
1563 }
1564 }
1565
1566
1567 /*
1568 * ndmp_stop_reader_thread
1569 *
1570 * Stop only the reader threads of a specific buffer
1571 *
1572 * Parameters:
1573 * session (input) - session pointer
1574 *
1575 * Returns:
1576 * void
1577 */
1578 void
1579 ndmp_stop_reader_thread(ndmpd_session_t *session)
1580 {
1581 ndmp_lbr_params_t *nlp;
1582 tlm_commands_t *cmds;
1583
1584 if ((nlp = ndmp_get_nlp(session)) == NULL) {
1585 syslog(LOG_DEBUG, "nlp == NULL");
1586 } else {
1587 cmds = &nlp->nlp_cmds;
1588 if (cmds->tcs_command != NULL) {
1589 cmds->tcs_reader = TLM_ABORT;
1590 cmds->tcs_command->tc_reader = TLM_ABORT;
1591 while (cmds->tcs_reader_count > 0) {
1592 syslog(LOG_DEBUG,
1593 "trying to stop reader thread");
1594 (void) sleep(1);
1595 }
1596 }
1597 }
1598 }
1599
1600
1601 /*
1602 * ndmp_stop_reader_thread
1603 *
1604 * Stop only the writer threads of a specific buffer
1605 *
1606 * Parameters:
1607 * session (input) - session pointer
1608 *
1609 * Returns:
1610 * void
1611 */
1612 void
1613 ndmp_stop_writer_thread(ndmpd_session_t *session)
1614 {
1615 ndmp_lbr_params_t *nlp;
1616 tlm_commands_t *cmds;
1617
1618 if ((nlp = ndmp_get_nlp(session)) == NULL) {
1619 syslog(LOG_DEBUG, "nlp == NULL");
1620 } else {
1621 cmds = &nlp->nlp_cmds;
1622 if (cmds->tcs_command != NULL) {
1623 (void) mutex_lock(&nlp->nlp_mtx);
1624 cmds->tcs_writer = TLM_ABORT;
1625 cmds->tcs_command->tc_writer = TLM_ABORT;
1626 (void) cond_broadcast(&nlp->nlp_cv);
1627 (void) mutex_unlock(&nlp->nlp_mtx);
1628 while (cmds->tcs_writer_count > 0) {
1629 syslog(LOG_DEBUG,
1630 "trying to stop writer thread");
1631 (void) sleep(1);
1632 }
1633 }
1634 }
1635 }
1636
1637
1638 /*
1639 * ndmp_free_reader_writer_ipc
1640 *
1641 * Free and release the reader/writer buffers and the IPC structure
1642 * for reader and writer threads.
1643 *
1644 * Parameters:
1645 * session (input) - session pointer
1646 *
1647 * Returns:
1648 * void
1649 */
1650 void
1651 ndmp_free_reader_writer_ipc(ndmpd_session_t *session)
1652 {
1653 ndmp_lbr_params_t *nlp;
1654 tlm_commands_t *cmds;
1655
1656 if ((nlp = ndmp_get_nlp(session)) != NULL) {
1657 cmds = &nlp->nlp_cmds;
1658 if (cmds->tcs_command != NULL) {
1659 syslog(LOG_DEBUG, "cmds->tcs_command->tc_ref: %d",
1660 cmds->tcs_command->tc_ref);
1661 tlm_release_reader_writer_ipc(cmds->tcs_command);
1662 }
1663 }
1664 }
1665
1666
1667 /*
1668 * ndmp_waitfor_op
1669 *
1670 * Wait for a session reference count to drop to zero
1671 *
1672 * Parameters:
1673 * session (input) - session pointer
1674 *
1675 * Returns:
1676 * void
1677 */
1678 void
1679 ndmp_waitfor_op(ndmpd_session_t *session)
1680 {
1681 if (session != NULL) {
1682 while (session->ns_nref > 0) {
1683 (void) sleep(1);
1684 }
1685 }
1686 }
1687
1688
1689 /*
1690 * ndmp_session_ref
1691 *
1692 * Increment the reference count of the session
1693 *
1694 * Parameters:
1695 * session (input) - session pointer
1696 *
1697 * Returns:
1698 * void
1699 */
1700 void
1701 ndmp_session_ref(ndmpd_session_t *session)
1702 {
1703 (void) mutex_lock(&session->ns_lock);
1704 session->ns_nref++;
1705 (void) mutex_unlock(&session->ns_lock);
1706 }
1707
1708
1709 /*
1710 * ndmp_session_unref
1711 *
1712 * Decrement the reference count of the session
1713 *
1714 * Parameters:
1715 * session (input) - session pointer
1716 *
1717 * Returns:
1718 * void
1719 */
1720 void
1721 ndmp_session_unref(ndmpd_session_t *session)
1722 {
1723 (void) mutex_lock(&session->ns_lock);
1724 session->ns_nref--;
1725 (void) mutex_unlock(&session->ns_lock);
1726 }
1727
1728
1729 /*
1730 * ndmp_addr2str_v3
1731 *
1732 * Convert the address type to a string
1733 *
1734 * Parameters:
1735 * type (input) - address type
1736 *
1737 * Returns:
1738 * type in string
1739 */
1740 char *
1741 ndmp_addr2str_v3(ndmp_addr_type type)
1742 {
1743 char *rv;
1744
1745 switch (type) {
1746 case NDMP_ADDR_LOCAL:
1747 rv = "Local";
1748 break;
1749 case NDMP_ADDR_TCP:
1750 rv = "TCP";
1751 break;
1752 case NDMP_ADDR_FC:
1753 rv = "FC";
1754 break;
1755 case NDMP_ADDR_IPC:
1756 rv = "IPC";
1757 break;
1758 default:
1759 rv = "Unknown";
1760 }
1761
1762 return (rv);
1763 }
1764
1765
1766 /*
1767 * ndmp_valid_v3addr_type
1768 *
1769 * Make sure that the NDMP address is from any of the
1770 * valid types
1771 *
1772 * Parameters:
1773 * type (input) - address type
1774 *
1775 * Returns:
1776 * 1: valid
1777 * 0: invalid
1778 */
1779 boolean_t
1780 ndmp_valid_v3addr_type(ndmp_addr_type type)
1781 {
1782 boolean_t rv;
1783
1784 switch (type) {
1785 case NDMP_ADDR_LOCAL:
1786 case NDMP_ADDR_TCP:
1787 case NDMP_ADDR_FC:
1788 case NDMP_ADDR_IPC:
1789 rv = TRUE;
1790 break;
1791 default:
1792 rv = FALSE;
1793 }
1794
1795 return (rv);
1796 }
1797
1798
1799 /*
1800 * ndmp_copy_addr_v3
1801 *
1802 * Copy NDMP address from source to destination (V2 and V3 only)
1803 *
1804 * Parameters:
1805 * dst (ouput) - destination address
1806 * src (input) - source address
1807 *
1808 * Returns:
1809 * void
1810 */
1811 void
1812 ndmp_copy_addr_v3(ndmp_addr_v3 *dst, ndmp_addr_v3 *src)
1813 {
1814 dst->addr_type = src->addr_type;
1815 switch (src->addr_type) {
1816 case NDMP_ADDR_LOCAL:
1817 /* nothing */
1818 break;
1819 case NDMP_ADDR_TCP:
1820 dst->tcp_ip_v3 = htonl(src->tcp_ip_v3);
1821 dst->tcp_port_v3 = src->tcp_port_v3;
1822 break;
1823 case NDMP_ADDR_FC:
1824 case NDMP_ADDR_IPC:
1825 default:
1826 break;
1827 }
1828 }
1829
1830
1831 /*
1832 * ndmp_copy_addr_v4
1833 *
1834 * Copy NDMP address from source to destination. V4 has a extra
1835 * environment list inside the address too which needs to be copied.
1836 *
1837 * Parameters:
1838 * dst (ouput) - destination address
1839 * src (input) - source address
1840 *
1841 * Returns:
1842 * void
1843 */
1844 void
1845 ndmp_copy_addr_v4(ndmp_addr_v4 *dst, ndmp_addr_v4 *src)
1846 {
1847 int i;
1848
1849 dst->addr_type = src->addr_type;
1850 dst->tcp_len_v4 = src->tcp_len_v4;
1851 switch (src->addr_type) {
1852 case NDMP_ADDR_LOCAL:
1853 /* nothing */
1854 break;
1855 case NDMP_ADDR_TCP:
1856 dst->tcp_addr_v4 = ndmp_malloc(sizeof (ndmp_tcp_addr_v4) *
1857 src->tcp_len_v4);
1858 if (dst->tcp_addr_v4 == 0)
1859 return;
1860
1861 for (i = 0; i < src->tcp_len_v4; i++) {
1862 dst->tcp_ip_v4(i) = htonl(src->tcp_ip_v4(i));
1863 dst->tcp_port_v4(i) = src->tcp_port_v4(i);
1864 dst->tcp_env_v4(i).addr_env_len = 0; /* Solaris */
1865 dst->tcp_env_v4(i).addr_env_val = 0; /* Solaris */
1866 }
1867 break;
1868 case NDMP_ADDR_FC:
1869 case NDMP_ADDR_IPC:
1870 default:
1871 break;
1872 }
1873 }
1874
1875
1876 /*
1877 * ndmp_connect_sock_v3
1878 *
1879 * Creates a socket and connects to the specified address/port
1880 *
1881 * Parameters:
1882 * addr (input) - IP address
1883 * port (input) - port number
1884 *
1885 * Returns:
1886 * 0: on success
1887 * -1: otherwise
1888 */
1889 int
1890 ndmp_connect_sock_v3(ulong_t addr, ushort_t port)
1891 {
1892 int sock;
1893 struct sockaddr_in sin;
1894
1895
1896 sock = socket(AF_INET, SOCK_STREAM, 0);
1897 if (sock < 0) {
1898 syslog(LOG_DEBUG, "Socket error: %m");
1899 return (-1);
1900 }
1901
1902 (void) memset((void *) &sin, 0, sizeof (sin));
1903 sin.sin_family = AF_INET;
1904 sin.sin_addr.s_addr = htonl(addr);
1905 sin.sin_port = htons(port);
1906 if (connect(sock, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
1907 syslog(LOG_DEBUG, "Connect error: %m");
1908 (void) close(sock);
1909 return (-1);
1910 }
1911
1912 syslog(LOG_DEBUG, "Remote addr %s:%d", inet_ntoa(IN_ADDR(addr)), port);
1913
1914 set_socket_options(sock);
1915
1916 return (sock);
1917 }
1918
1919 /*
1920 * ndmp_create_socket
1921 *
1922 * Creates a socket for listening for accepting data connections.
1923 *
1924 * Parameters:
1925 * session (input) - session pointer.
1926 * addr (output) - location to store address of socket.
1927 * port (output) - location to store port of socket.
1928 *
1929 * Returns:
1930 * 0 - success.
1931 * -1 - error.
1932 */
1933 int
1934 ndmp_create_socket(ulong_t *addr, ushort_t *port)
1935 {
1936 char *p;
1937 int length;
1938 int sd;
1939 struct sockaddr_in sin;
1940
1941 /* Try the user's prefered NIC IP address */
1942 p = ndmpd_get_prop(NDMP_MOVER_NIC);
1943
1944 /* Try host's IP address */
1945 if (!p || *p == 0)
1946 p = gethostaddr();
1947
1948 /* Try default NIC's IP address (if DNS failed) */
1949 if (!p)
1950 p = get_default_nic_addr();
1951
1952 /* Fail if no IP can be obtained */
1953 if (!p) {
1954 syslog(LOG_ERR, "Undetermined network port.");
1955 return (-1);
1956 }
1957
1958 *addr = inet_addr(p);
1959
1960 sd = socket(AF_INET, SOCK_STREAM, 0);
1961 if (sd < 0) {
1962 syslog(LOG_DEBUG, "Socket error: %m");
1963 return (-1);
1964 }
1965 sin.sin_family = AF_INET;
1966 sin.sin_addr.s_addr = INADDR_ANY;
1967 sin.sin_port = 0;
1968 length = sizeof (sin);
1969
1970 if (bind(sd, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
1971 syslog(LOG_DEBUG, "Bind error: %m");
1972 (void) close(sd);
1973 sd = -1;
1974 } else if (getsockname(sd, (struct sockaddr *)&sin, &length) < 0) {
1975 syslog(LOG_DEBUG, "getsockname error: %m");
1976 (void) close(sd);
1977 sd = -1;
1978 } else if (listen(sd, 5) < 0) {
1979 syslog(LOG_DEBUG, "Listen error: %m");
1980 (void) close(sd);
1981 sd = -1;
1982 } else
1983 *port = sin.sin_port;
1984
1985 return (sd);
1986 }
1987
1988
1989 /*
1990 * cctime
1991 *
1992 * Convert the specified time into a string. It's like
1993 * ctime(), but:
1994 * - chops the trailing '\n' of ctime.
1995 * - and returns "the epoch" if time is 0.
1996 *
1997 * Returns:
1998 * "": invalid argument.
1999 * "the epoch": if time is 0.
2000 * string format of the time.
2001 */
2002 char *
2003 cctime(time_t *t)
2004 {
2005 char *bp, *cp;
2006 static char tbuf[BUFSIZ];
2007
2008 if (!t)
2009 return ("");
2010
2011 if (*t == (time_t)0)
2012 return ("the epoch");
2013
2014 if ((bp = ctime_r(t, tbuf, BUFSIZ)) == NULL)
2015 return ("");
2016
2017 cp = strchr(bp, '\n');
2018 if (cp)
2019 *cp = '\0';
2020
2021 return (bp);
2022 }
2023
2024
2025 /*
2026 * ndmp_new_job_name
2027 *
2028 * Copy, at most, 'n' characters of the current backup
2029 * job name to the buffer in parameter 's1'.
2030 *
2031 * Parameters:
2032 *
2033 * s1 (input) - pointer to a user supplied buffer
2034 * n (input) - number of bytes to copy
2035 *
2036 * Returns:
2037 * count of bytes in name
2038 */
2039
2040 int
2041 ndmp_new_job_name(char *s1, size_t n) {
2042
2043 if (n >= TLM_MAX_BACKUP_JOB_NAME) {
2044 /*
2045 * TLM_MAX_BACKUP_JOB_NAME is the fixed length of
2046 * the encoded job name in the format `NdmpBackup.nnnn\0`,
2047 * where nnnn is a job sequence number. A null byte
2048 * is included. It is okay if the buffer is bigger than that.
2049 */
2050 return (snprintf(s1, n, "%10s.%04d",
2051 NDMP_RCF_BASENAME, ndmp_job_cnt++%1000));
2052 }
2053 return (0);
2054 }
2055
2056 /*
2057 * Check if the volume is already checkpointed. Assume it is not
2058 * by setting nlp_snapname to '\0' at first. It will be filled
2059 * in with the checkpoint (snapshot name) if one is found.
2060 */
2061 boolean_t
2062 fs_is_checkpointed(ndmp_lbr_params_t *nlp)
2063 {
2064 zfs_handle_t *zhp;
2065 snap_data_t si;
2066
2067 (void) mutex_lock(&zlib_mtx);
2068 if ((zhp = zfs_open(zlibh, nlp->nlp_vol, ZFS_TYPE_DATASET)) != NULL) {
2069 nlp->nlp_snapname[0] = '\0';
2070 si.creation_time = (time_t)0;
2071 si.last_snapshot = nlp->nlp_snapname;
2072 if (ndmp_find_latest_autosync(zhp, (void *) &si) != 0) {
2073 syslog(LOG_ERR,
2074 "Find AutoSync failed (err=%d): %s",
2075 errno, libzfs_error_description(zlibh));
2076 zfs_close(zhp);
2077 (void) mutex_unlock(&zlib_mtx);
2078 return (B_FALSE);
2079 }
2080 zfs_close(zhp);
2081 if (strlen(nlp->nlp_snapname) == 0) {
2082 syslog(LOG_DEBUG, "Apparently not an "
2083 "Auto-Sync - continue as normal backup");
2084 (void) mutex_unlock(&zlib_mtx);
2085 return (B_FALSE);
2086 }
2087 }
2088 (void) mutex_unlock(&zlib_mtx);
2089 syslog(LOG_DEBUG, "It is an autosync:");
2090 syslog(LOG_DEBUG, "nlp->nlp_vol = [%s]", nlp->nlp_vol);
2091 syslog(LOG_DEBUG, "nlp->nlp_snapname = [%s]", nlp->nlp_snapname);
2092 return (B_TRUE);
2093 }
2094
2095 /*
2096 * fs_is_valid_logvol
2097 *
2098 * Check if the log path exists
2099 *
2100 * Parameters:
2101 * path (input) - log path
2102 *
2103 * Returns:
2104 * FALSE: invalid
2105 * TRUE: valid
2106 */
2107 boolean_t
2108 fs_is_valid_logvol(char *path)
2109 {
2110 struct stat64 st;
2111
2112 if (stat64(path, &st) < 0)
2113 return (B_FALSE);
2114
2115 return (B_TRUE);
2116 }
2117
2118
2119 /*
2120 * ndmpd_mk_temp
2121 *
2122 * Make a temporary file using the working directory path and the
2123 * jobname
2124 *
2125 * Parameters:
2126 * buf (output) - the temporary file name path
2127 *
2128 * Returns:
2129 * buf
2130 */
2131 char *
2132 ndmpd_mk_temp(char * fname, char *buf)
2133 {
2134 const char *dir;
2135 char *rv;
2136
2137 if (!buf)
2138 return (NULL);
2139
2140 dir = ndmpd_get_prop(NDMP_DEBUG_PATH);
2141 if (dir == 0 || *dir == '\0') {
2142 syslog(LOG_DEBUG, "NDMP work path not specified");
2143 return (0);
2144 }
2145
2146 /*
2147 * Make sure the NDMP work directory exists.
2148 */
2149 if (ndmpd_mkdir(dir) < 0) {
2150 syslog(LOG_DEBUG,
2151 "Could not create NDMP work path %s", dir);
2152 return (0);
2153 }
2154
2155 if (!fs_is_valid_logvol((char *)dir)) {
2156 syslog(LOG_ERR,
2157 "Log file path cannot be on system volumes");
2158 return (0);
2159 }
2160
2161 dir += strspn(dir, " \t");
2162 if (!*dir) {
2163 syslog(LOG_DEBUG, "NDMP work path not specified");
2164 return (0);
2165 }
2166
2167 rv = buf;
2168
2169 (void) tlm_cat_path(buf, (char *)dir, fname);
2170
2171 return (rv);
2172 }
2173
2174 /*
2175 * ndmp_mkdir
2176 *
2177 * If the temporary bitmap database directory doesn't exist
2178 * create it. This keep from having to create directory
2179 * by hand when it is changed with svcadm.
2180 *
2181 * Parameters:
2182 * dir (input) - the path to create
2183 *
2184 * Returns:
2185 * 0 - success.
2186 * -1 - error.
2187 */
2188 static int
2189 ndmpd_mkdir(const char *dir)
2190 {
2191 char tmp[PATH_MAX];
2192 char *p = NULL;
2193 size_t len;
2194
2195 (void) snprintf(tmp, sizeof (tmp), "%s", dir);
2196 len = strlen(tmp);
2197 if (tmp[len - 1] == '/')
2198 tmp[len - 1] = '\0';
2199 for (p = tmp + 1; *p; p++) {
2200 if (*p == '/') {
2201 *p = '\0';
2202 if (mkdir(tmp, S_IRWXU) < 0) {
2203 if (errno != EEXIST) {
2204 syslog(LOG_ERR,
2205 "failed to create intermediate path %s\n",
2206 tmp);
2207 return (-1);
2208 }
2209 }
2210 *p = '/';
2211 }
2212 }
2213 if (mkdir(tmp, S_IRWXU) < 0) {
2214 if (errno != EEXIST) {
2215 syslog(LOG_ERR,
2216 "failed to create full path %s\n", tmp);
2217 return (-1);
2218 }
2219 }
2220 return (0);
2221 }
2222
2223 /*
2224 * ndmpd_make_bk_dir_path
2225 *
2226 * Make a directory path for temporary files under the NDMP
2227 * working directory.
2228 *
2229 * Parameters:
2230 * buf (output) - result path
2231 * fname (input) - the file name
2232 *
2233 * Returns:
2234 * buf
2235 */
2236 char *
2237 ndmpd_make_bk_dir_path(char *buf, char *fname)
2238 {
2239 const char *p;
2240 char *name;
2241 char path[PATH_MAX];
2242
2243 if (!buf || !fname || !*fname)
2244 return (NULL);
2245
2246 p = ndmpd_get_prop(NDMP_DEBUG_PATH);
2247 if (p == NULL || *p == '\0' || !fs_is_valid_logvol((char *)p)) {
2248 return (NULL);
2249 }
2250
2251 (void) strlcpy(path, (char *)p, PATH_MAX);
2252 (void) trim_whitespace(path);
2253
2254 if ((name = strrchr(fname, '/')) == 0)
2255 name = fname;
2256
2257 (void) tlm_cat_path(buf, path, name);
2258 return (buf);
2259 }
2260
2261 static int
2262 ndmp_match_checkpoint_name(zfs_handle_t *zhp, void *arg)
2263 {
2264 snap_data_t *sd = (snap_data_t *)arg;
2265 time_t snap_creation;
2266 nvlist_t *userprops = NULL;
2267
2268 if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
2269 if ((userprops = zfs_get_user_props(zhp)) != NULL) {
2270 /*
2271 * Destination AutoSync snap-shots have
2272 * 'nms:autosyncmark' property whereas the
2273 * source dataset snap-shot has has
2274 * 'nms:service' property. This finds either
2275 * for use as backup.
2276 */
2277 if (nvlist_exists(userprops, "nms:autosyncmark") ||
2278 nvlist_exists(userprops,
2279 "com.nexenta.nef:hprsvcid") ||
2280 nvlist_exists(userprops, "nms:service")) {
2281 snap_creation = (time_t)zfs_prop_get_int(zhp,
2282 ZFS_PROP_CREATION);
2283 if (snap_creation > sd->creation_time) {
2284 (void) strncpy(
2285 (char *) sd->last_snapshot,
2286 zfs_get_name(zhp),
2287 ZFS_MAX_DATASET_NAME_LEN);
2288 sd->creation_time = snap_creation;
2289 }
2290 }
2291 }
2292 }
2293 zfs_close(zhp);
2294 return (0);
2295 }
2296
2297 /*
2298 * ndmp_find_latest_autosync
2299 *
2300 * Given a dataset zfs_handlt_t find the latest "AutoSync" snapshot
2301 */
2302 int
2303 ndmp_find_latest_autosync(zfs_handle_t *zhp, void *arg)
2304 {
2305 int err;
2306 snap_data_t *si = (snap_data_t *)arg;
2307
2308 err = zfs_iter_dependents(zhp, B_FALSE,
2309 ndmp_match_checkpoint_name, (void *)si);
2310 if (err) {
2311 syslog(LOG_DEBUG,
2312 "Trying to find AutoSync zfs_iter_snapshots: %d", err);
2313 si->last_snapshot = '\0';
2314 return (-1);
2315 } else {
2316 syslog(LOG_DEBUG, "Found most recent AutoSync -> [%s]\n",
2317 si->last_snapshot);
2318 }
2319 return (0);
2320 }
2321
2322 /*
2323 * ndmp_is_chkpnt_root
2324 *
2325 * Is this a root checkpoint (snapshot) directory.
2326 * Note: a temporary function
2327 */
2328 boolean_t
2329 ndmp_is_chkpnt_root(char *path)
2330 {
2331 struct stat64 st;
2332
2333 if (stat64(path, &st) != 0) {
2334 syslog(LOG_DEBUG, "Couldn't stat path \"%s\"", path);
2335 return (TRUE);
2336 }
2337 return (FALSE);
2338 }
2339
2340
2341 /*
2342 * ndmpd_make_exc_list
2343 *
2344 * Make a list of files that should not be backed up.
2345 *
2346 * Parameters:
2347 * void
2348 *
2349 * Returns:
2350 * list - array of character strings
2351 */
2352 char **
2353 ndmpd_make_exc_list(void)
2354 {
2355 char *val, **cpp;
2356 int i, n;
2357
2358 n = sizeof (exls);
2359 if ((cpp = ndmp_malloc(n)) != NULL) {
2360 for (i = 0; exls[i] != NULL; i++)
2361 cpp[i] = exls[i];
2362
2363 /*
2364 * If ndmpd_get_prop returns NULL, the array will be
2365 * null-terminated.
2366 */
2367 val = ndmpd_get_prop(NDMP_DEBUG_PATH);
2368 cpp[i] = val;
2369 }
2370
2371 return (cpp);
2372 }
2373
2374
2375 /*
2376 * ndmp_get_bk_dir_ino
2377 *
2378 * Get the inode number of the backup directory
2379 */
2380 int
2381 ndmp_get_bk_dir_ino(ndmp_lbr_params_t *nlp)
2382 {
2383 int rv;
2384 struct stat64 st;
2385
2386 if (stat64(nlp->nlp_backup_path, &st) != 0) {
2387 rv = -1;
2388 syslog(LOG_ERR, "Failed to get inode # of \"%s\"",
2389 nlp->nlp_backup_path);
2390 } else {
2391 rv = 0;
2392 nlp->nlp_bkdirino = st.st_ino;
2393 }
2394
2395 return (rv);
2396 }
2397
2398
2399 /*
2400 * ndmp_check_utf8magic
2401 *
2402 * Check if the magic string for exists in the tar header. This
2403 * magic string (which also indicates that the file names are in
2404 * UTF8 format) is used as a crest to indetify our own tapes.
2405 * This checking is always done before all restores except DAR
2406 * restores.
2407 */
2408 boolean_t
2409 ndmp_check_utf8magic(tlm_cmd_t *cmd)
2410 {
2411 char *cp;
2412 int err, len, actual_size;
2413
2414 if (cmd == NULL) {
2415 syslog(LOG_DEBUG, "cmd == NULL");
2416 return (FALSE);
2417 }
2418 if (cmd->tc_buffers == NULL) {
2419 syslog(LOG_DEBUG, "cmd->tc_buffers == NULL");
2420 return (FALSE);
2421 }
2422
2423 /* wait until the first buffer gets full. */
2424 tlm_buffer_in_buf_wait(cmd->tc_buffers);
2425
2426 err = actual_size = 0;
2427 cp = tlm_get_read_buffer(RECORDSIZE, &err, cmd->tc_buffers,
2428 &actual_size);
2429 if (cp == NULL) {
2430 syslog(LOG_DEBUG, "Can't read from buffers, err: %d", err);
2431 return (FALSE);
2432 }
2433 len = strlen(NDMPUTF8MAGIC);
2434 if (actual_size < len) {
2435 syslog(LOG_DEBUG, "Not enough data in the buffers");
2436 return (FALSE);
2437 }
2438
2439 return ((strncmp(cp, NDMPUTF8MAGIC, len) == 0) ? TRUE : FALSE);
2440 }
2441
2442
2443 /*
2444 * ndmp_get_cur_bk_time
2445 *
2446 * Get the backup checkpoint time.
2447 */
2448 int
2449 ndmp_get_cur_bk_time(ndmp_lbr_params_t *nlp, time_t *tp)
2450 {
2451 int err;
2452
2453 if (!nlp || !tp) {
2454 syslog(LOG_ERR, "Invalid argument");
2455 return (-1);
2456 }
2457
2458 err = tlm_get_chkpnt_time(nlp->nlp_snapname, tp);
2459 if (err != 0) {
2460 syslog(LOG_ERR, "Can't checkpoint time from [%s]",
2461 nlp->nlp_snapname);
2462 } else {
2463 syslog(LOG_DEBUG, "Checkpoint time of [%s] is [%s]",
2464 nlp->nlp_snapname, cctime(tp));
2465 }
2466
2467 return (err);
2468 }
2469
2470
2471 /*
2472 * get_relative_path
2473 */
2474 char *
2475 ndmp_get_relative_path(char *base, char *fullpath)
2476 {
2477 char *p = fullpath;
2478
2479 if (!base || !*base)
2480 return (fullpath);
2481
2482 while (*base) {
2483 if (*base != *p)
2484 break;
2485 p++; base++;
2486 }
2487
2488 if (*p == '/')
2489 p++;
2490
2491 return ((*base) ? fullpath : p);
2492 }
2493
2494
2495 /*
2496 * ndmp_get_nlp
2497 *
2498 * Get NDMP local backup parameters
2499 *
2500 * Parameter:
2501 * session cooke
2502 *
2503 * Returns:
2504 * LBR structure
2505 */
2506 ndmp_lbr_params_t *
2507 ndmp_get_nlp(void *cookie)
2508 {
2509 if (cookie == NULL)
2510 return (NULL);
2511
2512 return (((ndmpd_session_t *)cookie)->ns_ndmp_lbr_params);
2513 }
2514
2515
2516 /*
2517 * is_tape_unit_ready
2518 *
2519 * Check if the tape device is ready or not
2520 */
2521 boolean_t
2522 is_tape_unit_ready(char *adptnm, int dev_id)
2523 {
2524 int try;
2525 int fd = 0;
2526
2527 try = TUR_MAX_TRY;
2528 if (dev_id <= 0) {
2529 if ((fd = open(adptnm, O_RDONLY | O_NDELAY)) < 0)
2530 return (FALSE);
2531 } else {
2532 fd = dev_id;
2533 }
2534 do {
2535 if (scsi_test_unit_ready(fd) >= 0) {
2536 syslog(LOG_DEBUG, "Unit is ready");
2537
2538 if (dev_id <= 0)
2539 (void) close(fd);
2540
2541 return (TRUE);
2542 }
2543
2544 syslog(LOG_DEBUG, "Unit not ready");
2545 (void) usleep(TUR_WAIT);
2546
2547 } while (--try > 0);
2548
2549 if (dev_id <= 0)
2550 (void) close(fd);
2551
2552 syslog(LOG_DEBUG, "Unit didn't get ready");
2553 return (FALSE);
2554 }
2555
2556
2557 /*
2558 * scsi_test_unit_ready
2559 *
2560 * This is for Test Unit Read, without this function, the only
2561 * impact is getting EBUSY's before each operation which we have
2562 * busy waiting loops checking EBUSY error code.
2563 */
2564 static int
2565 scsi_test_unit_ready(int dev_id)
2566 {
2567 struct uscsi_cmd ucmd;
2568 union scsi_cdb cdb;
2569 int retval;
2570
2571 (void) memset(&ucmd, 0, sizeof (struct uscsi_cmd));
2572 (void) memset(&cdb, 0, sizeof (union scsi_cdb));
2573 cdb.scc_cmd = SCMD_TEST_UNIT_READY;
2574 ucmd.uscsi_cdb = (caddr_t)&cdb;
2575 ucmd.uscsi_cdblen = CDB_GROUP0;
2576 ucmd.uscsi_flags |= USCSI_SILENT;
2577 ucmd.uscsi_timeout = 60; /* Allow maximum 1 min */
2578
2579 retval = ioctl(dev_id, USCSICMD, &ucmd);
2580
2581 if (retval != 0 && errno != EIO) {
2582 syslog(LOG_ERR,
2583 "Failed to send inquiry request to device: %m.");
2584 syslog(LOG_DEBUG, "Inquiry request failed for"
2585 " dev_id:%d err=%d -%m", dev_id, errno);
2586 retval = -errno;
2587 } else
2588 retval = -(ucmd.uscsi_status);
2589
2590 return (retval);
2591 }
2592
2593
2594 /*
2595 * ndmp_load_params
2596 *
2597 * Load the parameters.
2598 *
2599 * Parameter:
2600 * void
2601 *
2602 * Returns:
2603 * void
2604 */
2605 void
2606 ndmp_load_params(void)
2607 {
2608 ndmp_dump_path_node = ndmpd_get_prop_yorn(NDMP_DUMP_PATHNODE_ENV) ?
2609 TRUE : FALSE;
2610 ndmp_tar_path_node = ndmpd_get_prop_yorn(NDMP_TAR_PATHNODE_ENV) ?
2611 TRUE : FALSE;
2612 ndmp_ignore_ctime =
2613 ndmpd_get_prop_yorn(NDMP_IGNCTIME_ENV) ? TRUE : FALSE;
2614 ndmp_include_lmtime = ndmpd_get_prop_yorn(NDMP_INCLMTIME_ENV) ?
2615 TRUE : FALSE;
2616 ndmp_max_tok_seq = atoi(ndmpd_get_prop_default(NDMP_MAXSEQ_ENV, "9"));
2617
2618 ndmp_full_restore_path = ndmpd_get_prop_yorn(NDMP_FULL_RESTORE_PATH) ?
2619 TRUE : FALSE;
2620
2621 ndmp_fhinode = ndmpd_get_prop_yorn(NDMP_FHIST_INCR_ENV) ? TRUE : FALSE;
2622
2623 /* Get the value from ndmp SMF property. */
2624 ndmp_dar_support = ndmpd_get_prop_yorn(NDMP_DAR_SUPPORT);
2625
2626 ndmp_autosync_support = ndmpd_get_prop_yorn(NDMP_AUTOSYNC_SUPPORT);
2627 ndmp_hpr_support = ndmpd_get_prop_yorn(NDMP_HPR_SUPPORT);
2628 /*
2629 * The HPR snapshot feature superscedes autosync and the two can't be
2630 * active together on the same system.
2631 */
2632 if (ndmp_hpr_support) {
2633 ndmp_autosync_support = 0;
2634 syslog(LOG_DEBUG, "NDMP_HPR_SUPPORT set to [%d]",
2635 ndmp_hpr_support);
2636 }
2637
2638 if (ndmp_autosync_support) {
2639 syslog(LOG_DEBUG, "NDMP_AUTOSYNC_SUPPORT set to [%d]",
2640 ndmp_autosync_support);
2641 }
2642
2643 if ((ndmp_ver = atoi(ndmpd_get_prop(NDMP_VERSION_ENV))) == 0)
2644 ndmp_ver = NDMPVER;
2645 }
2646
2647 /*
2648 * randomize
2649 *
2650 * Randomize the contents of a buffer
2651 *
2652 * Parameter:
2653 * buffer (output) - destination buffer
2654 * size (input) - buffer size
2655 *
2656 * Returns:
2657 * void
2658 */
2659 void
2660 randomize(unsigned char *buffer, int size)
2661 {
2662 /* LINTED improper alignment */
2663 unsigned int *p = (unsigned int *)buffer;
2664 unsigned int dwlen = size / sizeof (unsigned int);
2665 unsigned int remlen = size % sizeof (unsigned int);
2666 unsigned int tmp;
2667 unsigned int i;
2668
2669 for (i = 0; i < dwlen; i++)
2670 *p++ = random();
2671
2672 if (remlen) {
2673 tmp = random();
2674 (void) memcpy(p, &tmp, remlen);
2675 }
2676 }
2677
2678 /*
2679 * ndmpd_get_file_entry_type
2680 *
2681 * Converts the mode to the NDMP file type
2682 *
2683 * Parameter:
2684 * mode (input) - file mode
2685 * ftype (output) - file type
2686 *
2687 * Returns:
2688 * void
2689 */
2690 void
2691 ndmpd_get_file_entry_type(int mode, ndmp_file_type *ftype)
2692 {
2693 switch (mode & S_IFMT) {
2694 case S_IFIFO:
2695 *ftype = NDMP_FILE_FIFO;
2696 break;
2697 case S_IFCHR:
2698 *ftype = NDMP_FILE_CSPEC;
2699 break;
2700 case S_IFDIR:
2701 *ftype = NDMP_FILE_DIR;
2702 break;
2703 case S_IFBLK:
2704 *ftype = NDMP_FILE_BSPEC;
2705 break;
2706 case S_IFREG:
2707 *ftype = NDMP_FILE_REG;
2708 break;
2709 case S_IFLNK:
2710 *ftype = NDMP_FILE_SLINK;
2711 break;
2712 default:
2713 *ftype = NDMP_FILE_SOCK;
2714 break;
2715 }
2716 }
2717
2718 /*
2719 * Set a private data in the plugin context
2720 */
2721 void
2722 ndmp_context_set_specific(ndmp_context_t *nctx, void *ptr)
2723 {
2724 nctx->nc_pldata = ptr;
2725 }
2726
2727 /*
2728 * Get a private data in the plugin context
2729 */
2730 void *
2731 ndmp_context_get_specific(ndmp_context_t *nctx)
2732 {
2733 return (nctx->nc_pldata);
2734 }
2735
2736 ndmpd_backup_type_t
2737 ndmp_get_backup_type(ndmp_context_t *ctx)
2738 {
2739 ndmpd_session_t *session = (ndmpd_session_t *)ctx->nc_ddata;
2740
2741 return (session->ns_butype);
2742 }