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