1 /*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
4 */
5
6 /*
7 * BSD 3 Clause License
8 *
9 * Copyright (c) 2007, The Storage Networking Industry Association.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * - Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 *
22 * - Neither the name of The Storage Networking Industry Association (SNIA)
23 * nor the names of its contributors may be used to endorse or promote
24 * products derived from this software without specific prior written
25 * permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/socket.h>
44 #include <syslog.h>
45 #include <netinet/in.h>
46 #include <errno.h>
47 #include <arpa/inet.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include "ndmpd_common.h"
51 #include "ndmpd.h"
52
53 static int ndmpd_data_error_send_v4(ndmpd_session_t *session,
54 ndmp_data_halt_reason reason);
55 static int ndmpd_data_error_send(ndmpd_session_t *session,
56 ndmp_data_halt_reason reason);
57 static void data_accept_connection_v3(void *cookie, int fd, ulong_t mode);
58 static int create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr,
59 ushort_t *port);
60 static ndmp_error data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr,
61 ushort_t port);
62 static int discard_data_v3(ndmpd_session_t *session, ulong_t length);
63 static void nlp_release_job_stat(ndmpd_session_t *session);
64 static u_longlong_t ndmpd_data_get_info(ndmpd_session_t *session);
65
66 static ndmp_error ndmpd_tar_start_backup_v2(ndmpd_session_t *, char *,
67 ndmp_pval *, ulong_t);
68 static ndmp_error ndmpd_tar_start_recover_v2(ndmpd_session_t *, char *,
69 ndmp_pval *, ulong_t, ndmp_name *, ulong_t);
70 static ndmp_error ndmpd_tar_start_backup_v3(ndmpd_session_t *, char *,
71 ndmp_pval *, ulong_t);
72 static ndmp_error ndmpd_tar_start_recover_v3(ndmpd_session_t *,
73 ndmp_pval *, ulong_t, ndmp_name_v3 *, ulong_t);
74
75 /*
76 * ************************************************************************
77 * NDMP V2 HANDLERS
78 * ************************************************************************
79 */
80
81 /*
82 * ndmpd_data_get_state_v2
83 *
84 * Request handler. Returns current data state.
85 *
86 * Parameters:
87 * connection (input) - connection handle.
88 * body (input) - request message body.
89 *
90 * Returns:
91 * void
92 */
93 /*ARGSUSED*/
94 void
95 ndmpd_data_get_state_v2(ndmp_connection_t *connection, void *body)
96 {
97 ndmp_data_get_state_reply_v2 reply;
98 ndmpd_session_t *session = ndmp_get_client_data(connection);
99
100 reply.error = NDMP_NO_ERR;
101 reply.operation = session->ns_data.dd_operation;
102 reply.state = session->ns_data.dd_state;
103 reply.halt_reason = session->ns_data.dd_halt_reason;
104
105 reply.est_time_remain =
106 session->ns_data.dd_module.dm_stats.ms_est_time_remaining;
107 reply.est_bytes_remain =
108 long_long_to_quad(
109 session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining);
110
111 reply.bytes_processed =
112 long_long_to_quad(ndmpd_data_get_info(session));
113
114 reply.mover = session->ns_data.dd_mover;
115 reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
116 reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
117
118 ndmp_send_reply(connection, &reply,
119 "sending data_get_state reply");
120 }
121
122
123 /*
124 * ndmpd_data_start_backup_v2
125 *
126 * Request handler. Starts a backup.
127 *
128 * Parameters:
129 * connection (input) - connection handle.
130 * body (input) - request message body.
131 *
132 * Returns:
133 * void
134 */
135 void
136 ndmpd_data_start_backup_v2(ndmp_connection_t *connection, void *body)
137 {
138 ndmp_data_start_backup_request_v2 *request;
139 ndmp_data_start_backup_reply_v2 reply;
140 ndmpd_session_t *session = ndmp_get_client_data(connection);
141 ndmp_error err;
142
143 request = (ndmp_data_start_backup_request_v2 *)body;
144
145 reply.error = NDMP_NO_ERR;
146 session->ns_data.dd_mover = request->mover;
147
148 err = ndmpd_tar_start_backup_v2(session, request->bu_type,
149 request->env.env_val, request->env.env_len);
150
151 /*
152 * start_backup sends the reply if the backup is successfully started.
153 * Otherwise, send the reply containing the error here.
154 */
155 if (err != NDMP_NO_ERR) {
156 syslog(LOG_ERR, "err: %d", err);
157 reply.error = err;
158 ndmp_send_reply(connection, &reply,
159 "sending data_start_backup reply");
160 ndmpd_data_cleanup(session);
161 }
162 }
163
164 /*
165 * ndmpd_data_start_recover_v2
166 *
167 * Request handler. Starts a restore.
168 *
169 * Parameters:
170 * connection (input) - connection handle.
171 * body (input) - request message body.
172 *
173 * Returns:
174 * void
175 */
176 void
177 ndmpd_data_start_recover_v2(ndmp_connection_t *connection, void *body)
178 {
179 ndmp_data_start_recover_request_v2 *request;
180 ndmp_data_start_recover_reply_v2 reply;
181 ndmpd_session_t *session = ndmp_get_client_data(connection);
182 ndmp_error err;
183
184 request = (ndmp_data_start_recover_request_v2 *) body;
185 session->ns_data.dd_mover = request->mover;
186
187 err = ndmpd_tar_start_recover_v2(session, request->bu_type,
188 request->env.env_val, request->env.env_len,
189 request->nlist.nlist_val, request->nlist.nlist_len);
190
191 /*
192 * start_recover sends the reply if the recover is successfully started.
193 * Otherwise, send the reply containing the error here.
194 */
195 if (err != NDMP_NO_ERR) {
196 reply.error = err;
197 ndmp_send_reply(connection, &reply,
198 "sending ndmp_data_start_recover_request_v2 reply");
199 ndmpd_data_cleanup(session);
200 }
201 }
202
203 /*
204 * ndmpd_data_get_env_v2
205 *
206 * Request handler. Returns the environment variable array sent
207 * with the backup request. This request may only be sent with
208 * a backup operation is in progress.
209 *
210 * Parameters:
211 * connection (input) - connection handle.
212 * body (input) - request message body.
213 *
214 * Returns:
215 * void
216 */
217 /*ARGSUSED*/
218 void
219 ndmpd_data_get_env_v2(ndmp_connection_t *connection, void *body)
220 {
221 ndmp_data_get_env_reply reply;
222 ndmpd_session_t *session = ndmp_get_client_data(connection);
223
224 (void) memset((void*)&reply, 0, sizeof (reply));
225 if (session->ns_data.dd_operation != NDMP_DATA_OP_BACKUP) {
226 syslog(LOG_ERR, "Backup operation not active.");
227 reply.error = NDMP_ILLEGAL_STATE_ERR;
228 reply.env.env_len = 0;
229 } else {
230 reply.error = NDMP_NO_ERR;
231 reply.env.env_len = session->ns_data.dd_env_len;
232 reply.env.env_val = session->ns_data.dd_env;
233 }
234
235 ndmp_send_reply(connection, &reply, "sending data_get_env reply");
236 }
237
238
239 /*
240 * ndmpd_data_stop_v2
241 *
242 * Request handler. Stops the current data operation.
243 *
244 * Parameters:
245 * connection (input) - connection handle.
246 * body (input) - request message body.
247 *
248 * Returns:
249 * void
250 */
251 /*ARGSUSED*/
252 void
253 ndmpd_data_stop_v2(ndmp_connection_t *connection, void *body)
254 {
255 ndmp_data_stop_reply reply;
256 ndmpd_session_t *session = ndmp_get_client_data(connection);
257
258 if (session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
259 reply.error = NDMP_ILLEGAL_STATE_ERR;
260 ndmp_send_reply(connection, &reply,
261 "sending data_stop reply");
262 return;
263 }
264 ndmp_waitfor_op(session);
265 ndmpd_data_cleanup(session);
266 ndmpd_file_history_cleanup(session, FALSE);
267
268 nlp_release_job_stat(session);
269
270 /* prepare for another data operation */
271 (void) ndmpd_data_init(session);
272 ndmpd_file_history_init(session);
273
274 reply.error = NDMP_NO_ERR;
275 ndmp_send_reply(connection, &reply, "sending data_stop reply");
276 }
277
278
279 /*
280 * ndmpd_data_abort_v2
281 *
282 * Request handler. Aborts the current backup/restore. The operation
283 * state is not changed to the halted state until after the operation
284 * has actually been aborted and the notify_halt request has been sent.
285 *
286 * Parameters:
287 * connection (input) - connection handle.
288 * body (input) - request message body.
289 *
290 * Returns:
291 * void
292 */
293 /*ARGSUSED*/
294 void
295 ndmpd_data_abort_v2(ndmp_connection_t *connection, void *body)
296 {
297 ndmp_data_abort_reply reply;
298 ndmpd_session_t *session = ndmp_get_client_data(connection);
299
300 if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
301 session->ns_data.dd_state == NDMP_DATA_STATE_HALTED) {
302 reply.error = NDMP_ILLEGAL_STATE_ERR;
303 ndmp_send_reply(connection, &reply,
304 "sending data_abort reply");
305 return;
306 }
307 /*
308 * Don't go to HALTED state yet. Need to wait for data operation to
309 * abort. When this happens, ndmpd_done will get called and will
310 * perform the halt processing.
311 */
312 session->ns_data.dd_abort = TRUE;
313 (*session->ns_data.dd_module.dm_abort_func)(
314 session->ns_data.dd_module.dm_module_cookie);
315
316 reply.error = NDMP_NO_ERR;
317 ndmp_send_reply(connection, &reply, "sending data_abort reply");
318 }
319
320 /*
321 * ************************************************************************
322 * NDMP V3 HANDLERS
323 * ************************************************************************
324 */
325
326 /*
327 * ndmpd_data_get_state_v3
328 *
329 * Request handler. Returns current data state.
330 *
331 * Parameters:
332 * connection (input) - connection handle.
333 * body (input) - request message body.
334 *
335 * Returns:
336 * void
337 */
338 /*ARGSUSED*/
339 void
340 ndmpd_data_get_state_v3(ndmp_connection_t *connection, void *body)
341 {
342 ndmp_data_get_state_reply_v3 reply;
343 ndmpd_session_t *session = ndmp_get_client_data(connection);
344
345 (void) memset((void*)&reply, 0, sizeof (reply));
346
347 reply.error = NDMP_NO_ERR;
348 reply.invalid = NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID
349 | NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID;
350 reply.operation = session->ns_data.dd_operation;
351 reply.state = session->ns_data.dd_state;
352 reply.halt_reason = session->ns_data.dd_halt_reason;
353
354 if (reply.operation == NDMP_DATA_OP_BACKUP)
355 reply.bytes_processed =
356 long_long_to_quad(
357 session->ns_data.dd_module.dm_stats.ms_bytes_processed);
358 else
359 reply.bytes_processed =
360 long_long_to_quad(ndmpd_data_get_info(session));
361
362 reply.est_bytes_remain = long_long_to_quad(0LL);
363 reply.est_time_remain = 0;
364 if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE)
365 ndmp_copy_addr_v3(&reply.data_connection_addr,
366 &session->ns_data.dd_data_addr);
367 reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
368 reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
369
370 ndmp_send_reply(connection, &reply,
371 "sending ndmp_data_get_state_v3 reply");
372 }
373
374
375 /*
376 * ndmpd_data_start_backup_v3
377 *
378 * Request handler. Starts a backup.
379 *
380 * Parameters:
381 * connection (input) - connection handle.
382 * body (input) - request message body.
383 *
384 * Returns:
385 * void
386 */
387 void
388 ndmpd_data_start_backup_v3(ndmp_connection_t *connection, void *body)
389 {
390 ndmp_data_start_backup_request_v3 *request;
391 ndmp_data_start_backup_reply_v3 reply;
392 ndmpd_session_t *session = ndmp_get_client_data(connection);
393
394 request = (ndmp_data_start_backup_request_v3 *)body;
395
396 (void) memset((void*)&reply, 0, sizeof (reply));
397
398 if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
399 syslog(LOG_ERR,
400 "Can't start new backup in NOT CONNECTED state.");
401 reply.error = NDMP_ILLEGAL_STATE_ERR;
402 goto _error;
403 }
404
405 if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
406 if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
407 syslog(LOG_ERR, "Write protected device.");
408 reply.error = NDMP_WRITE_PROTECT_ERR;
409 goto _error;
410 }
411 }
412
413 if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) {
414 session->ns_butype = NDMP_BUTYPE_TAR;
415 } else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) {
416 session->ns_butype = NDMP_BUTYPE_DUMP;
417 } else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) {
418 session->ns_butype = NDMP_BUTYPE_ZFS;
419 } else {
420 char msg_invalid[32];
421 char msg_types[32];
422
423 (void) snprintf(msg_invalid, 32, "Invalid backup type: %s.",
424 request->bu_type);
425 (void) snprintf(msg_types, 32,
426 "Supported backup types are tar, dump.");
427
428 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
429 msg_invalid);
430 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
431 msg_types);
432 syslog(LOG_ERR, "Invalid backup type: %s.",
433 request->bu_type);
434 syslog(LOG_ERR,
435 "Supported backup types are tar, dump.");
436
437 reply.error = NDMP_ILLEGAL_ARGS_ERR;
438 goto _error;
439 }
440
441 reply.error = ndmpd_tar_start_backup_v3(session,
442 request->bu_type, request->env.env_val,
443 request->env.env_len);
444
445 /*
446 * *_start_backup* sends the reply if the backup is
447 * successfully started. Otherwise, send the reply
448 * containing the error here.
449 */
450
451 _error:
452
453 if (reply.error != NDMP_NO_ERR) {
454 ndmp_send_reply(connection, &reply,
455 "sending data_start_backup_v3 reply");
456 ndmpd_data_cleanup(session);
457 }
458 }
459
460 /*
461 * ndmpd_data_start_recover_v3
462 *
463 * Request handler. Starts a restore.
464 *
465 * Parameters:
466 * connection (input) - connection handle.
467 * body (input) - request message body.
468 *
469 * Returns:
470 * void
471 */
472 void
473 ndmpd_data_start_recover_v3(ndmp_connection_t *connection, void *body)
474 {
475 ndmp_data_start_recover_request_v3 *request;
476 ndmp_data_start_recover_reply_v3 reply;
477 ndmpd_session_t *session = ndmp_get_client_data(connection);
478
479 request = (ndmp_data_start_recover_request_v3 *)body;
480
481 (void) memset((void*)&reply, 0, sizeof (reply));
482
483 if (session->ns_data.dd_state != NDMP_DATA_STATE_CONNECTED) {
484 syslog(LOG_ERR, "Can't start new recover in current state.");
485 reply.error = NDMP_ILLEGAL_STATE_ERR;
486 goto _error;
487 }
488
489 if (strcasecmp(request->bu_type, NDMP_TAR_TYPE) == 0) {
490 session->ns_butype = NDMP_BUTYPE_TAR;
491 } else if (strcasecmp(request->bu_type, NDMP_DUMP_TYPE) == 0) {
492 session->ns_butype = NDMP_BUTYPE_DUMP;
493 } else if (strcasecmp(request->bu_type, NDMP_ZFS_TYPE) == 0) {
494 session->ns_butype = NDMP_BUTYPE_ZFS;
495 } else {
496 char msg_invalid[32];
497 char msg_types[32];
498
499 (void) snprintf(msg_invalid, 32, "Invalid backup type: %s.",
500 request->bu_type);
501 (void) snprintf(msg_types, 32,
502 "Supported backup types are tar, dump.");
503
504 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
505 msg_invalid);
506 NDMP_APILOG((void *) session, NDMP_LOG_ERROR, ++ndmp_log_msg_id,
507 msg_types);
508 syslog(LOG_ERR, "Invalid backup type: %s.",
509 request->bu_type);
510 syslog(LOG_ERR,
511 "Supported backup types are tar, dump.");
512
513 reply.error = NDMP_ILLEGAL_ARGS_ERR;
514 goto _error;
515 }
516
517 reply.error = ndmpd_tar_start_recover_v3(session,
518 request->env.env_val, request->env.env_len,
519 request->nlist.nlist_val, request->nlist.nlist_len);
520
521 /*
522 * *_start_recover* sends the reply if the recover is
523 * successfully started. Otherwise, send the reply
524 * containing the error here.
525 */
526
527 _error:
528
529 if (reply.error != NDMP_NO_ERR) {
530 ndmp_send_reply(connection, &reply,
531 "sending data_start_recover_v3 reply");
532 ndmpd_data_error(session, NDMP_DATA_HALT_INTERNAL_ERROR);
533 ndmpd_data_cleanup(session);
534 }
535 }
536
537 /*
538 * ndmpd_data_abort_v3
539 *
540 * Request handler. Aborts the current backup/restore. The operation
541 * state is not changed to the halted state until after the operation
542 * has actually been aborted and the notify_halt request has been sent.
543 *
544 * Parameters:
545 * connection (input) - connection handle.
546 * body (input) - request message body.
547 *
548 * Returns:
549 * void
550 */
551 /*ARGSUSED*/
552 void
553 ndmpd_data_abort_v3(ndmp_connection_t *connection, void *body)
554 {
555 ndmp_data_abort_reply reply;
556 ndmpd_session_t *session = ndmp_get_client_data(connection);
557
558 switch (session->ns_data.dd_state) {
559 case NDMP_DATA_STATE_IDLE:
560 reply.error = NDMP_ILLEGAL_STATE_ERR;
561 break;
562
563 case NDMP_DATA_STATE_ACTIVE:
564 /*
565 * Don't go to HALTED state yet. Need to wait for data
566 * operation to abort. When this happens, ndmpd_done_v3
567 * will get called and will perform the halt processing.
568 */
569 reply.error = NDMP_NO_ERR;
570 session->ns_data.dd_abort = TRUE;
571 if (session->ns_data.dd_module.dm_abort_func)
572 (*session->ns_data.dd_module.dm_abort_func)(
573 session->ns_data.dd_module.dm_module_cookie);
574 break;
575
576 case NDMP_DATA_STATE_HALTED:
577 case NDMP_DATA_STATE_LISTEN:
578 case NDMP_DATA_STATE_CONNECTED:
579 reply.error = NDMP_NO_ERR;
580 session->ns_data.dd_abort = TRUE;
581 ndmpd_data_error(session, NDMP_DATA_HALT_ABORTED);
582 break;
583 default:
584 reply.error = NDMP_ILLEGAL_STATE_ERR;
585 syslog(LOG_ERR, "Unknown data V3 state %d",
586 session->ns_data.dd_state);
587 }
588
589 ndmp_send_reply(connection, &reply,
590 "sending data_abort_v3 reply");
591 }
592
593
594 /*
595 * ndmpd_data_stop_v3
596 *
597 * Request handler. Stops the current data operation.
598 *
599 * Parameters:
600 * connection (input) - connection handle.
601 * body (input) - request message body.
602 *
603 * Returns:
604 * void
605 */
606 /*ARGSUSED*/
607 void
608 ndmpd_data_stop_v3(ndmp_connection_t *connection, void *body)
609 {
610 ndmp_data_stop_reply reply;
611 ndmpd_session_t *session = ndmp_get_client_data(connection);
612
613 if (session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
614 reply.error = NDMP_ILLEGAL_STATE_ERR;
615 ndmp_send_reply(connection, &reply,
616 "sending data_stop_v3 reply");
617 return;
618 }
619 ndmp_waitfor_op(session);
620 ndmpd_data_cleanup(session);
621 ndmpd_file_history_cleanup(session, FALSE);
622
623 /* prepare for another data operation */
624 (void) ndmpd_data_init(session);
625 ndmpd_file_history_init(session);
626
627 reply.error = NDMP_NO_ERR;
628 ndmp_send_reply(connection, &reply,
629 "sending data_stop_v3 reply");
630 }
631
632
633 /*
634 * ndmpd_data_listen_v3
635 *
636 * Request handler. Configures the server to listen for a connection
637 * from a remote mover.
638 *
639 * Parameters:
640 * connection (input) - connection handle.
641 * body (input) - request message body.
642 *
643 * Returns:
644 * void
645 */
646 void
647 ndmpd_data_listen_v3(ndmp_connection_t *connection, void *body)
648 {
649 ndmp_data_listen_request_v3 *request;
650 ndmp_data_listen_reply_v3 reply;
651 ndmpd_session_t *session = ndmp_get_client_data(connection);
652 ulong_t addr;
653 ushort_t port;
654
655 request = (ndmp_data_listen_request_v3 *)body;
656
657 (void) memset((void*)&reply, 0, sizeof (reply));
658
659 if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
660 reply.error = NDMP_ILLEGAL_STATE_ERR;
661 syslog(LOG_ERR,
662 "Invalid internal data state to process listen request.");
663 } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
664 reply.error = NDMP_ILLEGAL_STATE_ERR;
665 syslog(LOG_ERR,
666 "Invalid mover state to process listen request.");
667 } else {
668 reply.error = NDMP_NO_ERR;
669 }
670
671 if (reply.error != NDMP_NO_ERR) {
672 ndmp_send_reply(connection, &reply,
673 "ndmp_data_listen_request_v3 reply");
674 return;
675 }
676
677 switch (request->addr_type) {
678 case NDMP_ADDR_LOCAL:
679 reply.data_connection_addr.addr_type = request->addr_type;
680 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
681 break;
682 case NDMP_ADDR_TCP:
683 if (create_listen_socket_v3(session, &addr, &port) < 0) {
684 reply.error = NDMP_IO_ERR;
685 break;
686 }
687
688 reply.error = NDMP_NO_ERR;
689 reply.data_connection_addr.addr_type = request->addr_type;
690 reply.data_connection_addr.tcp_ip_v3 = htonl(addr);
691 reply.data_connection_addr.tcp_port_v3 = htons(port);
692 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
693 session->ns_data.dd_data_addr.tcp_ip_v3 = addr;
694 session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(port);
695 syslog(LOG_DEBUG, "listen_socket: %d",
696 session->ns_data.dd_listen_sock);
697 break;
698
699 default:
700 syslog(LOG_ERR, "Invalid address type: %d",
701 request->addr_type);
702 reply.error = NDMP_ILLEGAL_ARGS_ERR;
703 break;
704 }
705
706 if (reply.error == NDMP_NO_ERR)
707 session->ns_data.dd_state = NDMP_DATA_STATE_LISTEN;
708
709 ndmp_send_reply(connection, &reply,
710 "ndmp_data_listen_request_v3 reply");
711 }
712
713
714 /*
715 * ndmpd_data_connect_v3
716 *
717 * Request handler. Connects the data server to either a local
718 * or remote mover.
719 *
720 * Parameters:
721 * connection (input) - connection handle.
722 * body (input) - request message body.
723 *
724 * Returns:
725 * void
726 */
727 void
728 ndmpd_data_connect_v3(ndmp_connection_t *connection, void *body)
729 {
730 ndmp_data_connect_request_v3 *request;
731 ndmp_data_connect_reply_v3 reply;
732 ndmpd_session_t *session = ndmp_get_client_data(connection);
733
734 request = (ndmp_data_connect_request_v3 *)body;
735
736 (void) memset((void*)&reply, 0, sizeof (reply));
737
738 if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
739 reply.error = NDMP_ILLEGAL_ARGS_ERR;
740 syslog(LOG_ERR, "Invalid address type %d",
741 request->addr.addr_type);
742 } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
743 reply.error = NDMP_ILLEGAL_STATE_ERR;
744 } else {
745 reply.error = NDMP_NO_ERR;
746 }
747
748 if (reply.error != NDMP_NO_ERR) {
749 ndmp_send_reply(connection, &reply,
750 "sending ndmp_data_connect_v3 reply");
751 return;
752 }
753
754 switch (request->addr.addr_type) {
755 case NDMP_ADDR_LOCAL:
756 /*
757 * Verify that the mover is listening for a
758 * local connection
759 */
760 if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN ||
761 session->ns_mover.md_listen_sock != -1) {
762 reply.error = NDMP_ILLEGAL_STATE_ERR;
763 syslog(LOG_ERR,
764 "Mover is not in local listen state.");
765 } else {
766 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
767 }
768 break;
769
770 case NDMP_ADDR_TCP:
771 reply.error = data_connect_sock_v3(session,
772 request->addr.tcp_ip_v3, request->addr.tcp_port_v3);
773 break;
774
775 default:
776 reply.error = NDMP_ILLEGAL_ARGS_ERR;
777 syslog(LOG_ERR, "Invalid address type %d",
778 request->addr.addr_type);
779 }
780
781 if (reply.error == NDMP_NO_ERR)
782 session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
783
784 ndmp_send_reply(connection, &reply,
785 "sending ndmp_data_connect_v3 reply");
786 }
787
788
789 /*
790 * ************************************************************************
791 * NDMP V4 HANDLERS
792 * ************************************************************************
793 */
794
795 /*
796 * ndmpd_data_get_env_v4
797 *
798 * Request handler. Returns the environment variable array sent
799 * with the backup request. This request may only be sent with
800 * a backup operation is in progress.
801 *
802 * Parameters:
803 * connection (input) - connection handle.
804 * body (input) - request message body.
805 *
806 * Returns:
807 * void
808 */
809 /*ARGSUSED*/
810 void
811 ndmpd_data_get_env_v4(ndmp_connection_t *connection, void *body)
812 {
813 ndmp_data_get_env_reply reply;
814 ndmpd_session_t *session = ndmp_get_client_data(connection);
815
816 (void) memset((void*)&reply, 0, sizeof (reply));
817
818 if (session->ns_data.dd_state != NDMP_DATA_STATE_ACTIVE &&
819 session->ns_data.dd_state != NDMP_DATA_STATE_HALTED) {
820 reply.error = NDMP_ILLEGAL_STATE_ERR;
821 reply.env.env_len = 0;
822 } else if (session->ns_data.dd_operation != NDMP_DATA_OP_BACKUP) {
823 syslog(LOG_ERR, "Backup operation not active.");
824 reply.error = NDMP_ILLEGAL_STATE_ERR;
825 reply.env.env_len = 0;
826 } else {
827 reply.error = NDMP_NO_ERR;
828 reply.env.env_len = session->ns_data.dd_env_len;
829 reply.env.env_val = session->ns_data.dd_env;
830 }
831
832 ndmp_send_reply(connection, &reply, "sending data_get_env reply");
833 }
834
835 /*
836 * ndmpd_data_get_state_v4
837 *
838 * Request handler. Returns current data state.
839 *
840 * Parameters:
841 * connection (input) - connection handle.
842 * body (input) - request message body.
843 *
844 * Returns:
845 * void
846 */
847 /*ARGSUSED*/
848 void
849 ndmpd_data_get_state_v4(ndmp_connection_t *connection, void *body)
850 {
851 ndmp_data_get_state_reply_v4 reply;
852 ndmpd_session_t *session = ndmp_get_client_data(connection);
853
854 (void) memset((void*)&reply, 0, sizeof (reply));
855
856 reply.error = NDMP_NO_ERR;
857 reply.unsupported = NDMP_DATA_STATE_EST_BYTES_REMAIN_INVALID
858 | NDMP_DATA_STATE_EST_TIME_REMAIN_INVALID;
859 reply.operation = session->ns_data.dd_operation;
860 reply.state = session->ns_data.dd_state;
861 reply.halt_reason = session->ns_data.dd_halt_reason;
862
863 if (reply.operation == NDMP_DATA_OP_BACKUP)
864 reply.bytes_processed = long_long_to_quad(
865 session->ns_data.dd_module.dm_stats.ms_bytes_processed);
866 else
867 reply.bytes_processed =
868 long_long_to_quad(ndmpd_data_get_info(session));
869
870 reply.est_bytes_remain = long_long_to_quad(0LL);
871 reply.est_time_remain = 0;
872 if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE)
873 ndmp_copy_addr_v4(&reply.data_connection_addr,
874 &session->ns_data.dd_data_addr_v4);
875
876 reply.read_offset = long_long_to_quad(session->ns_data.dd_read_offset);
877 reply.read_length = long_long_to_quad(session->ns_data.dd_read_length);
878
879 ndmp_send_reply(connection, &reply,
880 "sending ndmp_data_get_state_v4 reply");
881 free(reply.data_connection_addr.tcp_addr_v4);
882 }
883
884
885 /*
886 * ndmpd_data_connect_v4
887 *
888 * Request handler. Connects the data server to either a local
889 * or remote mover.
890 *
891 * Parameters:
892 * connection (input) - connection handle.
893 * body (input) - request message body.
894 *
895 * Returns:
896 * void
897 */
898 void
899 ndmpd_data_connect_v4(ndmp_connection_t *connection, void *body)
900 {
901 ndmp_data_connect_request_v4 *request;
902 ndmp_data_connect_reply_v4 reply;
903 ndmpd_session_t *session = ndmp_get_client_data(connection);
904
905 request = (ndmp_data_connect_request_v4 *)body;
906
907 (void) memset((void*)&reply, 0, sizeof (reply));
908
909 if (!ndmp_valid_v3addr_type(request->addr.addr_type)) {
910 reply.error = NDMP_ILLEGAL_ARGS_ERR;
911 syslog(LOG_ERR, "Invalid address type %d",
912 request->addr.addr_type);
913 } else if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
914 reply.error = NDMP_ILLEGAL_STATE_ERR;
915 } else {
916 reply.error = NDMP_NO_ERR;
917 }
918
919 if (reply.error != NDMP_NO_ERR) {
920 ndmp_send_reply(connection, &reply,
921 "sending ndmp_data_connect_v4 reply");
922 return;
923 }
924
925 switch (request->addr.addr_type) {
926 case NDMP_ADDR_LOCAL:
927 /*
928 * Verify that the mover is listening for a
929 * local connection
930 */
931 if (session->ns_mover.md_state != NDMP_MOVER_STATE_LISTEN ||
932 session->ns_mover.md_listen_sock != -1) {
933 reply.error = NDMP_ILLEGAL_STATE_ERR;
934 syslog(LOG_ERR,
935 "Mover is not in local listen state.");
936 } else {
937 session->ns_mover.md_state = NDMP_MOVER_STATE_ACTIVE;
938 }
939 break;
940
941 case NDMP_ADDR_TCP:
942 reply.error = data_connect_sock_v3(session,
943 request->addr.tcp_ip_v4(0), request->addr.tcp_port_v4(0));
944 break;
945
946 default:
947 reply.error = NDMP_ILLEGAL_ARGS_ERR;
948 syslog(LOG_ERR, "Invalid address type %d",
949 request->addr.addr_type);
950 }
951
952 if (reply.error == NDMP_NO_ERR)
953 session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
954
955 ndmp_send_reply(connection, &reply,
956 "sending ndmp_data_connect_v4 reply");
957 }
958
959 /*
960 * ndmpd_data_listen_v4
961 *
962 * Request handler. Configures the server to listen for a connection
963 * from a remote mover.
964 *
965 * Parameters:
966 * connection (input) - connection handle.
967 * body (input) - request message body.
968 *
969 * Returns:
970 * void
971 */
972 void
973 ndmpd_data_listen_v4(ndmp_connection_t *connection, void *body)
974 {
975 ndmp_data_listen_request_v4 *request;
976 ndmp_data_listen_reply_v4 reply;
977 ndmpd_session_t *session = ndmp_get_client_data(connection);
978 ulong_t addr;
979 ushort_t port;
980
981 request = (ndmp_data_listen_request_v4 *)body;
982
983 (void) memset((void*)&reply, 0, sizeof (reply));
984
985 if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
986 reply.error = NDMP_ILLEGAL_STATE_ERR;
987 syslog(LOG_ERR,
988 "Invalid internal data state to process listen request.");
989 } else if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE) {
990 reply.error = NDMP_ILLEGAL_STATE_ERR;
991 syslog(LOG_ERR,
992 "Invalid mover state to process listen request.");
993 } else {
994 reply.error = NDMP_NO_ERR;
995 }
996
997 if (reply.error != NDMP_NO_ERR) {
998 ndmp_send_reply(connection, &reply,
999 "ndmp_data_listen_request_v4 reply");
1000 return;
1001 }
1002
1003 switch (request->addr_type) {
1004 case NDMP_ADDR_LOCAL:
1005 reply.connect_addr.addr_type = request->addr_type;
1006 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
1007 break;
1008 case NDMP_ADDR_TCP:
1009 if (create_listen_socket_v3(session, &addr, &port) < 0) {
1010 reply.error = NDMP_IO_ERR;
1011 break;
1012 }
1013
1014 reply.error = NDMP_NO_ERR;
1015 reply.connect_addr.addr_type = request->addr_type;
1016 reply.connect_addr.tcp_addr_v4 =
1017 ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1018
1019 reply.connect_addr.tcp_ip_v4(0) = htonl(addr);
1020 reply.connect_addr.tcp_port_v4(0) = htons(port);
1021 reply.connect_addr.tcp_len_v4 = 1;
1022
1023 session->ns_data.dd_data_addr_v4.addr_type = NDMP_ADDR_TCP;
1024 session->ns_data.dd_data_addr_v4.tcp_addr_v4 =
1025 ndmp_malloc(sizeof (ndmp_tcp_addr_v4));
1026
1027 session->ns_data.dd_data_addr_v4.tcp_ip_v4(0) = addr;
1028 session->ns_data.dd_data_addr_v4.tcp_port_v4(0) = ntohs(port);
1029 session->ns_data.dd_data_addr_v4.tcp_len_v4 = 1;
1030
1031 /* Copy that to data_addr for compatibility */
1032 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
1033 session->ns_data.dd_data_addr.tcp_ip_v3 = addr;
1034 session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(port);
1035 syslog(LOG_DEBUG, "listen_socket: %d",
1036 session->ns_data.dd_listen_sock);
1037 break;
1038
1039 default:
1040 syslog(LOG_ERR, "Invalid address type: %d",
1041 request->addr_type);
1042 reply.error = NDMP_ILLEGAL_ARGS_ERR;
1043 break;
1044 }
1045
1046 if (reply.error == NDMP_NO_ERR)
1047 session->ns_data.dd_state = NDMP_DATA_STATE_LISTEN;
1048
1049 ndmp_send_reply(connection, &reply,
1050 "ndmp_data_listen_request_v4 reply");
1051 }
1052
1053
1054 /*
1055 * ndmpd_data_start_recover_filehist_v4
1056 *
1057 * Request handler. Recovers the file history (not supported yet)
1058 * This command has an optional support in V4.
1059 *
1060 * Parameters:
1061 * connection (input) - connection handle.
1062 * body (input) - request message body.
1063 *
1064 * Returns:
1065 * void
1066 */
1067 /*ARGSUSED*/
1068 void
1069 ndmpd_data_start_recover_filehist_v4(ndmp_connection_t *connection, void *body)
1070 {
1071 ndmp_data_start_recover_filehist_reply_v4 reply;
1072
1073 syslog(LOG_DEBUG, "Request not supported");
1074 reply.error = NDMP_NOT_SUPPORTED_ERR;
1075
1076 ndmp_send_reply(connection, &reply,
1077 "sending ndmp_data_start_recover_filehist_reply_v4 reply");
1078 }
1079
1080 /*
1081 * ************************************************************************
1082 * LOCALS
1083 * ************************************************************************
1084 */
1085
1086 /*
1087 * ndmpd_data_error_send
1088 *
1089 * This function sends the notify message to the client.
1090 *
1091 * Parameters:
1092 * session (input) - session pointer.
1093 * reason (input) - halt reason.
1094 *
1095 * Returns:
1096 * Error code
1097 */
1098 /*ARGSUSED*/
1099 static int
1100 ndmpd_data_error_send(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1101 {
1102 ndmp_notify_data_halted_request req;
1103
1104 req.reason = session->ns_data.dd_halt_reason;
1105 req.text_reason = "";
1106
1107 return (ndmp_send_request(session->ns_connection,
1108 NDMP_NOTIFY_DATA_HALTED, NDMP_NO_ERR, &req, 0));
1109 }
1110
1111
1112 /*
1113 * ndmpd_data_error_send_v4
1114 *
1115 * This function sends the notify message to the client.
1116 *
1117 * Parameters:
1118 * session (input) - session pointer.
1119 * reason (input) - halt reason.
1120 *
1121 * Returns:
1122 * Error code
1123 */
1124 /*ARGSUSED*/
1125 static int
1126 ndmpd_data_error_send_v4(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1127 {
1128 ndmp_notify_data_halted_request_v4 req;
1129
1130 req.reason = session->ns_data.dd_halt_reason;
1131
1132 return ndmp_send_request(session->ns_connection,
1133 NDMP_NOTIFY_DATA_HALTED, NDMP_NO_ERR, &req, 0);
1134 }
1135
1136
1137 /*
1138 * ndmpd_data_error
1139 *
1140 * This function is called when a data error has been detected.
1141 * A notify message is sent to the client and the data server is
1142 * placed into the halted state.
1143 *
1144 * Parameters:
1145 * session (input) - session pointer.
1146 * reason (input) - halt reason.
1147 *
1148 * Returns:
1149 * void
1150 */
1151 void
1152 ndmpd_data_error(ndmpd_session_t *session, ndmp_data_halt_reason reason)
1153 {
1154 if (session->ns_data.dd_state == NDMP_DATA_STATE_IDLE ||
1155 session->ns_data.dd_state == NDMP_DATA_STATE_HALTED)
1156 return;
1157
1158 if (session->ns_data.dd_operation == NDMP_DATA_OP_BACKUP) {
1159 /*
1160 * Send/discard any buffered file history data.
1161 */
1162 ndmpd_file_history_cleanup(session,
1163 (reason == NDMP_DATA_HALT_SUCCESSFUL ? TRUE : FALSE));
1164
1165 /*
1166 * If mover local and successful backup, write any
1167 * remaining buffered data to tape.
1168 */
1169 if (session->ns_data.dd_data_addr.addr_type
1170 == NDMP_ADDR_LOCAL && reason == NDMP_DATA_HALT_SUCCESSFUL)
1171 (void) ndmpd_local_write_v3(session, 0, 0);
1172 }
1173
1174 session->ns_data.dd_state = NDMP_DATA_STATE_HALTED;
1175 session->ns_data.dd_halt_reason = reason;
1176
1177 if (session->ns_protocol_version == NDMPV4) {
1178 if (ndmpd_data_error_send_v4(session, reason) < 0)
1179 syslog(LOG_ERR,
1180 "Error sending notify_data_halted request");
1181 } else {
1182 if (ndmpd_data_error_send(session, reason) < 0)
1183 syslog(LOG_ERR,
1184 "Error sending notify_data_halted request");
1185 }
1186
1187 if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP) {
1188 if (session->ns_data.dd_sock != -1) {
1189 (void) ndmpd_remove_file_handler(session,
1190 session->ns_data.dd_sock);
1191 /*
1192 * ndmpcopy: we use the same socket for the mover,
1193 * so expect to close when mover is done!
1194 */
1195 if (session->ns_data.dd_sock !=
1196 session->ns_mover.md_sock)
1197 (void) close(session->ns_data.dd_sock);
1198
1199 session->ns_data.dd_sock = -1;
1200 }
1201 if (session->ns_data.dd_listen_sock != -1) {
1202 (void) ndmpd_remove_file_handler(session,
1203 session->ns_data.dd_listen_sock);
1204
1205 (void) close(session->ns_data.dd_listen_sock);
1206 session->ns_data.dd_listen_sock = -1;
1207 }
1208 } else {
1209 ndmpd_mover_error(session, NDMP_MOVER_HALT_CONNECT_CLOSED);
1210 }
1211 }
1212
1213
1214 /*
1215 * data_accept_connection_v3
1216 *
1217 * Accept a data connection from a remote mover.
1218 * Called by ndmpd_select when a connection is pending on
1219 * the data listen socket.
1220 *
1221 * Parameters:
1222 * cookie (input) - session pointer.
1223 * fd (input) - file descriptor.
1224 * mode (input) - select mode.
1225 *
1226 * Returns:
1227 * void
1228 */
1229 /*ARGSUSED*/
1230 static void
1231 data_accept_connection_v3(void *cookie, int fd, ulong_t mode)
1232 {
1233 ndmpd_session_t *session = (ndmpd_session_t *)cookie;
1234 int from_len;
1235 struct sockaddr_in from;
1236
1237 from_len = sizeof (from);
1238 session->ns_data.dd_sock = accept(fd, (struct sockaddr *)&from,
1239 &from_len);
1240
1241 syslog(LOG_DEBUG, "sock fd: %d",
1242 session->ns_data.dd_sock);
1243 syslog(LOG_DEBUG, "sin: port %d addr %s",
1244 ntohs(from.sin_port),
1245 inet_ntoa(IN_ADDR(from.sin_addr.s_addr)));
1246
1247 (void) ndmpd_remove_file_handler(session, fd);
1248 (void) close(session->ns_data.dd_listen_sock);
1249 session->ns_data.dd_listen_sock = -1;
1250
1251 if (session->ns_data.dd_sock < 0) {
1252 syslog(LOG_ERR, "Accept error: %m");
1253 ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1254 return;
1255 }
1256
1257 /*
1258 * Save the peer address.
1259 */
1260 session->ns_data.dd_data_addr.tcp_ip_v3 = from.sin_addr.s_addr;
1261 session->ns_data.dd_data_addr.tcp_port_v3 = ntohs(from.sin_port);
1262
1263 /* Set the parameter of the new socket */
1264 set_socket_options(session->ns_data.dd_sock);
1265
1266 session->ns_data.dd_state = NDMP_DATA_STATE_CONNECTED;
1267 }
1268
1269
1270 /*
1271 * create_listen_socket_v3
1272 *
1273 * Creates the data sockets for listening for a remote mover/data
1274 * incoming connections.
1275 */
1276 static int
1277 create_listen_socket_v3(ndmpd_session_t *session, ulong_t *addr, ushort_t *port)
1278 {
1279 session->ns_data.dd_listen_sock = ndmp_create_socket(addr, port);
1280 if (session->ns_data.dd_listen_sock < 0)
1281 return (-1);
1282
1283 /*
1284 * Add a file handler for the listen socket.
1285 * ndmpd_select will call data_accept_connection when a
1286 * connection is ready to be accepted.
1287 */
1288 if (ndmpd_add_file_handler(session, (void*)session,
1289 session->ns_data.dd_listen_sock, NDMPD_SELECT_MODE_READ, HC_MOVER,
1290 data_accept_connection_v3) < 0) {
1291 (void) close(session->ns_data.dd_listen_sock);
1292 session->ns_data.dd_listen_sock = -1;
1293 return (-1);
1294 }
1295 syslog(LOG_DEBUG, "addr: %s:%d",
1296 inet_ntoa(IN_ADDR(*addr)), ntohs(*port));
1297
1298 return (0);
1299 }
1300
1301
1302 /*
1303 * data_connect_sock_v3
1304 *
1305 * Connect the data interface socket to the specified ip/port
1306 *
1307 * Parameters:
1308 * session (input) - session pointer.
1309 * addr (input) - IP address
1310 * port (input) - port number
1311 *
1312 * Returns:
1313 * NDMP_NO_ERR - backup successfully started.
1314 * otherwise - error code of backup start error.
1315 */
1316 static ndmp_error
1317 data_connect_sock_v3(ndmpd_session_t *session, ulong_t addr, ushort_t port)
1318 {
1319 int sock;
1320
1321 sock = ndmp_connect_sock_v3(addr, port);
1322 if (sock < 0)
1323 return (NDMP_CONNECT_ERR);
1324
1325 session->ns_data.dd_sock = sock;
1326 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_TCP;
1327 session->ns_data.dd_data_addr.tcp_ip_v3 = ntohl(addr);
1328 session->ns_data.dd_data_addr.tcp_port_v3 = port;
1329
1330 return (NDMP_NO_ERR);
1331 }
1332
1333
1334 /*
1335 * ndmpd_tar_start_backup_v3
1336 *
1337 * Start the backup work
1338 *
1339 * Parameters:
1340 * session (input) - session pointer.
1341 * bu_type (input) - backup type.
1342 * env_val (input) - environment variable array.
1343 * env_len (input) - length of env_val.
1344 *
1345 * Returns:
1346 * NDMP_NO_ERR - backup successfully started.
1347 * otherwise - error code of backup start error.
1348 */
1349 static ndmp_error
1350 ndmpd_tar_start_backup_v3(ndmpd_session_t *session, char *bu_type,
1351 ndmp_pval *env_val, ulong_t env_len)
1352 {
1353 int err;
1354 ndmp_lbr_params_t *nlp;
1355 ndmpd_module_params_t *params;
1356 ndmp_data_start_backup_reply_v3 reply;
1357 pthread_t tid;
1358
1359 (void) memset((void*)&reply, 0, sizeof (reply));
1360
1361 err = ndmpd_save_env(session, env_val, env_len);
1362 if (err != NDMP_NO_ERR)
1363 return (err);
1364
1365 nlp = ndmp_get_nlp(session);
1366 NDMP_FREE(nlp->nlp_params);
1367 params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1368 if (!params)
1369 return (NDMP_NO_MEM_ERR);
1370
1371 params->mp_daemon_cookie = (void *)session;
1372 params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1373 params->mp_protocol_version = session->ns_protocol_version;
1374 params->mp_operation = NDMP_DATA_OP_BACKUP;
1375 params->mp_get_env_func = ndmpd_api_get_env;
1376 params->mp_add_env_func = ndmpd_api_add_env;
1377 params->mp_set_env_func = ndmpd_api_set_env;
1378 params->mp_get_name_func = 0;
1379 params->mp_dispatch_func = ndmpd_api_dispatch;
1380 params->mp_done_func = ndmpd_api_done_v3;
1381 if (session->ns_protocol_version == NDMPV4)
1382 params->mp_log_func_v3 = ndmpd_api_log_v4;
1383 else
1384 params->mp_log_func_v3 = ndmpd_api_log_v3;
1385
1386 params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1387 params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1388 params->mp_write_func = ndmpd_api_write_v3;
1389 params->mp_read_func = 0;
1390 params->mp_file_recovered_func = 0;
1391 params->mp_stats = &session->ns_data.dd_module.dm_stats;
1392 session->ns_data.dd_module.dm_module_cookie = 0;
1393
1394 if (strcmp(bu_type, NDMP_DUMP_TYPE) == 0) {
1395 NLP_SET(nlp, NLPF_DUMP);
1396 params->mp_file_history_path_func = 0;
1397 params->mp_file_history_dir_func =
1398 ndmpd_api_file_history_dir_v3;
1399 params->mp_file_history_node_func =
1400 ndmpd_api_file_history_node_v3;
1401 } else if (strcmp(bu_type, NDMP_TAR_TYPE) == 0) {
1402 NLP_SET(nlp, NLPF_TAR);
1403 params->mp_file_history_path_func =
1404 ndmpd_api_file_history_file_v3;
1405 params->mp_file_history_dir_func = 0;
1406 params->mp_file_history_node_func = 0;
1407 } else {
1408 NLP_UNSET(nlp, NLPF_DUMP);
1409 NLP_UNSET(nlp, NLPF_TAR);
1410 }
1411
1412 session->ns_data.dd_module.dm_start_func = ndmpd_tar_backup_starter_v3;
1413 session->ns_data.dd_module.dm_abort_func = ndmpd_tar_backup_abort_v3;
1414
1415 session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1416 session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1417 session->ns_data.dd_nlist_v3 = 0;
1418 session->ns_data.dd_nlist_len = 0;
1419 session->ns_data.dd_bytes_left_to_read = 0;
1420 session->ns_data.dd_position = 0;
1421 session->ns_data.dd_discard_length = 0;
1422 session->ns_data.dd_read_offset = 0;
1423 session->ns_data.dd_read_length = 0;
1424
1425 reply.error = ndmp_backup_get_params_v3(session, params);
1426 if (reply.error != NDMP_NO_ERR) {
1427 syslog(LOG_ERR, "err: %d", err);
1428 NDMP_FREE(nlp->nlp_params);
1429 return (reply.error);
1430 }
1431
1432 reply.error = NDMP_NO_ERR;
1433 if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1434 &reply) < 0) {
1435 syslog(LOG_DEBUG, "Sending data_start_backup_v3 reply");
1436 return (NDMP_NO_ERR);
1437 }
1438
1439 NS_INC(nbk);
1440 session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1441 session->ns_data.dd_operation = NDMP_DATA_OP_BACKUP;
1442 session->ns_data.dd_abort = FALSE;
1443
1444 /*
1445 * perform the backup
1446 *
1447 * Cannot wait for the thread to exit as we are replying to the
1448 * client request here.
1449 */
1450 err = pthread_create(&tid, NULL,
1451 (funct_t)session->ns_data.dd_module.dm_start_func,
1452 params);
1453
1454 if (err != 0) {
1455 syslog(LOG_ERR, "Can't start V3 backup session.");
1456 return (NDMP_ILLEGAL_ARGS_ERR);
1457 }
1458
1459 (void) pthread_detach(tid);
1460
1461 return (NDMP_NO_ERR);
1462 }
1463
1464 /*
1465 * ndmpd_tar_start_recover_v3
1466 *
1467 * Start the restore work
1468 *
1469 * Parameters:
1470 * session (input) - session pointer.
1471 * bu_type (input) - backup type.
1472 * env_val (input) - environment variable array.
1473 * env_len (input) - length of env_val.
1474 * nlist_val (input) - list of files.
1475 * nlist_len (input) - length of nlist_val.
1476 *
1477 * Returns:
1478 * NDMP_NO_ERR - recover successfully started.
1479 * otherwise - error code of recover start error.
1480 */
1481 static ndmp_error
1482 ndmpd_tar_start_recover_v3(ndmpd_session_t *session,
1483 ndmp_pval *env_val, ulong_t env_len, ndmp_name_v3 *nlist_val,
1484 ulong_t nlist_len)
1485 {
1486 ndmp_data_start_recover_reply_v3 reply;
1487 ndmpd_module_params_t *params;
1488 ndmp_lbr_params_t *nlp;
1489 pthread_t tid;
1490 int err;
1491
1492 (void) memset((void*)&reply, 0, sizeof (reply));
1493
1494 nlp = ndmp_get_nlp(session);
1495 NDMP_FREE(nlp->nlp_params);
1496 params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1497 if (!params) {
1498 return (NDMP_NO_MEM_ERR);
1499 }
1500
1501 reply.error = ndmpd_save_env(session, env_val, env_len);
1502 if (reply.error != NDMP_NO_ERR) {
1503 NDMP_FREE(nlp->nlp_params);
1504 return (NDMP_NO_MEM_ERR);
1505 }
1506
1507 reply.error = ndmpd_save_nlist_v3(session, nlist_val, nlist_len);
1508 if (reply.error != NDMP_NO_ERR) {
1509 NDMP_FREE(nlp->nlp_params);
1510 return (NDMP_NO_MEM_ERR);
1511 }
1512
1513 /*
1514 * Setup restore parameters.
1515 */
1516 params->mp_daemon_cookie = (void *)session;
1517 params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1518 params->mp_protocol_version = session->ns_protocol_version;
1519 params->mp_operation = NDMP_DATA_OP_RECOVER;
1520 params->mp_get_env_func = ndmpd_api_get_env;
1521 params->mp_add_env_func = ndmpd_api_add_env;
1522 params->mp_set_env_func = ndmpd_api_set_env;
1523 params->mp_get_name_func = ndmpd_api_get_name_v3;
1524 params->mp_dispatch_func = ndmpd_api_dispatch;
1525 params->mp_done_func = ndmpd_api_done_v3;
1526 if (session->ns_protocol_version == NDMPV4) {
1527 params->mp_log_func_v3 = ndmpd_api_log_v4;
1528 params->mp_file_recovered_func = ndmpd_api_file_recovered_v4;
1529 } else {
1530 params->mp_log_func_v3 = ndmpd_api_log_v3;
1531 params->mp_file_recovered_func = ndmpd_api_file_recovered_v3;
1532 }
1533
1534 params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1535 params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1536 params->mp_write_func = 0;
1537 params->mp_file_history_path_func = 0;
1538 params->mp_file_history_dir_func = 0;
1539 params->mp_file_history_node_func = 0;
1540 params->mp_read_func = ndmpd_api_read_v3;
1541 params->mp_seek_func = ndmpd_api_seek_v3;
1542 params->mp_stats = &session->ns_data.dd_module.dm_stats;
1543
1544 session->ns_data.dd_module.dm_module_cookie = 0;
1545 session->ns_data.dd_module.dm_start_func = ndmpd_tar_restore_starter_v3;
1546 session->ns_data.dd_module.dm_abort_func = ndmpd_tar_restore_abort_v3;
1547 session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1548 session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1549 session->ns_data.dd_bytes_left_to_read = 0;
1550 session->ns_data.dd_position = 0;
1551 session->ns_data.dd_discard_length = 0;
1552 session->ns_data.dd_read_offset = 0;
1553 session->ns_data.dd_read_length = 0;
1554
1555 err = ndmp_restore_get_params_v3(session, params);
1556 if (err != NDMP_NO_ERR) {
1557 NDMP_FREE(nlp->nlp_params);
1558 return (err);
1559 }
1560
1561 reply.error = NDMP_NO_ERR;
1562 if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
1563 &reply) < 0) {
1564 NDMP_FREE(nlp->nlp_params);
1565 ndmpd_free_nlist_v3(session);
1566 syslog(LOG_ERR,
1567 "Error sending ndmp_data_start_recover_reply");
1568 ndmpd_data_error(session, NDMP_DATA_HALT_CONNECT_ERROR);
1569 return (NDMP_NO_ERR);
1570 }
1571
1572 NS_INC(nrs);
1573 session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
1574 session->ns_data.dd_operation = NDMP_DATA_OP_RECOVER;
1575 session->ns_data.dd_abort = FALSE;
1576
1577 /*
1578 * perform the restore
1579 *
1580 * Cannot wait for the thread to exit as we are replying to the
1581 * client request here.
1582 */
1583 err = pthread_create(&tid, NULL,
1584 (funct_t)session->ns_data.dd_module.dm_start_func,
1585 params);
1586
1587 if (err != 0) {
1588 syslog(LOG_ERR, "Can't start V3 recover session.");
1589 return (NDMP_ILLEGAL_ARGS_ERR);
1590 }
1591
1592 (void) pthread_detach(tid);
1593
1594 return (NDMP_NO_ERR);
1595 }
1596
1597 /*
1598 * discard_data_v3
1599 *
1600 * Read and discard data from the data connection.
1601 * Called when a module has called ndmpd_seek() prior to
1602 * reading all of the data from the previous seek.
1603 *
1604 * Parameters:
1605 * session (input) - session pointer.
1606 *
1607 * Returns:
1608 * number of bytes read and discarded.
1609 * -1 - error.
1610 */
1611 static int
1612 discard_data_v3(ndmpd_session_t *session, ulong_t length)
1613 {
1614 static char buf[MAX_RECORD_SIZE];
1615 int n, toread;
1616
1617 toread = (length < MAX_RECORD_SIZE) ? length :
1618 MAX_RECORD_SIZE;
1619
1620 /* Read and discard the data. */
1621 n = read(session->ns_data.dd_sock, buf, toread);
1622 if (n < 0) {
1623 syslog(LOG_ERR, "Socket read error: %m.");
1624 n = -1;
1625 }
1626
1627 return (n);
1628 }
1629
1630
1631 /*
1632 * ndmpd_remote_read_v3
1633 *
1634 * Reads data from the remote mover.
1635 *
1636 * Parameters:
1637 * session (input) - session pointer.
1638 * data (input) - data to be written.
1639 * length (input) - data length.
1640 *
1641 * Returns:
1642 * 0 - data successfully read.
1643 * -1 - error.
1644 */
1645 int
1646 ndmpd_remote_read_v3(ndmpd_session_t *session, char *data, ulong_t length)
1647 {
1648 ulong_t count;
1649 ulong_t len;
1650 ssize_t n;
1651 ndmp_notify_data_read_request request;
1652 tlm_job_stats_t *jstat;
1653 longlong_t fsize;
1654
1655 count = 0;
1656 while (count < length) {
1657 len = length - count;
1658
1659 /*
1660 * If the end of the seek window has been reached then
1661 * send an ndmp_read request to the client.
1662 * The NDMP client will then send a mover_data_read request to
1663 * the remote mover and the mover will send more data.
1664 * This condition can occur if the module attempts to read past
1665 * a seek window set via a prior call to ndmpd_seek() or
1666 * the module has not issued a seek. If no seek was issued then
1667 * pretend that a seek was issued to read the entire tape.
1668 */
1669 if (session->ns_data.dd_bytes_left_to_read == 0) {
1670 /* ndmpd_seek() never called? */
1671 if (session->ns_data.dd_read_length == 0) {
1672 session->ns_data.dd_bytes_left_to_read = ~0LL;
1673 session->ns_data.dd_read_offset = 0LL;
1674 session->ns_data.dd_read_length = ~0LL;
1675 } else {
1676 /*
1677 * While restoring a file, restoreFile()
1678 * records the number of bytes still need to
1679 * be restored. We use this as a guidance
1680 * when asking for data from the tape.
1681 */
1682 jstat = session->ns_ndmp_lbr_params->nlp_jstat;
1683 fsize = jstat->js_bytes_in_file;
1684
1685 /*
1686 * Fall back to the old way if fsize if too
1687 * small.
1688 */
1689 if (fsize < len)
1690 fsize = len;
1691
1692 session->ns_data.dd_bytes_left_to_read = fsize;
1693 session->ns_data.dd_read_offset =
1694 session->ns_data.dd_position;
1695 session->ns_data.dd_read_length = fsize;
1696 }
1697
1698 request.offset =
1699 long_long_to_quad(session->ns_data.dd_read_offset);
1700 request.length =
1701 long_long_to_quad(session->ns_data.dd_read_length);
1702
1703 syslog(LOG_DEBUG, "to NOTIFY_DATA_READ [%lu, %lu]",
1704 session->ns_data.dd_read_offset,
1705 session->ns_data.dd_read_length);
1706
1707 if (ndmp_send_request_lock(session->ns_connection,
1708 NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR,
1709 &request, 0) < 0) {
1710 syslog(LOG_ERR,
1711 "Sending notify_data_read request");
1712 return (-1);
1713 }
1714 }
1715
1716 /*
1717 * If the module called ndmpd_seek() prior to reading all of the
1718 * data that the remote mover was requested to send, then the
1719 * excess data from the seek has to be discarded.
1720 */
1721 if (session->ns_data.dd_discard_length != 0) {
1722 n = discard_data_v3(session,
1723 (ulong_t)session->ns_data.dd_discard_length);
1724 if (n < 0)
1725 return (-1);
1726
1727 session->ns_data.dd_discard_length -= n;
1728 continue;
1729 }
1730
1731 /*
1732 * Don't attempt to read more data than the remote is sending.
1733 */
1734 if (len > session->ns_data.dd_bytes_left_to_read)
1735 len = session->ns_data.dd_bytes_left_to_read;
1736
1737 if ((n = read(session->ns_data.dd_sock, &data[count],
1738 len)) < 0) {
1739 syslog(LOG_ERR, "Socket read error: %m.");
1740 return (-1);
1741 }
1742
1743 /* read returns 0 if the connection was closed */
1744 if (n == 0) {
1745 syslog(LOG_ERR, "n 0 errno %d",
1746 errno);
1747 return (-1);
1748 }
1749
1750 count += n;
1751 session->ns_data.dd_bytes_left_to_read -= n;
1752 session->ns_data.dd_position += n;
1753 }
1754 return (0);
1755 }
1756
1757 /*
1758 * nlp_release_job_stat
1759 *
1760 * Unreference the job statistics
1761 *
1762 * Parameters:
1763 * session (input) - session pointer.
1764 *
1765 * Returns:
1766 * void
1767 */
1768 static void
1769 nlp_release_job_stat(ndmpd_session_t *session)
1770 {
1771 ndmp_lbr_params_t *nlp;
1772
1773 if ((nlp = ndmp_get_nlp(session)) == NULL) {
1774 return;
1775 }
1776 if (nlp->nlp_jstat != NULL) {
1777 nlp->nlp_bytes_total =
1778 (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
1779 tlm_un_ref_job_stats(nlp->nlp_jstat->js_job_name);
1780 nlp->nlp_jstat = NULL;
1781 }
1782 }
1783
1784
1785 /* *** ndmpd global internal functions *********************************** */
1786
1787 /*
1788 * ndmpd_data_init
1789 *
1790 * Initializes data specific session variables.
1791 *
1792 * Parameters:
1793 * session (input) - session pointer.
1794 *
1795 * Returns:
1796 * void
1797 */
1798 int
1799 ndmpd_data_init(ndmpd_session_t *session)
1800 {
1801 session->ns_data.dd_operation = NDMP_DATA_OP_NOACTION;
1802 session->ns_data.dd_state = NDMP_DATA_STATE_IDLE;
1803 session->ns_data.dd_halt_reason = NDMP_DATA_HALT_NA;
1804 session->ns_data.dd_abort = FALSE;
1805 session->ns_data.dd_env = 0;
1806 session->ns_data.dd_env_len = 0;
1807 session->ns_data.dd_nlist = 0;
1808 session->ns_data.dd_nlist_len = 0;
1809 session->ns_data.dd_mover.addr_type = NDMP_ADDR_LOCAL;
1810 session->ns_data.dd_sock = -1;
1811 session->ns_data.dd_read_offset = 0;
1812 session->ns_data.dd_read_length = 0;
1813 session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
1814 session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
1815 /*
1816 * NDMP V3
1817 */
1818 session->ns_data.dd_state = NDMP_DATA_STATE_IDLE;
1819 session->ns_data.dd_nlist_v3 = 0;
1820 session->ns_data.dd_data_addr.addr_type = NDMP_ADDR_LOCAL;
1821 session->ns_data.dd_listen_sock = -1;
1822 session->ns_data.dd_bytes_left_to_read = 0LL;
1823 session->ns_data.dd_position = 0LL;
1824 session->ns_data.dd_discard_length = 0LL;
1825 return (0);
1826 }
1827
1828
1829
1830 /*
1831 * ndmpd_data_cleanup
1832 *
1833 * Releases resources allocated during a data operation.
1834 *
1835 * Parameters:
1836 * session (input) - session pointer.
1837 *
1838 * Returns:
1839 * void
1840 */
1841 void
1842 ndmpd_data_cleanup(ndmpd_session_t *session)
1843 {
1844 if (session->ns_data.dd_listen_sock != -1) {
1845 syslog(LOG_DEBUG, "data.listen_sock: %d",
1846 session->ns_data.dd_listen_sock);
1847 (void) ndmpd_remove_file_handler(session,
1848 session->ns_data.dd_listen_sock);
1849 (void) close(session->ns_data.dd_listen_sock);
1850 session->ns_data.dd_listen_sock = -1;
1851 }
1852 if (session->ns_data.dd_sock != -1) {
1853 syslog(LOG_ERR, "data.sock: %d",
1854 session->ns_data.dd_sock);
1855
1856 /*
1857 * ndmpcopy: we use the same socket for the mover,
1858 * so expect to close when mover is done!
1859 */
1860 if (session->ns_data.dd_sock != session->ns_mover.md_sock)
1861 (void) close(session->ns_data.dd_sock);
1862
1863 session->ns_data.dd_sock = -1;
1864 }
1865
1866 ndmpd_free_env(session);
1867 ndmpd_free_nlist(session);
1868 }
1869
1870
1871 /*
1872 * ndmp_data_get_mover_mode
1873 *
1874 * Return the mover mode
1875 *
1876 * Parameters:
1877 * session (input) - session pointer.
1878 *
1879 * Returns:
1880 * remote - remote backup
1881 * local - local backup
1882 */
1883 char *
1884 ndmp_data_get_mover_mode(ndmpd_session_t *session)
1885 {
1886 char *rv;
1887
1888 switch (session->ns_protocol_version) {
1889 case NDMPV2:
1890 rv = ((session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP)
1891 ? "remote" : "local");
1892 break;
1893 case NDMPV3:
1894 rv = ((session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP)
1895 ? "remote" : "local");
1896 break;
1897 case NDMPV4:
1898 rv = ((session->ns_data.dd_data_addr.addr_type ==
1899 NDMP_ADDR_TCP ||
1900 (session->ns_data.dd_data_addr_v4.addr_type ==
1901 NDMP_ADDR_TCP)) ? "remote" : "local");
1902 break;
1903 default:
1904 rv = "Unknown";
1905 syslog(LOG_ERR, "Invalid protocol version %d.",
1906 session->ns_protocol_version);
1907 }
1908
1909 return (rv);
1910 }
1911
1912 /* *** static functions ******************************************** */
1913
1914 /*
1915 * ndmpd_tar_start_backup_v2
1916 *
1917 * Request handling code common to version 1 and
1918 * version 2 data_start_backup request handlers.
1919 *
1920 * Parameters:
1921 * session (input) - session pointer.
1922 * bu_type (input) - backup type.
1923 * env_val (input) - environment variable array.
1924 * env_len (input) - length of env_val.
1925 *
1926 * Returns:
1927 * NDMP_NO_ERR - backup successfully started.
1928 * otherwise - error code of backup start error.
1929 */
1930 static ndmp_error
1931 ndmpd_tar_start_backup_v2(ndmpd_session_t *session, char *bu_type,
1932 ndmp_pval *env_val, ulong_t env_len)
1933 {
1934 ndmp_data_start_backup_reply reply;
1935 ndmpd_module_params_t *params;
1936 ndmp_lbr_params_t *nlp;
1937 pthread_t tid;
1938 int err;
1939
1940 if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
1941 syslog(LOG_ERR, "Can't start new backup in current state.");
1942 return (NDMP_ILLEGAL_STATE_ERR);
1943 }
1944 if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
1945 strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
1946 syslog(LOG_ERR, "Invalid backup type: %s.", bu_type);
1947 syslog(LOG_ERR, "Supported backup types are tar and dump.");
1948 return (NDMP_ILLEGAL_ARGS_ERR);
1949 }
1950 if ((err = ndmpd_save_env(session, env_val, env_len)) != NDMP_NO_ERR)
1951 return (err);
1952
1953 nlp = ndmp_get_nlp(session);
1954 NDMP_FREE(nlp->nlp_params);
1955 params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
1956 if (params == NULL)
1957 return (NDMP_NO_MEM_ERR);
1958
1959 params->mp_daemon_cookie = (void *)session;
1960 params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
1961 params->mp_protocol_version = session->ns_protocol_version;
1962 params->mp_operation = NDMP_DATA_OP_BACKUP;
1963 params->mp_get_env_func = ndmpd_api_get_env;
1964 params->mp_add_env_func = ndmpd_api_add_env;
1965 params->mp_get_name_func = ndmpd_api_get_name;
1966 params->mp_dispatch_func = ndmpd_api_dispatch;
1967 params->mp_done_func = ndmpd_api_done_v2;
1968 params->mp_log_func = ndmpd_api_log_v2;
1969 params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
1970 params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
1971 params->mp_write_func = ndmpd_api_write_v2;
1972 params->mp_read_func = 0;
1973 params->mp_file_recovered_func = 0;
1974 params->mp_stats = &session->ns_data.dd_module.dm_stats;
1975
1976 session->ns_data.dd_module.dm_module_cookie = 0;
1977 if (strcmp(bu_type, NDMP_DUMP_TYPE) == 0) {
1978 NLP_SET(nlp, NLPF_DUMP);
1979 params->mp_file_history_path_func = 0;
1980 params->mp_file_history_dir_func =
1981 ndmpd_api_file_history_dir_v2;
1982 params->mp_file_history_node_func =
1983 ndmpd_api_file_history_node_v2;
1984 } else if (strcmp(bu_type, NDMP_TAR_TYPE) == 0) {
1985 /* backup type == NDMP_TAR_TYPE */
1986 NLP_SET(nlp, NLPF_TAR);
1987 params->mp_file_history_path_func =
1988 ndmpd_api_file_history_path_v2;
1989 params->mp_file_history_dir_func = 0;
1990 params->mp_file_history_node_func = 0;
1991 } else {
1992 NLP_UNSET(nlp, NLPF_DUMP);
1993 NLP_UNSET(nlp, NLPF_TAR);
1994 }
1995
1996 session->ns_data.dd_module.dm_start_func = ndmpd_tar_backup_starter;
1997 session->ns_data.dd_module.dm_abort_func = ndmpd_tar_backup_abort;
1998
1999 session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
2000 session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
2001 session->ns_data.dd_nlist = 0;
2002 session->ns_data.dd_nlist_len = 0;
2003 session->ns_data.dd_read_offset = 0;
2004 session->ns_data.dd_read_length = 0;
2005
2006 if ((err = ndmp_backup_extract_params(session,
2007 params)) != NDMP_NO_ERR) {
2008 syslog(LOG_ERR, "err: %d", err);
2009 NDMP_FREE(nlp->nlp_params);
2010 return (err);
2011 }
2012
2013 err = ndmpd_mover_connect(session, NDMP_MOVER_MODE_READ);
2014 if (err != NDMP_NO_ERR) {
2015 syslog(LOG_ERR,
2016 "mover connect err: %d", err);
2017 NDMP_FREE(nlp->nlp_params);
2018 return (err);
2019 }
2020
2021 session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
2022
2023 session->ns_data.dd_operation = NDMP_DATA_OP_BACKUP;
2024 session->ns_data.dd_abort = FALSE;
2025
2026 syslog(LOG_DEBUG, "starting backup");
2027
2028 reply.error = NDMP_NO_ERR;
2029 if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
2030 &reply) < 0) {
2031 syslog(LOG_DEBUG, "Sending data_start_backup reply");
2032 NDMP_FREE(nlp->nlp_params);
2033 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
2034 /*
2035 * ndmpcopy: we use the same socket for the mover,
2036 * so expect to close when mover is done!
2037 */
2038 if (session->ns_data.dd_sock !=
2039 session->ns_mover.md_sock)
2040 (void) close(session->ns_data.dd_sock);
2041
2042 session->ns_data.dd_sock = -1;
2043 } else
2044 ndmpd_mover_error(session,
2045 NDMP_MOVER_HALT_CONNECT_CLOSED);
2046 return (NDMP_NO_ERR);
2047 }
2048
2049 /*
2050 * perform the backup
2051 *
2052 * Cannot wait for the thread to exit as we are replying to the
2053 * client request here.
2054 */
2055 (void) pthread_create(&tid, NULL,
2056 (funct_t)session->ns_data.dd_module.dm_start_func,
2057 params);
2058
2059 if (err) {
2060 syslog(LOG_ERR, "Can't start V2 backup session.");
2061 return (NDMP_ILLEGAL_ARGS_ERR);
2062 }
2063
2064 (void) pthread_detach(tid);
2065
2066 return (NDMP_NO_ERR);
2067 }
2068
2069 /*
2070 * ndmpd_tar_start_recover_v2
2071 *
2072 * The main recover/restore function
2073 *
2074 * Parameters:
2075 * session (input) - session pointer.
2076 * bu_type (input) - backup type.
2077 * env_val (input) - environment variable array.
2078 * env_len (input) - length of env_val.
2079 * nlist_val (input) - list of files.
2080 * nlist_len (input) - length of nlist_val.
2081 *
2082 * Returns:
2083 * NDMP_NO_ERR - recover successfully started.
2084 * otherwise - error code of backup start error.
2085 */
2086 static ndmp_error
2087 ndmpd_tar_start_recover_v2(ndmpd_session_t *session, char *bu_type,
2088 ndmp_pval *env_val, ulong_t env_len, ndmp_name *nlist_val,
2089 ulong_t nlist_len)
2090 {
2091 ndmp_data_start_recover_reply_v2 reply;
2092 ndmpd_module_params_t *params;
2093 ndmp_lbr_params_t *nlp;
2094 pthread_t tid;
2095 int err;
2096
2097 if (session->ns_data.dd_state != NDMP_DATA_STATE_IDLE) {
2098 syslog(LOG_ERR, "Can't start new recover in current state.");
2099 return (NDMP_ILLEGAL_STATE_ERR);
2100 }
2101
2102 if (strcmp(bu_type, NDMP_DUMP_TYPE) != 0 &&
2103 strcmp(bu_type, NDMP_TAR_TYPE) != 0) {
2104 syslog(LOG_ERR, "Invalid backup type: %s.", bu_type);
2105 syslog(LOG_ERR, "Supported backup types are tar and dump.");
2106 return (NDMP_ILLEGAL_ARGS_ERR);
2107 }
2108
2109 reply.error = ndmpd_save_env(session, env_val, env_len);
2110 if (reply.error != NDMP_NO_ERR)
2111 return (NDMP_NO_MEM_ERR);
2112
2113 reply.error = ndmpd_save_nlist_v2(session, nlist_val, nlist_len);
2114 if (reply.error != NDMP_NO_ERR)
2115 return (NDMP_NO_MEM_ERR);
2116
2117 nlp = ndmp_get_nlp(session);
2118 NDMP_FREE(nlp->nlp_params);
2119 params = nlp->nlp_params = ndmp_malloc(sizeof (ndmpd_module_params_t));
2120 if (params == NULL)
2121 return (NDMP_NO_MEM_ERR);
2122
2123 /*
2124 * Setup restore parameters.
2125 */
2126 params->mp_daemon_cookie = (void *)session;
2127 params->mp_module_cookie = &session->ns_data.dd_module.dm_module_cookie;
2128 params->mp_protocol_version = session->ns_protocol_version;
2129 params->mp_operation = NDMP_DATA_OP_RECOVER;
2130 params->mp_get_env_func = ndmpd_api_get_env;
2131 params->mp_add_env_func = ndmpd_api_add_env;
2132 params->mp_get_name_func = ndmpd_api_get_name;
2133 params->mp_dispatch_func = ndmpd_api_dispatch;
2134 params->mp_done_func = ndmpd_api_done_v2;
2135 params->mp_log_func = ndmpd_api_log_v2;
2136 params->mp_add_file_handler_func = ndmpd_api_add_file_handler;
2137 params->mp_remove_file_handler_func = ndmpd_api_remove_file_handler;
2138 params->mp_write_func = 0;
2139 params->mp_file_history_path_func = 0;
2140 params->mp_file_history_dir_func = 0;
2141 params->mp_file_history_node_func = 0;
2142 params->mp_read_func = ndmpd_api_read_v2;
2143 params->mp_seek_func = ndmpd_api_seek_v2;
2144 params->mp_file_recovered_func = ndmpd_api_file_recovered_v2;
2145 params->mp_stats = &session->ns_data.dd_module.dm_stats;
2146
2147 session->ns_data.dd_module.dm_module_cookie = 0;
2148 session->ns_data.dd_module.dm_start_func = ndmpd_tar_restore_starter;
2149 session->ns_data.dd_module.dm_abort_func = ndmpd_tar_restore_abort;
2150 session->ns_data.dd_module.dm_stats.ms_est_bytes_remaining = 0;
2151 session->ns_data.dd_module.dm_stats.ms_est_time_remaining = 0;
2152 session->ns_data.dd_read_offset = 0;
2153 session->ns_data.dd_read_length = 0;
2154
2155 if ((err = ndmp_restore_extract_params(session,
2156 params)) != NDMP_NO_ERR) {
2157 NDMP_FREE(nlp->nlp_params);
2158 return (err);
2159 }
2160
2161 err = ndmpd_mover_connect(session, NDMP_MOVER_MODE_WRITE);
2162 if (err != NDMP_NO_ERR) {
2163 NDMP_FREE(nlp->nlp_params);
2164 return (err);
2165 }
2166
2167 session->ns_data.dd_state = NDMP_DATA_STATE_ACTIVE;
2168 session->ns_data.dd_operation = NDMP_DATA_OP_RECOVER;
2169 session->ns_data.dd_abort = FALSE;
2170
2171 reply.error = NDMP_NO_ERR;
2172 if (ndmp_send_response(session->ns_connection, NDMP_NO_ERR,
2173 &reply) < 0) {
2174 syslog(LOG_DEBUG, "Sending data_start_recover reply");
2175 NDMP_FREE(nlp->nlp_params);
2176 if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) {
2177 /*
2178 * ndmpcopy: we use the same socket for the mover,
2179 * so expect to close when mover is done!
2180 */
2181 if (session->ns_data.dd_sock !=
2182 session->ns_mover.md_sock)
2183 (void) close(session->ns_data.dd_sock);
2184
2185 session->ns_data.dd_sock = -1;
2186 } else {
2187 ndmpd_mover_error(session,
2188 NDMP_MOVER_HALT_CONNECT_CLOSED);
2189 }
2190 return (NDMP_NO_ERR);
2191 }
2192
2193
2194 /*
2195 * perform the restore
2196 *
2197 * Cannot wait for the thread to exit as we are replying to the
2198 * client request here.
2199 */
2200 (void) pthread_create(&tid, NULL,
2201 (funct_t)session->ns_data.dd_module.dm_start_func,
2202 params);
2203
2204 if (err != 0) {
2205 syslog(LOG_ERR, "Can't start V2 recover session.");
2206 return (NDMP_ILLEGAL_ARGS_ERR);
2207 }
2208
2209 (void) pthread_detach(tid);
2210
2211 return (NDMP_NO_ERR);
2212 }
2213
2214 /*
2215 * ndmpd_data_get_info
2216 *
2217 * Return the total number of bytes processed
2218 *
2219 * Parameters:
2220 * session (input) - session pointer.
2221 *
2222 * Returns:
2223 * the number of bytes processed
2224 */
2225 static u_longlong_t
2226 ndmpd_data_get_info(ndmpd_session_t *session)
2227 {
2228 ndmp_lbr_params_t *nlp;
2229
2230 nlp = ndmp_get_nlp(session);
2231 if (nlp == NULL)
2232 return ((u_longlong_t)0);
2233
2234 if (nlp->nlp_jstat == NULL)
2235 return (nlp->nlp_bytes_total);
2236
2237 return ((u_longlong_t)nlp->nlp_jstat->js_bytes_total);
2238 }