|
|
1.1 ! root 1: /* $Id: posix-tape.c,v 1.6 2003/10/16 02:48:23 fredette Exp $ */ ! 2: ! 3: /* host/posix/posix-tape.c - implementation of tapes on a POSIX system: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2003 Matt Fredette ! 7: * All rights reserved. ! 8: * ! 9: * Redistribution and use in source and binary forms, with or without ! 10: * modification, are permitted provided that the following conditions ! 11: * are met: ! 12: * 1. Redistributions of source code must retain the above copyright ! 13: * notice, this list of conditions and the following disclaimer. ! 14: * 2. Redistributions in binary form must reproduce the above copyright ! 15: * notice, this list of conditions and the following disclaimer in the ! 16: * documentation and/or other materials provided with the distribution. ! 17: * 3. All advertising materials mentioning features or use of this software ! 18: * must display the following acknowledgement: ! 19: * This product includes software developed by Matt Fredette. ! 20: * 4. The name of the author may not be used to endorse or promote products ! 21: * derived from this software without specific prior written permission. ! 22: * ! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ! 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ! 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ! 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ! 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! 33: * POSSIBILITY OF SUCH DAMAGE. ! 34: */ ! 35: ! 36: #include <tme/common.h> ! 37: _TME_RCSID("$Id: posix-tape.c,v 1.6 2003/10/16 02:48:23 fredette Exp $"); ! 38: ! 39: /* includes: */ ! 40: #include <tme/generic/tape.h> ! 41: #include <fcntl.h> ! 42: #include <stdlib.h> ! 43: #include <strings.h> ! 44: #include <sys/stat.h> ! 45: #include <sys/uio.h> ! 46: #ifdef HAVE_STDARG_H ! 47: #include <stdarg.h> ! 48: #else /* HAVE_STDARG_H */ ! 49: #include <varargs.h> ! 50: #endif /* HAVE_STDARG_H */ ! 51: ! 52: /* macros: */ ! 53: ! 54: /* tape flags: */ ! 55: #define TME_POSIX_TAPE_FLAG_RO TME_BIT(0) ! 56: #define TME_POSIX_TAPE_FLAG_DIRTY TME_BIT(1) ! 57: ! 58: /* the size of the control callout ring: */ ! 59: #define TME_POSIX_TAPE_CONTROL_RING_SIZE (16) ! 60: ! 61: /* the callout flags: */ ! 62: #define TME_POSIX_TAPE_CALLOUT_CHECK (0) ! 63: #define TME_POSIX_TAPE_CALLOUT_RUNNING TME_BIT(0) ! 64: #define TME_POSIX_TAPE_CALLOUTS_MASK (-2) ! 65: #define TME_POSIX_TAPE_CALLOUT_CONTROL TME_BIT(1) ! 66: ! 67: /* types: */ ! 68: ! 69: /* a posix tape control: */ ! 70: struct tme_posix_tape_control { ! 71: ! 72: /* the control: */ ! 73: unsigned int tme_posix_tape_control_which; ! 74: }; ! 75: ! 76: /* a posix tape segment: */ ! 77: struct tme_posix_tape_segment { ! 78: ! 79: /* tape segments are kept on a doubly linked list: */ ! 80: struct tme_posix_tape_segment *tme_posix_tape_segment_next; ! 81: struct tme_posix_tape_segment *tme_posix_tape_segment_prev; ! 82: ! 83: /* the filename of this tape segment: */ ! 84: char *tme_posix_tape_segment_filename; ! 85: ! 86: /* the file descriptor of this tape segment: */ ! 87: int tme_posix_tape_segment_fd; ! 88: ! 89: /* this is nonzero iff this tape segment is a real tape: */ ! 90: int tme_posix_tape_segment_real_tape; ! 91: }; ! 92: ! 93: /* a posix tape: */ ! 94: struct tme_posix_tape { ! 95: ! 96: /* backpointer to our element: */ ! 97: struct tme_element *tme_posix_tape_element; ! 98: ! 99: /* our mutex: */ ! 100: tme_mutex_t tme_posix_tape_mutex; ! 101: ! 102: /* our flags: */ ! 103: int tme_posix_tape_flags; ! 104: ! 105: /* the tape segments: */ ! 106: struct tme_posix_tape_segment *tme_posix_tape_segments; ! 107: ! 108: /* the connection: */ ! 109: struct tme_tape_connection *tme_posix_tape_connection; ! 110: ! 111: /* the callout flags: */ ! 112: int tme_posix_tape_callout_flags; ! 113: ! 114: /* the control ring buffer: */ ! 115: struct tme_posix_tape_control tme_posix_tape_controls[TME_POSIX_TAPE_CONTROL_RING_SIZE]; ! 116: unsigned int tme_posix_tape_control_head; ! 117: unsigned int tme_posix_tape_control_tail; ! 118: ! 119: /* the current tape segment: */ ! 120: struct tme_posix_tape_segment *tme_posix_tape_segment_current; ! 121: ! 122: /* the block sizes: */ ! 123: unsigned long tme_posix_tape_block_size_min; ! 124: unsigned long tme_posix_tape_block_size_max; ! 125: unsigned long tme_posix_tape_block_size_fixed; ! 126: ! 127: /* the tape buffer: */ ! 128: unsigned long tme_posix_tape_buffer_size; ! 129: tme_uint8_t *tme_posix_tape_buffer_data; ! 130: unsigned long tme_posix_tape_buffer_flags; ! 131: unsigned long tme_posix_tape_buffer_count_xfer; ! 132: }; ! 133: ! 134: /* this allocates the next control in the ring buffer: */ ! 135: struct tme_posix_tape_control * ! 136: _tme_posix_tape_control_new(struct tme_posix_tape *posix_tape) ! 137: { ! 138: int old_head; ! 139: struct tme_posix_tape_control *control; ! 140: ! 141: /* abort if the ring buffer overflows: */ ! 142: old_head = posix_tape->tme_posix_tape_control_head; ! 143: posix_tape->tme_posix_tape_control_head ! 144: = ((old_head ! 145: + 1) ! 146: & (TME_POSIX_TAPE_CONTROL_RING_SIZE ! 147: - 1)); ! 148: if ((posix_tape->tme_posix_tape_control_head ! 149: == posix_tape->tme_posix_tape_control_tail) ! 150: && (posix_tape->tme_posix_tape_connection ! 151: != NULL)) { ! 152: abort(); ! 153: } ! 154: ! 155: /* return the control: */ ! 156: control = &posix_tape->tme_posix_tape_controls[old_head]; ! 157: return (control); ! 158: } ! 159: ! 160: /* the posix tape callout function. it must be called with the mutex locked: */ ! 161: static void ! 162: _tme_posix_tape_callout(struct tme_posix_tape *posix_tape, ! 163: int new_callouts) ! 164: { ! 165: struct tme_tape_connection *conn_tape; ! 166: unsigned int old_tail; ! 167: struct tme_posix_tape_control *control; ! 168: int callouts, later_callouts; ! 169: int rc; ! 170: ! 171: /* add in any new callouts: */ ! 172: posix_tape->tme_posix_tape_callout_flags |= new_callouts; ! 173: ! 174: /* if this function is already running in another thread, simply ! 175: return now. the other thread will do our work: */ ! 176: if (posix_tape->tme_posix_tape_callout_flags ! 177: & TME_POSIX_TAPE_CALLOUT_RUNNING) { ! 178: return; ! 179: } ! 180: ! 181: /* callouts are now running: */ ! 182: posix_tape->tme_posix_tape_callout_flags ! 183: |= TME_POSIX_TAPE_CALLOUT_RUNNING; ! 184: ! 185: /* assume that we won't need any later callouts: */ ! 186: later_callouts = 0; ! 187: ! 188: /* loop while callouts are needed: */ ! 189: for (; ((callouts ! 190: = posix_tape->tme_posix_tape_callout_flags) ! 191: & TME_POSIX_TAPE_CALLOUTS_MASK); ) { ! 192: ! 193: /* clear the needed callouts: */ ! 194: posix_tape->tme_posix_tape_callout_flags ! 195: = (callouts ! 196: & ~TME_POSIX_TAPE_CALLOUTS_MASK); ! 197: callouts ! 198: &= TME_POSIX_TAPE_CALLOUTS_MASK; ! 199: ! 200: /* get the tape connection: */ ! 201: conn_tape = posix_tape->tme_posix_tape_connection; ! 202: ! 203: /* if we need to call out a control: */ ! 204: if (callouts & TME_POSIX_TAPE_CALLOUT_CONTROL) { ! 205: ! 206: /* there must be a control to call out: */ ! 207: old_tail = posix_tape->tme_posix_tape_control_tail; ! 208: assert (old_tail ! 209: != posix_tape->tme_posix_tape_control_head); ! 210: control ! 211: = &posix_tape->tme_posix_tape_controls[old_tail]; ! 212: ! 213: /* unlock the mutex: */ ! 214: tme_mutex_unlock(&posix_tape->tme_posix_tape_mutex); ! 215: ! 216: /* do the callout: */ ! 217: rc = TME_OK; ! 218: if (conn_tape != NULL) { ! 219: switch (control->tme_posix_tape_control_which) { ! 220: case TME_TAPE_CONTROL_LOAD: ! 221: case TME_TAPE_CONTROL_UNLOAD: ! 222: rc = ((*conn_tape->tme_tape_connection_control) ! 223: (conn_tape, ! 224: control->tme_posix_tape_control_which)); ! 225: break; ! 226: default: ! 227: rc = TME_OK; ! 228: assert(FALSE); ! 229: } ! 230: } ! 231: ! 232: /* lock the mutex: */ ! 233: tme_mutex_lock(&posix_tape->tme_posix_tape_mutex); ! 234: ! 235: /* if the callout was unsuccessful, remember that at some later ! 236: time this callout should be attempted again: */ ! 237: if (rc != TME_OK) { ! 238: later_callouts |= TME_POSIX_TAPE_CALLOUT_CONTROL; ! 239: } ! 240: ! 241: /* otherwise, this callout was successful: */ ! 242: else { ! 243: ! 244: /* advance the tail pointer: */ ! 245: posix_tape->tme_posix_tape_control_tail ! 246: = ((old_tail ! 247: + 1) ! 248: & (TME_POSIX_TAPE_CONTROL_RING_SIZE ! 249: - 1)); ! 250: ! 251: /* if there are more controls to callout, call them out now: */ ! 252: if (posix_tape->tme_posix_tape_control_tail ! 253: != posix_tape->tme_posix_tape_control_head) { ! 254: posix_tape->tme_posix_tape_callout_flags ! 255: |= TME_POSIX_TAPE_CALLOUT_CONTROL; ! 256: } ! 257: } ! 258: } ! 259: } ! 260: ! 261: /* put in any later callouts, and clear that callouts are running: */ ! 262: posix_tape->tme_posix_tape_callout_flags = later_callouts; ! 263: } ! 264: ! 265: /* this closes and frees all tape segments: */ ! 266: static void ! 267: _tme_posix_tape_segments_close(struct tme_posix_tape *posix_tape) ! 268: { ! 269: struct tme_posix_tape_segment *segment; ! 270: ! 271: /* while we have segments: */ ! 272: for (; posix_tape->tme_posix_tape_segments != NULL; ) { ! 273: ! 274: /* get the next segment and remove it from the list: */ ! 275: segment = posix_tape->tme_posix_tape_segments; ! 276: posix_tape->tme_posix_tape_segments = segment->tme_posix_tape_segment_next; ! 277: ! 278: /* if the segment file descriptor is open, close it: */ ! 279: if (segment->tme_posix_tape_segment_fd >= 0) { ! 280: close(segment->tme_posix_tape_segment_fd); ! 281: } ! 282: ! 283: /* free the segment filename: */ ! 284: tme_free(segment->tme_posix_tape_segment_filename); ! 285: ! 286: /* free the segment itself: */ ! 287: tme_free(segment); ! 288: } ! 289: ! 290: /* there is no current segment: */ ! 291: posix_tape->tme_posix_tape_segment_current = NULL; ! 292: } ! 293: ! 294: /* this unloads a tape: */ ! 295: static int ! 296: _tme_posix_tape_unload(struct tme_posix_tape *posix_tape) ! 297: { ! 298: ! 299: /* close and free all tape segments: */ ! 300: _tme_posix_tape_segments_close(posix_tape); ! 301: ! 302: return (TME_OK); ! 303: } ! 304: ! 305: /* this opens a tape segment and makes it the current segment: */ ! 306: static int ! 307: _tme_posix_tape_segment_open(struct tme_posix_tape *posix_tape, ! 308: struct tme_posix_tape_segment *segment) ! 309: { ! 310: ! 311: /* there is no current segment: */ ! 312: posix_tape->tme_posix_tape_segment_current = NULL; ! 313: ! 314: /* open the segment: */ ! 315: segment->tme_posix_tape_segment_fd ! 316: = open(segment->tme_posix_tape_segment_filename, ! 317: ((posix_tape->tme_posix_tape_flags & TME_POSIX_TAPE_FLAG_RO) ! 318: ? O_RDONLY ! 319: : O_RDWR)); ! 320: ! 321: /* if the open failed: */ ! 322: if (segment->tme_posix_tape_segment_fd < 0) { ! 323: return (errno); ! 324: } ! 325: ! 326: /* set the current segment: */ ! 327: posix_tape->tme_posix_tape_segment_current = segment; ! 328: return (TME_OK); ! 329: } ! 330: ! 331: /* this rewinds a tape: */ ! 332: static int ! 333: _tme_posix_tape_rewind(struct tme_posix_tape *posix_tape) ! 334: { ! 335: struct tme_posix_tape_segment *segment; ! 336: int rc; ! 337: ! 338: /* assume this will succeed: */ ! 339: rc = TME_OK; ! 340: ! 341: /* if there is a current segment and it's not the first ! 342: segment: */ ! 343: segment = posix_tape->tme_posix_tape_segment_current; ! 344: if (segment != NULL ! 345: && segment != posix_tape->tme_posix_tape_segments) { ! 346: ! 347: /* this must be a normal file: */ ! 348: assert (!segment->tme_posix_tape_segment_real_tape); ! 349: ! 350: /* if the segment is open, close it: */ ! 351: if (segment->tme_posix_tape_segment_fd >= 0) { ! 352: close(segment->tme_posix_tape_segment_fd); ! 353: segment->tme_posix_tape_segment_fd = -1; ! 354: } ! 355: } ! 356: ! 357: /* get the first segment: */ ! 358: segment = posix_tape->tme_posix_tape_segments; ! 359: ! 360: /* if this is a real tape: */ ! 361: if (segment->tme_posix_tape_segment_real_tape) { ! 362: ! 363: /* the tape must be open: */ ! 364: assert (segment->tme_posix_tape_segment_fd >= 0); ! 365: ! 366: /* XXX TBD */ ! 367: abort(); ! 368: } ! 369: ! 370: /* otherwise, this is a normal file: */ ! 371: else { ! 372: ! 373: /* if the file isn't open, open it, else ! 374: seek it to the beginning: */ ! 375: if (segment->tme_posix_tape_segment_fd < 0) { ! 376: rc = _tme_posix_tape_segment_open(posix_tape, ! 377: segment); ! 378: } ! 379: else { ! 380: if (lseek(segment->tme_posix_tape_segment_fd, ! 381: 0, SEEK_SET) != 0) { ! 382: rc = errno; ! 383: } ! 384: } ! 385: } ! 386: ! 387: return (rc); ! 388: } ! 389: ! 390: /* this skips file marks: */ ! 391: static int ! 392: _tme_posix_tape_mark_skip(struct tme_posix_tape *posix_tape, ! 393: unsigned int count, ! 394: int forward) ! 395: { ! 396: struct tme_posix_tape_segment *segment; ! 397: int rc; ! 398: ! 399: segment = posix_tape->tme_posix_tape_segment_current; ! 400: ! 401: /* if we are at end-of-media, or if we're skipping no marks, do ! 402: nothing: */ ! 403: if (segment == NULL ! 404: || count == 0) { ! 405: return (TME_OK); ! 406: } ! 407: ! 408: /* this segment must be a normal file: */ ! 409: assert (!segment->tme_posix_tape_segment_real_tape); ! 410: ! 411: /* if this segment is open, close it: */ ! 412: if (segment->tme_posix_tape_segment_fd >= 0) { ! 413: close(segment->tme_posix_tape_segment_fd); ! 414: segment->tme_posix_tape_segment_fd = -1; ! 415: } ! 416: ! 417: /* skip the marks: */ ! 418: for (; segment != NULL && count-- > 0; ) { ! 419: segment ! 420: = (forward ! 421: ? segment->tme_posix_tape_segment_next ! 422: : segment->tme_posix_tape_segment_prev); ! 423: } ! 424: ! 425: /* for now, if we are skipping in reverse we must have a segment - ! 426: what do we do otherwise? */ ! 427: assert (forward || segment != NULL); ! 428: ! 429: /* clear the active segment pointer: */ ! 430: posix_tape->tme_posix_tape_segment_current = NULL; ! 431: ! 432: /* if we have a segment, open it: */ ! 433: if (segment != NULL) { ! 434: rc = _tme_posix_tape_segment_open(posix_tape, ! 435: segment); ! 436: assert (rc == TME_OK); ! 437: } ! 438: ! 439: /* if we are skipping in reverse, we must leave the tape on the ! 440: beginning of media side of the file mark: */ ! 441: if (!forward) { ! 442: rc = (lseek(segment->tme_posix_tape_segment_fd, ! 443: 0, ! 444: SEEK_END) < 0); ! 445: assert (rc == 0); ! 446: } ! 447: ! 448: return (TME_OK); ! 449: } ! 450: ! 451: /* this finishes a transfer. it must be called with the mutex locked: */ ! 452: static int ! 453: _tme_posix_tape_xfer1(struct tme_posix_tape *posix_tape, ! 454: int *_flags, ! 455: unsigned long *_count_xfer, ! 456: unsigned long *_count_bytes, ! 457: int xfer_read) ! 458: { ! 459: struct tme_posix_tape_segment *segment; ! 460: unsigned long count_xfer, count_bytes_user, count_bytes_tape; ! 461: unsigned long xfer_factor, block_size; ! 462: long rc; ! 463: ! 464: /* assume that we will return no flags: */ ! 465: *_flags = 0; ! 466: ! 467: /* get the transfer count: */ ! 468: count_xfer = posix_tape->tme_posix_tape_buffer_count_xfer; ! 469: ! 470: /* get any forced block size: */ ! 471: block_size = posix_tape->tme_posix_tape_block_size_min; ! 472: if (block_size != posix_tape->tme_posix_tape_block_size_min) { ! 473: block_size = 0; ! 474: } ! 475: ! 476: /* if the request is for one or more blocks at a fixed block size: */ ! 477: if (posix_tape->tme_posix_tape_buffer_flags ! 478: & TME_TAPE_FLAG_FIXED) { ! 479: ! 480: /* the device must be in fixed block size mode: */ ! 481: xfer_factor = posix_tape->tme_posix_tape_block_size_fixed; ! 482: if (xfer_factor == 0) { ! 483: assert (block_size != 0); ! 484: xfer_factor = block_size; ! 485: } ! 486: else { ! 487: assert (block_size == 0 ! 488: || block_size == xfer_factor); ! 489: block_size = xfer_factor; ! 490: } ! 491: } ! 492: ! 493: /* otherwise, the request is for one block at a variable block size: */ ! 494: else { ! 495: ! 496: /* the device might be forcing a block size: */ ! 497: xfer_factor = 1; ! 498: if (block_size == 0) { ! 499: block_size = count_xfer; ! 500: } ! 501: } ! 502: ! 503: /* calculate the byte count for the user: */ ! 504: count_bytes_user = count_xfer * xfer_factor; ! 505: ! 506: /* calculate the byte count for the tape. this is ! 507: the byte count for the user rounded up to the ! 508: block size: */ ! 509: count_bytes_tape = count_bytes_user % block_size; ! 510: count_bytes_tape ! 511: = (count_bytes_user ! 512: + (count_bytes_tape ! 513: ? (block_size ! 514: - count_bytes_tape) ! 515: : 0)); ! 516: ! 517: /* get the current segment: */ ! 518: segment = posix_tape->tme_posix_tape_segment_current; ! 519: ! 520: /* if this is a read: */ ! 521: if (xfer_read) { ! 522: ! 523: /* if we are out of segments: */ ! 524: if (segment == NULL) { ! 525: ! 526: /* act like we read zero bytes: */ ! 527: rc = 0; ! 528: } ! 529: ! 530: /* otherwise, do the read: */ ! 531: else { ! 532: ! 533: /* do the read: */ ! 534: rc = read(segment->tme_posix_tape_segment_fd, ! 535: posix_tape->tme_posix_tape_buffer_data, ! 536: count_bytes_user); ! 537: ! 538: /* if this segment is not a real tape, and we're expected to ! 539: transfer more bytes than the user requested, seek over the ! 540: extra bytes, leaving the medium "positioned after the block": */ ! 541: if (!segment->tme_posix_tape_segment_real_tape ! 542: && count_bytes_tape > count_bytes_user) { ! 543: lseek(segment->tme_posix_tape_segment_fd, ! 544: (count_bytes_tape - count_bytes_user), ! 545: SEEK_CUR); ! 546: } ! 547: } ! 548: } ! 549: ! 550: /* otherwise, this is a write: */ ! 551: else { ! 552: ! 553: /* we must have a segment and it must be a real tape: */ ! 554: assert (segment != NULL ! 555: && segment->tme_posix_tape_segment_real_tape); ! 556: ! 557: /* do the write: */ ! 558: rc = write(segment->tme_posix_tape_segment_fd, ! 559: posix_tape->tme_posix_tape_buffer_data, ! 560: count_bytes_user); ! 561: } ! 562: ! 563: /* if the transfer got an error: */ ! 564: if (rc < 0) { ! 565: ! 566: /* return the error: */ ! 567: /* XXX is this sufficient? */ ! 568: *_count_bytes = 0; ! 569: *_count_xfer = 0; ! 570: return (errno); ! 571: } ! 572: ! 573: /* otherwise, we transferred some or none of the data: */ ! 574: else { ! 575: ! 576: /* return the final byte count: */ ! 577: *_count_bytes = rc; ! 578: ! 579: /* if the request was for one or more blocks at a fixed block size: */ ! 580: if (posix_tape->tme_posix_tape_buffer_flags ! 581: & TME_TAPE_FLAG_FIXED) { ! 582: ! 583: /* return the number of blocks successfully transferred: */ ! 584: *_count_xfer = (rc / xfer_factor); ! 585: } ! 586: ! 587: /* otherwise, the request is for one block at a variable block size: */ ! 588: else { ! 589: ! 590: /* return the actual size of the block transferred: */ ! 591: ! 592: /* if the user asked for what we thought was a whole block, but ! 593: we transferred less, how much we did transfer is the actual ! 594: block size: */ ! 595: if (count_bytes_user == block_size ! 596: && (unsigned long) rc < block_size) { ! 597: *_count_xfer = rc; ! 598: } ! 599: ! 600: /* otherwise, if this segment is a real tape, we don't know how ! 601: long the block really was. for now, we just return what we ! 602: are using as the block size: */ ! 603: /* XXX it may be possible to do an ioctl to get the true ! 604: residual: */ ! 605: else if (segment->tme_posix_tape_segment_real_tape) { ! 606: *_count_xfer = block_size; ! 607: } ! 608: ! 609: /* otherwise, this segment isn't a real tape, so we can return ! 610: what we are using as the block size: */ ! 611: else { ! 612: *_count_xfer = block_size; ! 613: } ! 614: } ! 615: ! 616: /* if we didn't read as much from the tape as we were supposed to: */ ! 617: if ((unsigned long) rc < count_bytes_tape) { ! 618: ! 619: /* if we read an exact multiple of the block size (including ! 620: zero blocks), the read was short because of a file mark. ! 621: return the mark (EOF) condition: */ ! 622: if ((rc % block_size) == 0) { ! 623: ! 624: /* return the mark condition: */ ! 625: *_flags |= TME_TAPE_FLAG_MARK; ! 626: ! 627: /* if this segment was not a real tape device, skip the file ! 628: mark - i.e., move to the next segment: */ ! 629: if (segment != NULL ! 630: && !segment->tme_posix_tape_segment_real_tape) { ! 631: rc = _tme_posix_tape_mark_skip(posix_tape, ! 632: 1, TRUE); ! 633: assert (rc == TME_OK); ! 634: } ! 635: } ! 636: ! 637: /* otherwise, the read was short because we read a partial ! 638: block. return the incorrect length indication (ILI) ! 639: condition: */ ! 640: else { ! 641: *_flags |= TME_TAPE_FLAG_ILI; ! 642: } ! 643: } ! 644: } ! 645: ! 646: return (TME_OK); ! 647: } ! 648: ! 649: /* this starts a transfer. it must be called with the mutex locked: */ ! 650: static int ! 651: _tme_posix_tape_xfer0(struct tme_posix_tape *posix_tape, ! 652: int flags, ! 653: unsigned long count_xfer, ! 654: unsigned long *_count_bytes) ! 655: { ! 656: unsigned long xfer_factor, count_bytes; ! 657: int old_flags; ! 658: unsigned long old_count_xfer, old_count_bytes; ! 659: int rc; ! 660: ! 661: /* if the buffer is dirty: */ ! 662: if (posix_tape->tme_posix_tape_flags ! 663: & TME_POSIX_TAPE_FLAG_DIRTY) { ! 664: ! 665: /* write out the buffer: */ ! 666: rc = _tme_posix_tape_xfer1(posix_tape, ! 667: &old_flags, ! 668: &old_count_xfer, ! 669: &old_count_bytes, ! 670: FALSE); ! 671: assert (rc == TME_OK); ! 672: ! 673: /* this buffer is no longer dirty: */ ! 674: posix_tape->tme_posix_tape_flags ! 675: &= ~TME_POSIX_TAPE_FLAG_DIRTY; ! 676: } ! 677: ! 678: /* set the parameters of this transfer: */ ! 679: posix_tape->tme_posix_tape_buffer_flags = flags; ! 680: posix_tape->tme_posix_tape_buffer_count_xfer = count_xfer; ! 681: ! 682: /* if the request is for one or more blocks at a fixed block size: */ ! 683: if (posix_tape->tme_posix_tape_buffer_flags ! 684: & TME_TAPE_FLAG_FIXED) { ! 685: ! 686: /* it is an error if the device isn't in fixed block size mode: */ ! 687: xfer_factor = posix_tape->tme_posix_tape_block_size_fixed; ! 688: if (xfer_factor == 0) { ! 689: xfer_factor = posix_tape->tme_posix_tape_block_size_min; ! 690: if (xfer_factor != posix_tape->tme_posix_tape_block_size_max) { ! 691: return (EINVAL); ! 692: } ! 693: } ! 694: } ! 695: ! 696: /* otherwise, the request is for one block at a variable block size: */ ! 697: else { ! 698: xfer_factor = 1; ! 699: } ! 700: ! 701: /* calculate the byte count: */ ! 702: count_bytes = count_xfer * xfer_factor; ! 703: ! 704: /* if the buffer isn't big enough: */ ! 705: if (posix_tape->tme_posix_tape_buffer_size ! 706: < count_bytes) { ! 707: ! 708: /* resize the buffer: */ ! 709: posix_tape->tme_posix_tape_buffer_size ! 710: = count_bytes; ! 711: posix_tape->tme_posix_tape_buffer_data ! 712: = tme_renew(tme_uint8_t, ! 713: posix_tape->tme_posix_tape_buffer_data, ! 714: posix_tape->tme_posix_tape_buffer_size); ! 715: } ! 716: ! 717: /* done: */ ! 718: *_count_bytes = count_bytes; ! 719: return (TME_OK); ! 720: } ! 721: ! 722: /* this releases the current buffer: */ ! 723: static int ! 724: _tme_posix_tape_release(struct tme_tape_connection *conn_tape, ! 725: int *_flags, ! 726: unsigned long *_count_xfer) ! 727: { ! 728: struct tme_posix_tape *posix_tape; ! 729: unsigned long count_bytes; ! 730: int rc; ! 731: ! 732: /* recover our data structure: */ ! 733: posix_tape = (struct tme_posix_tape *) conn_tape->tme_tape_connection.tme_connection_element->tme_element_private; ! 734: ! 735: /* assume that this call will succeed: */ ! 736: rc = TME_OK; ! 737: ! 738: /* lock the mutex: */ ! 739: tme_mutex_lock(&posix_tape->tme_posix_tape_mutex); ! 740: ! 741: /* if the buffer is dirty: */ ! 742: rc = TME_OK; ! 743: if (posix_tape->tme_posix_tape_flags ! 744: & TME_POSIX_TAPE_FLAG_DIRTY) { ! 745: ! 746: /* write out the buffer: */ ! 747: rc = _tme_posix_tape_xfer1(posix_tape, ! 748: _flags, ! 749: _count_xfer, ! 750: &count_bytes, ! 751: FALSE); ! 752: ! 753: /* this buffer is no longer dirty: */ ! 754: posix_tape->tme_posix_tape_flags ! 755: &= ~TME_POSIX_TAPE_FLAG_DIRTY; ! 756: } ! 757: ! 758: /* unlock the mutex: */ ! 759: tme_mutex_unlock(&posix_tape->tme_posix_tape_mutex); ! 760: ! 761: return (rc); ! 762: } ! 763: ! 764: /* this returns a read buffer: */ ! 765: static int ! 766: _tme_posix_tape_read(struct tme_tape_connection *conn_tape, ! 767: int *_flags, ! 768: unsigned long *_count_xfer, ! 769: unsigned long *_count_bytes, ! 770: const tme_uint8_t **_buffer) ! 771: { ! 772: struct tme_posix_tape *posix_tape; ! 773: int rc; ! 774: ! 775: /* recover our data structure: */ ! 776: posix_tape = (struct tme_posix_tape *) conn_tape->tme_tape_connection.tme_connection_element->tme_element_private; ! 777: ! 778: /* lock the mutex: */ ! 779: tme_mutex_lock(&posix_tape->tme_posix_tape_mutex); ! 780: ! 781: /* start the transfer: */ ! 782: rc = _tme_posix_tape_xfer0(posix_tape, ! 783: *_flags, ! 784: *_count_xfer, ! 785: _count_bytes); ! 786: *_buffer = posix_tape->tme_posix_tape_buffer_data; ! 787: ! 788: /* if the start succeeded, finish the transfer: */ ! 789: if (rc == TME_OK) { ! 790: rc = _tme_posix_tape_xfer1(posix_tape, ! 791: _flags, ! 792: _count_xfer, ! 793: _count_bytes, ! 794: TRUE); ! 795: } ! 796: ! 797: /* unlock the mutex: */ ! 798: tme_mutex_unlock(&posix_tape->tme_posix_tape_mutex); ! 799: ! 800: return (rc); ! 801: } ! 802: ! 803: /* this returns a write buffer: */ ! 804: static int ! 805: _tme_posix_tape_write(struct tme_tape_connection *conn_tape, ! 806: int flags, ! 807: unsigned long count_xfer, ! 808: unsigned long *_count_bytes, ! 809: tme_uint8_t **_buffer) ! 810: { ! 811: struct tme_posix_tape *posix_tape; ! 812: int rc; ! 813: ! 814: /* recover our data structure: */ ! 815: posix_tape = (struct tme_posix_tape *) conn_tape->tme_tape_connection.tme_connection_element->tme_element_private; ! 816: ! 817: /* lock the mutex: */ ! 818: tme_mutex_lock(&posix_tape->tme_posix_tape_mutex); ! 819: ! 820: /* start the transfer: */ ! 821: rc = _tme_posix_tape_xfer0(posix_tape, ! 822: flags, ! 823: count_xfer, ! 824: _count_bytes); ! 825: *_buffer = posix_tape->tme_posix_tape_buffer_data; ! 826: ! 827: /* unlock the mutex: */ ! 828: tme_mutex_unlock(&posix_tape->tme_posix_tape_mutex); ! 829: ! 830: return (rc); ! 831: } ! 832: ! 833: /* the tape control handler: */ ! 834: #ifdef HAVE_STDARG_H ! 835: static int _tme_posix_tape_control(struct tme_tape_connection *conn_tape, ! 836: unsigned int control, ! 837: ...) ! 838: #else /* HAVE_STDARG_H */ ! 839: static int _tme_posix_tape_control(conn_tape, control, va_alist) ! 840: struct tme_tape_connection *conn_tape; ! 841: unsigned int control; ! 842: va_dcl ! 843: #endif /* HAVE_STDARG_H */ ! 844: { ! 845: struct tme_posix_tape *posix_tape; ! 846: unsigned long *sizes; ! 847: const unsigned long *csizes; ! 848: unsigned int count; ! 849: va_list control_args; ! 850: int *_flags; ! 851: int rc; ! 852: ! 853: /* recover our data structure: */ ! 854: posix_tape = (struct tme_posix_tape *) conn_tape->tme_tape_connection.tme_connection_element->tme_element_private; ! 855: ! 856: /* lock the mutex: */ ! 857: tme_mutex_lock(&posix_tape->tme_posix_tape_mutex); ! 858: ! 859: /* start the variable arguments: */ ! 860: #ifdef HAVE_STDARG_H ! 861: va_start(control_args, control); ! 862: #else /* HAVE_STDARG_H */ ! 863: va_start(control_args); ! 864: #endif /* HAVE_STDARG_H */ ! 865: ! 866: /* dispatch on the sequence type: */ ! 867: switch (control) { ! 868: ! 869: case TME_TAPE_CONTROL_LOAD: ! 870: _flags = va_arg(control_args, int *); ! 871: *_flags = (posix_tape->tme_posix_tape_segments != NULL); ! 872: rc = TME_OK; ! 873: break; ! 874: ! 875: case TME_TAPE_CONTROL_UNLOAD: ! 876: rc = _tme_posix_tape_unload(posix_tape); ! 877: break; ! 878: ! 879: case TME_TAPE_CONTROL_MARK_WRITE: ! 880: abort(); ! 881: ! 882: case TME_TAPE_CONTROL_DENSITY_GET: ! 883: abort(); ! 884: ! 885: case TME_TAPE_CONTROL_DENSITY_SET: ! 886: abort(); ! 887: ! 888: case TME_TAPE_CONTROL_BLOCK_SIZE_GET: ! 889: sizes = va_arg(control_args, unsigned long *); ! 890: sizes[0] = posix_tape->tme_posix_tape_block_size_min; ! 891: sizes[1] = posix_tape->tme_posix_tape_block_size_max; ! 892: sizes[2] = posix_tape->tme_posix_tape_block_size_fixed; ! 893: rc = TME_OK; ! 894: break; ! 895: ! 896: case TME_TAPE_CONTROL_BLOCK_SIZE_SET: ! 897: csizes = va_arg(control_args, const unsigned long *); ! 898: ! 899: /* the minimum block size must be less than or equal to ! 900: the maximum block size: */ ! 901: if (csizes[0] > csizes[1]) { ! 902: return (EINVAL); ! 903: } ! 904: ! 905: /* if we aren't given a fixed block size: */ ! 906: if (csizes[2] == 0) { ! 907: ! 908: /* if the minimum and maximum block sizes are the same, ! 909: we are in fixed block size mode: */ ! 910: if (csizes[0] == csizes[1]) { ! 911: posix_tape->tme_posix_tape_block_size_fixed = csizes[0]; ! 912: } ! 913: ! 914: /* otherwise, we are not in fixed block size mode: */ ! 915: else { ! 916: posix_tape->tme_posix_tape_block_size_fixed = 0; ! 917: } ! 918: } ! 919: ! 920: /* otherwise, we are given a fixed block size. it must ! 921: be within the minimum and maximum block sizes: */ ! 922: else { ! 923: if (csizes[2] < csizes[0] ! 924: || csizes[2] > csizes[1]) { ! 925: return (EINVAL); ! 926: } ! 927: posix_tape->tme_posix_tape_block_size_fixed = csizes[2]; ! 928: } ! 929: ! 930: /* set the minimum and maximum block sizes: */ ! 931: posix_tape->tme_posix_tape_block_size_min = csizes[0]; ! 932: posix_tape->tme_posix_tape_block_size_max = csizes[1]; ! 933: rc = TME_OK; ! 934: break; ! 935: ! 936: case TME_TAPE_CONTROL_MARK_SKIPF: ! 937: case TME_TAPE_CONTROL_MARK_SKIPR: ! 938: count = va_arg(control_args, unsigned int); ! 939: rc = _tme_posix_tape_mark_skip(posix_tape, ! 940: count, ! 941: (control ! 942: == TME_TAPE_CONTROL_MARK_SKIPF)); ! 943: break; ! 944: ! 945: case TME_TAPE_CONTROL_REWIND: ! 946: rc = _tme_posix_tape_rewind(posix_tape); ! 947: break; ! 948: ! 949: default: ! 950: abort(); ! 951: } ! 952: ! 953: /* end the variable arguments: */ ! 954: va_end(control_args); ! 955: ! 956: /* unlock the mutex: */ ! 957: tme_mutex_unlock(&posix_tape->tme_posix_tape_mutex); ! 958: ! 959: return (rc); ! 960: } ! 961: ! 962: /* our internal command function: */ ! 963: static int ! 964: __tme_posix_tape_command(struct tme_posix_tape *posix_tape, ! 965: const char * const * args, ! 966: char **_output) ! 967: { ! 968: struct tme_posix_tape_segment *segment, **_prev; ! 969: struct tme_posix_tape_control *control; ! 970: struct stat statbuf; ! 971: int flags; ! 972: int arg_i; ! 973: int usage; ! 974: int rc; ! 975: int new_callouts; ! 976: ! 977: /* assume we won't need any new callouts: */ ! 978: new_callouts = 0; ! 979: ! 980: /* check the command: */ ! 981: usage = FALSE; ! 982: arg_i = 1; ! 983: ! 984: /* the "load" command: */ ! 985: if (TME_ARG_IS(args[arg_i], "load")) { ! 986: arg_i++; ! 987: ! 988: /* if a tape is currently loaded, it must be unloaded first: */ ! 989: if (posix_tape->tme_posix_tape_segments != NULL) { ! 990: tme_output_append_error(_output, ! 991: _("%s: tape already loaded; must unload first"), ! 992: args[0]); ! 993: return (EBUSY); ! 994: } ! 995: ! 996: /* check for flags, which must all come before the tape segment ! 997: filenames: */ ! 998: flags = 0; ! 999: for (;;) { ! 1000: ! 1001: /* the "read-only" flag: */ ! 1002: if (TME_ARG_IS(args[arg_i], "read-only")) { ! 1003: flags |= TME_POSIX_TAPE_FLAG_RO; ! 1004: arg_i++; ! 1005: } ! 1006: ! 1007: else { ! 1008: break; ! 1009: } ! 1010: } ! 1011: ! 1012: /* all of the remaining arguments must be tape segment filenames. ! 1013: assume that all segments open successfully: */ ! 1014: rc = TME_OK; ! 1015: ! 1016: /* open the tape segments: */ ! 1017: segment = NULL; ! 1018: posix_tape->tme_posix_tape_segments = NULL; ! 1019: for (_prev = &posix_tape->tme_posix_tape_segments; ! 1020: ; ! 1021: _prev = &segment->tme_posix_tape_segment_next) { ! 1022: ! 1023: /* stop if we're out of filenames: */ ! 1024: if (args[arg_i] == NULL) { ! 1025: break; ! 1026: } ! 1027: ! 1028: /* allocate a new tape segment and link it in: */ ! 1029: segment = tme_new0(struct tme_posix_tape_segment, 1); ! 1030: segment->tme_posix_tape_segment_filename ! 1031: = tme_strdup(args[arg_i]); ! 1032: segment->tme_posix_tape_segment_next = NULL; ! 1033: segment->tme_posix_tape_segment_prev = *_prev; ! 1034: *_prev = segment; ! 1035: ! 1036: /* open the segment file: */ ! 1037: segment->tme_posix_tape_segment_fd ! 1038: = open(segment->tme_posix_tape_segment_filename, ! 1039: O_RDONLY); ! 1040: if (segment->tme_posix_tape_segment_fd < 0) { ! 1041: rc = errno; ! 1042: break; ! 1043: } ! 1044: ! 1045: /* stat the segment file: */ ! 1046: if (fstat(segment->tme_posix_tape_segment_fd, ! 1047: &statbuf) < 0) { ! 1048: rc = errno; ! 1049: break; ! 1050: } ! 1051: ! 1052: /* if this is a block device: */ ! 1053: if (S_ISBLK(statbuf.st_mode)) { ! 1054: tme_output_append_error(_output, ! 1055: _("cannot use a block device: %s"), ! 1056: args[arg_i]); ! 1057: rc = EINVAL; ! 1058: break; ! 1059: } ! 1060: ! 1061: /* if this is a character device: */ ! 1062: else if (S_ISCHR(statbuf.st_mode)) { ! 1063: ! 1064: /* if this is not the only segment: */ ! 1065: if (posix_tape->tme_posix_tape_segments != segment ! 1066: || args[arg_i + 1] != NULL) { ! 1067: tme_output_append_error(_output, ! 1068: _("a real device must be the only tape segment: ")); ! 1069: rc = EINVAL; ! 1070: break; ! 1071: } ! 1072: ! 1073: /* this is a real tape: */ ! 1074: segment->tme_posix_tape_segment_real_tape = TRUE; ! 1075: } ! 1076: ! 1077: /* otherwise, this is a regular file: */ ! 1078: else { ! 1079: ! 1080: /* this tape must be read-only: */ ! 1081: flags |= TME_POSIX_TAPE_FLAG_RO; ! 1082: } ! 1083: ! 1084: /* if this is not the first segment, close the file: */ ! 1085: if (posix_tape->tme_posix_tape_segments != segment) { ! 1086: close(segment->tme_posix_tape_segment_fd); ! 1087: segment->tme_posix_tape_segment_fd = -1; ! 1088: } ! 1089: ! 1090: /* advance to the next segment filename: */ ! 1091: arg_i++; ! 1092: } ! 1093: ! 1094: /* if we got an error: */ ! 1095: if (rc != TME_OK) { ! 1096: ! 1097: /* append any segment filename to the error: */ ! 1098: if (segment != NULL) { ! 1099: tme_output_append_error(_output, ! 1100: "%s", ! 1101: segment->tme_posix_tape_segment_filename); ! 1102: } ! 1103: ! 1104: /* close and free the segments: */ ! 1105: _tme_posix_tape_segments_close(posix_tape); ! 1106: } ! 1107: ! 1108: /* otherwise, if we opened no segments: */ ! 1109: else if (posix_tape->tme_posix_tape_segments == NULL) { ! 1110: tme_output_append_error(_output, ! 1111: "%s %s load [read-only] { %s | %s [ .. %s ] }", ! 1112: _("usage:"), ! 1113: args[0], ! 1114: _("DEVICE"), ! 1115: _("FILENAME"), ! 1116: _("FILENAME")); ! 1117: rc = EINVAL; ! 1118: } ! 1119: ! 1120: /* otherwise, a tape has now been loaded: */ ! 1121: else { ! 1122: ! 1123: /* a tape has now been loaded: */ ! 1124: posix_tape->tme_posix_tape_flags ! 1125: = flags; ! 1126: ! 1127: /* the first segment is still open. make it the current segment: */ ! 1128: posix_tape->tme_posix_tape_segment_current ! 1129: = posix_tape->tme_posix_tape_segments; ! 1130: ! 1131: /* call out a LOAD control: */ ! 1132: control = _tme_posix_tape_control_new(posix_tape); ! 1133: control->tme_posix_tape_control_which = TME_TAPE_CONTROL_LOAD; ! 1134: new_callouts |= TME_POSIX_TAPE_CALLOUT_CONTROL; ! 1135: } ! 1136: } ! 1137: ! 1138: /* the "unload" command: */ ! 1139: else if (TME_ARG_IS(args[arg_i], "unload")) { ! 1140: ! 1141: /* if no tape is currently loaded: */ ! 1142: if (posix_tape->tme_posix_tape_segments == NULL) { ! 1143: tme_output_append_error(_output, ! 1144: _("%s: no tape loaded"), ! 1145: args[0]); ! 1146: return (ENXIO); ! 1147: } ! 1148: ! 1149: /* we must have no arguments: */ ! 1150: if (args[arg_i + 1] != NULL) { ! 1151: tme_output_append_error(_output, ! 1152: "%s %s unload", ! 1153: _("usage:"), ! 1154: args[0]); ! 1155: return (EINVAL); ! 1156: } ! 1157: ! 1158: /* unload the tape: */ ! 1159: _tme_posix_tape_unload(posix_tape); ! 1160: ! 1161: /* call out an UNLOAD control: */ ! 1162: control = _tme_posix_tape_control_new(posix_tape); ! 1163: control->tme_posix_tape_control_which = TME_TAPE_CONTROL_UNLOAD; ! 1164: new_callouts |= TME_POSIX_TAPE_CALLOUT_CONTROL; ! 1165: rc = TME_OK; ! 1166: } ! 1167: ! 1168: /* any other command: */ ! 1169: else { ! 1170: if (args[arg_i] != NULL) { ! 1171: tme_output_append_error(_output, ! 1172: "%s '%s', ", ! 1173: _("unknown command"), ! 1174: args[1]); ! 1175: } ! 1176: tme_output_append_error(_output, ! 1177: _("available %s commands: %s"), ! 1178: args[0], ! 1179: "load unload"); ! 1180: return (EINVAL); ! 1181: } ! 1182: ! 1183: /* make any new callouts: */ ! 1184: _tme_posix_tape_callout(posix_tape, new_callouts); ! 1185: ! 1186: return (rc); ! 1187: } ! 1188: ! 1189: /* our command function: */ ! 1190: static int ! 1191: _tme_posix_tape_command(struct tme_element *element, ! 1192: const char * const * args, ! 1193: char **_output) ! 1194: { ! 1195: struct tme_posix_tape *posix_tape; ! 1196: int rc; ! 1197: ! 1198: /* recover our data structure: */ ! 1199: posix_tape = (struct tme_posix_tape *) element->tme_element_private; ! 1200: ! 1201: /* lock the mutex: */ ! 1202: tme_mutex_lock(&posix_tape->tme_posix_tape_mutex); ! 1203: ! 1204: /* call the internal command function: */ ! 1205: rc = __tme_posix_tape_command(posix_tape, ! 1206: args, ! 1207: _output); ! 1208: ! 1209: /* unlock the mutex: */ ! 1210: tme_mutex_unlock(&posix_tape->tme_posix_tape_mutex); ! 1211: ! 1212: return (rc); ! 1213: } ! 1214: ! 1215: /* this breaks a posix tape connection: */ ! 1216: static int ! 1217: _tme_posix_tape_connection_break(struct tme_connection *conn, ! 1218: unsigned int state) ! 1219: { ! 1220: abort(); ! 1221: } ! 1222: ! 1223: /* this makes a posix tape connection: */ ! 1224: static int ! 1225: _tme_posix_tape_connection_make(struct tme_connection *conn, ! 1226: unsigned int state) ! 1227: { ! 1228: struct tme_posix_tape *posix_tape; ! 1229: struct tme_tape_connection *conn_tape; ! 1230: ! 1231: /* recover our data structure: */ ! 1232: posix_tape = (struct tme_posix_tape *) conn->tme_connection_element->tme_element_private; ! 1233: ! 1234: /* both sides must be tape connections: */ ! 1235: assert(conn->tme_connection_type == TME_CONNECTION_TAPE); ! 1236: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_TAPE); ! 1237: ! 1238: /* we're always set up to answer calls across the connection, ! 1239: so we only have to do work when the connection has gone full, ! 1240: namely taking the other side of the connection: */ ! 1241: if (state == TME_CONNECTION_FULL) { ! 1242: ! 1243: /* lock the mutex: */ ! 1244: tme_mutex_lock(&posix_tape->tme_posix_tape_mutex); ! 1245: ! 1246: /* save this connection to our list of connections: */ ! 1247: conn_tape = (struct tme_tape_connection *) conn->tme_connection_other; ! 1248: posix_tape->tme_posix_tape_connection = conn_tape; ! 1249: ! 1250: /* unlock the mutex: */ ! 1251: tme_mutex_unlock(&posix_tape->tme_posix_tape_mutex); ! 1252: } ! 1253: ! 1254: return (TME_OK); ! 1255: } ! 1256: ! 1257: /* this makes a new connection side for a posix tape: */ ! 1258: static int ! 1259: _tme_posix_tape_connections_new(struct tme_element *element, ! 1260: const char * const *args, ! 1261: struct tme_connection **_conns, ! 1262: char **_output) ! 1263: { ! 1264: struct tme_posix_tape *posix_tape; ! 1265: struct tme_tape_connection *conn_tape; ! 1266: struct tme_connection *conn; ! 1267: ! 1268: /* recover our data structure: */ ! 1269: posix_tape = (struct tme_posix_tape *) element->tme_element_private; ! 1270: ! 1271: /* if we already have a connection, there's nothing to do: */ ! 1272: if (posix_tape->tme_posix_tape_connection != NULL) { ! 1273: return (TME_OK); ! 1274: } ! 1275: ! 1276: /* create our side of a tape connection: */ ! 1277: conn_tape = tme_new0(struct tme_tape_connection, 1); ! 1278: conn = &conn_tape->tme_tape_connection; ! 1279: ! 1280: /* fill in the generic connection: */ ! 1281: conn->tme_connection_next = *_conns; ! 1282: conn->tme_connection_type = TME_CONNECTION_TAPE; ! 1283: conn->tme_connection_score = tme_tape_connection_score; ! 1284: conn->tme_connection_make = _tme_posix_tape_connection_make; ! 1285: conn->tme_connection_break = _tme_posix_tape_connection_break; ! 1286: ! 1287: /* fill in the tape connection: */ ! 1288: conn_tape->tme_tape_connection_read ! 1289: = _tme_posix_tape_read; ! 1290: conn_tape->tme_tape_connection_write ! 1291: = _tme_posix_tape_write; ! 1292: conn_tape->tme_tape_connection_release ! 1293: = _tme_posix_tape_release; ! 1294: conn_tape->tme_tape_connection_control ! 1295: = _tme_posix_tape_control; ! 1296: ! 1297: /* return the connection side possibility: */ ! 1298: *_conns = conn; ! 1299: return (TME_OK); ! 1300: } ! 1301: ! 1302: /* the new posix tape function: */ ! 1303: TME_ELEMENT_SUB_NEW_DECL(tme_host_posix,tape) { ! 1304: struct tme_posix_tape *posix_tape; ! 1305: int flags; ! 1306: int arg_i; ! 1307: int usage; ! 1308: ! 1309: /* check our arguments: */ ! 1310: flags = 0; ! 1311: arg_i = 1; ! 1312: usage = FALSE; ! 1313: ! 1314: /* loop reading our arguments: */ ! 1315: for (;;) { ! 1316: ! 1317: if (0) { ! 1318: } ! 1319: ! 1320: /* if we've run out of arguments: */ ! 1321: else if (args[arg_i + 0] == NULL) { ! 1322: ! 1323: break; ! 1324: } ! 1325: ! 1326: /* this is a bad argument: */ ! 1327: else { ! 1328: tme_output_append_error(_output, ! 1329: "%s %s", ! 1330: args[arg_i], ! 1331: _("unexpected")); ! 1332: usage = TRUE; ! 1333: break; ! 1334: } ! 1335: } ! 1336: ! 1337: if (usage) { ! 1338: tme_output_append_error(_output, ! 1339: "%s %s", ! 1340: _("usage:"), ! 1341: args[0]); ! 1342: return (EINVAL); ! 1343: } ! 1344: ! 1345: /* start the tape structure: */ ! 1346: posix_tape = tme_new0(struct tme_posix_tape, 1); ! 1347: posix_tape->tme_posix_tape_element = element; ! 1348: tme_mutex_init(&posix_tape->tme_posix_tape_mutex); ! 1349: posix_tape->tme_posix_tape_flags = flags; ! 1350: posix_tape->tme_posix_tape_segments = NULL; ! 1351: posix_tape->tme_posix_tape_segment_current = NULL; ! 1352: ! 1353: /* XXX these are fake values for now: */ ! 1354: posix_tape->tme_posix_tape_block_size_min = 512; ! 1355: posix_tape->tme_posix_tape_block_size_max = 32768; ! 1356: posix_tape->tme_posix_tape_block_size_fixed = 0; ! 1357: ! 1358: /* start the tape buffer. the 16384 isn't magic, it's just a ! 1359: starting point: */ ! 1360: posix_tape->tme_posix_tape_buffer_size = 16384; ! 1361: posix_tape->tme_posix_tape_buffer_data ! 1362: = tme_new(tme_uint8_t, ! 1363: posix_tape->tme_posix_tape_buffer_size); ! 1364: ! 1365: /* fill the element: */ ! 1366: element->tme_element_private = posix_tape; ! 1367: element->tme_element_connections_new = _tme_posix_tape_connections_new; ! 1368: element->tme_element_command = _tme_posix_tape_command; ! 1369: ! 1370: return (TME_OK); ! 1371: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.