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