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