1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
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
42 #include <sys/param.h>
43 #include <fcntl.h>
44 #include <sys/mtio.h>
45 #include <errno.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <unistd.h>
49 #include "ndmpd_common.h"
50 #include "ndmpd.h"
51
52 static void tape_open_send_reply(ndmp_connection_t *connection, int err);
53 static void unbuffered_read(ndmpd_session_t *session, char *buf, long wanted,
54 ndmp_tape_read_reply *reply);
55 static boolean_t validmode(int mode);
56 static void common_tape_open(ndmp_connection_t *connection, char *devname,
57 int ndmpmode);
58 static void common_tape_close(ndmp_connection_t *connection);
59
60 /*
61 * Configurable delay & time when the tape is
62 * busy during opening the tape.
63 */
64 int ndmp_tape_open_retries = 5;
65 int ndmp_tape_open_delay = 1000;
66
67 /*
68 * ************************************************************************
69 * NDMP V2 HANDLERS
70 * ************************************************************************
71 */
72
73 /*
74 * ndmpd_tape_open_v2
75 *
76 * This handler opens the specified tape device.
77 *
78 * Parameters:
79 * connection (input) - connection handle.
80 * body (input) - request message body.
81 *
82 * Returns:
83 * void
84 */
85 void
ndmpd_tape_open_v2(ndmp_connection_t * connection,void * body)86 ndmpd_tape_open_v2(ndmp_connection_t *connection, void *body)
87 {
88 ndmp_tape_open_request_v2 *request = (ndmp_tape_open_request_v2 *) body;
89 ndmpd_session_t *session = ndmp_get_client_data(connection);
90 char adptnm[SCSI_MAX_NAME];
91 int mode;
92 int sid, lun;
93 int err;
94 scsi_adapter_t *sa;
95 int devid;
96
97 err = NDMP_NO_ERR;
98
99 if (session->ns_tape.td_fd != -1 || session->ns_scsi.sd_is_open != -1) {
100 NDMP_LOG(LOG_INFO,
101 "Connection already has a tape or scsi device open");
102 err = NDMP_DEVICE_OPENED_ERR;
103 } else if (request->mode != NDMP_TAPE_READ_MODE &&
104 request->mode != NDMP_TAPE_WRITE_MODE &&
105 request->mode != NDMP_TAPE_RAW1_MODE) {
106 err = NDMP_ILLEGAL_ARGS_ERR;
107 }
108
109 if ((sa = scsi_get_adapter(0)) != NULL) {
110 NDMP_LOG(LOG_DEBUG,
111 "Adapter device opened: %s", request->device.name);
112 (void) strlcpy(adptnm, request->device.name, SCSI_MAX_NAME-2);
113 adptnm[SCSI_MAX_NAME-1] = '\0';
114 sid = lun = -1;
115 }
116 /* try to get the scsi id etc.... */
117 if (sa) {
118 scsi_find_sid_lun(sa, request->device.name, &sid, &lun);
119 if (ndmp_open_list_find(request->device.name, sid, lun) == 0 &&
120 (devid = tape_open(request->device.name,
121 O_RDWR | O_NDELAY)) < 0) {
122 NDMP_LOG(LOG_ERR, "Failed to open device %s: %m.",
123 request->device.name);
124 err = NDMP_NO_DEVICE_ERR;
125 }
126 else
127 (void) close(devid);
128 } else {
129 NDMP_LOG(LOG_ERR, "%s: No such tape device.",
130 request->device.name);
131 err = NDMP_NO_DEVICE_ERR;
132 }
133 if (err != NDMP_NO_ERR) {
134 tape_open_send_reply(connection, err);
135 return;
136 }
137
138 switch (ndmp_open_list_add(connection, adptnm, sid, lun, devid)) {
139 case 0:
140 err = NDMP_NO_ERR;
141 break;
142 case EBUSY:
143 err = NDMP_DEVICE_BUSY_ERR;
144 break;
145 case ENOMEM:
146 err = NDMP_NO_MEM_ERR;
147 break;
148 default:
149 err = NDMP_IO_ERR;
150 }
151 if (err != NDMP_NO_ERR) {
152 tape_open_send_reply(connection, err);
153 return;
154 }
155
156 /*
157 * According to Connectathon 2001, the 0x7fffffff is a secret
158 * code between "Workstartion Solutions" and * net_app.
159 * If mode is set to this value, tape_open() won't fail if
160 * the tape device is not ready.
161 */
162 if (request->mode != NDMP_TAPE_RAW1_MODE &&
163 !is_tape_unit_ready(adptnm, 0)) {
164 (void) ndmp_open_list_del(adptnm, sid, lun);
165 tape_open_send_reply(connection, NDMP_NO_TAPE_LOADED_ERR);
166 return;
167 }
168
169 mode = (request->mode == NDMP_TAPE_READ_MODE) ? O_RDONLY : O_RDWR;
170 mode |= O_NDELAY;
171 if ((session->ns_tape.td_fd = open(request->device.name, mode)) < 0) {
172 NDMP_LOG(LOG_ERR, "Failed to open tape device %s: %m.",
173 request->device.name);
174 switch (errno) {
175 case EACCES:
176 err = NDMP_WRITE_PROTECT_ERR;
177 break;
178 case ENXIO:
179 case ENOENT:
180 err = NDMP_NO_DEVICE_ERR;
181 break;
182 case EBUSY:
183 err = NDMP_DEVICE_BUSY_ERR;
184 break;
185 default:
186 err = NDMP_IO_ERR;
187 }
188
189 (void) ndmp_open_list_del(adptnm, sid, lun);
190 tape_open_send_reply(connection, err);
191 return;
192 }
193
194 session->ns_tape.td_mode = request->mode;
195 session->ns_tape.td_sid = sid;
196 session->ns_tape.td_lun = lun;
197 (void) strlcpy(session->ns_tape.td_adapter_name, adptnm, SCSI_MAX_NAME);
198 session->ns_tape.td_record_count = 0;
199 session->ns_tape.td_eom_seen = FALSE;
200
201 NDMP_LOG(LOG_DEBUG, "Tape is opened fd: %d", session->ns_tape.td_fd);
202
203 tape_open_send_reply(connection, NDMP_NO_ERR);
204 }
205
206
207 /*
208 * ndmpd_tape_close_v2
209 *
210 * This handler closes the currently open tape device.
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_tape_close_v2(ndmp_connection_t * connection,void * body)221 ndmpd_tape_close_v2(ndmp_connection_t *connection, void *body)
222 {
223 ndmp_tape_close_reply reply;
224 ndmpd_session_t *session = ndmp_get_client_data(connection);
225
226 if (session->ns_tape.td_fd == -1) {
227 NDMP_LOG(LOG_ERR, "Tape device is not open.");
228 reply.error = NDMP_DEV_NOT_OPEN_ERR;
229 ndmp_send_reply(connection, (void *) &reply,
230 "sending tape_close reply");
231 return;
232 }
233 common_tape_close(connection);
234
235 }
236
237 /*
238 * ndmpd_tape_get_state_v2
239 *
240 * This handler handles the tape_get_state request.
241 * Status information for the currently open tape device is returned.
242 *
243 * Parameters:
244 * connection (input) - connection handle.
245 * body (input) - request message body.
246 *
247 * Returns:
248 * void
249 */
250 /*ARGSUSED*/
251 void
ndmpd_tape_get_state_v2(ndmp_connection_t * connection,void * body)252 ndmpd_tape_get_state_v2(ndmp_connection_t *connection, void *body)
253
254 {
255 ndmp_tape_get_state_reply_v2 reply;
256 ndmpd_session_t *session = ndmp_get_client_data(connection);
257 struct mtget mtstatus;
258 struct mtdrivetype_request dtpr;
259 struct mtdrivetype dtp;
260
261 if (session->ns_tape.td_fd == -1) {
262 NDMP_LOG(LOG_ERR, "Tape device is not open.");
263 reply.error = NDMP_DEV_NOT_OPEN_ERR;
264 ndmp_send_reply(connection, (void *) &reply,
265 "sending tape_get_state reply");
266 return;
267 }
268
269 if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) < 0) {
270 NDMP_LOG(LOG_ERR, "Failed to get status from tape: %m.");
271 NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
272 reply.error = NDMP_IO_ERR;
273 ndmp_send_reply(connection, (void *)&reply,
274 "sending tape_get_state reply");
275 return;
276 }
277
278 dtpr.size = sizeof (struct mtdrivetype);
279 dtpr.mtdtp = &dtp;
280 if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
281 NDMP_LOG(LOG_ERR,
282 "Failed to get drive type information from tape: %m.");
283 NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
284 reply.error = NDMP_IO_ERR;
285 ndmp_send_reply(connection, (void *)&reply,
286 "sending tape_get_state reply");
287 return;
288 }
289
290 reply.flags = 0;
291
292 reply.file_num = mtstatus.mt_fileno;
293 reply.soft_errors = 0;
294 reply.block_size = dtp.bsize;
295 if (dtp.bsize == 0)
296 reply.blockno = mtstatus.mt_blkno;
297 else
298 reply.blockno = mtstatus.mt_blkno *
299 (session->ns_mover.md_record_size / dtp.bsize);
300
301 reply.soft_errors = 0;
302 reply.total_space = long_long_to_quad(0); /* not supported */
303 reply.space_remain = long_long_to_quad(0); /* not supported */
304
305 NDMP_LOG(LOG_DEBUG,
306 "flags: 0x%x, file_num: %d, block_size: %d, blockno: %d",
307 reply.flags, reply.file_num, reply.block_size, reply.blockno);
308
309 reply.error = NDMP_NO_ERR;
310 ndmp_send_reply(connection, (void *) &reply,
311 "sending tape_get_state reply");
312 }
313
314
315 /*
316 * ndmpd_tape_mtio_v2
317 *
318 * This handler handles tape_mtio requests.
319 *
320 * Parameters:
321 * connection (input) - connection handle.
322 * body (input) - request message body.
323 *
324 * Returns:
325 * void
326 */
327 void
ndmpd_tape_mtio_v2(ndmp_connection_t * connection,void * body)328 ndmpd_tape_mtio_v2(ndmp_connection_t *connection, void *body)
329 {
330 ndmp_tape_mtio_request *request = (ndmp_tape_mtio_request *) body;
331 ndmp_tape_mtio_reply reply;
332 ndmpd_session_t *session = ndmp_get_client_data(connection);
333
334 struct mtop tapeop;
335 struct mtget mtstatus;
336 int retry = 0;
337 int rc;
338
339 reply.resid_count = 0;
340
341 if (session->ns_tape.td_fd == -1) {
342 NDMP_LOG(LOG_ERR, "Tape device is not open.");
343 reply.error = NDMP_DEV_NOT_OPEN_ERR;
344 ndmp_send_reply(connection, (void *) &reply,
345 "sending tape_mtio reply");
346 return;
347 }
348
349 reply.error = NDMP_NO_ERR;
350 switch (request->tape_op) {
351 case NDMP_MTIO_FSF:
352 tapeop.mt_op = MTFSF;
353 break;
354 case NDMP_MTIO_BSF:
355 tapeop.mt_op = MTBSF;
356 break;
357 case NDMP_MTIO_FSR:
358 tapeop.mt_op = MTFSR;
359 break;
360 case NDMP_MTIO_BSR:
361 tapeop.mt_op = MTBSR;
362 break;
363 case NDMP_MTIO_REW:
364 tapeop.mt_op = MTREW;
365 break;
366 case NDMP_MTIO_EOF:
367 if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE)
368 reply.error = NDMP_PERMISSION_ERR;
369 tapeop.mt_op = MTWEOF;
370 break;
371 case NDMP_MTIO_OFF:
372 tapeop.mt_op = MTOFFL;
373 break;
374
375 case NDMP_MTIO_TUR: /* test unit ready */
376
377 if (is_tape_unit_ready(session->ns_tape.td_adapter_name,
378 session->ns_tape.td_fd) == 0)
379 /* tape not ready ? */
380 reply.error = NDMP_NO_TAPE_LOADED_ERR;
381 break;
382
383 default:
384 reply.error = NDMP_ILLEGAL_ARGS_ERR;
385 }
386
387 if (reply.error == NDMP_NO_ERR && request->tape_op != NDMP_MTIO_TUR) {
388 tapeop.mt_count = request->count;
389
390 do {
391 NS_UPD(twait, trun);
392 rc = ioctl(session->ns_tape.td_fd, MTIOCTOP, &tapeop);
393 NS_UPD(trun, twait);
394 NDMP_LOG(LOG_DEBUG,
395 "ioctl MTIO rc:%d, cmd:%d, retry:%d, error: %d",
396 rc, tapeop.mt_op, retry, errno);
397 } while (rc < 0 && errno == EIO &&
398 retry++ < 5);
399
400 /*
401 * Ignore I/O errors since these usually are the result of
402 * attempting to position past the beginning or end of the tape.
403 * The residual count will be returned and can be used to
404 * determine that the call was not completely successful.
405 */
406 if (rc < 0) {
407 NDMP_LOG(LOG_ERR,
408 "Failed to send command to tape: %m.");
409 NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCTOP) error: %m.");
410
411 /* MTWEOF doesnt have residual count */
412 if (tapeop.mt_op == MTWEOF)
413 reply.error = NDMP_IO_ERR;
414 else
415 reply.error = NDMP_NO_ERR;
416 reply.resid_count = tapeop.mt_count;
417 ndmp_send_reply(connection, (void *)&reply,
418 "sending tape_mtio reply");
419 return;
420 }
421
422 if (request->tape_op != NDMP_MTIO_REW &&
423 request->tape_op != NDMP_MTIO_OFF) {
424 if (ioctl(session->ns_tape.td_fd, MTIOCGET,
425 &mtstatus) < 0) {
426 NDMP_LOG(LOG_ERR,
427 "Failed to send command to tape: %m.");
428 NDMP_LOG(LOG_DEBUG,
429 "ioctl(MTIOCGET) error: %m.");
430 reply.error = NDMP_IO_ERR;
431 ndmp_send_reply(connection, (void *)&reply,
432 "sending tape_mtio reply");
433
434 return;
435 }
436
437 reply.resid_count = labs(mtstatus.mt_resid);
438 }
439 }
440
441 NDMP_LOG(LOG_DEBUG, "resid_count: %d",
442 reply.resid_count);
443 ndmp_send_reply(connection, (void *) &reply, "sending tape_mtio reply");
444 }
445
446
447 /*
448 * ndmpd_tape_write_v2
449 *
450 * This handler handles tape_write requests.
451 * This interface is a non-buffered interface. Each write request
452 * maps directly to a write to the tape device. It is the responsibility
453 * of the NDMP client to pad the data to the desired record size.
454 * It is the responsibility of the NDMP client to ensure that the
455 * length is a multiple of the tape block size if the tape device
456 * is in fixed block mode.
457 *
458 * Parameters:
459 * connection (input) - connection handle.
460 * body (input) - request message body.
461 *
462 * Returns:
463 * void
464 */
465 void
ndmpd_tape_write_v2(ndmp_connection_t * connection,void * body)466 ndmpd_tape_write_v2(ndmp_connection_t *connection, void *body)
467 {
468 ndmp_tape_write_request *request = (ndmp_tape_write_request *) body;
469 ndmp_tape_write_reply reply;
470 ndmpd_session_t *session = ndmp_get_client_data(connection);
471 ssize_t n;
472
473 reply.count = 0;
474
475 if (session->ns_tape.td_fd == -1) {
476 NDMP_LOG(LOG_ERR, "Tape device is not open.");
477 reply.error = NDMP_DEV_NOT_OPEN_ERR;
478 ndmp_send_reply(connection, (void *) &reply,
479 "sending tape_write reply");
480 return;
481 }
482 if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
483 NDMP_LOG(LOG_INFO, "Tape device opened in read-only mode");
484 reply.error = NDMP_PERMISSION_ERR;
485 ndmp_send_reply(connection, (void *) &reply,
486 "sending tape_write reply");
487 return;
488 }
489 if (request->data_out.data_out_len == 0) {
490 reply.error = NDMP_NO_ERR;
491 ndmp_send_reply(connection, (void *) &reply,
492 "sending tape_write reply");
493 return;
494 }
495
496 if (session->ns_tape.td_eom_seen) {
497 /*
498 * Refer to the comment at the top of this file for
499 * Mammoth2 tape drives.
500 */
501 NDMP_LOG(LOG_DEBUG, "eom_seen");
502 ndmpd_write_eom(session->ns_tape.td_fd);
503
504 session->ns_tape.td_eom_seen = FALSE;
505 reply.error = NDMP_EOM_ERR;
506 ndmp_send_reply(connection, (void *) &reply,
507 "sending tape_write reply");
508 return;
509 }
510
511 n = write(session->ns_tape.td_fd, request->data_out.data_out_val,
512 request->data_out.data_out_len);
513 if (n >= 0) {
514 session->ns_tape.td_write = 1;
515 NS_ADD(wtape, n);
516 }
517 if (n == 0) {
518 NDMP_LOG(LOG_DEBUG, "n == 0");
519 reply.error = NDMP_EOM_ERR;
520 session->ns_tape.td_eom_seen = FALSE;
521 } else if (n < 0) {
522 NDMP_LOG(LOG_ERR, "Tape write error: %m.");
523 reply.error = NDMP_IO_ERR;
524 } else {
525 reply.count = n;
526 reply.error = NDMP_NO_ERR;
527
528 /*
529 * a logical end of tape will return number of bytes written
530 * less than rquested, and one more request to write will
531 * give 0, and then no-space
532 */
533 if (n < request->data_out.data_out_len) {
534 NDMP_LOG(LOG_DEBUG, "LEOT: n: %d", n);
535 session->ns_tape.td_eom_seen = TRUE;
536 } else {
537 session->ns_tape.td_eom_seen = FALSE;
538 }
539 }
540 ndmp_send_reply(connection, &reply,
541 "sending tape_write reply");
542 }
543
544
545 /*
546 * ndmpd_tape_read_v2
547 *
548 * This handler handles tape_read requests.
549 * This interface is a non-buffered interface. Each read request
550 * maps directly to a read to the tape device. It is the responsibility
551 * of the NDMP client to issue read requests with a length that is at
552 * least as large as the record size used write the tape. The tape driver
553 * always reads a full record. Data is discarded if the read request is
554 * smaller than the record size.
555 * It is the responsibility of the NDMP client to ensure that the
556 * length is a multiple of the tape block size if the tape device
557 * is in fixed block mode.
558 *
559 * Parameters:
560 * connection (input) - connection handle.
561 * body (input) - request message body.
562 *
563 * Returns:
564 * void
565 */
566 void
ndmpd_tape_read_v2(ndmp_connection_t * connection,void * body)567 ndmpd_tape_read_v2(ndmp_connection_t *connection, void *body)
568 {
569 ndmp_tape_read_request *request = (ndmp_tape_read_request *) body;
570 ndmp_tape_read_reply reply;
571 ndmpd_session_t *session = ndmp_get_client_data(connection);
572 char *buf;
573
574 reply.data_in.data_in_len = 0;
575
576 if (session->ns_tape.td_fd == -1) {
577 NDMP_LOG(LOG_ERR, "Tape device is not open.");
578 reply.error = NDMP_DEV_NOT_OPEN_ERR;
579 ndmp_send_reply(connection, (void *)&reply,
580 "sending tape_read reply");
581 return;
582 }
583 if (request->count == 0) {
584 reply.error = NDMP_NO_ERR;
585 ndmp_send_reply(connection, (void *)&reply,
586 "sending tape_read reply");
587 return;
588 }
589 if ((buf = ndmp_malloc(request->count)) == 0) {
590 reply.error = NDMP_NO_MEM_ERR;
591 ndmp_send_reply(connection, (void *)&reply,
592 "sending tape_read reply");
593 return;
594 }
595
596 session->ns_tape.td_eom_seen = FALSE;
597
598 unbuffered_read(session, buf, request->count, &reply);
599
600 ndmp_send_reply(connection, (void *) &reply, "sending tape_read reply");
601 (void) free(buf);
602 }
603
604
605 /*
606 * ndmpd_tape_execute_cdb_v2
607 *
608 * This handler handles tape_execute_cdb requests.
609 *
610 * Parameters:
611 * connection (input) - connection handle.
612 * body (input) - request message body.
613 *
614 * Returns:
615 * void
616 */
617 void
ndmpd_tape_execute_cdb_v2(ndmp_connection_t * connection,void * body)618 ndmpd_tape_execute_cdb_v2(ndmp_connection_t *connection, void *body)
619 {
620 ndmp_tape_execute_cdb_request *request;
621 ndmp_tape_execute_cdb_reply reply;
622 ndmpd_session_t *session = ndmp_get_client_data(connection);
623
624 request = (ndmp_tape_execute_cdb_request *) body;
625
626 if (session->ns_tape.td_fd == -1) {
627 (void) memset((void *) &reply, 0, sizeof (reply));
628
629 NDMP_LOG(LOG_ERR, "Tape device is not open.");
630 reply.error = NDMP_DEV_NOT_OPEN_ERR;
631 ndmp_send_reply(connection, (void *) &reply,
632 "sending tape_execute_cdb reply");
633 } else {
634 session->ns_tape.td_eom_seen = FALSE;
635 ndmp_execute_cdb(session, session->ns_tape.td_adapter_name,
636 session->ns_tape.td_sid, session->ns_tape.td_lun,
637 (ndmp_execute_cdb_request *)request);
638 }
639 }
640
641
642 /*
643 * ************************************************************************
644 * NDMP V3 HANDLERS
645 * ************************************************************************
646 */
647
648 /*
649 * ndmpd_tape_open_v3
650 *
651 * This handler opens the specified tape device.
652 *
653 * Parameters:
654 * connection (input) - connection handle.
655 * body (input) - request message body.
656 *
657 * Returns:
658 * void
659 */
660 void
ndmpd_tape_open_v3(ndmp_connection_t * connection,void * body)661 ndmpd_tape_open_v3(ndmp_connection_t *connection, void *body)
662 {
663 ndmp_tape_open_request_v3 *request = (ndmp_tape_open_request_v3 *)body;
664
665 common_tape_open(connection, request->device, request->mode);
666 }
667
668
669 /*
670 * ndmpd_tape_get_state_v3
671 *
672 * This handler handles the ndmp_tape_get_state_request.
673 * Status information for the currently open tape device is returned.
674 *
675 * Parameters:
676 * connection (input) - connection handle.
677 * body (input) - request message body.
678 *
679 * Returns:
680 * void
681 */
682 /*ARGSUSED*/
683 void
ndmpd_tape_get_state_v3(ndmp_connection_t * connection,void * body)684 ndmpd_tape_get_state_v3(ndmp_connection_t *connection, void *body)
685 {
686 ndmp_tape_get_state_reply_v3 reply;
687 ndmpd_session_t *session = ndmp_get_client_data(connection);
688 struct mtdrivetype_request dtpr;
689 struct mtdrivetype dtp;
690 struct mtget mtstatus;
691
692 if (session->ns_tape.td_fd == -1) {
693 NDMP_LOG(LOG_ERR, "Tape device is not open.");
694 reply.error = NDMP_DEV_NOT_OPEN_ERR;
695 ndmp_send_reply(connection, (void *) &reply,
696 "sending tape_get_state reply");
697 return;
698 }
699
700 if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == -1) {
701 NDMP_LOG(LOG_ERR, "Failed to get status from tape: %m.");
702 NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
703
704 reply.error = NDMP_IO_ERR;
705 ndmp_send_reply(connection, (void *)&reply,
706 "sending tape_get_state reply");
707 return;
708 }
709
710 dtpr.size = sizeof (struct mtdrivetype);
711 dtpr.mtdtp = &dtp;
712 if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
713 NDMP_LOG(LOG_ERR,
714 "Failed to get drive type information from tape: %m.");
715 NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
716
717 reply.error = NDMP_IO_ERR;
718 ndmp_send_reply(connection, (void *)&reply,
719 "sending tape_get_state reply");
720 return;
721 }
722
723 reply.flags = 0;
724
725 reply.file_num = mtstatus.mt_fileno;
726 reply.soft_errors = 0;
727 reply.block_size = dtp.bsize;
728 if (dtp.bsize == 0)
729 reply.blockno = mtstatus.mt_blkno;
730 else
731 reply.blockno = mtstatus.mt_blkno *
732 (session->ns_mover.md_record_size / dtp.bsize);
733 reply.total_space = long_long_to_quad(0); /* not supported */
734 reply.space_remain = long_long_to_quad(0); /* not supported */
735 reply.partition = 0; /* not supported */
736
737 reply.soft_errors = 0;
738 reply.total_space = long_long_to_quad(0LL);
739 reply.space_remain = long_long_to_quad(0LL);
740
741 reply.invalid = NDMP_TAPE_STATE_SOFT_ERRORS_INVALID |
742 NDMP_TAPE_STATE_TOTAL_SPACE_INVALID |
743 NDMP_TAPE_STATE_SPACE_REMAIN_INVALID |
744 NDMP_TAPE_STATE_PARTITION_INVALID;
745
746
747 NDMP_LOG(LOG_DEBUG, "f 0x%x, fnum %d, bsize %d, bno: %d",
748 reply.flags, reply.file_num, reply.block_size, reply.blockno);
749
750 reply.error = NDMP_NO_ERR;
751 ndmp_send_reply(connection, (void *) &reply,
752 "sending tape_get_state reply");
753 }
754
755
756 /*
757 * ndmpd_tape_write_v3
758 *
759 * This handler handles tape_write requests.
760 * This interface is a non-buffered interface. Each write request
761 * maps directly to a write to the tape device. It is the responsibility
762 * of the NDMP client to pad the data to the desired record size.
763 * It is the responsibility of the NDMP client to ensure that the
764 * length is a multiple of the tape block size if the tape device
765 * is in fixed block mode.
766 *
767 * Parameters:
768 * connection (input) - connection handle.
769 * body (input) - request message body.
770 *
771 * Returns:
772 * void
773 */
774 void
ndmpd_tape_write_v3(ndmp_connection_t * connection,void * body)775 ndmpd_tape_write_v3(ndmp_connection_t *connection, void *body)
776 {
777 ndmp_tape_write_request *request = (ndmp_tape_write_request *) body;
778 ndmp_tape_write_reply reply;
779 ndmpd_session_t *session = ndmp_get_client_data(connection);
780 ssize_t n;
781
782 reply.count = 0;
783
784 if (session->ns_tape.td_fd == -1) {
785 NDMP_LOG(LOG_ERR, "Tape device is not open.");
786 reply.error = NDMP_DEV_NOT_OPEN_ERR;
787 ndmp_send_reply(connection, (void *) &reply,
788 "sending tape_write reply");
789 return;
790 }
791 if (session->ns_tape.td_mode == NDMP_TAPE_READ_MODE) {
792 NDMP_LOG(LOG_INFO, "Tape device opened in read-only mode");
793 reply.error = NDMP_PERMISSION_ERR;
794 ndmp_send_reply(connection, (void *) &reply,
795 "sending tape_write reply");
796 return;
797 }
798 if (request->data_out.data_out_len == 0) {
799 reply.error = NDMP_NO_ERR;
800 ndmp_send_reply(connection, (void *) &reply,
801 "sending tape_write reply");
802 return;
803 }
804
805 /*
806 * V4 suggests that this should not be accepted
807 * when mover is in listen or active state
808 */
809 if (session->ns_protocol_version == NDMPV4 &&
810 (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
811 session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE)) {
812
813 reply.error = NDMP_DEVICE_BUSY_ERR;
814 ndmp_send_reply(connection, (void *) &reply,
815 "sending tape_write reply");
816 return;
817 }
818
819 /*
820 * Refer to the comment at the top of this file for
821 * Mammoth2 tape drives.
822 */
823 if (session->ns_tape.td_eom_seen) {
824 NDMP_LOG(LOG_DEBUG, "eom_seen");
825 ndmpd_write_eom(session->ns_tape.td_fd);
826 session->ns_tape.td_eom_seen = FALSE;
827 reply.error = NDMP_EOM_ERR;
828 ndmp_send_reply(connection, (void *) &reply,
829 "sending tape_write reply");
830 return;
831 }
832
833 n = write(session->ns_tape.td_fd, request->data_out.data_out_val,
834 request->data_out.data_out_len);
835
836 session->ns_tape.td_eom_seen = FALSE;
837 if (n >= 0) {
838 session->ns_tape.td_write = 1;
839 NS_ADD(wtape, n);
840 }
841 if (n == 0) {
842 NDMP_LOG(LOG_INFO, "EOM detected");
843 reply.error = NDMP_EOM_ERR;
844 session->ns_tape.td_eom_seen = TRUE;
845 } else if (n < 0) {
846 NDMP_LOG(LOG_ERR, "Tape write error: %m.");
847 reply.error = NDMP_IO_ERR;
848 } else {
849 reply.count = n;
850 reply.error = NDMP_NO_ERR;
851 }
852
853 ndmp_send_reply(connection, (void *) &reply,
854 "sending tape_write reply");
855 }
856
857
858 /*
859 * ndmpd_tape_read_v3
860 *
861 * This handler handles tape_read requests.
862 * This interface is a non-buffered interface. Each read request
863 * maps directly to a read to the tape device. It is the responsibility
864 * of the NDMP client to issue read requests with a length that is at
865 * least as large as the record size used write the tape. The tape driver
866 * always reads a full record. Data is discarded if the read request is
867 * smaller than the record size.
868 * It is the responsibility of the NDMP client to ensure that the
869 * length is a multiple of the tape block size if the tape device
870 * is in fixed block mode.
871 *
872 * Parameters:
873 * connection (input) - connection handle.
874 * body (input) - request message body.
875 *
876 * Returns:
877 * void
878 */
879 void
ndmpd_tape_read_v3(ndmp_connection_t * connection,void * body)880 ndmpd_tape_read_v3(ndmp_connection_t *connection, void *body)
881 {
882 ndmp_tape_read_request *request = (ndmp_tape_read_request *) body;
883 ndmp_tape_read_reply reply;
884 ndmpd_session_t *session = ndmp_get_client_data(connection);
885 char *buf;
886 int n, len;
887
888 reply.data_in.data_in_len = 0;
889
890 if (session->ns_tape.td_fd == -1) {
891 NDMP_LOG(LOG_ERR, "Tape device is not open.");
892 reply.error = NDMP_DEV_NOT_OPEN_ERR;
893 ndmp_send_reply(connection, (void *) &reply,
894 "sending tape_read reply");
895 return;
896 }
897 if (request->count == 0) {
898 reply.error = NDMP_NO_ERR;
899 ndmp_send_reply(connection, (void *) &reply,
900 "sending tape_read reply");
901 return;
902 }
903
904 /*
905 * V4 suggests that this should not be accepted
906 * when mover is in listen or active state
907 */
908 if (session->ns_protocol_version == NDMPV4 &&
909 (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
910 session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE)) {
911
912 reply.error = NDMP_DEVICE_BUSY_ERR;
913 ndmp_send_reply(connection, (void *) &reply,
914 "sending tape_read reply");
915 return;
916 }
917
918 if ((buf = ndmp_malloc(request->count)) == NULL) {
919 reply.error = NDMP_NO_MEM_ERR;
920 ndmp_send_reply(connection, (void *) &reply,
921 "sending tape_read reply");
922 return;
923 }
924 session->ns_tape.td_eom_seen = FALSE;
925
926 n = read(session->ns_tape.td_fd, buf, request->count);
927 if (n < 0) {
928 /*
929 * This fix is for Symantec during importing
930 * of spanned data between the tapes.
931 */
932 if (errno == ENOSPC) {
933 reply.error = NDMP_EOF_ERR;
934 } else {
935 NDMP_LOG(LOG_ERR, "Tape read error: %m.");
936 reply.error = NDMP_IO_ERR;
937 }
938 } else if (n == 0) {
939 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
940
941 len = strlen(NDMP_EOM_MAGIC);
942 (void) memset(buf, 0, len);
943 n = read(session->ns_tape.td_fd, buf, len);
944 buf[len] = '\0';
945
946 NDMP_LOG(LOG_DEBUG, "Checking EOM: nread %d [%s]", n, buf);
947
948 if (strncmp(buf, NDMP_EOM_MAGIC, len) == 0) {
949 reply.error = NDMP_EOM_ERR;
950 NDMP_LOG(LOG_DEBUG, "NDMP_EOM_ERR");
951 } else {
952 reply.error = NDMP_EOF_ERR;
953 NDMP_LOG(LOG_DEBUG, "NDMP_EOF_ERR");
954 }
955 if (n > 0)
956 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSR, 1);
957 } else {
958 /*
959 * Symantec fix for import phase
960 *
961 * As import process from symantec skips filemarks
962 * they can come across to NDMP_EOM_MAGIC and treat
963 * it as data. This fix prevents the magic to be
964 * sent to the client and the read will return zero bytes
965 * and set the NDMP_EOM_ERR error. The tape should
966 * be positioned at the EOT side of the file mark.
967 */
968 len = strlen(NDMP_EOM_MAGIC);
969 if (n == len && strncmp(buf, NDMP_EOM_MAGIC, len) == 0) {
970 reply.error = NDMP_EOM_ERR;
971 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
972 NDMP_LOG(LOG_DEBUG, "NDMP_EOM_ERR");
973 } else {
974 session->ns_tape.td_pos += n;
975 reply.data_in.data_in_len = n;
976 reply.data_in.data_in_val = buf;
977 reply.error = NDMP_NO_ERR;
978 }
979 NS_ADD(rtape, n);
980 }
981
982 ndmp_send_reply(connection, (void *) &reply, "sending tape_read reply");
983 free(buf);
984 }
985
986
987 /*
988 * ************************************************************************
989 * NDMP V4 HANDLERS
990 * ************************************************************************
991 */
992
993 /*
994 * ndmpd_tape_get_state_v4
995 *
996 * This handler handles the ndmp_tape_get_state_request.
997 * Status information for the currently open tape device is returned.
998 *
999 * Parameters:
1000 * connection (input) - connection handle.
1001 * body (input) - request message body.
1002 *
1003 * Returns:
1004 * void
1005 */
1006 /*ARGSUSED*/
1007 void
ndmpd_tape_get_state_v4(ndmp_connection_t * connection,void * body)1008 ndmpd_tape_get_state_v4(ndmp_connection_t *connection, void *body)
1009 {
1010 ndmp_tape_get_state_reply_v4 reply;
1011 ndmpd_session_t *session = ndmp_get_client_data(connection);
1012 struct mtget mtstatus;
1013 struct mtdrivetype_request dtpr;
1014 struct mtdrivetype dtp;
1015
1016 if (session->ns_tape.td_fd == -1) {
1017 NDMP_LOG(LOG_ERR, "Tape device is not open.");
1018 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1019 ndmp_send_reply(connection, (void *) &reply,
1020 "sending tape_get_state reply");
1021 return;
1022 }
1023
1024 /*
1025 * Need code to detect NDMP_TAPE_STATE_NOREWIND
1026 */
1027
1028 if (ioctl(session->ns_tape.td_fd, MTIOCGET, &mtstatus) == -1) {
1029 NDMP_LOG(LOG_ERR,
1030 "Failed to get status information from tape: %m.");
1031 NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGET) error: %m.");
1032
1033 reply.error = NDMP_IO_ERR;
1034 ndmp_send_reply(connection, (void *)&reply,
1035 "sending tape_get_state reply");
1036 return;
1037 }
1038
1039 dtpr.size = sizeof (struct mtdrivetype);
1040 dtpr.mtdtp = &dtp;
1041 if (ioctl(session->ns_tape.td_fd, MTIOCGETDRIVETYPE, &dtpr) == -1) {
1042 NDMP_LOG(LOG_ERR,
1043 "Failed to get drive type information from tape: %m.");
1044 NDMP_LOG(LOG_DEBUG, "ioctl(MTIOCGETDRIVETYPE) error: %m.");
1045
1046 reply.error = NDMP_IO_ERR;
1047 ndmp_send_reply(connection, (void *)&reply,
1048 "sending tape_get_state reply");
1049 return;
1050 }
1051
1052 reply.flags = NDMP_TAPE_NOREWIND;
1053
1054 reply.file_num = mtstatus.mt_fileno;
1055 reply.soft_errors = 0;
1056 reply.block_size = dtp.bsize;
1057
1058 if (dtp.bsize == 0)
1059 reply.blockno = mtstatus.mt_blkno;
1060 else
1061 reply.blockno = mtstatus.mt_blkno *
1062 (session->ns_mover.md_record_size / dtp.bsize);
1063
1064 reply.total_space = long_long_to_quad(0); /* not supported */
1065 reply.space_remain = long_long_to_quad(0); /* not supported */
1066
1067 reply.soft_errors = 0;
1068 reply.total_space = long_long_to_quad(0LL);
1069 reply.space_remain = long_long_to_quad(0LL);
1070 reply.unsupported = NDMP_TAPE_STATE_SOFT_ERRORS_INVALID |
1071 NDMP_TAPE_STATE_TOTAL_SPACE_INVALID |
1072 NDMP_TAPE_STATE_SPACE_REMAIN_INVALID |
1073 NDMP_TAPE_STATE_PARTITION_INVALID;
1074
1075
1076 NDMP_LOG(LOG_DEBUG, "f 0x%x, fnum %d, bsize %d, bno: %d",
1077 reply.flags, reply.file_num, reply.block_size, reply.blockno);
1078
1079 reply.error = NDMP_NO_ERR;
1080 ndmp_send_reply(connection, (void *) &reply,
1081 "sending tape_get_state reply");
1082 }
1083 /*
1084 * ndmpd_tape_close_v4
1085 *
1086 * This handler (v4) closes the currently open tape device.
1087 *
1088 * Parameters:
1089 * connection (input) - connection handle.
1090 * body (input) - request message body.
1091 *
1092 * Returns:
1093 * void
1094 */
1095 /*ARGSUSED*/
1096 void
ndmpd_tape_close_v4(ndmp_connection_t * connection,void * body)1097 ndmpd_tape_close_v4(ndmp_connection_t *connection, void *body)
1098 {
1099 ndmp_tape_close_reply reply;
1100 ndmpd_session_t *session = ndmp_get_client_data(connection);
1101
1102 if (session->ns_tape.td_fd == -1) {
1103 NDMP_LOG(LOG_ERR, "Tape device is not open.");
1104 reply.error = NDMP_DEV_NOT_OPEN_ERR;
1105 ndmp_send_reply(connection, (void *) &reply,
1106 "sending tape_close reply");
1107 return;
1108 }
1109
1110 /*
1111 * V4 suggests that this should not be accepted
1112 * when mover is in listen or active state
1113 */
1114 if (session->ns_mover.md_state == NDMP_MOVER_STATE_LISTEN ||
1115 session->ns_mover.md_state == NDMP_MOVER_STATE_ACTIVE) {
1116
1117 reply.error = NDMP_DEVICE_BUSY_ERR;
1118 ndmp_send_reply(connection, (void *) &reply,
1119 "sending tape_close reply");
1120 return;
1121 }
1122
1123 common_tape_close(connection);
1124 }
1125
1126
1127 /*
1128 * ************************************************************************
1129 * LOCALS
1130 * ************************************************************************
1131 */
1132 /*
1133 * tape_open_send_reply
1134 *
1135 * Send a reply to the tape open message
1136 *
1137 * Parameters:
1138 * connection (input) - connection handle.
1139 * err (input) - NDMP error
1140 *
1141 * Returns:
1142 * void
1143 */
1144 static void
tape_open_send_reply(ndmp_connection_t * connection,int err)1145 tape_open_send_reply(ndmp_connection_t *connection, int err)
1146 {
1147 ndmp_tape_open_reply reply;
1148
1149 reply.error = err;
1150 ndmp_send_reply(connection, (void *) &reply, "sending tape_open reply");
1151 }
1152
1153 /*
1154 * unbuffered_read
1155 *
1156 * Perform tape read without read-ahead
1157 *
1158 * Parameters:
1159 * session (input) - session handle
1160 * bp (output) - read buffer
1161 * wanted (input) - number of bytes wanted
1162 * reply (output) - tape read reply message
1163 *
1164 * Returns:
1165 * void
1166 */
1167 static void
unbuffered_read(ndmpd_session_t * session,char * buf,long wanted,ndmp_tape_read_reply * reply)1168 unbuffered_read(ndmpd_session_t *session, char *buf, long wanted,
1169 ndmp_tape_read_reply *reply)
1170 {
1171 int n, len;
1172
1173 n = read(session->ns_tape.td_fd, buf, wanted);
1174 if (n < 0) {
1175 /*
1176 * This fix is for Symantec during importing
1177 * of spanned data between the tapes.
1178 */
1179 if (errno == ENOSPC) {
1180 reply->error = NDMP_EOF_ERR;
1181 } else {
1182 NDMP_LOG(LOG_ERR, "Tape read error: %m.");
1183 reply->error = NDMP_IO_ERR;
1184 }
1185 } else if (n == 0) {
1186 NDMP_LOG(LOG_DEBUG, "NDMP_EOF_ERR");
1187
1188 reply->error = NDMP_EOF_ERR;
1189
1190 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
1191
1192 len = strlen(NDMP_EOM_MAGIC);
1193 (void) memset(buf, 0, len);
1194 n = read(session->ns_tape.td_fd, buf, len);
1195 buf[len] = '\0';
1196
1197 NDMP_LOG(LOG_DEBUG, "Checking EOM: nread %d [%s]", n, buf);
1198
1199 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTBSF, 1);
1200
1201 if (strncmp(buf, NDMP_EOM_MAGIC, len) != 0)
1202 (void) ndmp_mtioctl(session->ns_tape.td_fd, MTFSF, 1);
1203 } else {
1204 session->ns_tape.td_pos += n;
1205 reply->data_in.data_in_len = n;
1206 reply->data_in.data_in_val = buf;
1207 reply->error = NDMP_NO_ERR;
1208 NS_ADD(rtape, n);
1209 }
1210 }
1211
1212
1213 /*
1214 * validmode
1215 *
1216 * Check the tape read mode is valid
1217 */
1218 static boolean_t
validmode(int mode)1219 validmode(int mode)
1220 {
1221 boolean_t rv;
1222
1223 switch (mode) {
1224 case NDMP_TAPE_READ_MODE:
1225 case NDMP_TAPE_WRITE_MODE:
1226 case NDMP_TAPE_RAW1_MODE:
1227 case NDMP_TAPE_RAW2_MODE:
1228 rv = TRUE;
1229 break;
1230 default:
1231 rv = FALSE;
1232 }
1233
1234 return (rv);
1235 }
1236
1237
1238 /*
1239 * common_tape_open
1240 *
1241 * Generic function for opening the tape for all versions
1242 *
1243 * Parameters:
1244 * connection (input) - connection handle.
1245 * devname (input) - tape device name to open.
1246 * ndmpmode (input) - mode of opening (read, write, raw)
1247 *
1248 * Returns:
1249 * void
1250 */
1251 static void
common_tape_open(ndmp_connection_t * connection,char * devname,int ndmpmode)1252 common_tape_open(ndmp_connection_t *connection, char *devname, int ndmpmode)
1253 {
1254 ndmpd_session_t *session = ndmp_get_client_data(connection);
1255 char adptnm[SCSI_MAX_NAME];
1256 int err;
1257 int mode;
1258 int sid, lun;
1259 scsi_adapter_t *sa;
1260 int devid;
1261
1262 err = NDMP_NO_ERR;
1263
1264 if (session->ns_tape.td_fd != -1 || session->ns_scsi.sd_is_open != -1) {
1265 NDMP_LOG(LOG_INFO,
1266 "Connection already has a tape or scsi device open");
1267 err = NDMP_DEVICE_OPENED_ERR;
1268 } else if (!validmode(ndmpmode))
1269 err = NDMP_ILLEGAL_ARGS_ERR;
1270 if ((sa = scsi_get_adapter(0)) != NULL) {
1271 NDMP_LOG(LOG_DEBUG, "Adapter device opened: %s", devname);
1272 (void) strlcpy(adptnm, devname, SCSI_MAX_NAME-2);
1273 adptnm[SCSI_MAX_NAME-1] = '\0';
1274 sid = lun = -1;
1275 }
1276 if (sa) {
1277 scsi_find_sid_lun(sa, devname, &sid, &lun);
1278 if (ndmp_open_list_find(devname, sid, lun) == 0 &&
1279 (devid = open(devname, O_RDWR | O_NDELAY)) < 0) {
1280 NDMP_LOG(LOG_ERR,
1281 "Failed to open device %s: %m.", devname);
1282 err = NDMP_NO_DEVICE_ERR;
1283 } else {
1284 (void) close(devid);
1285 }
1286 } else {
1287 NDMP_LOG(LOG_ERR, "%s: No such tape device.", devname);
1288 err = NDMP_NO_DEVICE_ERR;
1289 }
1290
1291 if (err != NDMP_NO_ERR) {
1292 tape_open_send_reply(connection, err);
1293 return;
1294 }
1295
1296 /*
1297 * If tape is not opened in raw mode and tape is not loaded
1298 * return error.
1299 */
1300 if (ndmpmode != NDMP_TAPE_RAW1_MODE &&
1301 ndmpmode != NDMP_TAPE_RAW2_MODE &&
1302 !is_tape_unit_ready(adptnm, 0)) {
1303 tape_open_send_reply(connection, NDMP_NO_TAPE_LOADED_ERR);
1304 return;
1305 }
1306
1307 mode = (ndmpmode == NDMP_TAPE_READ_MODE) ? O_RDONLY : O_RDWR;
1308 mode |= O_NDELAY;
1309 session->ns_tape.td_fd = open(devname, mode);
1310 if (session->ns_protocol_version == NDMPV4 &&
1311 session->ns_tape.td_fd < 0 &&
1312 ndmpmode == NDMP_TAPE_RAW_MODE && errno == EACCES) {
1313 /*
1314 * V4 suggests that if the tape is open in raw mode
1315 * and could not be opened with write access, it should
1316 * be opened read only instead.
1317 */
1318 ndmpmode = NDMP_TAPE_READ_MODE;
1319 session->ns_tape.td_fd = open(devname, O_RDONLY);
1320 }
1321 if (session->ns_tape.td_fd < 0) {
1322 NDMP_LOG(LOG_ERR, "Failed to open tape device %s: %m.",
1323 devname);
1324 switch (errno) {
1325 case EACCES:
1326 err = NDMP_WRITE_PROTECT_ERR;
1327 break;
1328 case ENOENT:
1329 err = NDMP_NO_DEVICE_ERR;
1330 break;
1331 case EBUSY:
1332 err = NDMP_DEVICE_BUSY_ERR;
1333 break;
1334 case EPERM:
1335 err = NDMP_PERMISSION_ERR;
1336 break;
1337 default:
1338 err = NDMP_IO_ERR;
1339 }
1340
1341 tape_open_send_reply(connection, err);
1342 return;
1343 }
1344
1345 switch (ndmp_open_list_add(connection,
1346 adptnm, sid, lun, session->ns_tape.td_fd)) {
1347 case 0:
1348 err = NDMP_NO_ERR;
1349 break;
1350 case EBUSY:
1351 err = NDMP_DEVICE_BUSY_ERR;
1352 break;
1353 case ENOMEM:
1354 err = NDMP_NO_MEM_ERR;
1355 break;
1356 default:
1357 err = NDMP_IO_ERR;
1358 }
1359 if (err != NDMP_NO_ERR) {
1360 tape_open_send_reply(connection, err);
1361 return;
1362 }
1363
1364 session->ns_tape.td_mode = ndmpmode;
1365 session->ns_tape.td_sid = sid;
1366 session->ns_tape.td_lun = lun;
1367 (void) strlcpy(session->ns_tape.td_adapter_name, adptnm, SCSI_MAX_NAME);
1368 session->ns_tape.td_record_count = 0;
1369 session->ns_tape.td_eom_seen = FALSE;
1370
1371 NDMP_LOG(LOG_DEBUG, "Tape is opened fd: %d", session->ns_tape.td_fd);
1372
1373 tape_open_send_reply(connection, NDMP_NO_ERR);
1374 }
1375
1376
1377 /*
1378 * common_tape_close
1379 *
1380 * Generic function for closing the tape
1381 *
1382 * Parameters:
1383 * connection (input) - connection handle.
1384 *
1385 * Returns:
1386 * void
1387 */
1388 static void
common_tape_close(ndmp_connection_t * connection)1389 common_tape_close(ndmp_connection_t *connection)
1390 {
1391 ndmpd_session_t *session = ndmp_get_client_data(connection);
1392 ndmp_tape_close_reply reply;
1393
1394 (void) ndmp_open_list_del(session->ns_tape.td_adapter_name,
1395 session->ns_tape.td_sid, session->ns_tape.td_lun);
1396 (void) close(session->ns_tape.td_fd);
1397 session->ns_tape.td_fd = -1;
1398 session->ns_tape.td_sid = 0;
1399 session->ns_tape.td_lun = 0;
1400 session->ns_tape.td_write = 0;
1401 (void) memset(session->ns_tape.td_adapter_name, 0,
1402 sizeof (session->ns_tape.td_adapter_name));
1403 session->ns_tape.td_record_count = 0;
1404 session->ns_tape.td_eom_seen = FALSE;
1405
1406 reply.error = NDMP_NO_ERR;
1407 ndmp_send_reply(connection, (void *) &reply,
1408 "sending tape_close reply");
1409 }
1410
1411 /*
1412 * tape_open
1413 *
1414 * Will try to open the tape with the given flags and
1415 * path using the given retries and delay intervals
1416 */
1417 int
tape_open(char * path,int flags)1418 tape_open(char *path, int flags)
1419 {
1420 int fd;
1421 int i = 0;
1422
1423 while ((fd = open(path, flags)) == -1 &&
1424 i++ < ndmp_tape_open_retries) {
1425 if (errno != EBUSY)
1426 break;
1427 (void) usleep(ndmp_tape_open_delay);
1428 }
1429 return (fd);
1430 }
1431