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