From 1c3607e4d1f94869e7887568fb40d16bb0d2407d Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sun, 15 Feb 2009 18:17:54 +0100 Subject: Import mtx_1.3.12.orig.tar.gz [dgit import orig mtx_1.3.12.orig.tar.gz] --- CHANGES | 373 ++ COMPATABILITY | 163 + FAQ | 144 + LICENSE | 280 ++ LICENSE.html | 515 +++ Makefile.in | 176 + README | 38 + README.win32 | 45 + TODO | 15 + build.win32 | 15 + config.guess | 1500 ++++++++ config.h.in | 37 + config.sub | 1616 +++++++++ configure | 6545 ++++++++++++++++++++++++++++++++++ configure.in | 113 + contrib/MTX.html | 209 ++ contrib/README | 3 + contrib/TapeChanger-MTX-0.71b.tar.gz | Bin 0 -> 6179 bytes contrib/config_sgen_solaris.sh | 151 + contrib/mtx-changer | 431 +++ contrib/mtx.py | 306 ++ contrib/mtxctl-0.0.2.tar.gz | Bin 0 -> 5688 bytes contrib/qdback.tar.gz | Bin 0 -> 11072 bytes contrib/tapechanger.html | 209 ++ contrib/tapeinfo.py | 55 + contrib/tapeload.pl | 118 + contrib/tapeunload.pl | 98 + debian/bash_completion | 45 + debian/changelog | 159 + debian/compat | 1 + debian/control | 16 + debian/copyright | 15 + debian/dirs | 2 + debian/rules | 69 + du/defs.h | 25 + du/scsi.c | 214 ++ install-sh | 253 ++ loaderinfo.1 | 90 + loaderinfo.c | 510 +++ makedist | 19 + mam2debug.c | 124 + mam2debug2.c | 124 + msvc/config.h | 37 + msvc/loaderinfo/loaderinfo.vcproj | 205 ++ msvc/mtx.sln | 50 + msvc/mtx/Distributions.txt | 49 + msvc/mtx/mtx.vcproj | 247 ++ msvc/nsmhack/nsmhack.vcproj | 213 ++ msvc/scsieject/scsieject.vcproj | 203 ++ msvc/scsitape/scsitape.vcproj | 203 ++ msvc/tapeinfo/tapeinfo.vcproj | 213 ++ mtx.1 | 257 ++ mtx.c | 1075 ++++++ mtx.doc | 209 ++ mtx.h | 607 ++++ mtx.spec | 109 + mtx.spec.in | 109 + mtxl.README.html | 165 + mtxl.c | 1907 ++++++++++ mtxl.h | 109 + nsmhack.c | 342 ++ scsi_aix.c | 159 + scsi_freebsd.c | 116 + scsi_hpux.c | 134 + scsi_linux.c | 491 +++ scsi_sgi.c | 81 + scsi_sun.c | 156 + scsi_win32.c | 355 ++ scsieject.1 | 116 + scsieject.c | 255 ++ scsitape.1 | 179 + scsitape.c | 941 +++++ sg_err.c | 645 ++++ sg_err.h | 140 + tapeinfo.1 | 72 + tapeinfo.c | 969 +++++ vms/000readme | 175 + vms/build.com | 34 + vms/defs.h | 42 + vms/descrip.mms | 77 + vms/ldrset.c | 183 + vms/ldrset.cld | 9 + vms/ldrutil.mar | 104 + vms/scsi.c | 400 +++ 84 files changed, 26963 insertions(+) create mode 100644 CHANGES create mode 100644 COMPATABILITY create mode 100644 FAQ create mode 100644 LICENSE create mode 100644 LICENSE.html create mode 100644 Makefile.in create mode 100644 README create mode 100644 README.win32 create mode 100644 TODO create mode 100755 build.win32 create mode 100755 config.guess create mode 100644 config.h.in create mode 100755 config.sub create mode 100755 configure create mode 100755 configure.in create mode 100644 contrib/MTX.html create mode 100644 contrib/README create mode 100644 contrib/TapeChanger-MTX-0.71b.tar.gz create mode 100755 contrib/config_sgen_solaris.sh create mode 100755 contrib/mtx-changer create mode 100644 contrib/mtx.py create mode 100644 contrib/mtxctl-0.0.2.tar.gz create mode 100644 contrib/qdback.tar.gz create mode 100644 contrib/tapechanger.html create mode 100644 contrib/tapeinfo.py create mode 100644 contrib/tapeload.pl create mode 100644 contrib/tapeunload.pl create mode 100644 debian/bash_completion create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/dirs create mode 100755 debian/rules create mode 100644 du/defs.h create mode 100644 du/scsi.c create mode 100755 install-sh create mode 100644 loaderinfo.1 create mode 100644 loaderinfo.c create mode 100755 makedist create mode 100644 mam2debug.c create mode 100644 mam2debug2.c create mode 100644 msvc/config.h create mode 100644 msvc/loaderinfo/loaderinfo.vcproj create mode 100644 msvc/mtx.sln create mode 100644 msvc/mtx/Distributions.txt create mode 100644 msvc/mtx/mtx.vcproj create mode 100644 msvc/nsmhack/nsmhack.vcproj create mode 100644 msvc/scsieject/scsieject.vcproj create mode 100644 msvc/scsitape/scsitape.vcproj create mode 100644 msvc/tapeinfo/tapeinfo.vcproj create mode 100644 mtx.1 create mode 100644 mtx.c create mode 100644 mtx.doc create mode 100644 mtx.h create mode 100644 mtx.spec create mode 100644 mtx.spec.in create mode 100644 mtxl.README.html create mode 100644 mtxl.c create mode 100644 mtxl.h create mode 100644 nsmhack.c create mode 100644 scsi_aix.c create mode 100644 scsi_freebsd.c create mode 100644 scsi_hpux.c create mode 100644 scsi_linux.c create mode 100644 scsi_sgi.c create mode 100644 scsi_sun.c create mode 100644 scsi_win32.c create mode 100644 scsieject.1 create mode 100644 scsieject.c create mode 100644 scsitape.1 create mode 100644 scsitape.c create mode 100644 sg_err.c create mode 100644 sg_err.h create mode 100644 tapeinfo.1 create mode 100644 tapeinfo.c create mode 100644 vms/000readme create mode 100644 vms/build.com create mode 100644 vms/defs.h create mode 100644 vms/descrip.mms create mode 100644 vms/ldrset.c create mode 100644 vms/ldrset.cld create mode 100644 vms/ldrutil.mar create mode 100644 vms/scsi.c diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..aa5439c --- /dev/null +++ b/CHANGES @@ -0,0 +1,373 @@ +CHANGES, mtx 1.3.12 +- Incorporate debian packaging +- Remove strip of binaries +- Remove unsupported nsmhack from list of binaries built by default +- Add support for building outside of source tree +- Update copyrights +- Fix typo in mtx.1 man page +- Clear outstanding UNIT ATTENTION state at start + +CHANGES, mtx 1.3.11 +- loaderinfo: Print RequestSense information if an operation fails. +- loaderinfo: Print all information from the Device Configuration Page. +- mtx: Fix problems with a lot of loaders determining the number of elements. +- mtx: Implement Previous command. +- mtx: Fix bugs in Last command. +- scsieject: New tool that handles start/stop, load/unload. +- tapeinfo: Fix inconsistencies in output. +- Fix timeout handling on Linux. +- Merge in fixes from the Debian and FreeBSD distributions. + +CHANGES, mtx 1.3.10 +- Add support for Microsoft Windows. +- Add support for Sony VGP-XL1B(2) Media Changer. + Thanks to Will (nodenet at hotmail dot com) +- Add build support for Microsoft Windows using MinGW native and Linux + cross-compile. +- Add build support for Microsoft Windows using Microsoft Visual Studio 2005. +- Add support for building on x86_64. +- Add more debugging information. +- Eliminate compiler warnings. + +CHANGES, mtx 1.3.9 +- Cleaned up scsi_linux.c a little to eliminate around 40 lines of code. +- Change to using SG_IO ioctl rather than write-read interface. This + should make us a little safer, as well as (on 2.6.x) letting us issue SCSI + commands to regular block devices as well as to /dev/sgXX devices. + WARNING: Can cause the system to *CRASH* if the SCSI device is in use, due + to brokenness inside the Linux kernel! It's always preferable to use the + /dev/sgXX device, which has specialness in its buffer handling that bypasses + some of the brokenness elsewhere in the SCSI subsystem. +- Check SG version before using SG_IO interface, so that if we're run on a + Linux 2.2 system and we were compiled on Linux 2.4 or above, +- If a tape is in the drive, make tapeinfo print out its partition info. Seems + to work on my DAT drive, anyhow (shrug). +- Minor cleanups in mtxl.c (other cleanups necessary in tapeinfo and etc.). + +CHANGES, mtx 1.3.8 +- Forgot about 8 bytes for header +- Handle pedantic loader whose firmware writer spends too much time + parsing phrases in the SCSI spec and not enough time in the + real world. + +CHANGES, mtx 1.3.6 +- The You Gotta Be F'ing Kidding Release (see rant on mailing list) +- Added AIX support with http://fz.eryx.net/aix/ GSC driver, courtesy + of Steve Heck. +- Make __WEIRD_CHAR_SUPPRESS the default to stop barcode garbling +- Fix core dump on invalid inputs in mtx.c +- Add retry with bigger ALLOCATION_LENGTH if + BYTE_COUNT_OF_REPORT_AVAILABLE is > than our original estimate. (see rant + on mailing list). +- Shut up the low-level SCSI sg_read and sg_write routines, which were poofting + all over the place on innocuous things like no EAAP. + +CHANGES, mtx 1.3.5 +- The I-Need-A-Job Release (see http://badtux.org) :-} +- Change Makefile so that it works w/systems whose 'install' program + accepts only one argument. That's it. +- Uncomment the Exabyte hack in the drive parsing code so that it works + with ATL loaders again. +- Add hack for ATL stacked loaders to keep them from reporting ghost slots + +CHANGES, mtx 1.3.4 +- Forward-ported the ATL/Exabyte patches from mtx 1.2 +- Added progress indicator to 'tapeinfo' for DAT drives. (PLEASE TEST) +- Purged a few more estinc.com out of the documentation, point to bru.com. + +CHANGES, mtx 1.3.3 +- Reversed James' long descriptor patch until can figure out what's wrong with + it. +- Fixed some debug declarations, courtesy of Kevin Wang. +- Point COMPATIBILITY file at mtx.sourceforge.net. + +CHANGES, mtx 1.3.2 +- Merged Makefile changes from mtx-1.2 code +- Changes from James Dugal to get all info for newer loaders, fix debugging + +CHANGES, mtx 1.3.1 +- add an Exchange command + +CHANGES, mtx 1.3.0 +- New Linux SCSI subsystem interface for 2.4 kernels, ripped boldly + from sgtools by Doug Gilbert +- mtx 'next' now skips blank slots, courtesy of Christopher McCrory +- mtx 'unload' now prints an error message telling you that you need to + eject the tape in the drive prior to unloading it, under certain + conditions. +- Started work on 'nsmhack' for controlling NSM jukeboxes. +- copy_barcode was off by one. +- 'position to element' command now added, courtesy of Mahlon Stacy + +CHANGES, mtx 1.2.15: +- Some Solaris fixes, courtesy of Matt Ward +- Fix URL in .spec file + +CHANGES, mtx 1.2.14: +- Fix so it'll work if 0 is result of SCSI open (e.g., in cron jobs on Linux) +- Move changelog to end of .spec file for easier reading +- Added a bit of text to beginning of COMPATIBILITY file + +CHANGES, mtx 1.2.13: +- Fixed some autoloader bugs w/autoloaders that don't report an arm. +- Fixed barcode backoff. +- Added "nobarcode" option +- Increased timeout for 'mtx inventory' to 30 minutes + (note: may increase this even more if needed, please let me know!) +- Shortened timeout for 'mtx inquiry' to 30 seconds +- tapeinfo now prints SCSI ID/LUN info if available (only on Linux at the + moment, sigh). +- update documentation w/new email addresses, updated compile directions, + various fixes. + +CHANGES, mtx 1.2.12: +- Fix FreeBSD compile bugs +- Fix SGI compile bugs +- Add HP/UX port (I hope!), courtesy of William Smith. +- Re-wrote ReadElementStatus to make work for %!@# brain dead firmware that + reports non-existent drives (I hope!). Also has side-effect of now working + with multiple-arm libraries (though it only sees first arm!). +- Cleaned up all -Wall messages. +- Cleaned up Linux Sparc, installs loaderinfo.1, courtesy of Matt Dainty. +- tapeinfo now reports status of CheckUnitReady. +- tapeinfo no longer puts out Block Position if CheckUnitReady says 'no'. +- tapeinfo now puts out Density Code and Medium Type/Not Loaded (modification + of patches sent in by Bob Rahe) + +CHANGES, mtx 1.2.11: +- Added a GNU autoconf Makefile.in (still provide a Makefile for your use) + *WARNING* autoconf is not yet working on all supported OS's! You may need + to do the old-fashioned 'edit Makefile' bit! +- Changed mtx.h and mtxl.c to include and define various things based upon + what features autoconf detected (e.g., if 'camlib.h', use FreeBSD-style + 'cam', if 'scsi/sg.h' use Linux-style 'sg', etc.). If I ever port to a + Unix that has same SCSI interface as one of the existing ports, autoconf + will handle it without me having to add another set of #if's or #ifdefs. +- Went ahead and tossed mtxctl into contrib. +- In 'tapeinfo', skip \0 characters in serial numbers (some use \0 + terminator, some do not, skip it if this one does). +- in 'tapeinfo', dump out the block position and (if at BOP) the "BOP: Yes" + flag. Also dump out other info such as block limits. +- Put file 'sparc-patch1' contributed by Chaskiel M Grundman, and applied + it (sigh) +- Added tapeinfo.py to 'contrib' directory +- Updated mtx.py in 'contrib' directory +- Created 'loaderinfo' program to report some misc. info about loaders. +- Created 'scsitape' program so that I don't have to keep messing with + #@$%@! tape ioctls on the various Unixes that I'm porting tape software + to. (But see the warnings!). +- Applied the Solaris patch to the read_element_status command (sigh). +- Added timeout adjustment to the SCSI subsystem. +- WARNING: DIGITAL UNIX AND VMS ARE PROBABLY IRREPERABLY BROKEN, due to the + timeout changes to the SCSI subsystem. If anybody wishes to fix them, + feel free to send me patches. +- added contrib program "mtx-changer" (an Amanda tape changer script for + ?Solaris? that uses mtx rather than stc) +- Jiggered Linux SCSI module for smarter error conditions handling (there are + some error conditions that are normal for READ of tape drives). +- Added contrib program "config_sgen_solaris.sh" which should ease + setting up the 'sgen' driver on Solaris 8 (still no easy Solaris 7 or + below config). + +CHANGES, mtx 1.2.10: +- Added FAQ and COMPATIBILITY (feel free to send me patches to these files!) +- Added LICENSE +- Added serial number to 'tapeinfo' output. +- Fixed stupid syntax error in mtx.c (compiled with gcc, not with others!) +- Fixed spec file for building rpms (maybe). +- Added an 'erase' command (undocumented) for use on Linux for doing + short erases on tapes (the Linux device driver defaults to a long erase). +- Made mtx inventory return an error code if the inventory + fails, so that we can wait for inventory to be completed at system + startup for libraries that auto-inventory (sigh). + +CHANGES, mtx 1.2.9: +- Added an 'eject' command that, if directed to a tape drive, will eject the + tape, and for some autoloaders, if directed to LUN 1, will eject the entire + magazine. +- Fixed the 'transfer' command to be 1 based rather than 0 based (sigh) +- Now properly reports bar code for the tape that's in the tape drive. +- Added some miscellaneous Python and Perl scripts to 'contrib'. Thanks + to Frank Samuelson for the Perl scripts. + +CHANGES, mtx 1.2.8: +- Spec file has been changed to use the "portable" patch supplied by Red + Hat so it should work on Linux Alpha and Linux SPARC too... maybe... +- Now will accept 4-byte element status for most element types, despite fact + that these don't comply with SCSI standards :-(. This should make many + older changers work, including HP optical changers. +- Fixed PeripheralDeviceType table, courtesy of Rob Turk. +- Now looks for CHANGER environment variable if a device is not specified + on the command line. If can't find CHANGER, then tries TAPE environment + variable. +- Properly sets TransportElementAddress in the CDB for the MOVE MEDIUM command + with what was discovered via the READ_ELEMENT_STATUS command, rather + than setting them to zero (SCSI spec says that zero should be the default + arm, but at least one changer out there didn't like it). +- Added a '--version' command (sigh). +- Added an 'inventory' command for Breece Hill libraries that don't + automatically do an inventory at powerup. + +CHANGES, mtx 1.2.7: +- Fixed problem w/single drive Exabyte 220 reporting element status data for + both drives (sigh). +- some general cleanup in the barcode fallback code (what a cruft!). Discovered + that ADIC DAT AUTOCHANGER does not work w/mtx because it produces + gibberish (will apparently only produce one element status page per request). +- Fixed the RPM .spec file to have updated file locations, doc locations. +- Fixed MoveMedium to say 'Output' for direction, to make it work with + Solaris 8 +- Some changes to the Solaris low-level module to report more errors (though + it still doesn't work as well as the Linux low-level module). Should now + work properly with Solaris 2.6/7/8. (Solaris changes courtesy of Richard + Fish of Enhanced Software Technologies). + +CHANGES, mtx 1.2.6: +- Fixed 'eepos' stuff to use | rather than || (whoops!) +- Accept a 4-byte element descriptor for the robot arm for certain older + autochangers. + +CHANGES, mtx 1.2.5: +- Added 'noattach' command. If on command line prior to other commands, forces + them to use the regular SCSI changer API rather than the _ATTACHED API, + no matter what the _ATTACHED bit in the Inquiry page said. +- Created 'tapeinfo' program. + +CHANGES, mtx 1.2.4: +- Major overhaul of element guts to dynamically allocate the arrays + using the result of a MODE_SENSE on the Element Address Assignment + Page. If mtx 1.2.3 works for you and mtx 1.2.4 does NOT work for you, + please un-comment the '#define DEBUG_MODE_SENSE' in file 'mtxl.c' and + EMAIL me the results. + +CHANGES, mtx 1.2.3: +- Fixed the source storage element number stuff (again, sigh) +- Because of above fix, 'next' etc. ought to work right again. + +CHANGES, mtx 1.2.2: +- Fixed that it was saying everything was an Import/Export element (oops!) +- Properly update the Import/Export element count. + +CHANGES, mtx 1.2.1: +- Now explicitly output that a Storage element is in fact an Import/Export + element. +- Added 'transfer' command to transfer between two Storage elements (so that + you can get a tape to an Import/Export element. +- Added 'eepos' command for controlling tray retraction on the Breecehill + import/export trays. (Works with "load" and "unload" commands too, though + that is not documented on "mtx -h"). + +CHANGES, mtx 1.2.0: +- Re-numbered now that Leonard has asked me to take over maintenance of the + 'mtx' program. +- Temporarily treat Import/Export elements the same as Storage elements. Need + to fix this eventually so that the GUI knows what kind of element we're + talking about. +- Removed quotes from the source element # to make it easier to parse + from Perl or Python (just do a split on spaces). +- Added sample program, 'mam2debug', showing how to use mtxl library for + your own programs (this happens to dump the Exabyte Mammoth 2's internal + debug buffer to a file, using the Mammoth2-specific SCSI commands to do so). + +CHANGES, mtxl 1.4.8: +- Whoops, report logical rather than physical when I have to scan for + open slots :-). + +CHANGES, mtxl 1.4.7: +- Update comment to reflect mtxl 1.4.6 stuff :-). +- Fix the part of the code that scans for open slots as sources for media. + +CHANGES, mtxl 1.4.6: +- Don't use _ATTACHED interface if it reports itself as a Medium Changer! + +CHANGES, mtxl 1.4.5: +- Changed "whoops" compile error on Linux (teach me to release w/o testing on + the most popular platform!) +- Changed declarations to remove compile-time warnings. + +CHANGES, mtxl 1.4.4: +- Added support for FreeBSD. (uses pass device, NOT native FreeBSD ch device). +- Change all 'int' DeviceFD to DEVICE_TYPE DeviceFD. Note that SGI and FreeBSD + use a struct * to access the CAM SCSI layer, rather than a file fd. +- Fixed goof where I'd hard-wired max # of elements to 127 for testing + purposes (it should be sum of MAX_STORAGE_ELEMENTS + MAX_TRANSFER_ELEMENTS + + MAX_TRANSPORT_ELEMENTS from mtx.h -- change those if you need more + elements, bearing in mind that the code for ReadElementStatus in + mtxl.c maxes out at 255 elements unless you fix that too). +- Cleaned some cruft out of the MOVE_MEDIUM code. +- Must have GNU Make to process Makefile. In reality, I don't know of + any machine where we voluntarily use the native 'make' command, because + a) there's a half dozen native 'make' all with their own perverted + syntaxes, and b) most of them are brain dead beyond belief. + +CHANGES, mtxl 1.4.3: +- Do an INQUIRY prior to doing a MOVE_MEDIUM or READ_ELEMENT_STATUS so that I + can detect the MChanger bit and use MOVE_MEDIUM_ATTACHED or + READ_ELEMENT_STATUS_ATTACHED commands instead. +- Successfully tested with dual drives! +- first, next, last now working +- Created a man page +- Created a 'make install', edit Makefile to alter destinations. + +CHANGES, mtxl 1.4.2: +- Found the problem with the DAT changer! It was burping on the + 'bar code' bit... so I intercept that sense key, re-issue w/out the + 'bar code' bit, and success! +- Added a 'TODO' file... + +CHANGES, mtxl 1.4.1: +- Added 'invert' qualifier to 'load' and 'unload' commands to invert + the media (for HP optical jukeboxes). Type './mtx' by itself to + see the syntax. +- Figured out why my code wasn't properly detecting errors -- + turns out the 'sg' device can return ok + status even when there is sense data to be reported! +- Still to fix: *still* isn't working right with my Seagate + 6-tape DDS-4 DAT changer... also need to put the + second drive into the Exabyte 220 to make sure the dual-drive stuff + works properly (!). + +CHANGES, mtxl 1.4: +- Have now tested the barcode (volume tag) stuff. It works! (Well, there was +an index-by-one problem that I had to squash, but after that...) +- Changed to use SCSI Generic device API on Linux rather than +SCSI_IOCTL_SEND_COMMAND API, which cut things off at 4095 bytes on i386 +Linux. +- Added a bunch of debugging output that needs to be ripped out :-(. +Make sure you remove the -DDEBUG from the Makefile, and probably + -DLONG_PRINT_REQUEST_SENSE too (unless you LIKE sense results that make +sense!) +- Still have annoying bug on Linux of only reading 1st 16 bytes of sense +data. Alas, this appears to be a problem in the Linux 2.2 kernel, not in +anything that we're doing :-(. Hmm... cdrecord has the same problem, Mr. +Schilling says he's been saying it's a problem since 1997. Sigh. +- Still need to test the dual-drive stuff! + +CHANGES, mtxl 1.3: +- Hacked in the barcode (volume tag) stuff. NEED SOMEONE TO TEST +WHETHER IT WORKS! +- started issuing redundant initial READ_ELEMENT_STATUS with Allocation Length +of 8 in order to get a BYTE_COUNT_OF_REPORT_AVAILABLE in order to calculate a +better Allocation Length for the "real" READ_ELEMENT_STATUS. Trying to send a +query to a small 6-tape changer with an Allocation Length suited for a +200-element tape library was resulting in some errors and lockups on the +part of the tape changer device. +- first, last, next, previous are STILL broken. Sorry :-(. + +CHANGES, mtxl 1.2: + +- Changed many output messages to make them more easily parsed by +scripts written in awk/perl/python +- Extracted out a library of SCSI tape library routines usable by "C" +programs (must be GPL'ed). Extensive re-arranging of code. +- Added support for multiple drives. +- Started adding support for tape changers that use the "MCHangr" +bit rather than a separate ID or LUN. +- Increased limits so we could deal with LARGE tape libraries. +- Started adding support for barcode readers in said tape libraries +- broke first, last, next, previous. Sorry :-(. +- Added ability to chain commands on command line. Thus could say 'mtx -f +/dev/sg4 unload 4 0 load 7 0' to unload a tape from drive 0 and load the +tape in slot 7 into drive 0. + + diff --git a/COMPATABILITY b/COMPATABILITY new file mode 100644 index 0000000..e8cde0d --- /dev/null +++ b/COMPATABILITY @@ -0,0 +1,163 @@ +WARNING: THIS FILE IS OBSOLETE AND FOR HISTORICAL USE ONLY. Please +see http://mtx.sourceforge.net for a more up-to-date compatibility list. + +Operating Systems: +----------------- + +mtx 1.2 is currently known to work flawlessly under the following +operating systems: + +Linux (2.2.5 kernel and above) +FreeBSD (tested with versions 3.2 and above, but should work for all 3.x + and 4.x). + +Various people have reported that they have managed to make mtx work +on various versions of Solaris. Please check the mtx list archives ( +http://mtx.sourceforge.net ) to see how they've done it. + +IRIX 6.5 apparently works flawlessly: + +(Richard.Lefebvre(@AROBAS)cerca(.POINT)umontreal(.POINT)ca): +I just wanted to send you 1 or 2 comments on mtx. I just downloaded it +last friday to use with and SGI Origin2000 and an 8 slot DLT autoloader. +The whole thing compiled fine (under gcc). + +From Dan Wright (dtwright at uiuc dot uiuc.edu): + I just wanted to send an e-mail to let you know that mtx 1.2.9 + works great for me on IRIX 6.5 with an ADIC FastStor DLT8000. + IRIX 6.5 has a generic scsi interface installed by default, so to + access the autoloader I use "mtx -f /dev/scsi/sc1d1l0" (bus 1 id 1 + lun 0). + +---------------- +Changer Devices +---------------- +The following has been directly tested: + +* Exabyte 220 with 1 drive (21 slots) +* Exabyte 220 with 2 drives (21 slots) +* Exabyte EZ-17 (7 slots) + Known quirks: Must eject tape using 'mt' or 'tapectl' prior to using + the 'unload' command. + +* Seagate DDS-4 DAT AutoLoader (1 drive, 6 slots) + Product ID: 'DAT 06241-XXX' + Known quirks: Uses LUN 1 for robot. On Linux, must compile kernel with + "Scan SCSI LUNs" or add the following line to your /etc/lilo.conf (and + re-run /sbin/lilo): + append="max_scsi_luns=2" + +* DISC D-40 optical library (2 drives, 40 slots, 1 import/export): Yes, + it really does report that it's a Maxoptix! + Product Type: Medium Changer + Vendor ID: 'Maxoptix' + Product ID: 'MAXLYB ' + Revision: '3.04' + Attached Changer: No + +The following have been tested by others, and information may be +incomplete or in error even. + +* Compaq DLT Library 20/40, 1 drive 15 slots (antony at elizatravel dot com) + Vendor: HP Model: C5173-4000 + +* Vendor ID: 'ADIC ' (boris dot klug at ibs dash ag dot de) + Product ID: 'VLS DLT ' 7 slot 1 import/export 1 drive. + +* Unknown Overland changer (phreno at pacbell dot net): +> > > Vendor ID: 'OVERLAND' +> > > Product ID: 'LXB ' + +* "old Exabyte 10e tape loaders" (drew at pctc dot com) + +* Unknown HP DLT changer: (eric at collab dot net) +> > Storage Changer /dev/sgd:1 Drives, 15 Slots ( 0 Import/Export ) +> > Vendor ID: 'HP ' +> > Product ID: 'C5173-4000 ' + +* "Lago Sys LS-380L/StorageTek 9704/Imation ITL-2225 (mine's a + StorageTek labeled)" 25-slot, 2-drive, 1-arm, 1-import/export + (eswan at lips dot net) + +* HP SureStore Optical 80fx. (mmarchione at nyhomes dot org ) + Vendor: HP Model: C1160F Rev: 0.40 + Type: Medium Changer ANSI SCSI revision: 02 + +* Breece Hill tape library (unknown configuration, unknown reporter): + Vendor ID: 'BHTI' + Product ID: 'Q2 ' + Oddities: Must either turn on auto-inventory, or run 'mtx inventory' + prior to running any other mtx command. Reads bar codes by yanking + tapes out of slots and waving them in front of bar code reader, so + inventory of tapes with no bar code is VERY slow (bar code your tapes!). + + +* Seagate Scorpion DDS-3 4-tape autochanger + (jsled at normandy dot smarttouch dot com): + Vendor ID: 'ARCHIVE ' + Product ID: 'Python 04377-XXX' + +* Overland 15 tape 1 drive DLT changer: (asmith at umdgrb dot umd dot edu) + Vendor ID: 'OVERLAND' + Product ID: 'LXB ' + +* ADIC DAT AutoChanger -- 1 drive, 12 slots, 1 import-export: + Vendor ID: 'ADIC ' (andrew_gray at irobotics dot com) + Product ID: 'DAT AutoChanger ' + Quirks: firmware version 0357 does not appear to work w/mtx (request + from ADIC that they upgrade your firmeware to 0361, which does + seem to work), firmware version revision `0462` does work. Use + 'mtx inquiry' to detirmine which firmware you have. + +* HP 1/20 DLT loader: "We have a HP 1/20, but I think it's all the + same hardware. mtx works fine with it." (jo2y at midnightlinux dot com) + +* Exabyte 120 (116 slots, 4 tape drives): (wsb at paralleldata dot com) + Quirks: This loader does not properly support the loader slot assignment + page used to allocate element structures, so the #defines must be + changed in mtx.h for MAX_STORAGE_ELEMENTS, MAX_TRANSFER_ELEMENTS, and + MAX_TRANSPORT_ELEMENTS. May also need to increase the SCSI timeout to + do inventories. Takes a LONG time to do inventories if you don't have + bar codes! + +* Exabyte 210 (wsb at paralleldata dot com) + + +* Adic FastStor DLT4000 (7-Slot 1 drive): + Vendor ID: 'ADIC ' + Product ID: 'FastStor DLT ' + +* Ecrix AutoPak VXA (15-slot 1 drive) in configuration mode 0 (mark + at commerceengine dot com): + "This drive can be configured to emulate several types, but I've + only tested it in this one mode." + Vendor ID: 'SPECTRA ' + Product ID: '215 ' + Revision: '1008' + Attached Changer: No + SerialNumber: '023201' + +* ATL P1000 2 drive, 31 slot, 1 import/output: (dna plus mtx at clas.ufl.edu) + # ./mtx -f /dev/scsi/changer/c2t0d0 inquiry + Product Type: Medium Changer + Vendor ID: 'ATL ' + Product ID: 'P1000 6220070' + Revision: '2.01' + Attached Changer: No + +* NSM DVD Jukebox: + Storage Changer /dev/sg4:4 Drives, 561 Slots ( 1 Import/Export ) +Product Type: Medium Changer + Vendor ID: 'NSM ' + Product ID: 'NSM6000 ' + Revision: '1120' + Attached Changer: No + +* Spectralogic Treefrog/Bullfrog: + Storage Changer /dev/sg0:2 Drives, 15 Slots ( 0 Import/Export ) +Product Type: Medium Changer +Vendor ID: 'SPECTRA ' +Product ID: '10000 ' +Revision: 'X010' +Attached Changer: No + diff --git a/FAQ b/FAQ new file mode 100644 index 0000000..186242f --- /dev/null +++ b/FAQ @@ -0,0 +1,144 @@ +Frequently Asked Questions List, v 1.0.1 + +Index: + I. Compiling + II. Finding the correct device + III. Operational Issues + +Part I: Compiling. + +Q: Where is the Makefile in the tarball? +A: MTX now uses GNU Autoconf to generate the Makefile. Type "./configure" + while in the extracted mtx directory. + +Q: Typing 'make' gives me a bunch of errors in the Makefile. Why can't + you provide a Makefile that works? +A: Note that you need the GNU 'make'. The BSD 'make' won't work, and + Solaris 'make' probably won't work either. If you want a better + configuration and makefile system, write one, then EMAIL me the results -- + mtx is Open Source software and needs your code contributions to grow. + +Q: How do I compile for operating systems other than Linux? +A: MTX no longer needs you to edit the Makefile to compile for operating + systems other than Linux. Just type ./configure and go with it. + +Q: How do I port it to OS's other than the supported ones? +A: Create a new scsi_ module using one of the existing modules as an + example (scsi_freebsd.c might be a good model). Decide what symbol + you want #ifdef'ed in order to include that scsi_ module. Edit + mtxl.c to #include your scsi_ module. Edit the Makefile to add the + new target, including the -D needed to #include your new scsi_ module. + +********************************************************************* +Part II: Finding the correct device. + +Q: Why does this command not work?? + [root@Scotty mtxl-1.4.8]# ./mtx -f /dev/st0 inquiry + In /var/log/messages I see: + st0: Write not multiple of tape block size. +A: Note that mtx 1.2 and above use the SCSI GENERIC interface on Linux, + FreeBSD, and Solaris (at least). They do NOT use the tape device node. + +Q: When I do 'mtx -f /dev/sga inquiry' it shows + Product Type: Tape Drive + Vendor Id: HP + Product ID: C1553A + But when I do a 'mtx -f /dev/sga status' it fails. Why?! +A: You're trying to send a robotics command to a tape drive. You need + to send robotics commands to robotics devices, not to tape drives. Look in + /proc/scsi/scsi (Linux) or camcontrol (FreeBSD) to find out what the + robotics device is. It will be reported as a 'Medium Changer', not a + 'Sequential Access' or 'Tape Drive'. + +Q: When I do 'cat /proc/scsi/scsi' it shows only one device, the tape device! +A: You are using a DAT autochanger that has one SCSI ID but two LUN's, LUN 0 + and LUN 1. You need to compile a new kernel with SCAN SCSI LUNS enabled + or add this line to your /etc/lilo.conf (then run /sbin/lilo and reboot): + append="max_scsi_luns=2" + +Q: I'm tired of typing '-f /dev/sgc' all the time. How do I set a default + device that 'mtx' looks at? +A: Set the CHANGER environment variable. For example, with 'bash': + export CHANGER=/dev/sgc + +Q: I get "modprobe: can't locate module char-major-21" + syslog messages being squirreled away into a file on our syslog host, + and mtx doesn't work. What's the problem? +A: You need to compile SCSI generic support into your kernel (or as a module). + +Q: When I installed mtx, a message showed + up on the console stating that a scsi changer was found at + dev sgr. However, I have no device /dev/sgr. +A: On Linux, do 'mknod /dev/sgr c 21 19' to create a device node. By default + only 16 SCSI generic nodes are created, which might not be enough if + you have multiple SCSI controllers with lots of devices. + +****************************************************** +III. Operational issues: + +Q: I'm using Red Hat 7.0 and mtx works fine when I type ./mtx from the + command line, but when I use it from scripts I get the following: + mtx: Request Sense: Error Code=70 (Current) + mtx: Request Sense: Sense Key=Aborted Command + mtx: Request Sense: Additional Sense Code = 4E + mtx: Request Sense: Additional Sense Qualifier = 00 + What's happening? +A: Do "rpm -e mtx". Red Hat 7.0 includes a busted version of mtx. Your + script is apparently picking up the busted mtx in your path. Get rid + of the busted mtx, make sure that /usr/local/bin (or wherever you + put the "good" mtx) is in the path, and all should be well. + +Q: I get + # /usr/local/bin/mtx -f /dev/sgr status + mtx: Request Sense: Error Code=70 (Current) + mtx: Request Sense: Sense Key=Not Ready + mtx: Request Sense: Additional Sense Code = 04 + mtx: Request Sense: Additional Sense Qualifier = 8E + mtx: READ ELEMENT STATUS Command Failed + What gives? +A: Make sure your loader is in random mode, not sequential mode. + Most "real" loaders (as vs. DAT autoloaders) will not properly report + status information unless they are in "random" mode. + + +Q: I issue 'mtx load 5' and it loads tape 5. But when I try to put the tape + back in the magazine, we hit problems: + mtx: MOVE MEDIUM from Element Address 82 to 5 Failed + What gives? +A: Many loaders require you to first eject the tape (using 'mt' or 'tapectl') + before you issue an 'unload' command via 'mtx'. + +Q: My Breece Hill loader does not properly report its slots. +A: Either set the "auto-inventory" feature in the loader's control panel, + or run 'mtx inventory' prior to running 'mtx status'. + +Q: My Breece Hill loader takes a long time to do an inventory. mtx times + out and spits all over the place. Help! +A: Many loaders that support barcodes will perform poorly if you place tapes + into them without bar codes. Place bar codes on all your tapes and you + should be able to run 'mtx inventory' without that failure. + +Q: How do I eject the magazine of my autoloader? +A: Many low-end DAT autoloaders support the removable media 'EJECT' command + sent to the robotics device, even though it's not documented (or required) + in the SCSI standards. If the loader is at /dev/sgb, simply do + 'mtx -f /dev/sgb eject' and see what happens. (If nothing happens, + your autoloader doesn't support 'eject'). Some high-end libraries have + their own proprietary way for ejecting magazine trays, generally + involving abuse of the 'transfer' command and 'eepos' addendums, + but this is totally non-standard and undocumented. + +Q: Is there a standard for cleaning tape bar codes? +A: Many libraries, and many backup programs, expect cleaning tape bar + codes to start with "CLN". + +Q: How do I report a bug? +A: First, read this FAQ. Next, check the mtx list archives at + http://mtx.sourceforge.net to make sure that it's not already addressed + by somebody else. If your problem is still not solved, send + (to the mtx list) the following information: + Result of 'mtx inquiry' on the loader, + Result of 'mtx status' on the loader (minus a bunch of tapes if + it's a 50+ tape loader!), + Results of the operation that isn't working correctly. + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c7aea18 --- /dev/null +++ b/LICENSE @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/LICENSE.html b/LICENSE.html new file mode 100644 index 0000000..40bc73d --- /dev/null +++ b/LICENSE.html @@ -0,0 +1,515 @@ + + + +GNU General Public License - GNU Project - Free Software Foundation (FSF) + + + +

GNU General Public License

+ +

+


+ +

+ +

Table of Contents

+ + +

+ +


+ +

+ + + +

GNU GENERAL PUBLIC LICENSE

+

+Version 2, June 1991 + +

+ +
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+ + + +

Preamble

+ +

+ The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + +

+

+ When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +

+

+ To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +

+

+ For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + +

+

+ We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +

+

+ Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +

+

+ Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + +

+

+ The precise terms and conditions for copying, distribution and +modification follow. + +

+ + +

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+ + +

+ +0. + This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". +

+ +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + +

+ +1. + You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. +

+ +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. +

+ +2. + You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: +

+ +

+ +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. +

+ +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. +

+ +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +

+ +3. + You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + + + +

+ +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. +

+ +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. +

+ +4. + You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + +

+ +5. + You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +

+ +6. + Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +

+ +7. + If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. +

+ +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. +

+ +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. +

+ +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +

+ +8. + If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +

+ +9. + The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. +

+ +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + +

+ + +10. + If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + + +

NO WARRANTY

+ +

+ +11. + BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +

+ +12. + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +

+ + +

END OF TERMS AND CONDITIONS

+ + + +

How to Apply These Terms to Your New Programs

+ +

+ If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +

+

+ To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + +

+ +
+one line to give the program's name and an idea of what it does.
+Copyright (C) yyyy  name of author
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+ +

+Also add information on how to contact you by electronic and paper mail. + +

+

+If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + +

+ +
+Gnomovision version 69, Copyright (C) year name of author
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
+type `show w'.  This is free software, and you are welcome
+to redistribute it under certain conditions; type `show c' 
+for details.
+
+ +

+The hypothetical commands `show w' and `show c' should show +the appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and +`show c'; they could even be mouse-clicks or menu items--whatever +suits your program. + +

+

+You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + +

+ +
+Yoyodyne, Inc., hereby disclaims all copyright
+interest in the program `Gnomovision'
+(which makes passes at compilers) written 
+by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+
+ +

+This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +


+ +

+FSF & GNU inquiries & questions to +gnu@gnu.org. +send other questions to +gnu@gnu.org. +

+Copyright notice above.
+Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111, USA +

+


+ + diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..6b967cf --- /dev/null +++ b/Makefile.in @@ -0,0 +1,176 @@ +# WARNING -- THIS HAS BEEN RE-WRITTEN TO USE GNU MAKE. DO NOT +# TRY TO PROCESS THIS WITH A NORMAL MAKE! (FREEBSD GUYS, THIS MEANS +# USE GMAKE, NOT REGULAR BSD MAKE!) +# +# Valid targets: +# linux86 freebsd86 solarissparc sgi dec vms +# +# Makefile changes by Lars Kellogg-Stedman for better integration with +# GNU Autoconf. + +# Version # for 'make dist'... +VERSION=1.3.12 + +BINS = mtx@EXEEXT@ tapeinfo@EXEEXT@ loaderinfo@EXEEXT@ scsitape@EXEEXT@ scsieject@EXEEXT@ +EXTRA_BINS = nsmhack@EXEEXT@ +DBGS := $(BINS:%@EXEEXT@=%.dbg) +MAN = mtx.1 tapeinfo.1 loaderinfo.1 scsitape.1 scsieject.1 +MAN_HTML := $(MAN:%.1=%.html) +MAN_TXT := $(MAN:%.1=%.txt) + +TARGET = @TARGET@ +CPU = @CPU@ +CC = @CC@ +INSTALL = @INSTALL@ + +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ -DVERSION="\"$(VERSION)\"" -I$(srcdir) -I. +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +USE_OBJCOPY = @USE_OBJCOPY@ + +INSTALL_DOC = $(INSTALL) -m 644 +INSTALL_BIN = $(INSTALL) -m 755 +INSTALL_DIR = $(INSTALL) -m 755 -d + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +sbindir = @sbindir@ +mandir = @mandir@ +srcdir = @srcdir@ + +VPATH = $(srcdir) + +# +# Linux on x86... +# +ifeq ($(TARGET),linux) +CFLAGS += -Wall +CPPFLAGS += -DLONG_PRINT_REQUEST_SENSE=1 +endif + +ifeq ($(TARGET),mingw) +CFLAGS += -Wall +CPPFLAGS += -DLONG_PRINT_REQUEST_SENSE=1 +endif + +# +# FreeBSD +# +ifeq ($(TARGET),freebsd86) +CPPFLAGS += -DLONG_PRINT_REQUEST_SENSE=1 +LIBS += -lcam +endif + +ifeq ($(TARGET),hpux) +CFLAGS += -O -D_HPUX_SOURCE -D __hpux__ +endif + +# +# Solaris/SPARC +# +ifeq ($(TARGET),solarissparc) +CFLAGS += -O6 +endif + +# +# SGI IRIX +# +ifeq ($(TARGET),sgi) +CFLAGS += -O6 +LIBS += -lds +endif + +# +# Digital Unix +# +ifeq ($(TARGET),dec) +CFLAGS += -O +endif + +# +# OpenVMS (see vms/000readme) +# +ifeq ($(TARGET),vms) +See vms/000readme for information. +endif + +%.dbg : %@EXEEXT@ +ifeq ($(USE_OBJCOPY),yes) + objcopy --only-keep-debug $< $@ + objcopy --strip-debug $< + objcopy --add-gnu-debuglink=$@ $< +else + strip $< -o $@ +endif + +all: $(BINS) + +dbgs: $(DBGS) + +install: $(BINS) + $(INSTALL_DIR) $(sbindir) + for file in $(BINS); do \ + $(INSTALL_BIN) "$$file" $(sbindir) ; \ + done + $(INSTALL_DIR) $(mandir) $(mandir)/man1 + for file in mtx.1 tapeinfo.1 scsitape.1 scsieject.1 loaderinfo.1 ; do \ + $(INSTALL_DOC) "$$file" $(mandir)/man1 ; \ + done + +clean: + rm -f *.o *~ mtx-*.zip + rm -f $(BINS) + rm -f $(DBGS) + rm -f $(MAN_HTML) + rm -f $(MAN_TXT) + rm -f mam2debug@EXEEXT@ mam2debug2@EXEEXT@ + rm -rf autom4te.cache + +distclean: clean + rm -f Makefile config.h config.log config.cache config.status + +dist: distclean + ./makedist $(VERSION) + +loaderinfo@EXEEXT@: loaderinfo.o mtxl.o mtxl.h mtx.h $(EXTRA) + $(CC) $(LDFLAGS) -o loaderinfo@EXEEXT@ loaderinfo.o mtxl.o $(EXTRA) $(LIBS) + +nsmhack@EXEEXT@: nsmhack.o mtxl.o $(EXTRA) + $(CC) $(LDFLAGS) -o nsmhack@EXEEXT@ nsmhack.o mtxl.o $(EXTRA) $(LIBS) + +mtx@EXEEXT@: mtx.o mtxl.o mtxl.h mtx.h $(EXTRA) + $(CC) $(LDFLAGS) -o mtx@EXEEXT@ mtx.o mtxl.o $(EXTRA) $(LIBS) + +mam2debug@EXEEXT@: mtxl.o mam2debug.o mtx.h $(EXTRA) + $(CC) $(LDFLAGS) -o mam2debug@EXEEXT@ mtxl.o mam2debug.o $(EXTRA) $(LIBS) + +tapeinfo@EXEEXT@: tapeinfo.o mtxl.o mtx.h mtxl.h $(EXTRA) + $(CC) $(LDFLAGS) -o tapeinfo@EXEEXT@ tapeinfo.o mtxl.o $(EXTRA) $(LIBS) + +mam2debug2@EXEEXT@: mtxl.o mam2debug2.o mtx.h $(EXTRA) + $(CC) $(LDFLAGS) -o mam2debug2@EXEEXT@ mtxl.o mam2debug2.o $(EXTRA) $(LIBS) + +scsitape@EXEEXT@: scsitape.o mtxl.o mtxl.h mtx.h $(EXTRA) + $(CC) $(LDFLAGS) -o scsitape@EXEEXT@ scsitape.o mtxl.o $(EXTRA) $(LIBS) + +scsitape.o: scsitape.c mtx.h mtxl.h + +scsieject@EXEEXT@: scsieject.o mtxl.o mtxl.h mtx.h $(EXTRA) + $(CC) $(LDFLAGS) -o scsieject@EXEEXT@ scsieject.o mtxl.o $(EXTRA) $(LIBS) + +scsieject.o: scsieject.c mtx.h mtxl.h + +loaderinfo.o: loaderinfo.c mtx.h mtxl.h + +tapeinfo.o: tapeinfo.c mtx.h mtxl.h + +mam2debug.o: mam2debug.c mtx.h mtxl.h + +mam2debug2.o: mam2debug2.c mtx.h mtxl.h + +mtx.o: mtx.c mtx.h mtxl.h + +mtxl.o: mtxl.c mtx.h mtxl.h scsi_linux.c scsi_win32.c + +nsmhack.o: nsmhack.c mtxl.h mtx.h diff --git a/README b/README new file mode 100644 index 0000000..f81f6ca --- /dev/null +++ b/README @@ -0,0 +1,38 @@ +MTX + +Programs: + mtx is the media changer control program + tapeinfo dumps some interesting stuff out of tape drives' mode pages and +sense pages. + loaderinfo dumps some interesting stuff out of loaders' mode pages and +sense pages. + scsitape sends raw SCSI commands to tape drives. Do not use this unless +you know exactly what you're doing, because you can easily get into a feud +with the system's own tape driver and end up locking up the whole system. + +INSTALLATION: + +WARNING: MUST HAVE GNU 'make' TO DO THIS! (e.g. use 'gmake' on freebsd, not +BSD 'make'!). + +Type ./configure to create a Makefile. Type 'make', then 'make +install'. Type 'man mtx' for info about mtx, and 'man tapeinfo' for +info about tapeinfo. Enjoy. + +Credits: + +The original 'mtx' program is copyright 1996-1997 by Leonard Zubkoff +. This version was modified for multi-drive, +optical changer, and tape library support by Eric Lee Green +. Also added FreeBSD support. Please see the man page +for current info, and the file 'mtx.doc' for historical info. + +My thanks to Doug Bonnell of Breece Hill for suggestions on +dynamically allocating element info, Tien That Ton of Tandberg for +being the original tester of the Import/Export Element stuff, Ken +Porter for RPM's, William D. Smith for the HP/UX port, Kai Makisara +for the barcode backoff fix, and to all the other people out there who +have used it, found problems with it, and let me know about it (you +know who you are). + + -- Eric Lee Green diff --git a/README.win32 b/README.win32 new file mode 100644 index 0000000..cf8c39d --- /dev/null +++ b/README.win32 @@ -0,0 +1,45 @@ +BUILDING FOR MICROSOFT WINDOWS +============================== + +You can perform the build using either MinGW or Microsoft Visual Studio 2005. + + Microsoft Visual Studio 2005 + ---------------------------- + + Open the solution in msvc/mtx.sln. + + Select the Build / Build Solution menu item. + + + MinGW with GCC + -------------- + + You must be using at least version 2.16.91 of binutils. + + To generate the initial configure script, this only needs to be + done once. + + ./configure --host=mingw32 + make + +CHANGES FROM UNIX +================= + +The only difference is in the naming of devices. On Linux the changer is +accessed using /dev/sg, on Windows you use Changer. + +On Linux the tape drive is referenced using /dev/nst, on Windows you use Tape. + +There is one exception, in the case where there isn't a driver loaded for the device. +This is usually only the case on Windows 2000 or if the Windows XP or Windows Server +2003 system supplied driver has been disabled. + +In the case where there is no driver loaded you can access the device directly +through the SCSI driver using the following notation: + + ::: + + Port is the adapter number + Bus is the SCSI bus number relative to the adapter + Target is the SCSI device's target ID + LUN is the SCSI device's logical unit number diff --git a/TODO b/TODO new file mode 100644 index 0000000..4a7c757 --- /dev/null +++ b/TODO @@ -0,0 +1,15 @@ +1 Fix the big element descriptor overflow problem by adding a retry/reallocate + if things overflow. +1 Add a 'timeout' command to adjust the timeout (timeout will be in seconds!). +1 Add IES command (sets CDB[5] to something in routine Inventory() ). +1 Fix 'scsitape' READ and WRITE so that block counts work. +1 Add EXCHANGE command so that we can exchange media between slots in + NSM/DISC optical jukeboxes. +1 If moving media to/from import/export slot, try to do it even if the slot + reports that it's empty or full, this will let us stick our tongue out + on NSM/DISC optical jukeboxes for importing media. +2 Fix ports to other Unixes/VMS. +2 Add a range to 'mtx status' so that we request status only of + the elements we're interested in, rather than of all of them. + (nice for the very big loaders!). +3 Better Import/Export port support? diff --git a/build.win32 b/build.win32 new file mode 100755 index 0000000..5c2c00a --- /dev/null +++ b/build.win32 @@ -0,0 +1,15 @@ +manpages="mtx.1 tapeinfo.1 loaderinfo.1 scsitape.1 scsieject.1" +txtpages="mtx.txt tapeinfo.txt loaderinfo.txt scsitape.txt scsieject.txt" +htmlpages="mtx.html tapeinfo.html loaderinfo.html scsitape.html scsieject.html" + +./configure --host=mingw32 +make +make dbgs + +for i in $manpages +do + groff -et -Thtml -mandoc $i | col -b > `basename $i .1`.html + groff -et -Tascii -mandoc $i | col -b > `basename $i .1`.txt +done + +zip mtx-$1.zip README.win32 *.exe $htmlpages $txtpages diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..396482d --- /dev/null +++ b/config.guess @@ -0,0 +1,1500 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +# Inc. + +timestamp='2006-07-02' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + x86:Interix*:[3456]*) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T:Interix*:[3456]*) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..7282e46 --- /dev/null +++ b/config.h.in @@ -0,0 +1,37 @@ +/* Copyright 2001 Enhanced Software Technologies Inc. + * Released under GNU General Public License V2 or Above + * See http://www.gnu.org for more information about the terms of + * the GNU General Public License. + * $Date: 2007-02-13 08:45:31 -0800 (Tue, 13 Feb 2007) $ + * $Revision: 144 $ + */ + +#ifndef CONFIG_H +#define CONFIG_H 1 + +/* autoconf changes these. */ +#define HAVE_STRING_H 0 +#define HAVE_UNISTD_H 0 +#define HAVE_STDLIB_H 0 +#define HAVE_STDARG_H 0 +#define HAVE_SYS_PARAM_H 0 +#define HAVE_SCSI_SCSI_H 0 +#define HAVE_SCSI_SCSI_IOCTL_H 0 +#define HAVE_SCSI_SG_H 0 +#define HAVE_SYS_GSCDDS_H 0 +#define HAVE_CAMLIB_H 0 +#define HAVE_SYS_SCSI_IMPL_USCSI_H 0 +#define HAVE_SYS_SCSI_CTL_H 0 +#define HAVE_DSLIB_H 0 +#define HAVE_DU_DEFS_H 0 +#define HAVE_SYS_STAT_H 0 +#define HAVE_SYS_TYPES_H 0 +#define HAVE_FCNTL_H 0 +#define HAVE_SYS_IOCTL_H 0 +#define HAVE_SYS_MTIO_H 0 +#define HAVE_DDK_NTDDSCSI_H 0 + +#define WORDS_BIGENDIAN 0 + +#endif + diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..fab0aa3 --- /dev/null +++ b/config.sub @@ -0,0 +1,1616 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +# Inc. + +timestamp='2006-09-20' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 0000000..2e4bd13 --- /dev/null +++ b/configure @@ -0,0 +1,6545 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="mtx.c" +ac_default_prefix=/usr/local +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +build +build_cpu +build_vendor +build_os +host +host_cpu +host_vendor +host_os +target +target_cpu +target_vendor +target_os +TARGET +CPU +CC +CFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CC +EXEEXT +OBJEXT +INSTALL_PROGRAM +INSTALL_SCRIPT +INSTALL_DATA +USE_OBJCOPY +CPP +GREP +EGREP +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_config_headers="$ac_config_headers config.h" + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 +echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} + { (exit 1); exit 1; }; } + +{ echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6; } +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 +echo "$as_me: error: invalid value of canonical build" >&2;} + { (exit 1); exit 1; }; };; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6; } +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} + { (exit 1); exit 1; }; } +fi + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 +echo "$as_me: error: invalid value of canonical host" >&2;} + { (exit 1); exit 1; }; };; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ echo "$as_me:$LINENO: checking target system type" >&5 +echo $ECHO_N "checking target system type... $ECHO_C" >&6; } +if test "${ac_cv_target+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&2;} + { (exit 1); exit 1; }; } +fi + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_target" >&5 +echo "${ECHO_T}$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical target" >&5 +echo "$as_me: error: invalid value of canonical target" >&2;} + { (exit 1); exit 1; }; };; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + +case "$host_os" in + *linux*) cat >>confdefs.h <<\_ACEOF +#define LINUX 1 +_ACEOF + + TARGET=linux + ;; + *solaris*) cat >>confdefs.h <<\_ACEOF +#define SOLARIS 1 +_ACEOF + + TARGET=solarissparc + ;; + *sunos*) TARGET=solarissparc + ;; + *freebsd*) TARGET=freebsd86 + ;; + *aix*) TARGET=aix + ;; + *irix*) TARGET=sgi + ;; + *hp*) TARGET=hpux + ;; + *HP*) TARGET=hpux + ;; + *sequent*) cat >>confdefs.h <<\_ACEOF +#define SEQUENT 1 +_ACEOF + + ;; + *MINGW*) TARGET=mingw + ;; + *MinGW*) TARGET=mingw + ;; + *mingw*) TARGET=mingw + ;; + *) TARGET=$host_os + ;; +esac + +case "$host_cpu" in + # force us down to '386 if we're on some other machine. + *?86*) host_cpu='i386' + CPU=386 + ;; + *) CPU=$host_cpu; + ;; +esac + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +# Extract the first word of "objcopy", so it can be a program name with args. +set dummy objcopy; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_USE_OBJCOPY+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$USE_OBJCOPY"; then + ac_cv_prog_USE_OBJCOPY="$USE_OBJCOPY" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_USE_OBJCOPY="yes" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_USE_OBJCOPY" && ac_cv_prog_USE_OBJCOPY="no" +fi +fi +USE_OBJCOPY=$ac_cv_prog_USE_OBJCOPY +if test -n "$USE_OBJCOPY"; then + { echo "$as_me:$LINENO: result: $USE_OBJCOPY" >&5 +echo "${ECHO_T}$USE_OBJCOPY" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_GREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_GREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_EGREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_EGREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +for ac_header in \ + unistd.h \ + stdlib.h \ + errno.h \ + fcntl.h \ + stdarg.h \ + string.h \ + scsi/scsi.h \ + scsi/scsi_ioctl.h \ + scsi/sg.h \ + sys/gscdds.h \ + camlib.h \ + cam/cam_ccb.h \ + cam/scsi/scsi_message.h \ + sys/fsid.h \ + sys/fstyp.h \ + sys/stat.h \ + sys/types.h \ + sys/mnttab.h \ + sys/param.h \ + sys/time.h \ + sys/scsi/impl/uscsi.h \ + sys/scsi.h \ + sys/scsi_ctl.h \ + sys/ioctl.h \ + sys/mtio.h \ + sys/param.h \ + dslib.h \ + du/defs.h \ + ddk/ntddscsi.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6; } +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset cs; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_const=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6; } +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef size_t ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_size_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_size_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +echo "${ECHO_T}$ac_cv_type_size_t" >&6; } +if test $ac_cv_type_size_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for pid_t" >&5 +echo $ECHO_N "checking for pid_t... $ECHO_C" >&6; } +if test "${ac_cv_type_pid_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef pid_t ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_pid_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_pid_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5 +echo "${ECHO_T}$ac_cv_type_pid_t" >&6; } +if test $ac_cv_type_pid_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5 +echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6; } +if test "${ac_cv_header_time+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +if ((struct tm *) 0) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_time=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_time=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5 +echo "${ECHO_T}$ac_cv_header_time" >&6; } +if test $ac_cv_header_time = yes; then + +cat >>confdefs.h <<\_ACEOF +#define TIME_WITH_SYS_TIME 1 +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5 +echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6; } +if test "${ac_cv_struct_tm+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +struct tm tm; + int *p = &tm.tm_sec; + return !p; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_struct_tm=time.h +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_struct_tm=sys/time.h +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5 +echo "${ECHO_T}$ac_cv_struct_tm" >&6; } +if test $ac_cv_struct_tm = sys/time.h; then + +cat >>confdefs.h <<\_ACEOF +#define TM_IN_SYS_TIME 1 +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for int" >&5 +echo $ECHO_N "checking for int... $ECHO_C" >&6; } +if test "${ac_cv_type_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef int ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_int=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_int=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5 +echo "${ECHO_T}$ac_cv_type_int" >&6; } + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ echo "$as_me:$LINENO: checking size of int" >&5 +echo $ECHO_N "checking size of int... $ECHO_C" >&6; } +if test "${ac_cv_sizeof_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_int=$ac_lo;; +'') if test "$ac_cv_type_int" = yes; then + { { echo "$as_me:$LINENO: error: cannot compute sizeof (int) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (int) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } + else + ac_cv_sizeof_int=0 + fi ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } +static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (ac__type_sizeof_))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%ld\n", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%lu\n", i); + } + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_int=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +if test "$ac_cv_type_int" = yes; then + { { echo "$as_me:$LINENO: error: cannot compute sizeof (int) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (int) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } + else + ac_cv_sizeof_int=0 + fi +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5 +echo "${ECHO_T}$ac_cv_sizeof_int" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_INT $ac_cv_sizeof_int +_ACEOF + + +{ echo "$as_me:$LINENO: checking for long" >&5 +echo $ECHO_N "checking for long... $ECHO_C" >&6; } +if test "${ac_cv_type_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef long ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_long=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_long=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5 +echo "${ECHO_T}$ac_cv_type_long" >&6; } + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ echo "$as_me:$LINENO: checking size of long" >&5 +echo $ECHO_N "checking size of long... $ECHO_C" >&6; } +if test "${ac_cv_sizeof_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef long ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef long ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef long ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef long ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef long ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_long=$ac_lo;; +'') if test "$ac_cv_type_long" = yes; then + { { echo "$as_me:$LINENO: error: cannot compute sizeof (long) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (long) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } + else + ac_cv_sizeof_long=0 + fi ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef long ac__type_sizeof_; +static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } +static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (ac__type_sizeof_))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%ld\n", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%lu\n", i); + } + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_long=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +if test "$ac_cv_type_long" = yes; then + { { echo "$as_me:$LINENO: error: cannot compute sizeof (long) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (long) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } + else + ac_cv_sizeof_long=0 + fi +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5 +echo "${ECHO_T}$ac_cv_sizeof_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG $ac_cv_sizeof_long +_ACEOF + + +{ echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 +echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6; } +if test "${ac_cv_c_bigendian+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # See if sys/param.h defines the BYTE_ORDER macro. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN && defined LITTLE_ENDIAN \ + && BYTE_ORDER && BIG_ENDIAN && LITTLE_ENDIAN) + bogus endian macros +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + # It does; now see whether it defined to BIG_ENDIAN or not. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_bigendian=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_bigendian=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # It does not; compile a test program. +if test "$cross_compiling" = yes; then + # try to guess the endianness by grepping values into an object file + ac_cv_c_bigendian=unknown + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; +short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; +void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } +short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; +short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; +void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } +int +main () +{ + _ascii (); _ebcdic (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then + ac_cv_c_bigendian=yes +fi +if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=no +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 +echo "${ECHO_T}$ac_cv_c_bigendian" >&6; } +case $ac_cv_c_bigendian in + yes) + +cat >>confdefs.h <<\_ACEOF +#define WORDS_BIGENDIAN 1 +_ACEOF + ;; + no) + ;; + *) + { { echo "$as_me:$LINENO: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&5 +echo "$as_me: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} + { (exit 1); exit 1; }; } ;; +esac + + + + + +{ echo "$as_me:$LINENO: checking return type of signal handlers" >&5 +echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6; } +if test "${ac_cv_type_signal+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +return *(signal (0, 0)) (0) == 1; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_signal=int +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_signal=void +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5 +echo "${ECHO_T}$ac_cv_type_signal" >&6; } + +cat >>confdefs.h <<_ACEOF +#define RETSIGTYPE $ac_cv_type_signal +_ACEOF + + + +for ac_func in vprintf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +{ echo "$as_me:$LINENO: checking for _doprnt" >&5 +echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6; } +if test "${ac_cv_func__doprnt+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define _doprnt to an innocuous variant, in case declares _doprnt. + For example, HP-UX 11i declares gettimeofday. */ +#define _doprnt innocuous__doprnt + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _doprnt (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef _doprnt + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char _doprnt (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub__doprnt || defined __stub____doprnt +choke me +#endif + +int +main () +{ +return _doprnt (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_func__doprnt=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func__doprnt=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5 +echo "${ECHO_T}$ac_cv_func__doprnt" >&6; } +if test $ac_cv_func__doprnt = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DOPRNT 1 +_ACEOF + +fi + +fi +done + + + + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +build!$build$ac_delim +build_cpu!$build_cpu$ac_delim +build_vendor!$build_vendor$ac_delim +build_os!$build_os$ac_delim +host!$host$ac_delim +host_cpu!$host_cpu$ac_delim +host_vendor!$host_vendor$ac_delim +host_os!$host_os$ac_delim +target!$target$ac_delim +target_cpu!$target_cpu$ac_delim +target_vendor!$target_vendor$ac_delim +target_os!$target_os$ac_delim +TARGET!$TARGET$ac_delim +CPU!$CPU$ac_delim +CC!$CC$ac_delim +CFLAGS!$CFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CC!$ac_ct_CC$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim +INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim +INSTALL_DATA!$INSTALL_DATA$ac_delim +USE_OBJCOPY!$USE_OBJCOPY$ac_delim +CPP!$CPP$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 67; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + :H) + # + # CONFIG_HEADER + # +_ACEOF + +# Transform confdefs.h into a sed script `conftest.defines', that +# substitutes the proper values into config.h.in to produce config.h. +rm -f conftest.defines conftest.tail +# First, append a space to every undef/define line, to ease matching. +echo 's/$/ /' >conftest.defines +# Then, protect against being on the right side of a sed subst, or in +# an unquoted here document, in config.status. If some macros were +# called several times there might be several #defines for the same +# symbol, which is useless. But do not sort them, since the last +# AC_DEFINE must be honored. +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where +# NAME is the cpp macro being defined, VALUE is the value it is being given. +# PARAMS is the parameter list in the macro definition--in most cases, it's +# just an empty string. +ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' +ac_dB='\\)[ (].*,\\1define\\2' +ac_dC=' ' +ac_dD=' ,' + +uniq confdefs.h | + sed -n ' + t rset + :rset + s/^[ ]*#[ ]*define[ ][ ]*// + t ok + d + :ok + s/[\\&,]/\\&/g + s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p + s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p + ' >>conftest.defines + +# Remove the space that was appended to ease matching. +# Then replace #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +# (The regexp can be short, since the line contains either #define or #undef.) +echo 's/ $// +s,^[ #]*u.*,/* & */,' >>conftest.defines + +# Break up conftest.defines: +ac_max_sed_lines=50 + +# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" +# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" +# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" +# et cetera. +ac_in='$ac_file_inputs' +ac_out='"$tmp/out1"' +ac_nxt='"$tmp/out2"' + +while : +do + # Write a here document: + cat >>$CONFIG_STATUS <<_ACEOF + # First, check the format of the line: + cat >"\$tmp/defines.sed" <<\\CEOF +/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def +/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def +b +:def +_ACEOF + sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS + ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in + sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail + grep . conftest.tail >/dev/null || break + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines conftest.tail + +echo "ac_result=$ac_in" >>$CONFIG_STATUS +cat >>$CONFIG_STATUS <<\_ACEOF + if test x"$ac_file" != x-; then + echo "/* $configure_input */" >"$tmp/config.h" + cat "$ac_result" >>"$tmp/config.h" + if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f $ac_file + mv "$tmp/config.h" $ac_file + fi + else + echo "/* $configure_input */" + cat "$ac_result" + fi + rm -f "$tmp/out12" + ;; + + + esac + +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/configure.in b/configure.in new file mode 100755 index 0000000..10aa09d --- /dev/null +++ b/configure.in @@ -0,0 +1,113 @@ +dnl Copyright 2001 Enhanced Software Technologies Inc. +dnl Written Jan. 2001 Eric Lee Green + +dnl Process this file with autoconf to produce a configure script. +AC_INIT(mtx.c) +AC_CONFIG_HEADER(config.h) + +dnl Check system. +AC_CANONICAL_SYSTEM +AC_PREFIX_DEFAULT(/usr/local) + +case "$host_os" in + *linux*) AC_DEFINE(LINUX) + TARGET=linux + ;; + *solaris*) AC_DEFINE(SOLARIS) + TARGET=solarissparc + ;; + *sunos*) TARGET=solarissparc + ;; + *freebsd*) TARGET=freebsd86 + ;; + *aix*) TARGET=aix + ;; + *irix*) TARGET=sgi + ;; + *hp*) TARGET=hpux + ;; + *HP*) TARGET=hpux + ;; + *sequent*) AC_DEFINE(SEQUENT) + ;; + *MINGW*) TARGET=mingw + ;; + *MinGW*) TARGET=mingw + ;; + *mingw*) TARGET=mingw + ;; + *) TARGET=$host_os + ;; +esac +AC_SUBST(TARGET) +case "$host_cpu" in + # force us down to '386 if we're on some other machine. + *?86*) host_cpu='i386' + CPU=386 + ;; + *) CPU=$host_cpu; + ;; +esac + +AC_SUBST(CPU) + + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_INSTALL +AC_CHECK_PROG(USE_OBJCOPY, objcopy, yes, no) + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(\ + unistd.h \ + stdlib.h \ + errno.h \ + fcntl.h \ + stdarg.h \ + string.h \ + scsi/scsi.h \ + scsi/scsi_ioctl.h \ + scsi/sg.h \ + sys/gscdds.h \ + camlib.h \ + cam/cam_ccb.h \ + cam/scsi/scsi_message.h \ + sys/fsid.h \ + sys/fstyp.h \ + sys/stat.h \ + sys/types.h \ + sys/mnttab.h \ + sys/param.h \ + sys/time.h \ + sys/scsi/impl/uscsi.h \ + sys/scsi.h \ + sys/scsi_ctl.h \ + sys/ioctl.h \ + sys/mtio.h \ + sys/param.h \ + dslib.h \ + du/defs.h \ + ddk/ntddscsi.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T +AC_TYPE_PID_T +AC_HEADER_TIME +AC_STRUCT_TM +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) +AC_C_BIGENDIAN + + + +dnl Checks for library functions. +dnl AC_FUNC_ALLOCA + +AC_TYPE_SIGNAL +AC_FUNC_VPRINTF + +dnl Check for files + +AC_OUTPUT(Makefile) diff --git a/contrib/MTX.html b/contrib/MTX.html new file mode 100644 index 0000000..8ea9fce --- /dev/null +++ b/contrib/MTX.html @@ -0,0 +1,209 @@ + + +TapeChanger::MTX - use 'mtx' to manipulate a tape library + + + + + + + + + + + +
+

+

NAME

+

TapeChanger::MTX - use 'mtx' to manipulate a tape library

+

+


+

SYNOPSIS

+
+  use TapeChanger::MTX;
+
+  my $loaded = TapeChanger::MTX->loadedtape;
+  print "Currently loaded: $loaded\n" if ($loaded);
+
+  TapeChanger::MTX->loadtape('next');
+  my $nowloaded = TapeChanger::MTX->loadedtape; 
+  print "Currently loaded: $nowloaded\n" if ($nowloaded);
+
+
+
+See below for more available functions.
+

+


+

DESCRIPTION

+

TapeChanger::MTX is a module to manipulate a tape library using the 'mtx' +tape library program. It is meant to work with a simple shell/perl script +to load and unload tapes as appropriate, and to provide a interface for +more complicated programs to do the same. The below functions and +variables should do as good a job as explaining this as anything.

+

+


+

VARIABLES

+
+
$TapeChanger::MTX::MT +=item $TapeChanger::MTX::MTX
+
+What is the location of the 'mt' and 'mtx' binaries? Can be set with +'$MT' and '$MTX' in ~/.mtxrc, or defaults to '/usr/sbin/mt' and +'/usr/local/sbin/mtx'. +

+
$TapeChanger::MTX::DRIVE
+
+
$TapeChanger::MTX::CONTROL
+
+What are the names of the tape (DRIVE) and changer (CONTROL) device +nodes? Can be set with $DRIVE or $CONTROL in ~/.mtxrc, or default to +'/dev/rmt/0' and '/dev/changer' respectively. +

+
$TapeChanger::MTX::EJECT
+
+Does the tape drive have to eject the tape before the changer retrieves +it? It's okay to say 'yes' if it's not necessary, in most cases. Can be +set with $EJECT in ~/.mtxrc, or defaults to '1'. +

+
$TapeChanger::MTX::READY_TIME
+
+How long should we wait to see if the drive is ready, in seconds, after +mounting a volume? Can be set with $READY_TIME in ~/.mtxrc, or defaults +to 60. +

+
$TapeChanger::MTX::DEBUG
+
+Print debugging information? Set to '0' for normal verbosity, '1' for +debugging information, or '-1' for 'quiet mode' (be as quiet as possible). +

+

+


+

USAGE

+

This module uses the following functions:

+
+
tape_cmd ( COMMAND )
+
+
mt_cmd ( COMMAND )
+
+Runs 'mtx' and 'mt' as appropriate. COMMAND is the command you're +trying to send to them. Uses 'warn()' to print the commands to the screen +if $TapeChanger::MTX::DEBUG is set. +

+
numdrives ()
+
+
numslots ()
+
+
loadedtape ()
+
+Returns the number of drives, number of slots, and currently loaded tape +values, respectively, by parsing tape_cmd('status'). +

+
loadtape ( SLOT [, DRIVE] )
+
+Loads a tape into the tape changer, and waits until the drive is again +ready to be written to. SLOT can be any of the following (with the +relevant function indicated): +
+  current       C<loadedtape()>
+  prev          C<loadprevtape()>
+  next          C<loadnexttape()>
+  first         C<loadfirsttape()>
+  last          C<loadlasttape()>
+  0             C<_ejectdrive()>
+  1..99         Loads the specified tape number, ejecting whatever is
+                currently in the drive.
+

DRIVE is the drive to load, and defaults to 0. Returns 0 if +successful, an error string otherwise.

+

+
loadnexttape ()
+
+
loadprevtape ()
+
+
loadfirsttape ()
+
+
loadlasttape ()
+
+Loads the next, previous, first, and last tapes in the changer +respectively. Use tape_cmd('next'), tape_cmd('previous'), +tape_cmd('first'), and tape_cmd('last'), respectively. +

+
ejecttape ()
+
+Ejects the tape, by first ejecting the tape from the drive +(mt_cmd(rewind) then mt_cmd(offline)) and then returning it to its +slot (tape_cmd(unload)). Returns 1 if successful, 0 otherwise. +

+
resetchanger ()
+
+Resets the changer, ejecting the tape and loading the first one from the +changer. +

+
checkdrive ()
+
+Checks to see if the drive is ready or not, by waiting for up to +$TapeChanger::MTX::READY_TIME seconds to see if it can get status +information using mt_cmd(status). Returns 1 if so, 0 otherwise. +

+
reportstatus
+
+Returns a string containing the loaded tape and the drive that it's +mounted on. +

+
cannot_run ()
+
+Does some quick checks to see if you're actually capable of using this +module, based on your user permissions. Returns a list of problems if +there are any, 0 otherwise. +

+

+


+

NOTES

+

~/.mtxrc is automatically loaded when this module is used, if it exists, +using do(). This could cause security problems if you're trying to use +this with setuid() programs - so just don't do that. If you want someone +to have permission to mess with the tape drive and/or changer, let them +have that permission directly.

+

+


+

REQUIREMENTS

+

Perl 5.6.0 or better, an installed 'mtx' binary, and a tape changer and +reader connected to the system.

+

+


+

TODO

+

Support for Input/Export slots is not included, though it may be later. +Possibly works for multiple drives per changer, but I haven't tested it, +so I probably missed something. 'load previous' doesn't actually work, +because mtx doesn't support it (though the help says it does).

+

+


+

SEE ALSO

+

mtx, mt, tapechanger. Inspired by stc-changer, which comes +with the AMANDA tape backup package (http://www.amanda.org), and MTX, +available at http://mtx.sourceforge.net.

+

+


+

AUTHOR

+

Tim Skirvin <tskirvin@uiuc.edu>

+

+


+

COPYRIGHT

+

Copyright 2001-2002 by the University of Illinois Board of Trustees and +Tim Skirvin <tskirvin@ks.uiuc.edu>.

+ + + + diff --git a/contrib/README b/contrib/README new file mode 100644 index 0000000..832ee0a --- /dev/null +++ b/contrib/README @@ -0,0 +1,3 @@ +Everything in here is copyrighted by its original copyright holder. +The contents of this directory are not maintained as part of the 'mtx' +project, they are maintained by their original copyright holders. diff --git a/contrib/TapeChanger-MTX-0.71b.tar.gz b/contrib/TapeChanger-MTX-0.71b.tar.gz new file mode 100644 index 0000000..a42a2e0 Binary files /dev/null and b/contrib/TapeChanger-MTX-0.71b.tar.gz differ diff --git a/contrib/config_sgen_solaris.sh b/contrib/config_sgen_solaris.sh new file mode 100755 index 0000000..080c127 --- /dev/null +++ b/contrib/config_sgen_solaris.sh @@ -0,0 +1,151 @@ +#!/bin/sh +# Copyright 2001 Enhanced Software Technologies Inc. +# All Rights Reserved +# +# This software is licensed under the terms of the Free Software Foundation's +# General Public License, version 2. See http://www.fsf.org for more +# inforation on the General Public License. It is released for public use in +# the hope that others will find it useful. Please contact eric@estinc.com +# if you have problems. Also check out our backup products at +# http://www.estinc.com (grin). +# +# usage: config_sgen_solaris.sh check|[un]install +# +# This configures sgen under Solaris (we hope! :-). Note that this +# *CAN* do a reboot of the system. Do NOT call this function unless +# you are willing to let it do a reboot of the system! Also note that +# this *must* be run as user 'root', since it does highly grokety things. + + +mode="$1" +cvs upd +SGEN="/kernel/drv/sgen" +SGEN_CONF="/kernel/drv/sgen.conf" + +do_check() { + if test ! -f $SGEN_CONF; then + # sgen.conf not installed... + return 1 + fi + + changer_type_count=`grep "changer" $SGEN_CONF | grep -v "^#" | wc -l` + target_count=`grep "target=" $SGEN_CONF | grep -v "^#" | wc -l` + + if test $changer_type_count = 0 -o $target_count = 0; then + # sgen.conf not configured + return 1 + fi + + # sgen.conf installed, and configured + return 0 +} + +do_install() { + + # see if already installed + do_check + if test $? = 0; then + echo "sgen already configured, skipping" + return 0 # successfully installed (?) + fi + + if test ! -f $SGEN; then + echo "sgen driver not installed, aborting" + return 1 + fi + + echo "configuring sgen driver..." + + echo 'device-type-config-list="changer"; # BRU-PRO' >>$SGEN_CONF + target=0 + while test $target -le 15; do + echo "name=\"sgen\" class=\"scsi\" target=$target lun=0; # BRU-PRO" >>$SGEN_CONF + target=`expr $target + 1` + done + + echo "Attempting to reload driver..." + rem_drv sgen >/dev/null 2>&1 + add_drv sgen + if test "$?" != "0"; then + # failed + touch /reconfigure + echo "Driver was successfully configured, but could not be re-loaded." + echo "The system must be rebooted for the driver changes to take effect." + + ans="" + while test "$ans" = ""; do + printf "Do you want to reboot now (shutdown -g 1 -y -i 6)? [Y/n] " + read ans + + if test "$ans" = "Y"; then + ans="y" + fi + + if test "$ans" = "N"; then + ans="n" + fi + + if test "$ans" != "y" -a "$ans" != "n"; then + echo "Please enter 'y' or 'n'" + ans="" + fi + done + + if test "$ans" = "y"; then + shutdown -g 1 -y -i 6 + # will be killed by reboot... + while true; do + echo "Waiting for reboot..." + sleep 300 + done + fi + + # not rebooted, exit with error + return 2 + fi + + # successful + return 0 +} + +do_uninstall() { + do_check + if test $? = 1; then + echo "sgen not configured, skipping" + return 0 # successfully uninstalled (?) + fi + + printf "removing BRU-PRO configuration from $SGEN_CONF..." + grep -v "# BRU-PRO" $SGEN_CONF > ${SGEN_CONF}.$$ || return 1 + cat ${SGEN_CONF}.$$ >${SGEN_CONF} || return 1 + rm -f ${SGEN_CONF}.$$ >/dev/null || return 1 + printf "done\n" + + touch /reconfigure + printf "Devices will be reconfigured at next reboot.\n" + return 0 +} + +uname | grep SunOS >/dev/null 2>&1 +if test $? != 0; then + echo "$0: not on Solaris, ABORT!" + exit 99 +fi + +case "$mode" in + check) + do_check + ;; + install) + do_install + ;; + uninstall) + do_uninstall + ;; + *) + echo "usage: $0 check|[un]install" + exit 1 + ;; +esac + +exit $? \ No newline at end of file diff --git a/contrib/mtx-changer b/contrib/mtx-changer new file mode 100755 index 0000000..cf68ddd --- /dev/null +++ b/contrib/mtx-changer @@ -0,0 +1,431 @@ +#! /bin/sh +############################################################################### +# AMANDA Tape Changer script for use with the MTX tape changer program +# Version 1.0 - Tue Feb 20 13:59:39 CST 2001 +# +# Based on 'stc-changer' by Eric Berggren (eric@ee.pdx.edu) +# Updated by Tim Skirvin (tskirvin@ks.uiuc.edu) +# +# Given that there's no license...let's make this the Perl Artistic License. +# Just make sure you give me and Eric credit if you modify this. +############################################################################### + +### USER CONFIGURATION +# Name of the tape drive (takes place of "tapedev" option in amanda.conf) +# and default driver number in library (usu 0) that DRIVE_NAME points to +DRIVE_NAME="/dev/rmt/0n" +DRIVE_NUM=0 + +# Location of "STC" command and control device +MTX_CMD="/usr/local/sbin/mtx"; +MTX_CONTROL="/dev/scsi/changer/c4t1d0"; + +# Whether tape drive must eject tape before changer retrieves +# (ie, EXB-2x0). Usually okay if set while not necessary, bad if +# required but not set. +DRIVE_MUST_EJECT=1 + +# How long to check drive readiness (in seconds) after mounting (or +# ejecting) a volume (on some libraries, the motion or eject command may +# complete before the drive has the volume fully mounted and online, +# or ready for retrieval, resulting in "Drive not ready"/"Media not +# ready" errors). Do an "mt status" command every 5 seconds upto this +# time. +DRIVE_READY_TIME_MAX=120 + +# tape "mt" command location... +MT_CMD="/usr/bin/mt" # called via "MT_CMD -f DRIVE_NAME rewind" & + # "MT_CMD -f DRIVE_NAME offline" to eject + # and "MT_CMD -f DRIVE_NAME status" to get ready info + +############################################################################## +# +NumDrives=-1 +NumSlots=-1 +LastSlot=-1 +LoadedTape=-1 + +# +# Usage information +# +usage() +{ + echo + echo "Usage: $Progname [arg...]" + echo " -info reports capability and loaded tape" + echo " -slot loads specified tape into drive" + echo " current reports current mounted tape" + echo " next loads logically next tape (loops to top)" + echo " prev loads logically previous tape (loops to bot)" + echo " first loads first tape" + echo " last loads last tape" + echo " 0..99 loads tape from specified slot#" + echo " -eject uloads current mounted tape" + echo " -reset resets changer (and drive); loads first tape" + echo + exit 5 +} + +# +# Perform "stc" changer command (& handle the "fatal" errors) +# else, set 'CommandResStr' and 'CommandRawResStr' to the result string +# and 'CommandResCode' to the exit code +# +dotapecmd() +{ + cmd=$1 + arg=$2 + + CommandResStr=`$MTX_CMD $MTX_CONTROL $cmd $arg 2>&1` + CommandRawResStr=$CommandResStr + CommandResCode=$? + + CommandResStr=`echo $CommandResStr | head -1 | sed 's/^[^:]*: //'` + if [ $CommandResCode -gt 1 ]; then + echo "0 $Progname: returned $CommandResStr" + exit 2 + fi +} + +# +# Unload tape from drive (a drive command; "ejecttape" is a changer command +# to actually retrieve the tape). Needed by some changers (controlled by +# setting "DRIVE_MUST_EJECT") +# +ejectdrive() +{ + # Tell drive to eject tape before changer retrieves; req'd by some + # drives (ie, EXB-2x0). Not needed by QDLT-4x00. Do a "rewind" + # command first, then "offline" to eject (instead of "rewoffl") + # + if [ "$DRIVE_MUST_EJECT" -ne 0 ]; then + mtresstr=`$MT_CMD -f $DRIVE_NAME rewind 2>&1` + mtrescode=$? + + if [ $mtrescode -ne 0 ]; then + if echo "$mtresstr" | egrep -s 'no tape'; then + :; # no tape mounted; assume okay... + else + # can't eject tape, bad; output: reason + echo "0 $mtresstr" + exit 1 + fi + else + mtresstr=`$MT_CMD -f $DRIVE_NAME offline 2>&1` + mtrescode=$? + + checkdrive 1 + fi + fi +} + +# +# Check drive readiness after (un)mounting a volume (which may take a while +# after the volume change command completes) +# +checkdrive() +{ + unmounting=$1 + + if [ "$DRIVE_READY_TIME_MAX" -gt 0 ]; then + + # sleep time between checks + pausetime=5 + + # number of interations to check + numchecks=`expr $DRIVE_READY_TIME_MAX / $pausetime` + if [ "$numchecks" -eq 0 ]; then + numchecks=1 + fi + + # check until success, or out of attempts... + while [ "$numchecks" -gt 0 ]; do + mtresstr=`$MT_CMD -f $DRIVE_NAME status 2>&1` + mtrescode=$? + + if [ $mtrescode -eq 0 ]; then + # Success ? + return 0 + else + # pause, before trying again.... + if [ "$numchecks" -gt 1 ]; then + sleep $pausetime + + # if unmounting a volume, check for 'mt' command + # failure; (sleep first for additional comfort) + if [ "$unmounting" -ne 0 ]; then + return 0 + fi + fi + fi + numchecks=`expr $numchecks - 1` + done + + # failed; output: -1 reason + echo "-1 drive won't report ready" + exit 1 + fi +} + +# +# Get changer parameters +# +getchangerparms() +{ + dotapecmd status + if [ $CommandResCode -eq 0 ] && \ + echo "$CommandResStr" | egrep -s '^Storage Changer'; then + + NumDrives=`echo $dspec | wc -l` + NumDrives=`echo "$CommandRawResStr" | \ + grep 'Data Transfer Element' | wc -l` + if [ "$NumDrives" -le "$DRIVE_NUM" ]; then + echo "$Program: Invalid drive # specified ($DRIVE_NUM > $NumDrives)" + exit 3 + fi + # grep 'Data Transfer Element $DRIVE_NUM' | \ + LoadedTape=`echo "$CommandRawResStr" | \ + grep 'Data Transfer Element' | \ + grep 'Storage Element [0-9]' | \ + awk '{ print $7 }' ` + if [ -z "$LoadedTape" -o "$LoadedTape" = "e" ]; then + LoadedTape=-1 + fi + NumSlots=`echo "$CommandRawResStr" | \ + grep 'Storage Element [0-9]\{1,\}:' | \ + grep -v 'Data Element' | \ + wc -l | sed -e 's/ //g' ` + LastSlot=`expr $NumSlots - 1` + else + echo \ + "$Progname: Can't get changer parameters; Result was $CommandResStr" + exit 3 + fi +} + +# +# Display changer info +# +changerinfo() +{ + getchangerparms + + # output status string: currenttape numslots randomaccess? + echo "$LoadedTape $NumSlots 1" + exit 0 +} + +# +# Eject current mounted tape +# +ejecttape() +{ + getchangerparms + ct=$LoadedTape + + # If no tape reported mounted, assume success (could be bad if changer + # lost track of tape) + # + if [ $ct -lt 0 ]; then + CommandResCode=0 + else + ejectdrive + dotapecmd unload + fi + + if [ $CommandResCode -ne 0 ]; then + # failed; output: reason + echo "$ct $CommandResStr" + exit 1 + else + # success; output: drive + echo "$ct $DRIVE_NAME" + exit 0 + fi +} + +# +# Move specified tape into drive (operation level) +# +doloadtape() +{ + slot=$1 + if [ "$slot" -eq "$LoadedTape" ]; then + return 0 + fi + ejectdrive + dotapecmd load $slot + return $CommandResCode +} + +# +# Load next available tape into drive +# +loadnexttape() +{ + curslot=$1 + direction=$2 + + startslot=$curslot + while true; do + if doloadtape $curslot; then + return 0 + else + if echo $CommandResStr | egrep -s 'Slot.*reported empty'; then + + if [ "$direction" -lt 0 ]; then + curslot=`expr $curslot - 1` + if [ "$curslot" -lt 0 ]; then + curslot=$LastSlot + fi + else + curslot=`expr $curslot + 1` + if [ "$curslot" -gt "$LastSlot" ]; then + curslot=0 + fi + fi + + # Check if we're back to where we started... + if [ "$curslot" = "$startslot" ]; then + if [ "$direction" -lt 0 ]; then + CommandResStr="No previous volume available" + else + CommandResStr="No subsequent volume available" + fi + return 1 + fi + else + return 1 + fi + fi + done +} + +# +# Report loadtape() status +# +reportstatus() +{ + if [ $CommandResCode -eq 0 ]; then + # success; output currenttape drivename + echo "$LoadedTape $DRIVE_NAME" + exit 0 + else + # failed (empty slot?); output currenttape reason + echo "$LoadedTape $CommandResStr" + exit 1 + fi +} + + +# +# Move specified tape into drive (command level) +# +loadtape() +{ + slot=$1 + + getchangerparms + + case "$slot" in + current) + if [ $LoadedTape -lt 0 ]; then + CommandResStr="Can't determine current tape; drive empty ?" + CommandResCode=1 + fi + ;; + prev) + if [ $LoadedTape -le 0 ]; then + loadnexttape $LastSlot -1 + else + loadnexttape `expr $LoadedTape - 1` -1 + fi + ;; + next) + if [ $LoadedTape -ge $LastSlot -o $LoadedTape -lt 0 ]; then + loadnexttape 0 1 + else + loadnexttape `expr $LoadedTape + 1` 1 + fi + ;; + first) + loadnexttape 0 1 + ;; + last) + loadnexttape $LastSlot -1 + ;; + [0-9]*) + doloadtape $slot + ;; + *) + # error; no valid slot specified + echo "$Progname: No valid slot specified" + exit 1 + ;; + esac + + if [ $CommandResCode -eq 0 ]; then + getchangerparms + checkdrive + fi + reportstatus +} + +# +# Reset changer to known state +# +resetchanger() +{ + ejectdrive + dotapecmd reset + if [ $CommandResCode -ne 0 ]; then + # failed; output: failed? reason + echo "-1 $CommandResStr" + exit 2; + else + loadtape first + fi +} + +############################################################################# +# +# MAIN +# +Progname=`basename $0` + +if [ ! -x "$MTX_CMD" ]; then + echo "-1 $Progname: cannot run STC command ($MTX_CMD)" + exit 2 +fi +if [ -n "$MTX_CONTROL" ]; then + if echo "$MTX_CONTROL" | egrep -s '^-f'; then + :; + else + MTX_CONTROL="-f $MTX_CONTROL" + fi +fi +if [ -n "$DRIVE_NUM" ]; then + DRIVE_NUM=0 +fi + +if [ $# -ge 1 ]; then command=$1; else command="-usage"; fi + +case "$command" in + -info) + changerinfo + ;; + -slot) + loadtape $2 + ;; + -eject) + ejecttape + ;; + -reset) + resetchanger + ;; + *) + usage + ;; +esac + +exit 0 diff --git a/contrib/mtx.py b/contrib/mtx.py new file mode 100644 index 0000000..1e60c15 --- /dev/null +++ b/contrib/mtx.py @@ -0,0 +1,306 @@ +# Copyright 2000 Enhanced Software Technologies Inc. +# Released under Free Software Foundation's General Public License, +# Version 2 or above +# +# This is an example of how to parse the 'mtx' output from a scripting +# language. +# +# Routine to call 'mtx' and read status, or +# whatever. +# +# We do this here rather than creating a Python "C" module because: +# 1) Reduces complexity of compile environment +# 2) Easier debugging. +# 3) More in keeping with the Unix philosophy of things. +# 4) Easier to add new functionality. +# +# + +import string +import os +import time # we can do some waiting here... + +def readpipe(command): + result="" + + infile=os.popen(command,"r") + + try: + s=infile.read() + except: + s="" + pass + if not s: + return None # didn't get anything :-(. + result=result+s + return result + + + + +# these are returned by the mtx.status routine: +class slotstatus: + def __init__(self,slotnum,middle,barcode=None): + middle=string.strip(middle) + try: + left,right=string.split(middle," ") + except: + left=middle + right=None + pass + # Note: We will not be able to test this at the moment since the + # 220 has no import/export port! + if right=="IMPORT/EXPORT": + self.importexport=1 + else: + self.importexport=0 + pass + self.slotnum=int(slotnum) # make sure it's an integer... + if left=="Full": + self.full=1 + else: + self.full=None + pass + if not barcode: + self.voltag=None + else: + l=string.split(barcode,"=",1) + self.voltag=l[1] + pass + return + pass + +# Drive status lines have this format: +#Data Transfer Element 0:Full (Storage Element 10 Loaded):VolumeTag = B0000009H +#Data Transfer Element 1:Empty + +class drivestatus: + def __init__(self,slotnum,middle,barcode=None): + self.slotnum=slotnum + if middle=="Empty": + self.full=None + self.origin=None + self.voltag=None + return + else: + self.full=1 + pass + + # okay, we know we have a tape in the drive. + # split and find out our origin: we will always have + # an origin, even if the #$@% mtx program had to dig one + # out of the air: + + l=string.split(middle," ") + self.origin=int(l[3]) + + if not barcode: + self.voltag=None # barcode of this element. + else: + l=string.split(barcode," ") + self.voltag=string.strip(l[2]) + pass + return + pass + +# This is the return value for mtx.status. +class mtxstatus: + def __init__(self): + self.numdrives=None + self.numslots=None + self.numexport=None + self.drives=[] # a list of drivestatus instances. + self.slots=[] # a list of slotstatus instances + self.export=[] # another list of slotstatus instances + return + pass + +# call 'mtx' and get barcode info, if possible: +# okay, we now have a string that consists of a number of lines. +# we want to explode this string into its component parts. +# Example format: +# Storage Changer /dev/sgd:2 Drives, 21 Slots +# Data Transfer Element 0:Full (Storage Element '5' Loaded) +# Data Transfer Element 1:Empty +# Storage Element 1:Full :VolumeTag=CLNA0001 +# Storage Element 2:Full :VolumeTag=B0000009 +# Storage Element 3:Full :VolumeTag=B0000010 +# .... +# What we want to do, then, is: +# 1) Turn it into lines by doing a string.split on newline. +# 2) Split the 1st line on ":" to get left and right. +# 3) Split the right half on space to get #drives "Drives," #slots +# 4) process the drives (Full,Empty, etc.) +# 5) For each of the remaining lines: Split on ':' +# 6) Full/Empty status is in 2) +# +configdir="/opt/brupro/bin" # sigh. + +def status(device): + retval=mtxstatus() + command="%s/mtx -f %s status" % (configdir,device) + result=readpipe(command) + if not result: + return None # sorry! + # now to parse: + + try: + lines=string.split(result,"\n") + except: + return None # sorry, no status! + + # print "DEBUG:lines=",lines + + try: + l=string.split(lines[0],":") + except: + return None # sorry, no status! + + # print "DEBUG:l=",l + leftside=l[0] + rightside=l[1] + if len(l) > 2: + barcode=l[3] + else: + barcode=None + pass + t=string.split(rightside) + retval.numdrives=int(t[0]) + retval.numslots=int(t[2]) + + for s in lines[1:]: + if not s: + continue # skip blank lines! + #print "DEBUG:s=",s + parts=string.split(s,":") + leftpart=string.split(parts[0]) + rightpart=parts[1] + try: + barcode=parts[2] + except: + barcode=None + pass + #print "DEBUG:leftpart=",leftpart + if leftpart[0]=="Data" and leftpart[1]=="Transfer": + retval.drives.append(drivestatus(leftpart[3],rightpart,barcode)) + pass + if leftpart[0]=="Storage" and leftpart[1]=="Element": + element=slotstatus(leftpart[2],rightpart,barcode) + if element.importexport: + retval.export.append(element) + else: + retval.slots.append(element) + pass + pass + continue + + return retval + +# Output of a mtx inquiry looks like: +# +#Product Type: Medium Changer +#Vendor ID: 'EXABYTE ' +#Product ID: 'Exabyte EZ17 ' +#Revision: '1.07' +#Attached Changer: No +# +# We simply return a hash table with these values { left:right } format. + +def mtxinquiry(device): + command="%s/mtx -f %s inquiry" % (configdir,device) + str=readpipe(command) # calls the command, returns all its data. + + str=string.strip(str) + lines=string.split(str,"\n") + retval={} + for l in lines: + # DEBUG # + l=string.strip(l) + print "splitting line: '",l,"'" + idx,val=string.split(l,':',1) + val=string.strip(val) + if val[0]=="'": + val=val[1:-1] # strip off single quotes, sigh. + pass + retval[idx]=val + continue + return retval + +# Now for the easy part: + +def load(device,slot,drive=0): + command="%s/mtx -f %s load %s %s >/dev/null " % (configdir,device,slot,drive) + status=os.system(command) + return status + +def unload(device,slot,drive=0): + command="%s/mtx -f %s unload %s %s >/dev/null " % (configdir,device,slot,drive) + return os.system(command) + +def inventory(device): + command="%s/mtx -f %s inventory >/dev/null " % (configdir,device) + return os.system(command) + +def wait_for_inventory(device): + # loop while we have an error return... + errcount=0 + while inventory(device): + if errcount==0: + print "Waiting for loader '%s'" % device + pass + time.sleep(1) + try: + s=status(device) + except: + s=None + pass + if s: + return 0 # well, whatever we're doing, we're inventoried :-( + errcount=errcount+1 + if errcount==600: # we've been waiting for 10 minutes :-( + return 1 # sorry! + continue + return 0 # we succeeded! + +# RCS REVISION LOG: +# $Log$ +# Revision 1.1 2001/06/05 17:10:51 elgreen +# Initial revision +# +# Revision 1.2 2000/12/22 14:17:19 eric +# mtx 1.2.11pre1 +# +# Revision 1.14 2000/11/12 20:35:29 eric +# do string.strip on the voltag +# +# Revision 1.13 2000/11/04 00:33:38 eric +# if we can get an inventory on the loader after we send it 'mtx inventory', +# then obviously we managed to do SOMETHING. +# +# Revision 1.12 2000/10/28 00:04:34 eric +# added wait_for_inventory command +# +# Revision 1.11 2000/10/27 23:27:58 eric +# Added inventory command... +# +# Revision 1.10 2000/10/01 01:06:29 eric +# evening checkin +# +# Revision 1.9 2000/09/29 02:49:29 eric +# evening checkin +# +# Revision 1.8 2000/09/02 01:05:33 eric +# Evening Checkin +# +# Revision 1.7 2000/09/01 00:08:11 eric +# strip lines in mtxinquiry +# +# Revision 1.6 2000/09/01 00:05:33 eric +# debugging +# +# Revision 1.5 2000/08/31 23:46:01 eric +# fix def: +# +# Revision 1.4 2000/08/31 23:44:06 eric +# =->== +# diff --git a/contrib/mtxctl-0.0.2.tar.gz b/contrib/mtxctl-0.0.2.tar.gz new file mode 100644 index 0000000..de41b7d Binary files /dev/null and b/contrib/mtxctl-0.0.2.tar.gz differ diff --git a/contrib/qdback.tar.gz b/contrib/qdback.tar.gz new file mode 100644 index 0000000..761a216 Binary files /dev/null and b/contrib/qdback.tar.gz differ diff --git a/contrib/tapechanger.html b/contrib/tapechanger.html new file mode 100644 index 0000000..8ea9fce --- /dev/null +++ b/contrib/tapechanger.html @@ -0,0 +1,209 @@ + + +TapeChanger::MTX - use 'mtx' to manipulate a tape library + + + + + + + + + + + +
+

+

NAME

+

TapeChanger::MTX - use 'mtx' to manipulate a tape library

+

+


+

SYNOPSIS

+
+  use TapeChanger::MTX;
+
+  my $loaded = TapeChanger::MTX->loadedtape;
+  print "Currently loaded: $loaded\n" if ($loaded);
+
+  TapeChanger::MTX->loadtape('next');
+  my $nowloaded = TapeChanger::MTX->loadedtape; 
+  print "Currently loaded: $nowloaded\n" if ($nowloaded);
+
+
+
+See below for more available functions.
+

+


+

DESCRIPTION

+

TapeChanger::MTX is a module to manipulate a tape library using the 'mtx' +tape library program. It is meant to work with a simple shell/perl script +to load and unload tapes as appropriate, and to provide a interface for +more complicated programs to do the same. The below functions and +variables should do as good a job as explaining this as anything.

+

+


+

VARIABLES

+
+
$TapeChanger::MTX::MT +=item $TapeChanger::MTX::MTX
+
+What is the location of the 'mt' and 'mtx' binaries? Can be set with +'$MT' and '$MTX' in ~/.mtxrc, or defaults to '/usr/sbin/mt' and +'/usr/local/sbin/mtx'. +

+
$TapeChanger::MTX::DRIVE
+
+
$TapeChanger::MTX::CONTROL
+
+What are the names of the tape (DRIVE) and changer (CONTROL) device +nodes? Can be set with $DRIVE or $CONTROL in ~/.mtxrc, or default to +'/dev/rmt/0' and '/dev/changer' respectively. +

+
$TapeChanger::MTX::EJECT
+
+Does the tape drive have to eject the tape before the changer retrieves +it? It's okay to say 'yes' if it's not necessary, in most cases. Can be +set with $EJECT in ~/.mtxrc, or defaults to '1'. +

+
$TapeChanger::MTX::READY_TIME
+
+How long should we wait to see if the drive is ready, in seconds, after +mounting a volume? Can be set with $READY_TIME in ~/.mtxrc, or defaults +to 60. +

+
$TapeChanger::MTX::DEBUG
+
+Print debugging information? Set to '0' for normal verbosity, '1' for +debugging information, or '-1' for 'quiet mode' (be as quiet as possible). +

+

+


+

USAGE

+

This module uses the following functions:

+
+
tape_cmd ( COMMAND )
+
+
mt_cmd ( COMMAND )
+
+Runs 'mtx' and 'mt' as appropriate. COMMAND is the command you're +trying to send to them. Uses 'warn()' to print the commands to the screen +if $TapeChanger::MTX::DEBUG is set. +

+
numdrives ()
+
+
numslots ()
+
+
loadedtape ()
+
+Returns the number of drives, number of slots, and currently loaded tape +values, respectively, by parsing tape_cmd('status'). +

+
loadtape ( SLOT [, DRIVE] )
+
+Loads a tape into the tape changer, and waits until the drive is again +ready to be written to. SLOT can be any of the following (with the +relevant function indicated): +
+  current       C<loadedtape()>
+  prev          C<loadprevtape()>
+  next          C<loadnexttape()>
+  first         C<loadfirsttape()>
+  last          C<loadlasttape()>
+  0             C<_ejectdrive()>
+  1..99         Loads the specified tape number, ejecting whatever is
+                currently in the drive.
+

DRIVE is the drive to load, and defaults to 0. Returns 0 if +successful, an error string otherwise.

+

+
loadnexttape ()
+
+
loadprevtape ()
+
+
loadfirsttape ()
+
+
loadlasttape ()
+
+Loads the next, previous, first, and last tapes in the changer +respectively. Use tape_cmd('next'), tape_cmd('previous'), +tape_cmd('first'), and tape_cmd('last'), respectively. +

+
ejecttape ()
+
+Ejects the tape, by first ejecting the tape from the drive +(mt_cmd(rewind) then mt_cmd(offline)) and then returning it to its +slot (tape_cmd(unload)). Returns 1 if successful, 0 otherwise. +

+
resetchanger ()
+
+Resets the changer, ejecting the tape and loading the first one from the +changer. +

+
checkdrive ()
+
+Checks to see if the drive is ready or not, by waiting for up to +$TapeChanger::MTX::READY_TIME seconds to see if it can get status +information using mt_cmd(status). Returns 1 if so, 0 otherwise. +

+
reportstatus
+
+Returns a string containing the loaded tape and the drive that it's +mounted on. +

+
cannot_run ()
+
+Does some quick checks to see if you're actually capable of using this +module, based on your user permissions. Returns a list of problems if +there are any, 0 otherwise. +

+

+


+

NOTES

+

~/.mtxrc is automatically loaded when this module is used, if it exists, +using do(). This could cause security problems if you're trying to use +this with setuid() programs - so just don't do that. If you want someone +to have permission to mess with the tape drive and/or changer, let them +have that permission directly.

+

+


+

REQUIREMENTS

+

Perl 5.6.0 or better, an installed 'mtx' binary, and a tape changer and +reader connected to the system.

+

+


+

TODO

+

Support for Input/Export slots is not included, though it may be later. +Possibly works for multiple drives per changer, but I haven't tested it, +so I probably missed something. 'load previous' doesn't actually work, +because mtx doesn't support it (though the help says it does).

+

+


+

SEE ALSO

+

mtx, mt, tapechanger. Inspired by stc-changer, which comes +with the AMANDA tape backup package (http://www.amanda.org), and MTX, +available at http://mtx.sourceforge.net.

+

+


+

AUTHOR

+

Tim Skirvin <tskirvin@uiuc.edu>

+

+


+

COPYRIGHT

+

Copyright 2001-2002 by the University of Illinois Board of Trustees and +Tim Skirvin <tskirvin@ks.uiuc.edu>.

+ + + + diff --git a/contrib/tapeinfo.py b/contrib/tapeinfo.py new file mode 100644 index 0000000..d5df136 --- /dev/null +++ b/contrib/tapeinfo.py @@ -0,0 +1,55 @@ +# Copyright 2000 Enhanced Software Technologies Inc. +# All Rights Reserved +# Released under Free Software Foundation's General Public License, +# Version 2 or above + +# Routine to call 'tapeinfo' and read status for a node. This is an +# example of how to parse the 'tapeinfo' output from a scripting language. +# + +import os +import string +import sys + + +configdir="/opt/brupro/bin" # sigh. + +def inquiry(device): + retval={} + + # okay, now do the thing: + + command="%s/tapeinfo -f %s" % (configdir,device) + + # Now to read: + + infile=os.popen(command,"r") + + try: + s=infile.readline() + except: + s="" + pass + if not s: + return None # did not get anything. + while s: + s=string.strip(s) + idx,val=string.split(s,':',1) + val=string.strip(val) + if val[0]=="'": + val=val[1:-1] # strip off single quotes, sigh. + val=string.strip(val) + pass + while "\0" in val: + # zapo! + val=string.replace(val,"\0","") + pass + retval[idx]=val + try: + s=infile.readline() + except: + s="" + pass + continue # to top of loop! + return retval + diff --git a/contrib/tapeload.pl b/contrib/tapeload.pl new file mode 100644 index 0000000..de1f221 --- /dev/null +++ b/contrib/tapeload.pl @@ -0,0 +1,118 @@ +!/usr/bin/perl +########################## tapeload ########################### +# This script uses mtx 1.2.9pre2 to load a tape based +# on its volume tag. You can +# specify a tape drive by number, but if you don`t, it puts the +# tape in the first available drive and returns the number of that drive, +# both from the standard output and as the exit value. +# A negative exit value indicates an error. +# If volume tags are missing from any full slot, bar codes are rescanned +# automatically. +# +# usage: +# tapeload TAPE_LABEL_1 # Loads tape with label TAPE_LABEL_1 into a drive +# or +# tapeload TAPE_LABEL_1 1 # Loads tape with label TAPE_LABEL_1 into drive #1 +# + +# Set this variable to your mtx binary and proper scsi library device. +$MTXBIN="/usr/local/bin/mtx -f /dev/sga" ; + +# Additions and corrections are welcome. +# This software comes with absolutely no warranty and every other imaginable +# disclaimer. +# -- Frank Samuelson sam@milagro.lanl.gov +################################################################## + +@wt= &mdo("status"); #slurp in the list of slots + +# Check to be certain that every full slot has a volume tag +for ($i=0; $i< $#wt; $i++) { # look through every line + if ( $wt[$i] =~ /Full/ && $wt[$i] !~ /VolumeTag/ ) { + # if the element is full, but there is no volume tag, do inventory + @wt= &mdo("inventory status"); + break; + } +} + +#try to find our tape +$slot=-1; +for ($i=0; $i< $#wt; $i++) { # look through every line + if ($wt[$i] =~ / *Storage Element (d*):Full :VolumeTag=(.*)/ ) { + if ($ARGV[0] eq $2) { # We found the tape + $slot=$1; # set the slot number + break; # stop reading the rest of the file. + } + } +} + +if ( $slot>0) { # we found the tape you wanted. + + $drivefound=-1; # set flag to bad value + for ($i=0; $i< $#wt; $i++) { # look through every line + # if this is a tape drive + if ($wt[$i] =~ / *Data Transfer Element (d*):(.*)/ ) { #parse the line + $drive=$1; + $state=$2; +# print STDERR "$wt[$i] $drive $state"; + if ($state =~ /Full/) { # This drive is full. + # if we are looking for a particular drive and this is it + if ( $#ARGV==1 && $drive == $ARGV[1]) { + print STDERR " ERROR: Specified drive $ARGV[1] is full."; + print STDERR @wt; + exit(-6); + } + } elsif ($state =~ /Empty/) { #This is a tape drive and it`s empty. + if ( $#ARGV==1 ) { # If we want a particular drive + if ($drive == $ARGV[1]) { # and this is it, + $drivefound=$drive; # mark it so. + break; + } + } else { # If any old drive will do + $drivefound=$drive; # Mark it. + break; + } + } else { # This is a tape drive, but what the heck is it? + print STDERR " Cannot assess drive status in line"; + print STDERR $wt[$i]; + exit(-7); + } + } + } + + if ( $drivefound < 0 ) { # specified drive was not found + print STDERR "Error: Specified drive $ARGV[1] was not found"; + print STDERR @wt; + exit(-8); + } + # Now we actually load the tape. + @dump=&mdo(" load $slot $drivefound "); + print "$drivefound"; + exit($drivefound); + # The end. + + +} else { + print STDERR " Ug. Tape $ARGV[0] is not in the library."; + print STDERR @wt; + exit(-4); +} + + +sub mdo # a subroutine to call mtx ; +{ +# print STDERR "$_[0]"; + if (!open(FD,"$MTXBIN $_[0] |")) { #call mtx function + print STDERR " ERRKK. Could not start mtx "; + exit (-9); + } + + @twt= ; # slurp in the output + + if (! close(FD)) { # if mtx exited with a nonzero value... + print STDERR " Mtx gave an error. Tapeload is exiting... "; + exit (-10); + } + + @twt; +} diff --git a/contrib/tapeunload.pl b/contrib/tapeunload.pl new file mode 100644 index 0000000..e52a4ef --- /dev/null +++ b/contrib/tapeunload.pl @@ -0,0 +1,98 @@ +#!/usr/bin/perl +########################## tapeunload ########################### +# This script uses mtx 1.2.9pre2 to unload a tape +# based on its volume tag. You can +# specify a slot into which the tape should go, but if you don`t, it puts the +# tape into the slot from which it was taken. This slot number +# is returned +# both from the standard output and as the exit value. +# A negative exit value indicates an error. +# If volume tags are missing from any full slot or drive, +# bar codes are rescanned automatically. +# Note: This script assumes that the tape is ready to be removed from +# the drive. That means you may have to unload the tape from the drive +# with "mt offline" before the tape can be moved to a storage slot. +# + +# usage: +# tapeunload TAPE_LABEL_1 +# Removes tape with label TAPE_LABEL_1 from a drive and puts it +# back into its storage slot. Or, +# tapeunload TAPE_LABEL_1 40 +# Removes tape with label TAPE_LABEL_1 from a drive and puts it +# into its storage slot 40. +# + +# Set this variable to your mtx binary and proper scsi library device. +$MTXBIN="/usr/local/bin/mtx -f /dev/sga" ; + +# Additions and corrections are welcome. +# This software comes with absolutely no warranty and every other imaginable +# disclaimer. +# -- Frank Samuelson sam@milagro.lanl.gov + +################################################################## + +@wt= &mdo("status"); #slurp in the list of slots + +# Check to be certain that every full slot has a volume tag +# Rescanning probably will not help. I haven`t seen any bar code +# readers that read tapes that are in the drives. But you never know... +for ($i=0; $i< $#wt; $i++) { # look through every line + if ( $wt[$i] =~ /Full/ && $wt[$i] !~ /VolumeTag/ ) { + # if the element is full, but there is no volume tag, do inventory + @wt= &mdo("inventory status"); + break; + } +} + +#try to find our tape +$drivein=-1; +for ($i=0; $i< $#wt; $i++) { # look through every line + # for a full tape drive + if ($wt[$i] =~ / *Data Transfer Element (d*):Full (Storage Element +(d*) Loaded):VolumeTag = (.*)/ ){ + if ($ARGV[0] eq $3) { # We found our tape + $drivein=$1; # set the drive number + $slottogo=$2; # set the slot number + break; # stop reading the rest of the file. + } + } +} + +if ( $drivein>=0) { # we found the tape you wanted. + if ($#ARGV==1) { #If an alternative slot was requested, set it. + $slottogo=$ARGV[1]; # and let mtx handle the errors. + } + + # Now we unload the tape. + @dump=&mdo(" unload $slottogo $drivein "); + print "$slottogo"; + exit($slottogo); + # The end. + + +} else { + print STDERR " Ug. Tape $ARGV[0] is not in a tape drive."; + print STDERR @wt; + exit(-4); +} + + +sub mdo # a subroutine to call mtx ; +{ +# print STDERR "$_[0]"; + if (!open(FD,"$MTXBIN $_[0] |")) { #call mtx function + print STDERR " ERRKK. Could not start mtx "; + exit (-9); + } + + @twt= ; # slurp in the output + + if (! close(FD)) { # if mtx exited with a nonzero value... + print STDERR " Mtx gave an error. Tapeload is exiting... "; + exit (-10); + } + + @twt; +} diff --git a/debian/bash_completion b/debian/bash_completion new file mode 100644 index 0000000..71852c0 --- /dev/null +++ b/debian/bash_completion @@ -0,0 +1,45 @@ +# mtx completion by Jon Middleton +# +# $Id: bash_completion,v 1.1 2004-02-15 05:43:25 bdale Exp $ + +_mtx() +{ + local cur prev options tapes drives + + COMPREPLY=() + cur=${COMP_WORDS[COMP_CWORD]} + prev=${COMP_WORDS[COMP_CWORD-1]} + + options="-f nobarcode invert noattach --version inquiry noattach \ + inventory status load unload eepos first last next" + + tapes=$(mtx status | \ + awk '/Storage Element [0-9]+:Full/ { printf "%s ", $3 }') + tapes=${tapes//:Full} + + drives=$(mtx status | \ + awk '/Data Transfer Element [0-9]+:(Full|Empty)/ { printf "%s ", $4 }') + drives=${drives//:Full} + drives=${drives//:Empty} + + if [ $COMP_CWORD -gt 1 ]; then + case $prev in + load) + COMPREPLY=( $( compgen -W "$tapes" -- $cur ) ) + ;; + unload|first|last|next) + COMPREPLY=( $( compgen -W "$drives" -- $cur ) ) + ;; + -f) + true + ;; + *) + true + ;; + esac + else + COMPREPLY=( $( compgen -W "$options" -- $cur ) ) + fi + return 0 +} +complete -F _mtx mtx diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..860dd53 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,159 @@ +mtx (1.3.12-1) unstable; urgency=low + + * Incorporate debian packaging into upsteam version + * Remove strip of binaries + * Remove unsupported nsmhack from list of binaries built by default + * Add support for building outside of source tree + * Update copyrights + * Fix typo in mtx.1 man page + * Clear outstanding UNIT ATTENTION state at start + + -- Robert Nelson Tue, 19 Aug 2008 09:04:00 +0000 + +mtx (1.3.11-1) unstable; urgency=low + + * new upstream version, closes: #425687, #425688 + * don't let Makefile.in strip binaries, let dh_strip do it, closes: #437589 + + -- Bdale Garbee Tue, 15 Apr 2008 14:34:32 -0600 + +mtx (1.2.17rel-2) unstable; urgency=low + + * update config.sub and config.guess in rules clean target using the + autotools-dev package, closes: #367467 + + -- Bdale Garbee Sat, 19 Aug 2006 18:44:54 -0600 + +mtx (1.2.17rel-1) unstable; urgency=low + + * new upstream version + + -- Bdale Garbee Wed, 28 Jun 2006 23:57:44 -0400 + +mtx (1.2.16rel-5) unstable; urgency=low + + * add build-deps needed for GNU/kFreeBSD, closes: #367467 + * update debhelper build dependency + + -- Bdale Garbee Wed, 28 Jun 2006 23:42:00 -0400 + +mtx (1.2.16rel-4) unstable; urgency=medium + + * revert SG_SCSI_DEFAULT_TIMEOUT to 5 minutes since at least the Sony + TLS-9000 takes more than a minute to load sometimes, closes: #229169 + * remove 'previous' from command summary, since it's not actually + implemented in the program, closes: #230041 + * include bash_completion file from Jon Middleton, closes: #227456 + + -- Bdale Garbee Sat, 14 Feb 2004 22:36:23 -0700 + +mtx (1.2.16rel-3) unstable; urgency=low + + * apply patch from Torsten Werner that elminates + hard-coding of the value of HZ, closes: #224147 + + -- Bdale Garbee Tue, 16 Dec 2003 10:04:26 -0700 + +mtx (1.2.16rel-2) unstable; urgency=low + + * apply patch from R.A.Owen that fixes the "staggered" + output from the status command on some changers, closes: #129910 + + -- Bdale Garbee Tue, 9 Apr 2002 19:30:06 -0600 + +mtx (1.2.16rel-1) unstable; urgency=low + + * new upstream version, bug-fixing release, reportedly fixes timeout + problem with some drives, closes: #113947 + + -- Bdale Garbee Mon, 4 Mar 2002 01:27:48 -0700 + +mtx (1.2.15-1) unstable; urgency=low + + * new upstream source + * update standards version, rebuild rules file + * man pages all included now, mtx-changer and other pieces from contrib + provided as examples, though chg-mtx in the amanda package is probably + a better choice for use with amanda, closes: #113728 + * apply diffs to correct "spelling errors" (actually hyphenation) in the + descriptions in the control file, closes: #125160 + + -- Bdale Garbee Sun, 30 Dec 2001 21:28:46 -0700 + +mtx (1.2.10-1) unstable; urgency=low + + * new upstream source + + -- Bdale Garbee Mon, 11 Dec 2000 17:34:13 -0700 + +mtx (1.0-10) frozen unstable; urgency=low + + * deliver mtx.doc, lost when the package was made FHS compliant, + closes: #56276 Target frozen since including the documentation + is worthwhile for potato, and there is no added risk. + + -- Bdale Garbee Wed, 9 Feb 2000 12:27:58 -0700 + +mtx (1.0-9) unstable; urgency=low + + * fix postinst/postrm scripts to be executable again + + -- Bdale Garbee Tue, 11 Jan 2000 23:00:17 -0700 + +mtx (1.0-8) unstable; urgency=low + + * update to latest standards revision, add Build-Depends + * fix all the lintian errors that aren't intentional, override the two + permissions warnings since they're precisely what is needed + + -- Bdale Garbee Fri, 7 Jan 2000 02:47:08 -0700 + +mtx (1.0-7) unstable; urgency=low + + * grab a local copy of scsi_ioctl.h from the 2.2.10 kernel source tree. This + doesn't change often in any way we care about, and this is much simpler + than having to reference a live kernel tree somewhere... + * move to debhelper and CVS + + -- Bdale Garbee Sun, 20 Jun 1999 10:42:39 -0600 + +mtx (1.0-6) unstable; urgency=low + + * put mtx in group backup, setuid root, perms set so that only members of + group backup can run mtx. This makes mtx compatible with amanda. + + -- Bdale Garbee Tue, 27 Jan 1998 15:06:13 -0700 + +mtx (1.0-5) unstable; urgency=low + + * explicit include path to find in the + /usr/src/linux/include tree. closes bug 16877 + + -- Bdale Garbee Sun, 25 Jan 1998 23:02:46 -0700 + +mtx (1.0-4) unstable; urgency=low + + * actually install the mtx.doc file that's referenced in the man page /o\ + + -- Bdale Garbee Sun, 21 Sep 1997 02:38:50 -0600 + +mtx (1.0-3) unstable; urgency=low + + * libc6 + + -- Bdale Garbee Thu, 4 Sep 1997 02:56:39 -0600 + +mtx (1.0-2) unstable; urgency=low + + * Add an 'mtx-changer' wrapper script from the amanda-users mailing list + to make this more useful with Amanda. + * Hack mtx-changer to report 6 slots instead of 4, since I have an HP + SureStore 12000e. Should make it configurable, someday. + + -- Bdale Garbee Sun, 10 Aug 1997 03:50:42 -0600 + +mtx (1.0-1) unstable; urgency=low + + * Initial Release. + + -- Bdale Garbee Sun, 10 Aug 1997 03:05:18 -0600 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +4 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..fa6c9d0 --- /dev/null +++ b/debian/control @@ -0,0 +1,16 @@ +Source: mtx +Section: admin +Priority: extra +Maintainer: Robert Nelson +Build-Depends: debhelper (>= 4), libcam-dev [kfreebsd-i386 kfreebsd-amd64], autotools-dev +Standards-Version: 3.7.3 + +Package: mtx +Architecture: any +Depends: ${shlibs:Depends} +Description: controls tape autochangers + MTX can be used to manipulate tape auto-changers, also known as "jukeboxes", + such that backup software can make use of the multiple tape capabilities of + the auto-changer. In particular, this is necessary glue for using a backup + system like Amanda with a DDS auto-changer like the HP Surestore 12000e. + diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..28fd2e0 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,15 @@ +This package was debianized by Bdale Garbee bdale@gag.com on +Sun, 10 Aug 1997 03:05:18 -0600. + +mtx was downloaded from http://mtx.sourceforge.net/ + +Copyright: + + Copyright 1997, 1998 Leonard Zubkoff + Changes copyright 2000, 2001 Eric Green + Changes copyright 2007-2008 by Robert Nelson + + GPL, version 2 + +On Debian GNU/Linux systems, the complete text of the GNU General +Public License can be found in `/usr/share/common-licenses/GPL'. diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 0000000..ce5d4fb --- /dev/null +++ b/debian/dirs @@ -0,0 +1,2 @@ +etc/bash_completion.d +usr/sbin diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..79c0cb2 --- /dev/null +++ b/debian/rules @@ -0,0 +1,69 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +export DH_VERBOSE=1 + +configure: configure-stamp +configure-stamp: + dh_testdir + ./configure --prefix=/usr + touch configure-stamp + +build: build-stamp + +build-stamp: configure-stamp + dh_testdir + $(MAKE) + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + [ ! -f Makefile ] || $(MAKE) distclean + + -test -r /usr/share/misc/config.sub && \ + cp -f /usr/share/misc/config.sub config.sub + -test -r /usr/share/misc/config.guess && \ + cp -f /usr/share/misc/config.guess config.guess + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + make install bindir=`pwd`/debian/mtx/bin prefix=`pwd`/debian/mtx/usr \ + mandir=`pwd`/debian/mtx/usr/share/man + install -o root -g root -m 0644 debian/bash_completion \ + debian/mtx/etc/bash_completion.d/mtx + +# Build architecture-independent files here. +binary-indep: build install + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installdocs + dh_installexamples contrib/* + dh_installmenu + dh_installcron +# dh_installman + dh_installinfo + dh_installchangelogs CHANGES + dh_link + dh_strip + dh_compress + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/du/defs.h b/du/defs.h new file mode 100644 index 0000000..2da35e7 --- /dev/null +++ b/du/defs.h @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include +#include +#include + +typedef int DEVICE_TYPE; + +#ifdef __osf__ +#include +#include +#include +#else /* must be ultrix */ +#include +#endif +#include +#include +#include +#include +#define DEV_CAM "/dev/cam" /* CAM device path */ + + +#define DIGITAL_UNIX diff --git a/du/scsi.c b/du/scsi.c new file mode 100644 index 0000000..8f11e16 --- /dev/null +++ b/du/scsi.c @@ -0,0 +1,214 @@ +/* SCSI.C - Digital Unix-specific SCSI routines. +** +** TECSys Development, Inc., April 1998 +** +** This module began life as a part of XMCD, an X-windows CD player +** program for many platforms. No real functionality from the original XMCD +** is present in this module, but in the interest of making certain that +** proper credit is given where it may be due, the copyrights and inclusions +** from the XMCD module OS_DEC.C are included below. +** +** The portions of coding in this module ascribable to TECSys Development +** are hereby also released under the terms and conditions of version 2 +** of the GNU General Public License as described below.... +*/ + +/* + * libdi - scsipt SCSI Device Interface Library + * + * Copyright (C) 1993-1997 Ti Kan + * E-mail: ti@amb.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Digital UNIX (OSF/1) and Ultrix support + * + * Contributing author: Matt Thomas + * E-Mail: thomas@lkg.dec.com + * + * This software fragment contains code that interfaces the + * application to the Digital UNIX and Ultrix operating systems. + * The term Digital, Ultrix and OSF/1 are used here for identification + * purposes only. + */ + +static int bus = -1, + target = -1, + lun = -1; + +static int SCSI_OpenDevice(char *DeviceName) +{ + int fd; + struct stat stbuf; + int saverr; + + /* Check for validity of device node */ + if (stat(DeviceName, &stbuf) < 0) + { + FatalError("cannot stat SCSI device '%s' - %m\n", DeviceName); + } + if (!S_ISCHR(stbuf.st_mode)) + { + FatalError("device '%s': not appropriate device type - %m\n", DeviceName); + } + + if ((fd = open(DeviceName, O_RDONLY | O_NDELAY, 0)) >= 0) + { + struct devget devget; + + if (ioctl(fd, DEVIOCGET, &devget) >= 0) + { +#ifdef __osf__ + lun = devget.slave_num % 8; + devget.slave_num /= 8; +#else + lun = 0; +#endif + target = devget.slave_num % 8; + devget.slave_num /= 8; + bus = devget.slave_num % 8; + (void) close(fd); + + if ((fd = open(DEV_CAM, O_RDWR, 0)) >= 0 || + (fd = open(DEV_CAM, O_RDONLY, 0)) >= 0) + { + return (fd); + } + fd = bus = target = lun = -1; + FatalError("error %d opening SCSI device '%s' - %m\n", + errno, DEV_CAM); + } + else + { + (void) close(fd); + fd = bus = target = lun = -1; + FatalError("error %d on DEVIOCGET ioctl for '%s' - %m\n", + errno, DeviceName); + } + } + else + { + saverr = errno; + fd = bus = target = lun = -1; + FatalError("cannot open SCSI device '%s', error %d - %m\n", + DeviceName, saverr); + } + + fd = bus = target = lun = -1; + return -1; +} + + +static void SCSI_CloseDevice(char *DeviceName, int DeviceFD) +{ + (void) close(DeviceFD); + bus = target = lun = -1; +} + + +static int SCSI_ExecuteCommand(int DeviceFD, + Direction_T Direction, + CDB_T *CDB, + int CDB_Length, + void *DataBuffer, + int DataBufferLength, + RequestSense_T *RequestSense) +{ + UAGT_CAM_CCB uagt; + CCB_SCSIIO ccb; + + if (DeviceFD < 0) + return -1; + + (void) memset(&uagt, 0, sizeof(uagt)); + (void) memset(&ccb, 0, sizeof(ccb)); + + /* Setup the user agent ccb */ + uagt.uagt_ccb = (CCB_HEADER *) &ccb; + uagt.uagt_ccblen = sizeof(CCB_SCSIIO); + + /* Setup the scsi ccb */ + (void) memcpy((unsigned char *) ccb.cam_cdb_io.cam_cdb_bytes, + CDB, CDB_Length); + ccb.cam_cdb_len = CDB_Length; + ccb.cam_ch.my_addr = (CCB_HEADER *) &ccb; + ccb.cam_ch.cam_ccb_len = sizeof(CCB_SCSIIO); + ccb.cam_ch.cam_func_code = XPT_SCSI_IO; + + if (DataBuffer != NULL && DataBufferLength > 0) + { + ccb.cam_ch.cam_flags |= (Direction == Input) ? + CAM_DIR_IN : CAM_DIR_OUT; + uagt.uagt_buffer = (u_char *) DataBuffer; + uagt.uagt_buflen = DataBufferLength; + } + else + ccb.cam_ch.cam_flags |= CAM_DIR_NONE; + + ccb.cam_ch.cam_flags |= CAM_DIS_AUTOSENSE; + ccb.cam_data_ptr = uagt.uagt_buffer; + ccb.cam_dxfer_len = uagt.uagt_buflen; + ccb.cam_timeout = 300; /* Timeout set to 5 minutes */ + + ccb.cam_sense_ptr = (u_char *) RequestSense; + ccb.cam_sense_len = sizeof(RequestSense_T); + + ccb.cam_ch.cam_path_id = bus; + ccb.cam_ch.cam_target_id = target; + ccb.cam_ch.cam_target_lun = lun; + + if (ioctl(DeviceFD, UAGT_CAM_IO, (caddr_t) &uagt) < 0) + { + return -1; + } + + /* Check return status */ + if ((ccb.cam_ch.cam_status & CAM_STATUS_MASK) != CAM_REQ_CMP) + { + if (ccb.cam_ch.cam_status & CAM_SIM_QFRZN) + { + (void) memset(&ccb, 0, sizeof(ccb)); + (void) memset(&uagt, 0, sizeof(uagt)); + + /* Setup the user agent ccb */ + uagt.uagt_ccb = (CCB_HEADER *) &ccb; + uagt.uagt_ccblen = sizeof(CCB_RELSIM); + + /* Setup the scsi ccb */ + ccb.cam_ch.my_addr = (struct ccb_header *) &ccb; + ccb.cam_ch.cam_ccb_len = sizeof(CCB_RELSIM); + ccb.cam_ch.cam_func_code = XPT_REL_SIMQ; + + ccb.cam_ch.cam_path_id = bus; + ccb.cam_ch.cam_target_id = target; + ccb.cam_ch.cam_target_lun = lun; + + if (ioctl(DeviceFD, UAGT_CAM_IO, (caddr_t) &uagt) < 0) + return -1; + } + + printf( "mtx: %s:\n%s=0x%x %s=0x%x\n", + "SCSI command fault", + "Opcode", + CDB[0], + "Status", + ccb.cam_scsi_status); + return -1; + } + + return 0; +} diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..b66097a --- /dev/null +++ b/install-sh @@ -0,0 +1,253 @@ +#!/bin/sh +# $Date: 2001-06-05 10:10:15 -0700 (Tue, 05 Jun 2001) $ +# $Revision: 2 $ +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/loaderinfo.1 b/loaderinfo.1 new file mode 100644 index 0000000..ea6da04 --- /dev/null +++ b/loaderinfo.1 @@ -0,0 +1,90 @@ +.\" tapeinfo.1 Document copyright 2000 Eric Lee Green +.\" Program Copyright 2000 Eric Lee Green +.\" Copyright 2007-2008 by Robert Nelson +.\" +.\" This is free documentation; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License as +.\" published by the Free Software Foundation; either version 2 of +.\" the License, or (at your option) any later version. +.\" +.\" The GNU General Public License's references to "object code" +.\" and "executables" are to be interpreted as the output of any +.\" document formatting or typesetting system, including +.\" intermediate and printed output. +.\" +.\" This manual is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public +.\" License along with this manual; if not, write to the Free +.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +.\" USA. +.\" +.TH LOADERINFO 1 LOADERINFO1.0 +.SH NAME +loaderinfo \- report SCSI tape device info +.SH SYNOPSIS +loaderinfo -f +.SH DESCRIPTION +The +.B loaderinfo +command reads various information from SCSI tape loaders. Its intended +use is for high-level programs that are trying to decide what the +capabilities of a device are. +.P +The following are printed: +.TP 10 +.B Element Address Assignment Page: +This tells how many elements are in the loader, and what their raw +hardware addresses are. + +.TP 10 +.B Transport Geometry Descriptor Page: +Will display whether media is invertible or not (usable with some +optical jukeboxes for detirmining whether to "flip" media after writing +to the first side). + +.TP 10 +.B Device Capabilities Page +Currently will only display whether we can transfer between slots (i.e. +whether 'mtx transfer' works). + +.TP 10 +.B Inquiry Page +Aside from the normal inquiry info, will also print out whether we have +a bar code reader (for loaders that support the Exabyte extension for +reporting presense of said reader). + + +.SH OPTIONS +The first argument, given following +.B -f +, is the SCSI generic device corresponding to your tape loader. +Consult your operating system's documentation for more information (for +example, under Linux these are generally start at /dev/sg0 +under FreeBSD these start at /dev/pass0). +.P +Under FreeBSD, 'camcontrol devlist' will tell you what SCSI devices you +have, along with which 'pass' device controls them. Under Linux, +"cat /proc/scsi/scsi" will tell you what SCSI devices you have. Under +Solaris 8, +.B find /devices -name '*changer*' +will display the device names for your attached changers. Make sure +to configure your 'sgen' driver first. + +.SH BUGS AND LIMITATIONS +.P +This program has only been tested on Linux with a limited number of +loaders (Ecrix Autopack, Exabyte 220). +.P +.SH AVAILABILITY +.B loaderinfo +is currently being maintained by Robert Nelson +as part of the 'mtx' suite of programs. The 'mtx' home page is +http://mtx.sourceforge.net and the actual code is currently available there and via +SVN from http://sourceforge.net/projects/mtx. + +.SH SEE ALSO +.BR mt (1), tapeinfo (1), mtx (1) diff --git a/loaderinfo.c b/loaderinfo.c new file mode 100644 index 0000000..b23867e --- /dev/null +++ b/loaderinfo.c @@ -0,0 +1,510 @@ +/* Copyright 2000 Enhanced Software Technologies Inc. + * Copyright 2007-2008 by Robert Nelson + * Released under terms of the GNU General Public License as + * required by the license on 'mtxl.c'. + */ + +/* +* $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ +* $Revision: 193 $ +*/ + +/* What this does: Basically dumps out contents of: + * Mode Sense: Element Address Assignment Page (0x1d) + * 1Eh (Transport Geometry Parameters) has a bit which indicates is + * a robot is capable of rotating the media. It`s the + * `Rotate` bit, byte 2, bit 1. + * Device Capabilities page (0x1f) + * Inquiry -- prints full inquiry info. + * DeviceType: + * Manufacturer: + * ProdID: + * ProdRevision: + * If there is a byte 55, we use the Exabyte extension to + * print out whether we have a bar code reader or not. This is + * bit 0 of byte 55. + * + * Next, we request element status on the drives. We do not + * request volume tags though. If Exabyte + * extensions are supported, we report the following information for + * each drive: + * + * Drive number + * EXCEPT (with ASC and ASCQ), if there is a problem. + * SCSI address and LUN + * Tape drive Serial number + * + */ + +#include +#include "mtx.h" +#include "mtxl.h" + +DEVICE_TYPE MediumChangerFD; /* historic purposes... */ + +char *argv0; + +/* A table for printing out the peripheral device type as ASCII. */ +static char *PeripheralDeviceType[32] = +{ + "Disk Drive", + "Tape Drive", + "Printer", + "Processor", + "Write-once", + "CD-ROM", + "Scanner", + "Optical", + "Medium Changer", + "Communications", + "ASC IT8", + "ASC IT8", + "RAID Array", + "Enclosure Services", + "OCR/W", + "Bridging Expander", /* 0x10 */ + "Reserved", /* 0x11 */ + "Reserved", /* 0x12 */ + "Reserved", /* 0x13 */ + "Reserved", /* 0x14 */ + "Reserved", /* 0x15 */ + "Reserved", /* 0x16 */ + "Reserved", /* 0x17 */ + "Reserved", /* 0x18 */ + "Reserved", /* 0x19 */ + "Reserved", /* 0x1a */ + "Reserved", /* 0x1b */ + "Reserved", /* 0x1c */ + "Reserved", /* 0x1d */ + "Reserved", /* 0x1e */ + "Unknown" /* 0x1f */ +}; + + +/* okay, now for the structure of an Element Address Assignment Page: */ + +typedef struct EAAP +{ + unsigned char Page_Code; + unsigned char Parameter_Length; + unsigned char MediumTransportElementAddress[2]; + unsigned char NumMediumTransportElements[2]; + unsigned char FirstStorageElementAdddress[2]; + unsigned char NumStorageElements[2]; + unsigned char FirstImportExportElementAddress[2]; + unsigned char NumImportExportElements[2]; + unsigned char FirstDataTransferElementAddress[2]; + unsigned char NumDataTransferElements[2]; + unsigned char Reserved[2]; +} EAAP_Type; + +/* okay, now for the structure of a transport geometry + * descriptor page: + */ +typedef struct TGDP +{ + unsigned char Page_Code; + unsigned char ParameterLength; + unsigned char Rotate; + unsigned char ElementNumber; /* we don't care about this... */ +} TGDP_Type; + + +/* Structure of the Device Capabilities Page: */ +typedef struct DCP +{ + unsigned char Page_Code; + unsigned char ParameterLength; + unsigned char CanStore; /* bits about whether elements can store carts */ + unsigned char SMC2_Caps; + unsigned char MT_Transfer; /* bits about whether mt->xx transfers work. */ + unsigned char ST_Transfer; /* bits about whether st->xx transfers work. */ + unsigned char IE_Transfer; /* bits about whether id->xx transfers work. */ + unsigned char DT_Transfer; /* bits about whether DT->xx transfers work. */ + unsigned char Reserved[4]; /* more reserved data */ + unsigned char MT_Exchange; /* bits about whether mt->xx exchanges work. */ + unsigned char ST_Exchange; /* bits about whether st->xx exchanges work. */ + unsigned char IE_Exchange; /* bits about whether id->xx exchanges work. */ + unsigned char DT_Exchange; /* bits about whether DT->xx exchanges work. */ + unsigned char Reserved2[4]; /* more reserved data */ +} DCP_Type; + +#define MT_BIT 0x01 +#define ST_BIT 0x02 +#define IE_BIT 0x04 +#define DT_BIT 0x08 + +/* Okay, now for the inquiry information: */ + +static void ReportInquiry(DEVICE_TYPE MediumChangerFD) +{ + RequestSense_T RequestSense; + Inquiry_T *Inquiry; + int i; + + Inquiry = RequestInquiry(MediumChangerFD,&RequestSense); + if (Inquiry == NULL) + { + PrintRequestSense(&RequestSense); + FatalError("INQUIRY Command Failed\n"); + } + + printf("Product Type: %s\n",PeripheralDeviceType[Inquiry->PeripheralDeviceType]); + + printf("Vendor ID: '"); + for (i = 0; i < sizeof(Inquiry->VendorIdentification); i++) + printf("%c", Inquiry->VendorIdentification[i]); + + printf("'\nProduct ID: '"); + for (i = 0; i < sizeof(Inquiry->ProductIdentification); i++) + printf("%c", Inquiry->ProductIdentification[i]); + + printf("'\nRevision: '"); + for (i = 0; i < sizeof(Inquiry->ProductRevisionLevel); i++) + printf("%c", Inquiry->ProductRevisionLevel[i]); + + printf("'\n"); + + if (Inquiry->MChngr) + { + /* check the attached-media-changer bit... */ + printf("Attached Changer: Yes\n"); + } + else + { + printf("Attached Changer: No\n"); + } + + /* Now see if we have a bar code flag: */ + if (Inquiry->AdditionalLength > 50) + { + /* see if we have 56 bytes: */ + if (Inquiry->VendorFlags & 1) + { + printf("Bar Code Reader: Yes\n"); + } + else + { + printf("Bar Code Reader: No\n"); + } + } + + free(Inquiry); /* well, we're about to exit, but ... */ +} + +/*********** MODE SENSE *******************/ +/* We need 3 different mode sense pages. This is a generic + * routine for obtaining mode sense pages. + */ + +static unsigned char +*mode_sense(DEVICE_TYPE fd, char pagenum, int alloc_len, RequestSense_T *RequestSense) +{ + CDB_T CDB; + unsigned char *input_buffer; /*the input buffer -- has junk prepended to + * actual sense page. + */ + unsigned char *tmp; + unsigned char *retval; /* the return value. */ + int i,pagelen; + + if (alloc_len > 255) + { + FatalError("mode_sense(6) can only read up to 255 characters!\n"); + } + + input_buffer = (unsigned char *)xzmalloc(256); /* overdo it, eh? */ + + /* clear the sense buffer: */ + slow_bzero((char *)RequestSense, sizeof(RequestSense_T)); + + /* returns an array of bytes in the page, or, if not possible, NULL. */ + CDB[0] = 0x1a; /* Mode Sense(6) */ + CDB[1] = 0x08; + CDB[2] = pagenum; /* the page to read. */ + CDB[3] = 0; + CDB[4] = 255; /* allocation length. This does max of 256 bytes! */ + CDB[5] = 0; + + if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, + input_buffer, 255, RequestSense) != 0) + { +#ifdef DEBUG_MODE_SENSE + fprintf(stderr,"Could not execute mode sense...\n"); + fflush(stderr); +#endif + return NULL; /* sorry, couldn't do it. */ + } + + /* First skip past any header.... */ + tmp = input_buffer + 4 + input_buffer[3]; + /* now find out real length of page... */ + pagelen=tmp[1] + 2; + retval = xmalloc(pagelen); + /* and copy our data to the new page. */ + for (i = 0; i < pagelen; i++) + { + retval[i] = tmp[i]; + } + /* okay, free our input buffer: */ + free(input_buffer); + return retval; +} + +/* Report the Element Address Assignment Page */ +static void ReportEAAP(DEVICE_TYPE MediumChangerFD) +{ + EAAP_Type *EAAP; + RequestSense_T RequestSense; + + EAAP = (EAAP_Type *)mode_sense(MediumChangerFD, 0x1d, sizeof(EAAP_Type), &RequestSense); + + if (EAAP == NULL) + { + PrintRequestSense(&RequestSense); + printf("EAAP: No\n"); + return; + } + + /* we did get an EAAP, so do our thing: */ + printf("EAAP: Yes\n"); + printf("Number of Medium Transport Elements: %d\n", ( ((unsigned int)EAAP->NumMediumTransportElements[0]<<8) + (unsigned int)EAAP->NumMediumTransportElements[1])); + printf("Number of Storage Elements: %d\n", ( ((unsigned int)EAAP->NumStorageElements[0]<<8) + (unsigned int)EAAP->NumStorageElements[1])); + printf("Number of Import/Export Elements: %d\n", ( ((unsigned int)EAAP->NumImportExportElements[0]<<8) + (unsigned int)EAAP->NumImportExportElements[1])); + printf("Number of Data Transfer Elements: %d\n", ( ((unsigned int)EAAP->NumDataTransferElements[0]<<8) + (unsigned int)EAAP->NumDataTransferElements[1])); + + free(EAAP); +} + +/* See if we can get some invert information: */ + +static void Report_TGDP(DEVICE_TYPE MediumChangerFD) +{ + TGDP_Type *result; + + RequestSense_T RequestSense; + + result=(TGDP_Type *)mode_sense(MediumChangerFD,0x1e,255,&RequestSense); + + if (!result) + { + printf("Transport Geometry Descriptor Page: No\n"); + return; + } + + printf("Transport Geometry Descriptor Page: Yes\n"); + + /* Now print out the invert bit: */ + if ( result->Rotate & 1 ) + { + printf("Invertable: Yes\n"); + } + else + { + printf("Invertable: No\n"); + } + + free(result); +} + +/* Okay, let's get the Device Capabilities Page. We don't care + * about much here, just whether 'mtx transfer' will work (i.e., + * ST->ST). + */ + +void TransferExchangeTargets(unsigned char ucValue, char *szPrefix) +{ + if (ucValue & DT_BIT) + { + printf("%sData Transfer", szPrefix); + } + + if (ucValue & IE_BIT) + { + printf("%s%sImport/Export", ucValue > (IE_BIT | (IE_BIT - 1)) ? ", " : "", szPrefix); + } + + if (ucValue & ST_BIT) + { + printf("%s%sStorage", ucValue > (ST_BIT | (ST_BIT - 1)) ? ", " : "", szPrefix); + } + + if (ucValue & MT_BIT) + { + printf("%s%sMedium Transfer", ucValue > (MT_BIT | (MT_BIT - 1)) ? ", " : "", szPrefix); + } +} + +static void Report_DCP(DEVICE_TYPE MediumChangerFD) +{ + DCP_Type *result; + RequestSense_T RequestSense; + + /* Get the page. */ + result=(DCP_Type *)mode_sense(MediumChangerFD,0x1f,sizeof(DCP_Type),&RequestSense); + if (!result) + { + printf("Device Configuration Page: No\n"); + return; + } + + printf("Device Configuration Page: Yes\n"); + + printf("Storage: "); + + if (result->CanStore & DT_BIT) + { + printf("Data Transfer"); + } + + if (result->CanStore & IE_BIT) + { + printf("%sImport/Export", result->CanStore > (IE_BIT | (IE_BIT - 1)) ? ", " : ""); + } + + if (result->CanStore & ST_BIT) + { + printf("%sStorage", result->CanStore > (ST_BIT | (ST_BIT - 1)) ? ", " : ""); + } + + if (result->CanStore & MT_BIT) + { + printf("%sMedium Transfer", result->CanStore > (MT_BIT | (MT_BIT - 1)) ? ", " : ""); + } + + printf("\n"); + + printf("SCSI Media Changer (rev 2): "); + + if (result->SMC2_Caps & 0x01) + { + printf("Yes\n"); + + printf("Volume Tag Reader Present: %s\n", result->SMC2_Caps & 0x02 ? "Yes" : "No"); + printf("Auto-Clean Enabled: %s\n", result->SMC2_Caps & 0x04 ? "Yes" : "No"); + } + else + { + printf("No\n"); + } + + printf("Transfer Medium Transport: "); + if ((result->MT_Transfer & 0x0F) != 0) + { + TransferExchangeTargets(result->MT_Transfer, "->"); + } + else + { + printf("None"); + } + + printf("\nTransfer Storage: "); + if ((result->ST_Transfer & 0x0F) != 0) + { + TransferExchangeTargets(result->ST_Transfer, "->"); + } + else + { + printf("None"); + } + + printf("\nTransfer Import/Export: "); + if ((result->IE_Transfer & 0x0F) != 0) + { + TransferExchangeTargets(result->IE_Transfer, "->"); + } + else + { + printf("None"); + } + + printf("\nTransfer Data Transfer: "); + if ((result->DT_Transfer & 0x0F) != 0) + { + TransferExchangeTargets(result->DT_Transfer, "->"); + } + else + { + printf("None"); + } + + printf("\nExchange Medium Transport: "); + if ((result->MT_Exchange & 0x0F) != 0) + { + TransferExchangeTargets(result->MT_Exchange, "<>"); + } + else + { + printf("None"); + } + + printf("\nExchange Storage: "); + if ((result->ST_Exchange & 0x0F) != 0) + { + TransferExchangeTargets(result->ST_Exchange, "<>"); + } + else + { + printf("None"); + } + + printf("\nExchange Import/Export: "); + if ((result->IE_Exchange & 0x0F) != 0) + { + TransferExchangeTargets(result->IE_Exchange, "<>"); + } + else + { + printf("None"); + } + + printf("\nExchange Data Transfer: "); + if ((result->DT_Exchange & 0x0F) != 0) + { + TransferExchangeTargets(result->DT_Exchange, "<>"); + } + else + { + printf("None"); + } + + printf("\n"); + + free(result); +} + +void usage(void) +{ + FatalError("Usage: loaderinfo -f \n"); +} + + +/* we only have one argument: "-f ". */ +int main(int argc, char **argv) +{ + DEVICE_TYPE fd; + char *filename; + + argv0=argv[0]; + if (argc != 3) + { + fprintf(stderr,"argc=%d",argc); + usage(); + } + + if (strcmp(argv[1],"-f")!=0) + { + usage(); + } + + filename=argv[2]; + + fd=SCSI_OpenDevice(filename); + + /* Now to call the various routines: */ + ReportInquiry(fd); + ReportEAAP(fd); + Report_TGDP(fd); + Report_DCP(fd); + exit(0); +} diff --git a/makedist b/makedist new file mode 100755 index 0000000..93f8121 --- /dev/null +++ b/makedist @@ -0,0 +1,19 @@ +#!/bin/sh + +# note -- this assumes 'bash' shell, GNU tar, 'gzip'. + +# pass a version number e.g. 1.4.3 as 1st parameter... +ME=`pwd` + +# okay, now to create a spec file w/the proper version number: +sed -e "1,\$s/@@VERSION@@/${1}/g" mtx.spec + +cd .. +if [ ! -s mtx-${1} ] +then + ln -s "${ME}" "mtx-${1}" +fi + + +tar --exclude CVS --exclude .svn -czvhf mtx-${1}.tar.gz mtx-${1} + diff --git a/mam2debug.c b/mam2debug.c new file mode 100644 index 0000000..7fb8231 --- /dev/null +++ b/mam2debug.c @@ -0,0 +1,124 @@ +/* Mammoth 2 Debug Buffer Dumper + Copyright 2000 Enhanced Software Technologies Inc. + Copyright 2007-2008 by Robert Nelson + +$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ +$Revision: 193 $ + + Written by Eric Lee Green + Released under the terms of the GNU General Public License v2 or + above. + + This is an example of how to use the mtx library file 'mtxl.c' to + do a special-purpose task -- dump the Mammoth2 debug buffer, in this case. + Note that this debug buffer is 1M-4M in size, thus may overwhelm the + SCSI generic subsystem on some supported platforms... + + syntax: + + mam2debug generic-filename output-filename. + + +*/ + +#include +#include +#include +#include + +#include "mtx.h" +#include "mtxl.h" + +/* This is a TOTALLY UNDOCUMENTED feature to read the debug data buffer + * in an Exabyte Mammoth II and dump it to a file: + */ + +static RequestSense_T *DumpM2DebugBuff(DEVICE_TYPE MediumChangerFD, int outfile) +{ + RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T)); + CDB_T CDB; + + unsigned char *databuffer; + unsigned char buff_descriptor[4]; + int numbytes; + int testbytes; + + CDB[0]=0x3c; /* command. */ + CDB[1]=0x03; /* mode - read buff_descriptor! */ + CDB[2]=0x01; /* page. */ + CDB[3]=0; /* offset. */ + CDB[4]=0; + CDB[5]=0; + CDB[6]=0; /* length. */ + CDB[7]=0; + CDB[8]=4; /* the descriptor is 4 long. */ + CDB[9]=0; + + if ((testbytes=SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 10, + buff_descriptor, 4, RequestSense)) != 0){ + fprintf(stderr,"mam2debug: could not read buff_descriptor. [%d]\n",testbytes); + return RequestSense; /* couldn't do it. */ + } + + /* okay, read numbytes: */ + numbytes=(buff_descriptor[1]<<16) + (buff_descriptor[2]<<8) + buff_descriptor[3]; + databuffer=(unsigned char *) xmalloc(numbytes+1000000); /* see if this helps :-(. */ + CDB[6]=buff_descriptor[1]; + CDB[7]=buff_descriptor[2]; + CDB[8]=buff_descriptor[3]; + + CDB[1]=0x02; /* mode -- read buffer! */ + + if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 10, + databuffer, numbytes, RequestSense) != 0){ + fprintf(stderr,"mam2debug: could not read buffer.\n"); + free(databuffer); + return RequestSense; /* couldn't do it. */ + } + + write(outfile,databuffer,numbytes); + close(outfile); + free(databuffer); + free(RequestSense); + return NULL; /* okay! */ +} + +static void usage(void) { + fprintf(stderr,"Usage: mam2debug scsi-generic-file output-file-name\n"); + exit(1); +} + +/* Now for the actual main() routine: */ + +int main(int argc,char** argv) { + DEVICE_TYPE changer_fd; + static RequestSense_T *result; + int outfile; + + if (argc != 3) { + usage(); + } + + changer_fd=SCSI_OpenDevice(argv[1]); + + if (changer_fd <= 0) { + fprintf(stderr,"Could not open input device\n"); + usage(); + } + + outfile=open(argv[2],O_CREAT|O_WRONLY); + if (outfile <=0) { + fprintf(stderr,"Could not open output file\n"); + usage(); + } + + result=DumpM2DebugBuff(changer_fd, outfile); + + if (result) { + PrintRequestSense(result); + exit(1); + } + + exit(0); +} + diff --git a/mam2debug2.c b/mam2debug2.c new file mode 100644 index 0000000..9d59395 --- /dev/null +++ b/mam2debug2.c @@ -0,0 +1,124 @@ +/* Mammoth 2 Debug Buffer Dumper + Copyright 2000 Enhanced Software Technologies Inc. + Copyright 2007-2008 by Robert Nelson + +$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ +$Revision: 193 $ + + Written by Eric Lee Green + Released under the terms of the GNU General Public License v2 or + above. + + This is an example of how to use the mtx library file 'mtxl.c' to + do a special-purpose task -- dump the Mammoth2 debug buffer, in this case. + Note that this debug buffer is 1M-4M in size, thus may overwhelm the + SCSI generic subsystem on some supported platforms... + + syntax: + + mam2debug generic-filename output-filename. + + +*/ + +#include +#include +#include +#include + +#include "mtx.h" +#include "mtxl.h" + +/* This is a TOTALLY UNDOCUMENTED feature to read the debug data buffer + * in an Exabyte Mammoth II and dump it to a file: + */ + +static RequestSense_T *DumpM2DebugBuff(DEVICE_TYPE MediumChangerFD, int outfile) +{ + RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T)); + CDB_T CDB; + + unsigned char *databuffer; + unsigned char buff_descriptor[4]; + int numbytes; + int testbytes; + + CDB[0]=0x3c; /* command. */ + CDB[1]=0x03; /* mode - read buff_descriptor! */ + CDB[2]=0x00; /* page -- data. */ + CDB[3]=0; /* offset. */ + CDB[4]=0; + CDB[5]=0; + CDB[6]=0; /* length. */ + CDB[7]=0; + CDB[8]=4; /* the descriptor is 4 long. */ + CDB[9]=0; + + if ((testbytes=SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 10, + buff_descriptor, 4, RequestSense)) != 0){ + fprintf(stderr,"mam2debug: could not read buff_descriptor. [%d]\n",testbytes); + return RequestSense; /* couldn't do it. */ + } + + /* okay, read numbytes: */ + numbytes=(buff_descriptor[1]<<16) + (buff_descriptor[2]<<8) + buff_descriptor[3]; + databuffer=(unsigned char *) xmalloc(numbytes+1000000); /* see if this helps :-(. */ + CDB[6]=buff_descriptor[1]; + CDB[7]=buff_descriptor[2]; + CDB[8]=buff_descriptor[3]; + + CDB[1]=0x02; /* mode -- read buffer! */ + + if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 10, + databuffer, numbytes, RequestSense) != 0){ + fprintf(stderr,"mam2debug: could not read buffer.\n"); + free(databuffer); + return RequestSense; /* couldn't do it. */ + } + + write(outfile,databuffer,numbytes); + close(outfile); + free(databuffer); + free(RequestSense); + return NULL; /* okay! */ +} + +static void usage(void) { + fprintf(stderr,"Usage: mam2debug scsi-generic-file output-file-name\n"); + exit(1); +} + +/* Now for the actual main() routine: */ + +int main(int argc,char** argv) { + DEVICE_TYPE changer_fd; + static RequestSense_T *result; + int outfile; + + if (argc != 3) { + usage(); + } + + changer_fd=SCSI_OpenDevice(argv[1]); + + if (changer_fd <= 0) { + fprintf(stderr,"Could not open input device\n"); + usage(); + } + + outfile=open(argv[2],O_CREAT|O_WRONLY); + if (outfile <=0) { + fprintf(stderr,"Could not open output file\n"); + usage(); + } + + result=DumpM2DebugBuff(changer_fd, outfile); + + if (result) { + PrintRequestSense(result); + exit(1); + } + + exit(0); +} + diff --git a/msvc/config.h b/msvc/config.h new file mode 100644 index 0000000..08902cb --- /dev/null +++ b/msvc/config.h @@ -0,0 +1,37 @@ +/* config.h. Generated by configure. */ +/* Copyright 2001 Enhanced Software Technologies Inc. + * Released under GNU General Public License V2 or Above + * See http://www.gnu.org for more information about the terms of + * the GNU General Public License. + * $Date: 2007-01-28 19:23:33 -0800 (Sun, 28 Jan 2007) $ + * $Revision: 125 $ + */ + +#ifndef CONFIG_H +#define CONFIG_H 1 + +/* autoconf changes these. */ +#define HAVE_STRING_H 1 +#define HAVE_UNISTD_H 0 +#define HAVE_STDLIB_H 1 +#define HAVE_STDARG_H 1 +#define HAVE_SCSI_SCSI_H 0 +#define HAVE_SCSI_SCSI_IOCTL_H 0 +#define HAVE_SCSI_SG_H 0 +#define HAVE_SYS_GSCDDS_H 0 +#define HAVE_CAMLIB_H 0 +#define HAVE_SYS_SCSI_IMPL_USCSI_H 0 +#define HAVE_SYS_SCSI_CTL_H 0 +#define HAVE_DSLIB_H 0 +#define HAVE_DU_DEFS_H 0 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_FCNTL_H 1 +#define HAVE_SYS_IOCTL_H 0 +#define HAVE_SYS_MTIO_H 0 +#define HAVE_DDK_NTDDSCSI_H 0 + +#define WORDS_BIGENDIAN 0 + +#endif + diff --git a/msvc/loaderinfo/loaderinfo.vcproj b/msvc/loaderinfo/loaderinfo.vcproj new file mode 100644 index 0000000..4d3df91 --- /dev/null +++ b/msvc/loaderinfo/loaderinfo.vcproj @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/mtx.sln b/msvc/mtx.sln new file mode 100644 index 0000000..3b39f7f --- /dev/null +++ b/msvc/mtx.sln @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loaderinfo", "loaderinfo\loaderinfo.vcproj", "{13712060-F1FC-4498-97A7-5DA5A38F04DD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mtx", "mtx\mtx.vcproj", "{7DD926F5-30EA-47D4-B67B-E32C0E221440}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scsitape", "scsitape\scsitape.vcproj", "{D19E95BD-87C6-4C91-A208-FB8338580F75}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tapeinfo", "tapeinfo\tapeinfo.vcproj", "{A1C8D34F-66EC-4F74-8261-C96B97727218}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsmhack", "nsmhack\nsmhack.vcproj", "{1B3C0A23-4021-4928-92FA-76743B7F7F76}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scsieject", "scsieject\scsieject.vcproj", "{E3B77A78-FD72-4AD7-933A-0503FB21551D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {13712060-F1FC-4498-97A7-5DA5A38F04DD}.Debug|Win32.ActiveCfg = Debug|Win32 + {13712060-F1FC-4498-97A7-5DA5A38F04DD}.Debug|Win32.Build.0 = Debug|Win32 + {13712060-F1FC-4498-97A7-5DA5A38F04DD}.Release|Win32.ActiveCfg = Release|Win32 + {13712060-F1FC-4498-97A7-5DA5A38F04DD}.Release|Win32.Build.0 = Release|Win32 + {7DD926F5-30EA-47D4-B67B-E32C0E221440}.Debug|Win32.ActiveCfg = Debug|Win32 + {7DD926F5-30EA-47D4-B67B-E32C0E221440}.Debug|Win32.Build.0 = Debug|Win32 + {7DD926F5-30EA-47D4-B67B-E32C0E221440}.Release|Win32.ActiveCfg = Release|Win32 + {7DD926F5-30EA-47D4-B67B-E32C0E221440}.Release|Win32.Build.0 = Release|Win32 + {D19E95BD-87C6-4C91-A208-FB8338580F75}.Debug|Win32.ActiveCfg = Debug|Win32 + {D19E95BD-87C6-4C91-A208-FB8338580F75}.Debug|Win32.Build.0 = Debug|Win32 + {D19E95BD-87C6-4C91-A208-FB8338580F75}.Release|Win32.ActiveCfg = Release|Win32 + {D19E95BD-87C6-4C91-A208-FB8338580F75}.Release|Win32.Build.0 = Release|Win32 + {A1C8D34F-66EC-4F74-8261-C96B97727218}.Debug|Win32.ActiveCfg = Debug|Win32 + {A1C8D34F-66EC-4F74-8261-C96B97727218}.Debug|Win32.Build.0 = Debug|Win32 + {A1C8D34F-66EC-4F74-8261-C96B97727218}.Release|Win32.ActiveCfg = Release|Win32 + {A1C8D34F-66EC-4F74-8261-C96B97727218}.Release|Win32.Build.0 = Release|Win32 + {1B3C0A23-4021-4928-92FA-76743B7F7F76}.Debug|Win32.ActiveCfg = Debug|Win32 + {1B3C0A23-4021-4928-92FA-76743B7F7F76}.Debug|Win32.Build.0 = Debug|Win32 + {1B3C0A23-4021-4928-92FA-76743B7F7F76}.Release|Win32.ActiveCfg = Release|Win32 + {1B3C0A23-4021-4928-92FA-76743B7F7F76}.Release|Win32.Build.0 = Release|Win32 + {E3B77A78-FD72-4AD7-933A-0503FB21551D}.Debug|Win32.ActiveCfg = Debug|Win32 + {E3B77A78-FD72-4AD7-933A-0503FB21551D}.Debug|Win32.Build.0 = Debug|Win32 + {E3B77A78-FD72-4AD7-933A-0503FB21551D}.Release|Win32.ActiveCfg = Release|Win32 + {E3B77A78-FD72-4AD7-933A-0503FB21551D}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/msvc/mtx/Distributions.txt b/msvc/mtx/Distributions.txt new file mode 100644 index 0000000..7f13a59 --- /dev/null +++ b/msvc/mtx/Distributions.txt @@ -0,0 +1,49 @@ +Debian +====== + +Maintainer: BDale Garbee (bdale@gag.com) (Official) +Stable Version: 1.2.16rel-4 +Testing Version: 1.2.17rel-2 + +Merged: Yes + +FreeBSD + +Maintainer: mbr@freebsd.org +Stable Version: 1.2.17rel + +Merged: Yes + +Gentoo +====== + +Maintainer: Tom Gall (tgall@gentoo.org) (Last change) +Stable Version: 1.2.18 + +Merged: No changes + +Mandriva +======== + +Maintainer: Buchan Milne +Stable Version: 1.2.18-1mdk + +Merged: No changes + + +Redhat +====== + +Maintainer: Jesse Keating (Last change) (jnovy@redhat.com) +Stable Version: 1.2.18-8 + +Merged: No additional changes + + +SuSE +==== + +Maintainer http://www.suse.de/feedback +Stable Version: 1.2.18rel-119 + +Merged: No additional changes diff --git a/msvc/mtx/mtx.vcproj b/msvc/mtx/mtx.vcproj new file mode 100644 index 0000000..bffae8e --- /dev/null +++ b/msvc/mtx/mtx.vcproj @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/nsmhack/nsmhack.vcproj b/msvc/nsmhack/nsmhack.vcproj new file mode 100644 index 0000000..9bebb9c --- /dev/null +++ b/msvc/nsmhack/nsmhack.vcproj @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/scsieject/scsieject.vcproj b/msvc/scsieject/scsieject.vcproj new file mode 100644 index 0000000..ca08707 --- /dev/null +++ b/msvc/scsieject/scsieject.vcproj @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/scsitape/scsitape.vcproj b/msvc/scsitape/scsitape.vcproj new file mode 100644 index 0000000..cc2d55b --- /dev/null +++ b/msvc/scsitape/scsitape.vcproj @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msvc/tapeinfo/tapeinfo.vcproj b/msvc/tapeinfo/tapeinfo.vcproj new file mode 100644 index 0000000..07e8ecc --- /dev/null +++ b/msvc/tapeinfo/tapeinfo.vcproj @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mtx.1 b/mtx.1 new file mode 100644 index 0000000..a5e6cc6 --- /dev/null +++ b/mtx.1 @@ -0,0 +1,257 @@ +.\" mtx.1 Document copyright 2000 Eric Lee Green +.\" Program Copyright 1996, 1997 Leonard Zubkoff +.\" Copyright 2007-2008 by Robert Nelson +.\" Extensive changes 2000 by Eric Lee Green +.\" +.\" This is free documentation; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License as +.\" published by the Free Software Foundation; either version 2 of +.\" the License, or (at your option) any later version. +.\" +.\" The GNU General Public License's references to "object code" +.\" and "executables" are to be interpreted as the output of any +.\" document formatting or typesetting system, including +.\" intermediate and printed output. +.\" +.\" This manual is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public +.\" License along with this manual; if not, write to the Free +.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +.\" USA. +.\" +.TH MTX 1 MTX1.3 +.SH NAME +mtx \- control SCSI media changer devices +.SH SYNOPSIS +mtx [-f ] [nobarcode] [invert] [noattach] command [ command ... ] +.SH DESCRIPTION +The +.B mtx +command controls single or multi-drive SCSI media changers such as +tape changers, autoloaders, tape libraries, or optical media jukeboxes. +It can also be used with media changers that use the 'ATTACHED' API, +presuming that they properly report the MChanger bit as required +by the SCSI T-10 SMC specification. +.SH OPTIONS +The first argument, given following +.B -f +, is the SCSI generic device corresponding to your media changer. +Consult your operating system's documentation for more information (for +example, under Linux these are generally /dev/sg0 through /dev/sg15, +under FreeBSD these are /dev/pass0 through /dev/passX, +under SunOS it may be a file under /dev/rdsk). +.P +The 'invert' option will invert (flip) the media (for optical jukeboxes that +allow such) before inserting it into the drive or returning it to the +storage slot. +.P +The 'noattach' option forces the regular media changer API even if the +media changer incorrectly reported that it uses the 'ATTACHED' API. +.P +The 'nobarcode' option forces the loader to not request barcodes even if +the loader is capable of reporting them. +.P +Following these options there may follow +one or more robotics control +commands. Note that the 'invert' and 'noattach' +options apply to ALL of robotics control +commands. + +.SH COMMANDS +.TP 10 +.B --version +Report the mtx version number (e.g. mtx 1.2.8) and exit. + +.TP 10 +.B inquiry +Report the product type (Medium Changer, Tape Drive, etc.), Vendor ID, +Product ID, Revision, and whether this uses the Attached Changer API +(some tape drives use this rather than reporting a Medium Changer on a +separate LUN or SCSI address). +.TP 10 +.B noattach +Make further commands use the regular media changer API rather than the +_ATTACHED API, no matter what the "Attached" bit said in the Inquiry info. +Needed with some brain-dead changers that report Attached bit but don't respond +to _ATTACHED API. +.TP 10 +.B inventory +Makes the robot arm go and check what elements are in the slots. This +is needed for a few libraries like the Breece Hill ones that do not +automatically check the tape inventory at system startup. +.TP 10 +.B status +Reports how many drives and storage elements are contained in the +device. For each drive, reports whether it has media loaded in it, and +if so, from which storage slot the media originated. For each storage +slot, reports whether it is empty or full, and if the media changer +has a bar code, MIC reader, or some other way of uniquely identifying +media without loading it into a drive, this reports the volume tag +and/or alternate volume tag for each piece of media. +For historical reasons drives are numbered from 0 and storage slots are +numbered from 1. +.TP 10 +.B load [ ] +Load media from slot into drive . Drive 0 is assumed +if the drive number is omitted. +.TP 10 +.B unload [] [ ] +Unloads media from drive into slot . If is +omitted, defaults to drive 0 (as do all commands). +If is omitted, defaults to the slot +that the drive was loaded from. Note that there's currently no way to +say 'unload drive 1's media to the slot it came from', other than to +explicitly use that slot number as the destination. +.TP 10 +.B [eepos ] transfer +Transfers media from one slot to another, assuming that your mechanism is +capable of doing so. Usually used to move media to/from an import/export +port. 'eepos' is used to extend/retract the import/export +tray on certain mid-range to high end tape libraries (if, e.g., the tray was +slot 32, you might say say 'eepos 1 transfer 32 32' to extend the tray). +Valid values for eepos +are 0 (do nothing to the import/export tray), 1, and 2 (what 1 and 2 do varies +depending upon the library, consult your library's SCSI-level +documentation). +.TP 10 +.B [eepos ] [invert] [invert2] exchange [] +Move medium from the first slot to the second slot, placing the medium +currently in the second slot either back into the first slot or into the +optional third slot. + +.TP 10 +.B first [] +Loads drive from the first slot in the media +changer. Unloads the drive if there is already media in it (note: you +may need to eject the tape using your OS's tape control commands +first). Note that this command may not be what you want on large +tape libraries -- e.g. on Exabyte 220, the first slot is usually a +cleaning tape. If is omitted, defaults to first drive. + +.TP 10 +.B last [] +Loads drive from the last slot in the media changer. Unloads +the drive if there is already a tape in it. (Note: you may need to eject +the tape using your OS's tape control commands first). +.TP 10 +.B next [] +Unloads the drive and loads the next tape in sequence. If the drive was +empty, loads the first tape into the drive. +.TP 10 +.B position +Positions the robot at a specific slot. Needed by some changers to +move to and open the import/export, or mailbox, slot. + +.SH AUTHORS +The original 'mtx' program was written by Leonard Zubkoff and extensively +revised for large multi-drive libraries with bar code readers +by Eric Lee Green . See 'mtx.c' for other contributors. +.SH BUGS AND LIMITATIONS +.P +You may need to do a 'mt offline' on the tape drive to eject the tape +before you can issue the 'mtx unload' command. The Exabyte EZ-17 and 220 +in particular will happily sit there snapping the robot arm's claws around +thin air trying to grab a tape that's not there. +.P +For some Linux distributions, you may need to re-compile the kernel to +scan SCSI LUN's in order to detect the media changer. Check /proc/scsi/scsi +to see what's going on. +.P +If you try to unload a tape to its 'source' slot, and said slot is +full, it will instead put the tape into the first empty +slot. Unfortunately the list of empty slots is not updated between +commands on the command line, so if you try to unload another drive to +a full 'source' slot during the same invocation of 'mtx', it will try +to unload to the same (no longer empty) slot and will urp with a SCSI +error. +.P + +This program reads the Mode Sense Element Address Assignment Page +(SCSI) and requests data on all available elements. For larger +libraries (more than a couple dozen elements) +this sets a big Allocation_Size in the SCSI command block for the +REQUEST_ELEMENT_STATUS command in order to be able to read the entire +result of a big tape library. Some operating systems may not be able +to handle this. Versions of Linux earlier than 2.2.6, in particular, +may fail this request due to inability to find contiguous pages of +memory for the SCSI transfer (later versions of Linux 'sg' device do +scatter-gather so that this should no longer be a problem). +.P +The +.B eepos +command remains in effect for all further commands on a command +line. Thus you might want to follow +.B eepos 1 transfer 32 32 +with +.B eepos 0 +as +the next command (which clears the +.B eepos +bits). +.P +Need a better name for 'eepos' command! ('eepos' is the name of the bit +field in the actual low-level SCSI command, and has nothing to do with what +it does). +.P + +This program has only been tested on Linux with a limited number of +tape loaders (a dual-drive Exabyte 220 tape library, with bar-code +reader and 21 slots, an Exabyte EZ-17 7-slot autoloader, and a Seagate +DDS-4 autochanger with 6 slots). It may not work on other operating systems +with larger libraries, +due to the big SCSI request size. +Please see the projecdt page http://sourceforge.net/projects/mtx for information +on reporting bugs, requesting features and the mailing list for peer support. +.SH HINTS +Under Linux, +.B cat /proc/scsi/scsi +will tell you what SCSI devices you have. +You can then refer to them as +.B /dev/sga, +.B /dev/sgb, +etc. by the order they +are reported. +.P +Under FreeBSD, +.B camcontrol devlist +will tell you what SCSI devices you +have, along with which +.B pass +device controls them. +.P +Under Solaris, set up your 'sgen' driver so that it'll look for +tape changers (see /kernel/drv/sgen.conf and the sgen man page), type +.B touch /reconfigure +then reboot. You can find your changer in /devices by typing +.B /usr/sbin/devfsadm -C +to clean out no-longer-extant entries in your /devices directory, then +.B find /devices -name \e\(**changer -print +to find the device name. Set the symbolic link +.B /dev/changer +to point +to that device name (if it is not doing so already). +.P +With BRU, set your mount and unmount commands as described on the BRU +web site at http://www.bru.com to move to the next tape when backing up +or restoring. With GNU +.B tar, +see +.B mtx.doc +for an example of how to use +.B tar +and +.B mtx +to make multi-tape backups. + +.SH AVAILABILITY +This version of +.B mtx +is currently being maintained by Robert Nelson . +The 'mtx' home page is http://mtx.sourceforge.net and the actual code is currently available +there and via SVN from http://sourceforge.net/projects/mtx. +.SH SEE ALSO +.BR mt (1), loaderinfo (1), tapeinfo (1), scsitape (1), scsieject (1) diff --git a/mtx.c b/mtx.c new file mode 100644 index 0000000..fab11bb --- /dev/null +++ b/mtx.c @@ -0,0 +1,1075 @@ +/* + + MTX -- SCSI Tape Attached Medium Changer Control Program + $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ + $Revision: 193 $ + + Copyright 1997-1998 by Leonard N. Zubkoff. + Copyright 1999-2006 by Eric Lee Green. + Copyright 2007-2008 by Robert Nelson + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for complete details. + + The author respectfully requests that any modifications to this software be + sent directly to him for evaluation and testing. + + Thanks to Philip A. Prindeville of Enteka Enterprise + Technology Service for porting MTX to Solaris/SPARC. + + Thanks to Carsten Koch for porting MTX to SGI IRIX. + + Thanks to TECSys Development, Inc. for porting MTX to Digital Unix and + OpenVMS. + + Near complete re-write Feb 2000 Eric Lee Green to add support for + multi-drive tape changers, extract out library stuff into mtxl.c, + and otherwise bring things up to date for dealing with LARGE tape jukeboxes + and other such enterprise-class storage subsystems. +*/ + +char *argv0; + +#include "mtx.h" /* various defines for bit order etc. */ +#include "mtxl.h" + +/* A table for printing out the peripheral device type as ASCII. */ +static char *PeripheralDeviceType[32] = +{ + "Disk Drive", /* 0 */ + "Tape Drive", /* 1 */ + "Printer", /* 2 */ + "Processor", /* 3 */ + "Write-once", /* 4 */ + "CD-ROM", /* 5 */ + "Scanner", /* 6 */ + "Optical", /* 7 */ + "Medium Changer", /* 8 */ + "Communications", /* 9 */ + "ASC IT8", /* a */ + "ASC IT8", /* b */ + "RAID Array", /* c */ + "Enclosure Services", /* d */ + "RBC Simplified Disk", /* e */ + "OCR/W", /* f */ + "Bridging Expander", /* 0x10 */ + "Reserved", /* 0x11 */ + "Reserved", /* 0x12 */ + "Reserved", /* 0x13 */ + "Reserved", /* 0x14 */ + "Reserved", /* 0x15 */ + "Reserved", /* 0x16 */ + "Reserved", /* 0x17 */ + "Reserved", /* 0x18 */ + "Reserved", /* 0x19 */ + "Reserved", /* 0x1a */ + "Reserved", /* 0x1b */ + "Reserved", /* 0x1c */ + "Reserved", /* 0x1d */ + "Reserved", /* 0x1e */ + "Unknown" /* 0x1f */ +}; + +static int argc; +static char **argv; + +static char *device=NULL; /* the device name passed as argument */ + +/* Unfortunately this must be true for SGI, because SGI does not + use an int :-(. +*/ + +static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) -1; +static int device_opened = 0; /* okay, replace check here. */ + +static int arg1 = -1; /* first arg to command */ +static int arg2 = -1; /* second arg to command */ +static int arg3 = -1; /* third arg to command, if exchange. */ + +static SCSI_Flags_T SCSI_Flags = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static Inquiry_T *inquiry_info; /* needed by MoveMedium etc... */ +static ElementStatus_T *ElementStatus = NULL; +void Position(int dest); + +/* pre-defined commands: */ +static void ReportInquiry(void); +static void Status(void); +static void Load(void); +static void Unload(void); +static void First(void); +static void Last(void); +static void Next(void); +static void Previous(void); +static void InvertCommand(void); +static void Transfer(void); +static void Eepos(void); +static void NoAttach(void); +static void Version(void); +static void do_Inventory(void); +static void do_Unload(void); +static void do_Erase(void); +static void NoBarCode(void); +static void do_Position(void); +static void Invert2(void); +static void Exchange(void); +static void AltReadElementStatus(void); + +struct command_table_struct +{ + int num_args; + char *name; + void (*command)(void); + int need_device; + int need_status; +} +command_table[] = +{ + { 0, "inquiry",ReportInquiry, 1,0}, + { 0, "status", Status, 1,1 }, + { 0, "invert", InvertCommand, 0,0}, + { 0, "noattach",NoAttach,0,0}, + { 1, "eepos", Eepos, 0,0}, + { 2, "load", Load, 1,1 }, + { 2, "unload", Unload, 1,1 }, + { 2, "transfer", Transfer, 1,1 }, + { 1, "first", First, 1,1 }, + { 1, "last", Last, 1,1 }, + { 1, "previous", Previous, 1,1 }, + { 1, "next", Next, 1,1 }, + { 0, "--version", Version, 0,0 }, + { 0, "inventory", do_Inventory, 1,0}, + { 0, "eject", do_Unload, 1, 0}, + { 0, "erase", do_Erase, 1, 0}, + { 0, "nobarcode", NoBarCode, 0,0}, + { 1, "position", do_Position, 1, 1}, + { 0, "invert2", Invert2, 0, 0}, + { 3, "exchange", Exchange, 1, 1 }, + { 0, "altres", AltReadElementStatus, 0,0}, + { 0, NULL, NULL } +}; + +static void Usage() +{ + fprintf(stderr, "Usage:\n\ + mtx --version\n\ + mtx [ -f ] noattach \n\ + mtx [ -f ] inquiry | inventory \n\ + mtx [ -f ] [altres] [nobarcode] status\n\ + mtx [ -f ] [altres] first []\n\ + mtx [ -f ] [altres] last []\n\ + mtx [ -f ] [altres] previous []\n\ + mtx [ -f ] [altres] next []\n\ + mtx [ -f ] [altres] [invert] load []\n\ + mtx [ -f ] [altres] [invert] unload [][]\n\ + mtx [ -f ] [altres] [eepos eepos-number] transfer \n\ + mtx [ -f ] [altres] [eepos eepos-number][invert][invert2] exchange \n\ + mtx [ -f ] [altres] position \n\ + mtx [ -f ] eject\n"); + +#ifndef VMS + exit(1); +#else + sys$exit(VMS_ExitCode); +#endif +} + + +static void Version(void) +{ + fprintf(stderr, "mtx version %s\n\n", VERSION); + Usage(); +} + + +static void NoAttach(void) +{ + SCSI_Flags.no_attached = 1; +} + + +static void InvertCommand(void) +{ + SCSI_Flags.invert = 1; /* invert_bit=1;*/ +} + + +static void Invert2(void) +{ + SCSI_Flags.invert2 = 1; /* invert2_bit=1;*/ +} + + +static void NoBarCode(void) +{ + SCSI_Flags.no_barcodes = 1; /* don't request barcodes */ +} + + +static void do_Position(void) +{ + int driveno,src; + + if (arg1 >= 0 && arg1 <= ElementStatus->StorageElementCount) + { + driveno = arg1 - 1; + } + else + { + driveno = 0; + } + + src = ElementStatus->StorageElementAddress[driveno]; + Position(src); +} + + +static void AltReadElementStatus(void) +{ + /* use alternative way to read element status from device - used to support XL1B2 */ + SCSI_Flags.querytype = MTX_ELEMENTSTATUS_READALL; +} + + +/* First and Last are easy. Next is the bitch. */ +static void First(void) +{ + int driveno; + /* okay, first see if we have a drive#: */ + if (arg1 >= 0 && arg1 < ElementStatus->DataTransferElementCount) + { + driveno = arg1; + } + else + { + driveno = 0; + } + + /* now see if there's anything *IN* that drive: */ + if (ElementStatus->DataTransferElementFull[driveno]) + { + /* if so, then unload it... */ + arg1 = ElementStatus->DataTransferElementSourceStorageElementNumber[driveno] + 1; + if (arg1 == 1) + { + printf("loading...done.\n"); /* it already has tape #1 in it! */ + return; + } + arg2 = driveno; + Unload(); + } + + /* and now to actually do the Load(): */ + arg1 = 1; /* first! */ + arg2 = driveno; + Load(); /* and voila! */ +} + +static void Last(void) +{ + int driveno; + + /* okay, first see if we have a drive#: */ + if (arg1 >= 0 && arg1 < ElementStatus->DataTransferElementCount) + { + driveno = arg1; + } + else + { + driveno = 0; + } + + /* now see if there's anything *IN* that drive: */ + if (ElementStatus->DataTransferElementFull[driveno]) + { + /* if so, then unload it... */ + arg1 = ElementStatus->DataTransferElementSourceStorageElementNumber[driveno] + 1; + if (arg1 >= (ElementStatus->StorageElementCount - ElementStatus->ImportExportCount)) + { + printf("loading...done.\n"); /* it already has last tape in it! */ + return; + } + arg2 = driveno; + Unload(); + } + + arg1 = ElementStatus->StorageElementCount - ElementStatus->ImportExportCount; /* the last slot... */ + arg2 = driveno; + Load(); +} + + +static void Previous(void) +{ + int driveno; + int current = ElementStatus->StorageElementCount - ElementStatus->ImportExportCount + 1; + + /* okay, first see if we have a drive#: */ + if (arg1 >= 0 && arg1 < ElementStatus->DataTransferElementCount) + { + driveno = arg1; + } + else + { + driveno = 0; + } + + /* Now to see if there's anything in that drive! */ + if (ElementStatus->DataTransferElementFull[driveno]) + { + /* if so, unload it! */ + current = ElementStatus->DataTransferElementSourceStorageElementNumber[driveno]; + if (current == 0) + { + FatalError("No More Media\n"); /* Already at the 1st slot...*/ + } + arg1 = current + 1; /* Args are 1 based */ + arg2 = driveno; + Unload(); + } + + /* Position current to previous element */ + for (current--; current >= 0; current--) + { + if (ElementStatus->StorageElementFull[current]) + { + arg1 = current + 1; + arg2 = driveno; + Load(); + return; + } + } + + FatalError("No More Media\n"); /* First slot */ +} + + +static void Next(void) +{ + int driveno; + int current = -1; + + /* okay, first see if we have a drive#: */ + if (arg1 >= 0 && arg1 < ElementStatus->DataTransferElementCount) + { + driveno = arg1; + } + else + { + driveno = 0; + } + + /* Now to see if there's anything in that drive! */ + if (ElementStatus->DataTransferElementFull[driveno]) + { + /* if so, unload it! */ + current = ElementStatus->DataTransferElementSourceStorageElementNumber[driveno]; + + arg1 = current + 1; + arg2 = driveno; + Unload(); + } + + for (current++; + current < (ElementStatus->StorageElementCount - ElementStatus->ImportExportCount); + current++) + { + if (ElementStatus->StorageElementFull[current]) + { + arg1 = current + 1; + arg2 = driveno; + Load(); + return; + } + } + + FatalError("No More Media\n"); /* last slot */ +} + +static void do_Inventory(void) +{ + if (Inventory(MediumChangerFD) < 0) + { + fprintf(stderr,"mtx:inventory failed\n"); + fflush(stderr); + exit(1); /* exit with an error status. */ + } +} + +/* + * For Linux, this allows us to do a short erase on a tape (sigh!). + * Note that you'll need to do a 'mt status' on the tape afterwards in + * order to get the tape driver in sync with the tape drive again. Also + * note that on other OS's, this might do other evil things to the tape + * driver. Note that to do an erase, you must first rewind using the OS's + * native tools! + */ +static void do_Erase(void) +{ + RequestSense_T *RequestSense; + RequestSense = Erase(MediumChangerFD); + if (RequestSense) + { + PrintRequestSense(RequestSense); + exit(1); /* exit with an error status. */ + } +} + + +/* This should eject a tape or magazine, depending upon the device sent + * to. + */ +static void do_Unload(void) +{ + if (LoadUnload(MediumChangerFD, 0) < 0) + { + fprintf(stderr, "mtx:eject failed\n"); + fflush(stderr); + } +} + +static void ReportInquiry(void) +{ + RequestSense_T RequestSense; + Inquiry_T *Inquiry; + int i; + + Inquiry = RequestInquiry(MediumChangerFD,&RequestSense); + if (Inquiry == NULL) + { + PrintRequestSense(&RequestSense); + FatalError("INQUIRY Command Failed\n"); + } + + printf("Product Type: %s\n", PeripheralDeviceType[Inquiry->PeripheralDeviceType]); + printf("Vendor ID: '"); + for (i = 0; i < sizeof(Inquiry->VendorIdentification); i++) + { + printf("%c", Inquiry->VendorIdentification[i]); + } + + printf("'\nProduct ID: '"); + for (i = 0; i < sizeof(Inquiry->ProductIdentification); i++) + { + printf("%c", Inquiry->ProductIdentification[i]); + } + + printf("'\nRevision: '"); + for (i = 0; i < sizeof(Inquiry->ProductRevisionLevel); i++) + { + printf("%c", Inquiry->ProductRevisionLevel[i]); + } + printf("'\n"); + + if (Inquiry->MChngr) + { + /* check the attached-media-changer bit... */ + printf("Attached Changer API: Yes\n"); + } + else + { + printf("Attached Changer API: No\n"); + } + + free(Inquiry); /* well, we're about to exit, but ... */ +} + +static void Status(void) +{ + int StorageElementNumber; + int TransferElementNumber; + + printf( " Storage Changer %s:%d Drives, %d Slots ( %d Import/Export )\n", + device, + ElementStatus->DataTransferElementCount, + ElementStatus->StorageElementCount, + ElementStatus->ImportExportCount); + + + for (TransferElementNumber = 0; + TransferElementNumber < ElementStatus->DataTransferElementCount; + TransferElementNumber++) + { + + printf("Data Transfer Element %d:", TransferElementNumber); + if (ElementStatus->DataTransferElementFull[TransferElementNumber]) + { + if (ElementStatus->DataTransferElementSourceStorageElementNumber[TransferElementNumber] > -1) + { + printf("Full (Storage Element %d Loaded)", + ElementStatus->DataTransferElementSourceStorageElementNumber[TransferElementNumber]+1); + } + else + { + printf("Full (Unknown Storage Element Loaded)"); + } + + if (ElementStatus->DataTransferPrimaryVolumeTag[TransferElementNumber][0]) + { + printf(":VolumeTag = %s", ElementStatus->DataTransferPrimaryVolumeTag[TransferElementNumber]); + } + + if (ElementStatus->DataTransferAlternateVolumeTag[TransferElementNumber][0]) + { + printf(":AlternateVolumeTag = %s", ElementStatus->DataTransferAlternateVolumeTag[TransferElementNumber]); + } + putchar('\n'); + } + else + { + printf("Empty\n"); + } + } + + for (StorageElementNumber = 0; + StorageElementNumber < ElementStatus->StorageElementCount; + StorageElementNumber++) + { + printf( " Storage Element %d%s:%s", StorageElementNumber + 1, + (ElementStatus->StorageElementIsImportExport[StorageElementNumber]) ? " IMPORT/EXPORT" : "", + (ElementStatus->StorageElementFull[StorageElementNumber] ? "Full " : "Empty")); + + if (ElementStatus->PrimaryVolumeTag[StorageElementNumber][0]) + { + printf(":VolumeTag=%s", ElementStatus->PrimaryVolumeTag[StorageElementNumber]); + } + + if (ElementStatus->AlternateVolumeTag[StorageElementNumber][0]) + { + printf(":AlternateVolumeTag=%s", ElementStatus->AlternateVolumeTag[StorageElementNumber]); + } + putchar('\n'); + } + +#ifdef VMS + VMS_DefineStatusSymbols(); +#endif +} + +void Position(int dest) +{ + if (PositionElement(MediumChangerFD,dest,ElementStatus) != NULL) + { + FatalError("Could not position transport\n"); + } +} + +void Move(int src, int dest) { + RequestSense_T *result; /* from MoveMedium */ + + result = MoveMedium(MediumChangerFD, src, dest, ElementStatus, inquiry_info, &SCSI_Flags); + if (result) + { + /* we have an error! */ + + if (result->AdditionalSenseCode == 0x30 && + result->AdditionalSenseCodeQualifier == 0x03) + { + FatalError("Cleaning Cartridge Installed and Ejected\n"); + } + + if (result->AdditionalSenseCode == 0x3A && + result->AdditionalSenseCodeQualifier == 0x00) + { + FatalError("Drive needs offline before move\n"); + } + + if (result->AdditionalSenseCode == 0x3B && + result->AdditionalSenseCodeQualifier == 0x0D) + { + FatalError("Destination Element Address %d is Already Full\n", dest); + } + + if (result->AdditionalSenseCode == 0x3B && + result->AdditionalSenseCodeQualifier == 0x0E) + { + FatalError("Source Element Address %d is Empty\n", src); + } + + PrintRequestSense(result); + FatalError("MOVE MEDIUM from Element Address %d to %d Failed\n", src, dest); + } +} + + +/* okay, now for the Load, Unload, etc. logic: */ + +static void Load(void) +{ + int src, dest; + + /* okay, check src, dest: arg1=src, arg2=dest */ + if (arg1 < 1) + { + FatalError("No source specified\n"); + } + + if (arg2 < 0) + { + arg2 = 0; /* default to 1st drive :-( */ + } + + arg1--; /* we use zero-based arrays */ + + if (!device_opened) + { + FatalError("No Media Changer Device Specified\n"); + } + + if (arg1 < 0 || arg1 >= ElementStatus->StorageElementCount) + { + FatalError( "Invalid argument '%d' to 'load' command\n", + arg1 + 1); + } + + if (arg2 < 0 || arg2 >= ElementStatus->DataTransferElementCount) + { + FatalError( "illegal argument '%d' to 'load' command\n", + arg2); + } + + if (ElementStatus->DataTransferElementFull[arg2]) + { + FatalError( "Drive %d Full (Storage Element %d loaded)\n", arg2, + ElementStatus->DataTransferElementSourceStorageElementNumber[arg2] + 1); + } + + /* Now look up the actual devices: */ + src = ElementStatus->StorageElementAddress[arg1]; + dest = ElementStatus->DataTransferElementAddress[arg2]; + + fprintf(stdout, "Loading media from Storage Element %d into drive %d...", arg1 + 1, arg2); + fflush(stdout); + + Move(src,dest); /* load it into the particular slot, if possible! */ + + fprintf(stdout,"done\n"); + fflush(stdout); + + /* now set the status for further commands on this line... */ + ElementStatus->StorageElementFull[arg1] = false; + ElementStatus->DataTransferElementFull[arg2] = true; +} + +static void Transfer(void) +{ + int src,dest; + + if (arg1 < 1) + { + FatalError("No source specified\n"); + } + + if (arg2 < 1) + { + FatalError("No destination specified\n"); + } + + if (arg1 > ElementStatus->StorageElementCount) + { + FatalError("Invalid source\n"); + } + + if (arg2 > ElementStatus->StorageElementCount) + { + FatalError("Invalid destination\n"); + } + + src = ElementStatus->StorageElementAddress[arg1 - 1]; + dest = ElementStatus->StorageElementAddress[arg2 - 1]; + Move(src,dest); +} + +/**************************************************************** + * Exchange() -- exchange medium in two slots, if so + * supported by the jukebox in question. + ***************************************************************/ + +static void Exchange(void) +{ + RequestSense_T *result; /* from ExchangeMedium */ + int src,dest,dest2; + + if (arg1 < 1) + { + FatalError("No source specified\n"); + } + + if (arg2 < 1) + { + FatalError("No destination specified\n"); + } + + if (arg1 > ElementStatus->StorageElementCount) + { + FatalError("Invalid source\n"); + } + + if (arg2 > ElementStatus->StorageElementCount) + { + FatalError("Invalid destination\n"); + } + + if (arg3 == -1) + { + arg3 = arg1; /* true exchange of medium */ + } + + src = ElementStatus->StorageElementAddress[arg1 - 1]; + dest = ElementStatus->StorageElementAddress[arg2 - 1]; + dest2 = ElementStatus->StorageElementAddress[arg3 - 1]; + + result = ExchangeMedium(MediumChangerFD, src, dest, dest2, ElementStatus, &SCSI_Flags); + if (result) + { + /* we have an error! */ + if (result->AdditionalSenseCode == 0x30 && + result->AdditionalSenseCodeQualifier == 0x03) + { + FatalError("Cleaning Cartridge Installed and Ejected\n"); + } + + if (result->AdditionalSenseCode == 0x3A && + result->AdditionalSenseCodeQualifier == 0x00) + { + FatalError("Drive needs offline before move\n"); + } + + if (result->AdditionalSenseCode == 0x3B && + result->AdditionalSenseCodeQualifier == 0x0D) + { + FatalError("Destination Element Address %d is Already Full\n", dest); + } + + if (result->AdditionalSenseCode == 0x3B && + result->AdditionalSenseCodeQualifier == 0x0E) + { + FatalError("Source Element Address %d is Empty\n", src); + } + + PrintRequestSense(result); + + FatalError("EXCHANGE MEDIUM from Element Address %d to %d Failed\n", src, dest); + } +} + +static void Eepos(void) +{ + if (arg1 < 0 || arg1 > 3) + { + FatalError("eepos equires argument between 0 and 3.\n"); + } + + SCSI_Flags.eepos = (unsigned char)arg1; +} + + +static void Unload(void) +{ + int src, dest; /* the actual SCSI-level numbers */ + + if (arg2 < 0) + { + arg2 = 0; /* default to 1st drive :-( */ + } + + /* check for filehandle: */ + if (!device_opened) + { + FatalError("No Media Changer Device Specified\n"); + } + + /* okay, we should be there: */ + if (arg1 < 0) + { + arg1 = ElementStatus->DataTransferElementSourceStorageElementNumber[arg2]; + if (arg1 < 0) + { + FatalError("No Source for tape in drive %d!\n",arg2); + } + } + else + { + arg1--; /* go from bogus 1-base to zero-base */ + } + + if (arg1 >= ElementStatus->StorageElementCount) + { + FatalError( "illegal argument '%d' to 'unload' command\n", + arg1 + 1); + } + + if (arg2 < 0 || arg2 >= ElementStatus->DataTransferElementCount) + { + FatalError( "illegal argument '%d' to 'unload' command\n", + arg2); + } + + if (!ElementStatus->DataTransferElementFull[arg2]) + { + FatalError("Data Transfer Element %d is Empty\n", arg2); + } + + /* Now see if something already lives where we wanna go... */ + if (ElementStatus->StorageElementFull[arg1]) + { + FatalError("Storage Element %d is Already Full\n", arg1 + 1); + } + + /* okay, now to get src, dest: */ + src=ElementStatus->DataTransferElementAddress[arg2]; + if (arg1 >= 0) + { + dest = ElementStatus->StorageElementAddress[arg1]; + } + else + { + dest = ElementStatus->DataTransferElementSourceStorageElementNumber[arg2]; + } + + if (dest < 0) + { + /* we STILL don't know... */ + FatalError("Do not know which slot to unload tape into!\n"); + } + + fprintf(stdout, "Unloading drive %d into Storage Element %d...", arg2, arg1 + 1); + fflush(stdout); /* make it real-time :-( */ + + Move(src,dest); + + fprintf(stdout, "done\n"); + fflush(stdout); + + ElementStatus->StorageElementFull[arg1] = true; + ElementStatus->DataTransferElementFull[arg2] = false; +} + +/***************************************************************** + ** ARGUMENT PARSING SUBROUTINES: Parse arguments, dispatch. + *****************************************************************/ + +/* *** + * int get_arg(idx): + * + * If we have an actual argument at the index position indicated (i.e. we + * have not gone off the edge of the world), we return + * its number. If we don't, or it's not a numeric argument, + * we return -1. Note that 'get_arg' is kind of misleading, we only accept + * numeric arguments, not any other kind. + */ +int get_arg(int idx) +{ + char *arg; + int retval = -1; + + if (idx >= argc) + { + return -1; /* sorry! */ + } + + arg=argv[idx]; + if (*arg < '0' || *arg > '9') + { + return -1; /* sorry! */ + } + + retval = atoi(arg); + return retval; +} + +/* open_device() -- set the 'fh' variable.... */ +void open_device(void) +{ + if (device_opened) + { + SCSI_CloseDevice("Unknown", MediumChangerFD); /* close it, sigh... new device now! */ + } + + MediumChangerFD = SCSI_OpenDevice(device); + device_opened = 1; /* SCSI_OpenDevice does an exit() if not. */ +} + + +/* we see if we've got a file open. If not, we open one :-(. Then + * we execute the actual command. Or not :-(. + */ +void execute_command(struct command_table_struct *command) +{ + RequestSense_T RequestSense; + + if (device == NULL && command->need_device) + { + /* try to get it from TAPE environment variable... */ + device = getenv("CHANGER"); + if (device == NULL) + { + device = getenv("TAPE"); + if (device == NULL) + { + device = "/dev/changer"; /* Usage(); */ + } + } + open_device(); + } + + if (!ElementStatus && command->need_status) + { + inquiry_info = RequestInquiry(MediumChangerFD,&RequestSense); + if (!inquiry_info) + { + PrintRequestSense(&RequestSense); + FatalError("INQUIRY command Failed\n"); + } + + ElementStatus = ReadElementStatus(MediumChangerFD, &RequestSense, inquiry_info, &SCSI_Flags); + if (!ElementStatus) + { + PrintRequestSense(&RequestSense); + FatalError("READ ELEMENT STATUS Command Failed\n"); + } + } + + /* okay, now to execute the command... */ + command->command(); +} + +/* parse_args(): + * Basically, we are parsing argv/argc. We can have multiple commands + * on a line now, such as "unload 3 0 load 4 0" to unload one tape and + * load in another tape into drive 0, and we execute these commands one + * at a time as we come to them. If we don't have a -f at the start, we + * barf. If we leave out a drive #, we default to drive 0 (the first drive + * in the cabinet). + */ + +int parse_args(void) +{ + int i, cmd_tbl_idx; + struct command_table_struct *command; + + i = 1; + while (i < argc) + { + if (strcmp(argv[i], "-f") == 0) + { + i++; + if (i >= argc) + { + Usage(); + } + + device = argv[i++]; + open_device(); /* open the device and do a status scan on it... */ + } + else + { + cmd_tbl_idx = 0; /* default to the first command... */ + command = &command_table[cmd_tbl_idx]; + + while (command->name != NULL) + { + if (strcmp(command->name, argv[i]) == 0) + { + /* we have a match... */ + break; + } + /* otherwise we don't have a match... */ + cmd_tbl_idx++; + command = &command_table[cmd_tbl_idx]; + } + + /* if it's not a command, exit.... */ + if (!command->name) + { + Usage(); + } + + i++; /* go to the next argument, if possible... */ + /* see if we need to gather arguments, though! */ + if (command->num_args == 0) + { + execute_command(command); /* execute_command handles 'stuff' */ + } + else + { + arg1 = get_arg(i); /* checks i... */ + + if (arg1 != -1) + { + i++; /* next! */ + } + + if (command->num_args>=2 && arg1 != -1) + { + arg2 = get_arg(i); + if (arg2 != -1) + { + i++; + } + + if (command->num_args==3 && arg2 != -1) + { + arg3 = get_arg(i); + if (arg3 != -1) + { + i++; + } + } + } + execute_command(command); + } + arg1 = -1; + arg2 = -1; + arg3 = -1; + } + } + + /* should never get here. */ + return 0; +} + + + +int main(int ArgCount, char *ArgVector[]) +{ +#ifdef VMS + RequestSense_T RequestSense; +#endif + + /* save these where we can get at them elsewhere... */ + argc = ArgCount; + argv = ArgVector; + + argv0 = argv[0]; + + parse_args(); /* also executes them as it sees them */ + +#ifndef VMS + if (device) + { + SCSI_CloseDevice(device, MediumChangerFD); + } + return 0; +#else + if (device) + { + ElementStatus = ReadElementStatus(MediumChangerFD,&RequestSense); + if (!ElementStatus) + { + PrintRequestSense(&RequestSense); + FatalError("READ ELEMENT STATUS Command Failed\n"); + } + VMS_DefineStatusSymbols(); + SCSI_CloseDevice(device, MediumChangerFD); + } + + return SS$_NORMAL; +#endif +} diff --git a/mtx.doc b/mtx.doc new file mode 100644 index 0000000..ae814e8 --- /dev/null +++ b/mtx.doc @@ -0,0 +1,209 @@ +[WARNING: This document is of historical value only! Please read + 'mtxl.README.html' and 'man mtx' for current documentation! The only + thing useful here is examples of how to use the 'tar' command for + multi-tape backups. +] + + MTX - SCSI Tape Medium Changer Control Program + + Version 1.1 for Linux, Solaris, IRIX, Digital Unix, and OpenVMS + + 2 June 1998 + + Leonard N. Zubkoff + Dandelion Digital + lnz@dandelion.com + + Copyright 1997-1998 by Leonard N. Zubkoff + + + INTRODUCTION + +The MTX program controls the robotic mechanism in DDS Autoloaders such as the +Seagate 4586NP (Archive Python 28849-XXX). This program is also reported to +work with the Seagate 4584NP, HP Surestore 12000, Quantum DLT 2500 XT, and AIWA +DL-210. The 4586NP responds to both Logical Units 0 and 1 on the selected +Target ID. Logical Unit 0 supports commands from the SCSI-3 Sequential Stream +Device Command Set and must be accessed via the SCSI tape devices /dev/st. +Logical Unit 1 only supports commands from the SCSI-3 Medium Changer Command +Set and must be accessed via the SCSI Generic devices /dev/sg. In addition, +Logical Unit 0 also acts as an Attached Medium Changer and supports the READ +ELEMENT STATUS and MOVE MEDIUM commands. Since using the Primary Device +(Logical Unit 0) via the Attached Medium Changer interface is sufficient for +the commands provided by this program, Logical Unit 1 is not normally used. +The AIWA DL-210, by contrast, does not support the Attached Medium Changer +commands on Logical Unit 0 and so MTX must be used with Logical Unit 1 via the +SCSI Generic devices /dev/sg. Note that when using the SCSI Generic devices +the Linux kernel option "max_scsi_luns=2" may be necessary. + +Medium Changers support four types of elements: Medium Transport Elements, +Storage Elements, Import Export Elements, and Data Transfer Elements. For the +limited case of DDS Autoloaders, only the Data Transfer Element and Storage +Element types are really applicable. The Data Transfer Element is the primary +device where a volume can be loaded to actually perform data transfers. A +Storage Element is a place a volume can be when it is waiting to be used. For +a DDS Autoloader, the Storage Elements are the slots in the cartridge where +tapes may be placed, and the Data Transfer Element is the tape mechanism. + +Every Medium Changer Element has a unique integer Element Address that +identifies it in the address space of all Elements known to the Medium Changer. +For the 4586NP, the Data Transfer Element is Address 1 and the Storage Elements +are Addresses 2-5 or 2-13. To simplify the human interface, this program does +not use Element Addresses directly. Rather, it uses Storage Element Numbers +which range from 1 to the number of Storage Elements available. + +The specific tape device to be operated on can either be supplied on the +command line with the "-f " option, or via the TAPE environment +variable. + + + BUILDING MTX + +The Makefile contains sections for Linux, Solaris/SPARC, SGI IRIX, and Digital +UNIX. Comment/uncomment as necessary for the target environment. For OpenVMS, +see the file "vms/000readme" for information on building MTX; a VMS release +including pre-built binaries should be available from the WKU VMS FILESERV +ARCHIVES, which are located at URLs http://www2.wku.edu/www/fileserv/ and +ftp://ftp.wku.edu/vms/fileserv/. + + + COMMANDS + +MTX provides the following commands: + + +mtx [ -f ] inquiry + +The "inquiry" command reports the Vendor ID, Product ID, and Revision from a +SCSI INQUIRY command. + +kelewan:~# setenv TAPE /dev/st0 + +kelewan:~# mtx inquiry +Vendor ID: 'ARCHIVE ', Product ID: 'Python 28849-XXX', Revision: '4.CM' + + +mtx [ -f ] status + +The "status" command reports on the status of the DDS Autloader. The report +indicates the status of the Data Transfer Element and each of the Storage +Elements. In the first example, no tape is currently loaded. In the second +example, Storage Element Number 1 is loaded. The Storage Element loaded into +the Data Transfer Element is usually reported by the DDS Autoloader, or it can +be inferred by MTX if there is only a single empty Storage Element. + +kelewan:~# mtx status +Data Transfer Element: Empty +Storage Element 1: Full +Storage Element 2: Full +Storage Element 3: Full +Storage Element 4: Full + + +kelewan:~# mtx status +Data Transfer Element: Full (Storage Element 1 Loaded) +Storage Element 1: Empty +Storage Element 2: Full +Storage Element 3: Full +Storage Element 4: Full + + +mtx [ -f ] load + +The "load" command loads the volume in Storage Element +into the Data Transfer Element. An error is signaled if the Data Transfer +Element is already full. + + +mtx [ -f ] unload [ ] + +The "unload" command unloads the volume in the Data Transfer Element into +Storage Element . If is not +provided, then the volume is unloaded back into the Storage Element from which +it was originally loaded, if known. An error is signaled if the Storage +Element is already full. + + +mtx [ -f ] first + +The "first" command unloads any volume in the Data Transfer Element and then +loads the volume in the lowest numbered non-empty Storage Element. If the +correct Storage Element is already loaded, the unload/load is suppressed. + + +mtx [ -f ] next + +The "next" command unloads any volume in the Data Transfer Element and then +loads the volume in the lowest numbered non-empty Storage Element above the +Storage Element that was just unloaded. If there is no next Storage Element, +the unload is still performed and the Data Transfer Element will be left empty +so that the volume is not accidentally overwritten. + + +mtx [ -f ] last + +The "last" command unloads any volume in the Data Transfer Element and then +loads the volume in the highest numbered non-empty Storage Element. If the +correct Storage Element is already loaded, the unload/load is suppressed. + + +mtx [ -f ] previous + +The "previous" command unloads any volume in the Data Transfer Element and then +loads the volume in the highest numbered non-empty Storage Element below the +Storage Element that was just unloaded. If there is no previous Storage +Element, the unload is still performed and the Data Transfer Element will be +left empty so that the volume is not accidentally overwritten. + + +The interface is designed to allow both explicit control of precisely which +Storage Element is loaded, as well as sequential access among only the Storage +Elements that actually have volumes present. Thus for example, one way of +using MTX would be to perform Monday's incremental backups on Storage Element +1, Tuesday's on Storage Element 2, and so on. Multi-volume full backups are +also conveniently supported, as in: + +setenv TAPE "/dev/st0" + +mtx status + +mtx first + +time tar --create --one-file-system --atime-preserve \ + --listed-incremental `date +%y%m%d`.ss \ + --multi-volume --new-volume-script "mtx next" \ + --directory / + +mtx first + +time tar --compare --multi-volume --new-volume-script "mtx next" \ + --directory / + +mtx unload + + + LINUX KERNEL REQUIREMENTS + +Because the MOVE MEDIUM command may require 60 seconds or more to perform a +volume load or unload request, a longer timeout must be provided. Linux +kernels 2.0.30 and 2.1.28 should already contain a long enough timeout. For +earlier kernels, edit the file "linux/drivers/scsi/scsi_ioctl.c" and add the +following entries to the switch statement in ioctl_command: + + case MOVE_MEDIUM: + case READ_ELEMENT_STATUS: + timeout = 5 * 60 * HZ; /* 5 minutes */ + retries = 1; + break; + +For older kernels, you may also need to add the following definitions to +"linux/include/scsi/scsi.h": + +#define MOVE_MEDIUM 0xa5 +#define READ_ELEMENT_STATUS 0xb8 + +Note also that "/usr/include/scsi" should be a symbolic link to the directory +"linux/include/scsi" from your kernel source. + +Finally, when using MTX you may see some console messages from the SCSI tape +driver mentioning that there is no tape present. These can safely be ignored. diff --git a/mtx.h b/mtx.h new file mode 100644 index 0000000..93b6c07 --- /dev/null +++ b/mtx.h @@ -0,0 +1,607 @@ +/* MTX -- SCSI Tape Attached Medium Control Program + + Copyright 1997-1998 Leonard N. Zubkoff + + Changes 1999 Eric Lee Green to add support for multi-drive tape changers. + Copyright 2007-2008 by Robert Nelson + + $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ + $Revision: 193 $ + See mtx.c for licensing information. + +*/ + +#ifndef MTX_H /* protect against multiple includes... */ +#define MTX_H 1 + +/* surround all the Unix-stuff w/ifndef VMS */ +#ifdef VMS +#include "[.vms]defs.h" +#else /* all the Unix stuff: */ + +#ifdef _MSC_VER +#include "msvc/config.h" /* all the autoconf stuff. */ +#else +#include "config.h" /* all the autoconf stuff. */ +#endif + +/* all the general Unix includes: */ + +#include +#include + +#if HAVE_STDLIB_H +# include +#endif + +#if HAVE_FCNTL_H +# include +#endif + +#if HAVE_SYS_TYPES_H +# include +#endif + +#if HAVE_STRING_H +# include +#else +# include +#endif + +#if HAVE_UNISTD_H +# include +#endif + +#if HAVE_STDARG_H +# include +#endif + +#if HAVE_SYS_STAT_H +# include +#endif + +#if HAVE_SYS_IOCTL_H +# include +#endif + +#if HAVE_SYS_PARAM_H +# include +#endif + +/* Now greatly modified to use GNU Autoconf stuff: */ +/* If we use the 'sg' interface, like Linux, do this: */ +#if HAVE_SCSI_SG_H +# include +# include +# include +typedef int DEVICE_TYPE; /* the sg interface uses this. */ +# define HAVE_GET_ID_LUN 1 /* signal that we have it... */ +#endif + +/* Windows Native programs built using MinGW */ +#if HAVE_DDK_NTDDSCSI_H +# define WIN32_LEAN_AND_MEAN +# include +# include +# undef DEVICE_TYPE + +typedef int DEVICE_TYPE; +#endif + +/* Windows Native programs built using Microsoft Visual C */ +#ifdef _MSC_VER +# define WIN32_LEAN_AND_MEAN +# include +# include +# include +# undef DEVICE_TYPE + +typedef int DEVICE_TYPE; +#endif + +/* The 'cam' interface, like FreeBSD: */ +#if HAVE_CAMLIB_H +# include /* easy (?) access to the CAM user library. */ +# include +# include /* sigh sigh sigh! */ +typedef struct cam_device *DEVICE_TYPE; +#endif + + +/* the 'uscsi' interface, as used on Solaris: */ +#if HAVE_SYS_SCSI_IMPL_USCSI_H +#include +typedef int DEVICE_TYPE; +#endif + +/* the scsi_ctl interface, as used on HP/UX: */ +#if HAVE_SYS_SCSI_CTL_H +# include +# include +# include +# include + typedef int DEVICE_TYPE; +# ifndef VERSION +# define VERSION "1.2.12 hbb" +# endif +#endif + +/* the 'gsc' interface, as used on AIX: */ +#if HAVE_SYS_GSCDDS_H +# include + typedef int DEVICE_TYPE; +#endif + + /* the 'dslib' interface, as used on SGI. */ +#if HAVE_DSLIB_H +#include +typedef dsreq_t *DEVICE_TYPE; /* 64-bit pointers/32bit int on later sgi? */ +#endif + + +#if ((defined(__alpha) && defined(__osf__)) || \ + defined(ultrix) || defined(__ultrix)) +#include "du/defs.h" +#endif + + +#endif /* VMS protect. */ + +/* Do a test for LITTLE_ENDIAN_BITFIELDS. Use WORDS_BIGENDIAN as set + * by configure: + */ + +#if WORDS_BIGENDIAN +# define BIG_ENDIAN_BITFIELDS +#else +# define LITTLE_ENDIAN_BITFIELDS +#endif + +/* Get rid of some Hocky Pux defines: */ +#ifdef S_NO_SENSE +#undef S_NO_SENSE +#endif +#ifdef S_RECOVERED_ERROR +#undef S_RECOVERED_ERROR +#endif +#ifdef S_NOT_READY +#undef S_NOT_READY +#endif +#ifdef S_MEDIUM_ERROR +#undef S_MEDIUM_ERROR +#endif +#ifdef S_HARDWARE_ERROR +#undef S_HARDWARE_ERROR +#endif +#ifdef S_UNIT_ATTENTION +#undef S_UNIT_ATTENTION +#endif +#ifdef S_BLANK_CHECK +#undef S_BLANK_CHECK +#endif +#ifdef S_VOLUME_OVERFLOW +#undef S_VOLUME_OVERFLOW +#endif + +/* Note: These are only used for defaults for when we don't have + * the element assignment mode page to tell us real amount... + */ +#define MAX_STORAGE_ELEMENTS 64 /* for the BIG jukeboxes! */ +#define MAX_TRANSFER_ELEMENTS 2 /* we just do dual-drive for now :-} */ +#define MAX_TRANSPORT_ELEMENTS 1 /* we just do one arm for now... */ + +#define MTX_ELEMENTSTATUS_ORIGINAL 0 +#define MTX_ELEMENTSTATUS_READALL 1 + +/* These are flags used for the READ_ELEMENT_STATUS and MOVE_MEDIUM + * commands: + */ +typedef struct SCSI_Flags_Struct +{ + unsigned char eepos; + unsigned char invert; + unsigned char no_attached; /* ignore _attached bit */ + unsigned char no_barcodes; /* don't try to get barcodes. */ + int numbytes; + int elementtype; + int numelements; + int attached; + int has_barcodes; + int querytype; //MTX_ELEMENTSTATUS + unsigned char invert2; /* used for EXCHANGE command, sigh. */ +} SCSI_Flags_T; + +#ifdef _MSC_VER +typedef unsigned char boolean; + +#define false 0 +#define true 1 + +typedef unsigned char Direction_T; + +#define Input 0 +#define Output 1 +#else +typedef enum { false, true } boolean; + +typedef enum { Input, Output } Direction_T; +#endif + + +typedef unsigned char CDB_T[12]; + + +typedef struct Inquiry +{ +#ifdef LITTLE_ENDIAN_BITFIELDS + unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ + unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ + unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ + boolean RMB:1; /* Byte 1 Bit 7 */ + unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ + unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ + unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ + unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ + unsigned char :2; /* Byte 3 Bits 4-5 */ + boolean TrmIOP:1; /* Byte 3 Bit 6 */ + boolean AENC:1; /* Byte 3 Bit 7 */ +#else + unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ + unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ + boolean RMB:1; /* Byte 1 Bit 7 */ + unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ + unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ + unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ + unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ + boolean AENC:1; /* Byte 3 Bit 7 */ + boolean TrmIOP:1; /* Byte 3 Bit 6 */ + unsigned char :2; /* Byte 3 Bits 4-5 */ + unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ +#endif + unsigned char AdditionalLength; /* Byte 4 */ + unsigned char :8; /* Byte 5 */ +#ifdef LITTLE_ENDIAN_BITFIELDS + boolean ADDR16:1; /* Byte 6 bit 0 */ + boolean Obs6_1:1; /* Byte 6 bit 1 */ + boolean Obs6_2:1; /* obsolete */ /* Byte 6 bit 2 */ + boolean MChngr:1; /* Media Changer */ /* Byte 6 bit 3 */ + boolean MultiP:1; /* Byte 6 bit 4 */ + boolean VS:1; /* Byte 6 bit 5 */ + boolean EncServ:1; /* Byte 6 bit 6 */ + boolean BQue:1; /* Byte 6 bit 7 */ +#else + boolean BQue:1; /* Byte 6 bit 7 */ + boolean EncServ:1; /* Byte 6 bit 6 */ + boolean VS:1; /* Byte 6 bit 5 */ + boolean MultiP:1; /* Byte 6 bit 4 */ + boolean MChngr:1; /* Media Changer */ /* Byte 6 bit 3 */ + boolean Obs6_2:1; /* obsolete */ /* Byte 6 bit 2 */ + boolean Obs6_1:1; /* Byte 6 bit 1 */ + boolean ADDR16:1; /* Byte 6 bit 0 */ +#endif +#ifdef LITTLE_ENDIAN_BITFIELDS + boolean SftRe:1; /* Byte 7 Bit 0 */ + boolean CmdQue:1; /* Byte 7 Bit 1 */ + boolean :1; /* Byte 7 Bit 2 */ + boolean Linked:1; /* Byte 7 Bit 3 */ + boolean Sync:1; /* Byte 7 Bit 4 */ + boolean WBus16:1; /* Byte 7 Bit 5 */ + boolean WBus32:1; /* Byte 7 Bit 6 */ + boolean RelAdr:1; /* Byte 7 Bit 7 */ +#else + boolean RelAdr:1; /* Byte 7 Bit 7 */ + boolean WBus32:1; /* Byte 7 Bit 6 */ + boolean WBus16:1; /* Byte 7 Bit 5 */ + boolean Sync:1; /* Byte 7 Bit 4 */ + boolean Linked:1; /* Byte 7 Bit 3 */ + boolean :1; /* Byte 7 Bit 2 */ + boolean CmdQue:1; /* Byte 7 Bit 1 */ + boolean SftRe:1; /* Byte 7 Bit 0 */ +#endif + unsigned char VendorIdentification[8]; /* Bytes 8-15 */ + unsigned char ProductIdentification[16]; /* Bytes 16-31 */ + unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ + unsigned char FullProductRevisionLevel[19]; /* bytes 36-54 */ + unsigned char VendorFlags; /* byte 55 */ +} +Inquiry_T; + +/* Hockey Pux may define these. If so, *UN*define them. */ +#ifdef ILI +#undef ILI +#endif + +#ifdef EOM +#undef EOM +#endif + +typedef struct RequestSense +{ +#ifdef LITTLE_ENDIAN_BITFIELDS + unsigned char ErrorCode:7; /* Byte 0 Bits 0-6 */ + boolean Valid:1; /* Byte 0 Bit 7 */ +#else + boolean Valid:1; /* Byte 0 Bit 7 */ + unsigned char ErrorCode:7; /* Byte 0 Bits 0-6 */ +#endif + unsigned char SegmentNumber; /* Byte 1 */ +#ifdef LITTLE_ENDIAN_BITFIELDS + unsigned char SenseKey:4; /* Byte 2 Bits 0-3 */ + unsigned char :1; /* Byte 2 Bit 4 */ + boolean ILI:1; /* Byte 2 Bit 5 */ + boolean EOM:1; /* Byte 2 Bit 6 */ + boolean Filemark:1; /* Byte 2 Bit 7 */ +#else + boolean Filemark:1; /* Byte 2 Bit 7 */ + boolean EOM:1; /* Byte 2 Bit 6 */ + boolean ILI:1; /* Byte 2 Bit 5 */ + unsigned char :1; /* Byte 2 Bit 4 */ + unsigned char SenseKey:4; /* Byte 2 Bits 0-3 */ +#endif + unsigned char Information[4]; /* Bytes 3-6 */ + unsigned char AdditionalSenseLength; /* Byte 7 */ + unsigned char CommandSpecificInformation[4]; /* Bytes 8-11 */ + unsigned char AdditionalSenseCode; /* Byte 12 */ + unsigned char AdditionalSenseCodeQualifier; /* Byte 13 */ + unsigned char :8; /* Byte 14 */ +#ifdef LITTLE_ENDIAN_BITFIELDS + unsigned char BitPointer:3; /* Byte 15 */ + boolean BPV:1; + unsigned char :2; + boolean CommandData :1; + boolean SKSV:1; +#else + boolean SKSV:1; + boolean CommandData :1; + unsigned char :2; + boolean BPV:1; + unsigned char BitPointer:3; /* Byte 15 */ +#endif + unsigned char FieldData[2]; /* Byte 16,17 */ +} +RequestSense_T; + +/* Okay, now for the element status mode sense page (0x1d): */ + +typedef struct ElementModeSensePageHeader { + unsigned char PageCode; /* byte 0 */ + unsigned char ParameterLengthList; /* byte 1; */ + unsigned char MediumTransportStartHi; /* byte 2,3 */ + unsigned char MediumTransportStartLo; + unsigned char NumMediumTransportHi; /* byte 4,5 */ + unsigned char NumMediumTransportLo; /* byte 4,5 */ + unsigned char StorageStartHi; /* byte 6,7 */ + unsigned char StorageStartLo; /* byte 6,7 */ + unsigned char NumStorageHi; /* byte 8,9 */ + unsigned char NumStorageLo; /* byte 8,9 */ + unsigned char ImportExportStartHi; /* byte 10,11 */ + unsigned char ImportExportStartLo; /* byte 10,11 */ + unsigned char NumImportExportHi; /* byte 12,13 */ + unsigned char NumImportExportLo; /* byte 12,13 */ + unsigned char DataTransferStartHi; /* byte 14,15 */ + unsigned char DataTransferStartLo; /* byte 14,15 */ + unsigned char NumDataTransferHi; /* byte 16,17 */ + unsigned char NumDataTransferLo; /* byte 16,17 */ + unsigned char Reserved1; /* byte 18, 19 */ + unsigned char Reserved2; /* byte 18, 19 */ +} ElementModeSensePage_T; + +typedef struct ElementModeSenseHeader { + int MaxReadElementStatusData; /* 'nuff for all of below. */ + int NumElements; /* total # of elements. */ + int MediumTransportStart; + int NumMediumTransport; + int StorageStart; + int NumStorage; + int ImportExportStart; + int NumImportExport; + int DataTransferStart; + int NumDataTransfer; +} ElementModeSense_T; + + +#ifdef _MSC_VER +typedef char ElementTypeCode_T; + +#define AllElementTypes 0 +#define MediumTransportElement 1 +#define StorageElement 2 +#define ImportExportElement 3 +#define DataTransferElement 4 +#else +typedef enum ElementTypeCode +{ + AllElementTypes = 0, + MediumTransportElement = 1, + StorageElement = 2, + ImportExportElement = 3, + DataTransferElement = 4 +} +ElementTypeCode_T; +#endif + + +typedef struct ElementStatusDataHeader +{ + unsigned char FirstElementAddressReported[2]; /* Bytes 0-1 */ + unsigned char NumberOfElementsAvailable[2]; /* Bytes 2-3 */ + unsigned char :8; /* Byte 4 */ + unsigned char ByteCountOfReportAvailable[3]; /* Bytes 5-7 */ +} +ElementStatusDataHeader_T; + + +typedef struct ElementStatusPage +{ + ElementTypeCode_T ElementTypeCode:8; /* Byte 0 */ +#ifdef LITTLE_ENDIAN_BITFIELDS + unsigned char :6; /* Byte 1 Bits 0-5 */ + boolean AVolTag:1; /* Byte 1 Bit 6 */ + boolean PVolTag:1; /* Byte 1 Bit 7 */ +#else + boolean PVolTag:1; /* Byte 1 Bit 7 */ + boolean AVolTag:1; /* Byte 1 Bit 6 */ + unsigned char :6; /* Byte 1 Bits 0-5 */ +#endif + unsigned char ElementDescriptorLength[2]; /* Bytes 2-3 */ + unsigned char :8; /* Byte 4 */ + unsigned char ByteCountOfDescriptorDataAvailable[3]; /* Bytes 5-7 */ +} +ElementStatusPage_T; + +typedef struct Element2StatusPage +{ + ElementTypeCode_T ElementTypeCode:8; /* Byte 0 */ + unsigned char VolBits ; /* byte 1 */ +#define E2_PVOLTAG 0x80 +#define E2_AVOLTAG 0x40 + unsigned char ElementDescriptorLength[2]; /* Bytes 2-3 */ + unsigned char :8; /* Byte 4 */ + unsigned char ByteCountOfDescriptorDataAvailable[3]; /* Bytes 5-7 */ +} +Element2StatusPage_T; + + + +typedef struct TransportElementDescriptorShort +{ + unsigned char ElementAddress[2]; /* Bytes 0-1 */ +#ifdef LITTLE_ENDIAN_BITFIELDS + boolean Full:1; /* Byte 2 Bit 0 */ + unsigned char :1; /* Byte 2 Bit 1 */ + boolean Except:1; /* Byte 2 Bit 2 */ + unsigned char :5; /* Byte 2 Bits 3-7 */ +#else + unsigned char :5; /* Byte 2 Bits 3-7 */ + boolean Except:1; /* Byte 2 Bit 2 */ + unsigned char :1; /* Byte 2 Bit 1 */ + boolean Full:1; /* Byte 2 Bit 0 */ +#endif + unsigned char :8; /* Byte 3 */ + unsigned char AdditionalSenseCode; /* Byte 4 */ + unsigned char AdditionalSenseCodeQualifier; /* Byte 5 */ + unsigned char :8; /* Byte 6 */ + unsigned char :8; /* Byte 7 */ + unsigned char :8; /* Byte 8 */ +#ifdef LITTLE_ENDIAN_BITFIELDS + unsigned char :6; /* Byte 9 Bits 0-5 */ + boolean SValid:1; /* Byte 9 Bit 6 */ + boolean Invert:1; /* Byte 9 Bit 7 */ +#else + boolean Invert:1; /* Byte 9 Bit 7 */ + boolean SValid:1; /* Byte 9 Bit 6 */ + unsigned char :6; /* Byte 9 Bits 0-5 */ +#endif + unsigned char SourceStorageElementAddress[2]; /* Bytes 10-11 */ +#ifdef HAS_LONG_DESCRIPTORS + unsigned char Reserved[4]; /* Bytes 12-15 */ +#endif +} +TransportElementDescriptorShort_T; + + +typedef struct TransportElementDescriptor +{ + unsigned char ElementAddress[2]; /* Bytes 0-1 */ +#ifdef LITTLE_ENDIAN_BITFIELDS + boolean Full:1; /* Byte 2 Bit 0 */ + unsigned char :1; /* Byte 2 Bit 1 */ + boolean Except:1; /* Byte 2 Bit 2 */ + unsigned char :5; /* Byte 2 Bits 3-7 */ +#else + unsigned char :5; /* Byte 2 Bits 3-7 */ + boolean Except:1; /* Byte 2 Bit 2 */ + unsigned char :1; /* Byte 2 Bit 1 */ + boolean Full:1; /* Byte 2 Bit 0 */ +#endif + unsigned char :8; /* Byte 3 */ + unsigned char AdditionalSenseCode; /* Byte 4 */ + unsigned char AdditionalSenseCodeQualifier; /* Byte 5 */ + unsigned char :8; /* Byte 6 */ + unsigned char :8; /* Byte 7 */ + unsigned char :8; /* Byte 8 */ +#ifdef LITTLE_ENDIAN_BITFIELDS + unsigned char :6; /* Byte 9 Bits 0-5 */ + boolean SValid:1; /* Byte 9 Bit 6 */ + boolean Invert:1; /* Byte 9 Bit 7 */ +#else + boolean Invert:1; /* Byte 9 Bit 7 */ + boolean SValid:1; /* Byte 9 Bit 6 */ + unsigned char :6; /* Byte 9 Bits 0-5 */ +#endif + unsigned char SourceStorageElementAddress[2]; /* Bytes 10-11 */ + unsigned char PrimaryVolumeTag[36]; /* barcode */ + unsigned char AlternateVolumeTag[36]; +#ifdef HAS_LONG_DESCRIPTORS + unsigned char Reserved[4]; /* 4 extra bytes? */ +#endif + +} +TransportElementDescriptor_T; + + + + +/* Now for element status data; */ + +typedef unsigned char barcode[37]; + +typedef struct ElementStatus { + + int StorageElementCount; + int ImportExportCount; + int DataTransferElementCount; + int *DataTransferElementAddress; /* array. */ + int *DataTransferElementSourceStorageElementNumber; /* array */ + barcode *DataTransferPrimaryVolumeTag; /* array. */ + barcode *DataTransferAlternateVolumeTag; /* array. */ + barcode *PrimaryVolumeTag; /* array */ + barcode *AlternateVolumeTag; /* array */ + int *StorageElementAddress; /* array */ + boolean *StorageElementIsImportExport; /* array */ + + int TransportElementAddress; /* assume only one of those... */ + + boolean *DataTransferElementFull; /* array */ + boolean *StorageElementFull; /* array */ + +} ElementStatus_T; + + +/* Now for the SCSI ID and LUN information: */ +typedef struct scsi_id { + int id; + int lun; +} scsi_id_t; + +#define MEDIUM_CHANGER_TYPE 8 /* what type bits are set for medium changers. */ + +/* The following two structs are used for the brain-dead functions of the + * NSM jukebox. + */ + +typedef struct NSM_Param { + unsigned char page_code; + unsigned char reserved; + unsigned char page_len_msb; + unsigned char page_len_lsb; + unsigned char allocation_msb; + unsigned char allocation_lsb; + unsigned char reserved2[2]; + unsigned char command_code[4]; + unsigned char command_params[2048]; /* egregious overkill. */ +} NSM_Param_T; + +extern RequestSense_T scsi_error_sense; + +typedef struct NSM_Result { + unsigned char page_code; + unsigned char reserved; + unsigned char page_len_msb; + unsigned char page_len_lsb; + unsigned char command_code[4]; + unsigned char ces_code[2]; + unsigned char return_data[0xffff]; /* egregioius overkill */ +} NSM_Result_T; + +#endif /* of multi-include protection. */ diff --git a/mtx.spec b/mtx.spec new file mode 100644 index 0000000..7ccba9b --- /dev/null +++ b/mtx.spec @@ -0,0 +1,109 @@ +Name: mtx +Version: 1.3.12 +Release: 1%{?dist} +Summary: SCSI media changer control program +License: GPL +Group: Utilities/System +Source0: ftp://ftp.opensource-sw.net/pub/mtx/stable/%{name}-%{version}.tar.gz +Url: http://%{name}.sourceforge.net +BuildRoot: /var/tmp/%{name}-%{version} + + +%description +The MTX program controls the robotic mechanism in autoloaders and tape +libraries such as the HP SureStore DAT 40x6, Exabyte EZ-17, and +Exabyte 220. This program is also reported to work with a variety of other tape +libraries and autochangers from Tandberg/Overland, Breece Hill, HP, and +Seagate. + +%prep +%setup -q + +%build +%configure +make + +%install +mkdir -p $RPM_BUILD_ROOT/sbin +install mtx $RPM_BUILD_ROOT/sbin/mtx +mkdir -p $RPM_BUILD_ROOT/usr/sbin +install loaderinfo $RPM_BUILD_ROOT/usr/sbin/loaderinfo +install scsieject $RPM_BUILD_ROOT/usr/sbin/scsieject +install scsitape $RPM_BUILD_ROOT/usr/sbin/scsitape +install tapeinfo $RPM_BUILD_ROOT/usr/sbin/tapeinfo +mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man1 +install mtx.1 $RPM_BUILD_ROOT/%{_mandir}/man1/mtx.1 +install loaderinfo.1 $RPM_BUILD_ROOT/%{_mandir}/man1/loaderinfo.1 +install scsieject.1 $RPM_BUILD_ROOT/%{_mandir}/man1/scsieject.1 +install scsitape.1 $RPM_BUILD_ROOT/%{_mandir}/man1/scsitape.1 +install tapeinfo.1 $RPM_BUILD_ROOT/%{_mandir}/man1/tapeinfo.1 + + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc mtx.doc CHANGES README mtxl.README.html +%doc COMPATABILITY FAQ LICENSE* TODO contrib +%{_mandir}/man1/* +/sbin/mtx +/usr/sbin/* + +%changelog +* Fri Sep 27 2002 Eric Green +- 1.3.0rel +- move changelog to end. +- change source directory to ftp.badtux.net. +- use * for files to catch new files. + +* Wed Apr 18 2001 Kenneth Porter +- 1.2.12pre1 +- Need to create usr/sbin for install + +* Fri Mar 02 2001 Eric Green +- 1.2.11pre6 +- Move tapeinfo,loaderinfo, scsitape to /usr/sbin rather than /sbin + +* Wed Feb 28 2001 Kenneth Porter +- 1.2.11pre5 +- Remove commented-out patch. +- Use mandir FHS macro and configure macro. +- Install more stuff. +- Use build policy for stripping. + +* Wed Jan 17 2001 Eric Green +- 1.2.11pre3 +- Removed patch, now use ./configure. + +* Mon Nov 27 2000 Eric Green +- 1.2.10 +- Fixed patching to use the portable.patch. + +* Tue Jul 25 2000 Eric Green +- 1.2.8 +- Added portability patch to mtx.spec so should compile on Red Hat Alpha etc. + +* Thu Jun 6 2000 Eric Green +- 1.2.7 +- Fixed single-drive Exabyte 220 special case. +- Fixed ADIC DAT Autochanger special case. +- Fixed mtx.spec to move the binaries to /sbin since we need root access + +* Fri May 12 2000 Kenneth Porter +- 1.2.6 +- Fixed 'eepos' stuff to use | rather than || (whoops!) +- Accept a 4-byte element descriptor for the robot arm for certain older +- autochangers. + +* Mon May 8 2000 Kenneth Porter +- Spell sourceforge right so the link at rpmfind.net will work. + +* Thu May 4 2000 Kenneth Porter +- 1.2.5 + +* Thu Oct 29 1998 Ian Macdonald +- moved mtx from /sbin to /bin, seeing as mt is also located there + +* Fri Oct 23 1998 Ian Macdonald +- first RPM release diff --git a/mtx.spec.in b/mtx.spec.in new file mode 100644 index 0000000..f6fd5ed --- /dev/null +++ b/mtx.spec.in @@ -0,0 +1,109 @@ +Name: mtx +Version: @@VERSION@@ +Release: 1%{?dist} +Summary: SCSI media changer control program +License: GPL +Group: Utilities/System +Source0: ftp://ftp.opensource-sw.net/pub/mtx/stable/%{name}-%{version}.tar.gz +Url: http://%{name}.sourceforge.net +BuildRoot: /var/tmp/%{name}-%{version} + + +%description +The MTX program controls the robotic mechanism in autoloaders and tape +libraries such as the HP SureStore DAT 40x6, Exabyte EZ-17, and +Exabyte 220. This program is also reported to work with a variety of other tape +libraries and autochangers from Tandberg/Overland, Breece Hill, HP, and +Seagate. + +%prep +%setup -q + +%build +%configure +make + +%install +mkdir -p $RPM_BUILD_ROOT/sbin +install mtx $RPM_BUILD_ROOT/sbin/mtx +mkdir -p $RPM_BUILD_ROOT/usr/sbin +install loaderinfo $RPM_BUILD_ROOT/usr/sbin/loaderinfo +install scsieject $RPM_BUILD_ROOT/usr/sbin/scsieject +install scsitape $RPM_BUILD_ROOT/usr/sbin/scsitape +install tapeinfo $RPM_BUILD_ROOT/usr/sbin/tapeinfo +mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man1 +install mtx.1 $RPM_BUILD_ROOT/%{_mandir}/man1/mtx.1 +install loaderinfo.1 $RPM_BUILD_ROOT/%{_mandir}/man1/loaderinfo.1 +install scsieject.1 $RPM_BUILD_ROOT/%{_mandir}/man1/scsieject.1 +install scsitape.1 $RPM_BUILD_ROOT/%{_mandir}/man1/scsitape.1 +install tapeinfo.1 $RPM_BUILD_ROOT/%{_mandir}/man1/tapeinfo.1 + + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc mtx.doc CHANGES README mtxl.README.html +%doc COMPATABILITY FAQ LICENSE* TODO contrib +%{_mandir}/man1/* +/sbin/mtx +/usr/sbin/* + +%changelog +* Fri Sep 27 2002 Eric Green +- 1.3.0rel +- move changelog to end. +- change source directory to ftp.badtux.net. +- use * for files to catch new files. + +* Wed Apr 18 2001 Kenneth Porter +- 1.2.12pre1 +- Need to create usr/sbin for install + +* Fri Mar 02 2001 Eric Green +- 1.2.11pre6 +- Move tapeinfo,loaderinfo, scsitape to /usr/sbin rather than /sbin + +* Wed Feb 28 2001 Kenneth Porter +- 1.2.11pre5 +- Remove commented-out patch. +- Use mandir FHS macro and configure macro. +- Install more stuff. +- Use build policy for stripping. + +* Wed Jan 17 2001 Eric Green +- 1.2.11pre3 +- Removed patch, now use ./configure. + +* Mon Nov 27 2000 Eric Green +- 1.2.10 +- Fixed patching to use the portable.patch. + +* Tue Jul 25 2000 Eric Green +- 1.2.8 +- Added portability patch to mtx.spec so should compile on Red Hat Alpha etc. + +* Thu Jun 6 2000 Eric Green +- 1.2.7 +- Fixed single-drive Exabyte 220 special case. +- Fixed ADIC DAT Autochanger special case. +- Fixed mtx.spec to move the binaries to /sbin since we need root access + +* Fri May 12 2000 Kenneth Porter +- 1.2.6 +- Fixed 'eepos' stuff to use | rather than || (whoops!) +- Accept a 4-byte element descriptor for the robot arm for certain older +- autochangers. + +* Mon May 8 2000 Kenneth Porter +- Spell sourceforge right so the link at rpmfind.net will work. + +* Thu May 4 2000 Kenneth Porter +- 1.2.5 + +* Thu Oct 29 1998 Ian Macdonald +- moved mtx from /sbin to /bin, seeing as mt is also located there + +* Fri Oct 23 1998 Ian Macdonald +- first RPM release diff --git a/mtxl.README.html b/mtxl.README.html new file mode 100644 index 0000000..7f7e6d4 --- /dev/null +++ b/mtxl.README.html @@ -0,0 +1,165 @@ + + + + + SCSI Media Changer and Backup Device Control System + + + + +
+

SCSI Media Changer and Backup Device Control System

+
+

+[Also see the SourceForge +project page.] +

+mtx is a set of low level driver programs to control features +of SCSI backup related devices such as autoloaders, tape changers, +media jukeboxes, and tape drives. It can also report much data, +including serial numbers, maximum block sizes, and TapeAlert(tm) +messages that most modern tape drives implement (to tell you the exact +reason why a backup or restore failed), as well as do raw SCSI READ +and WRITE commands to tape drives (not important on Linux, but +important on Solaris due to the fact that the Solaris tape driver +supports none of the additional features of tape drives invented after +1988). mtx is designed to be a low level driver in a larger +scripted backup solution, such as Amanda. +mtx is not +supposed to itself be a high level interface to the SCSI devices that +it controls. +

+This version has the following features: + +

    +
  • Will deal with LARGE media libraries (over a hundred elements). +
  • Supports multi-drive media changers such as the Exabyte 220 dual- +drive tape library. +
  • Supports the 'invert' bit for optical jukeboxes that need that in +order to flip their media. +
  • Supports the 'eepos' bits for libraries that need this to extend/retract +their import/export tray. +
  • Now supports import/export elements! +
  • Reports volume tags (bar codes) and "alternate volume tags" +(whatever those are!) for those tape libraries +that support them. +
  • Now runs under FreeBSD and at least Solaris 8. + +
  • Now has a 'man' page! +
  • The actual SCSI manipulation has been separated out into a library, so +that you can create your own "C" programs that manipulate SCSI media changers +directly. (Please note: this is under GPL, so any such programs will have +to be under GPL also). +
+ +

+ This program supposedly supports FreeBSD, Solaris, Linux, HP/UX, and +IRIX. Tru64 Unix and VMS are probably irretrievably broken at this +time. This program has been tested under FreeBSD, Solaris, and Linux, +and there only with a limited set of hardware. See the COMPATIBILITY +list in the source code. + +

Source Code

+The current source code is: + +RPMs may be available from the following place: + +A .spec file is now included in the 'mtx' distribution for building your +own RPM's. +

+Note that RPMs +are courtesy of Kenneth Porter, +who should be contacted regarding rpm-related problems. +

+ +

Known Bugs And Limitations

+
    +
  • + You may need to do a 'mt offline' (or equivalent for your OS) + on the tape drive to + eject the tape before you can issue the 'mtx unload' command. +The Exabyte EZ-17 and 220 in particular will happily + sit there snapping the robot arm's claws around thin air + trying to grab a tape that's not there. +
  • +The 'next' command does not understand the 'invert' bit (i.e., does not +recognize that for optical jukeboxes, the 'next' of side one is to unload, +invert, and reload the same disk). It always advances to the next +slot instead. +
  • + For some Linux distributions, you may need to re-compile + the kernel to scan SCSI LUN's in order to detect the media + changer. Check /proc/scsi/scsi to see what's going on. + +
  • + If you try to unload a tape to its 'source' slot, and said + slot is full, it will instead put the tape into the first + empty slot. Unfortunately the list of empty slots is not + updated between commands on the command line, so if you + try to unload another drive to a full 'source' slot during + the same invocation of 'mtx', it will try to unload to the + same (no longer empty) slot and will urp with a SCSI + error. + +
  • For big tape libraries (more than a couple dozen elements) this +may set a big Allocation_Size in the SCSI command block for the +REQUEST_ELEMENT_STATUS command. Some operating systems may not be able +to handle this. Versions of Linux earlier than 2.2.6, in particular, +may fail this request due to inability to find contiguous pages of +memory for the SCSI transfer (later versions of Linux 'sg' device do +scatter-gather so that this should no longer be a problem). + +
  • VMS and Tru64 support are probably irretrievably busted. + + +
  • This program will only use the first arm of multiple-arm robots unless +the robot re-maps all arms to one element ID. + +
  • It has been reported that this program works on Solaris 7 using the 'sst' +driver, and may work on Solaris 8 using the 'sgen' driver. 'sst' can +be gotten from the Amanda contrib directory at +http://download.sourceforge.net/amanda. + +
+ +

Philosophy

+The Unix philosophy is "many small tools chained together". mtx supplies +those small tools so that you can create your own backup and +recovery tools by chaining +mtx pieces together, whether it be with /bin/sh, Perl, Python, or +CAML. + + +

Support

+ + +

See Also:

+ +
+
Maintained by Eric Lee Green
+ Hosted by VA Linux's SourceForge

+ + + + +Last modified: Mon Jun 25 15:37:22 MST 2001 + + + diff --git a/mtxl.c b/mtxl.c new file mode 100644 index 0000000..3ae77a6 --- /dev/null +++ b/mtxl.c @@ -0,0 +1,1907 @@ +/* MTX -- SCSI Tape Attached Medium Changer Control Program + + Copyright 1997-1998 by Leonard N. Zubkoff. + Copyright 1999-2006 by Eric Lee Green. + Copyright 2007-2008 by Robert Nelson + + $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ + $Revision: 193 $ + + This file created Feb 2000 by Eric Lee Green from pieces + extracted from mtx.c, plus a near total re-write of most of the beast. + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for complete details. +*/ + + +/* + * FatalError: changed Feb. 2000 elg@badtux.org to eliminate a buffer + * overflow :-(. That could be important if mtxl is SUID for some reason. +*/ + +#include "mtx.h" +#include "mtxl.h" + +/* #define DEBUG_NSM 1 */ + +/* #define DEBUG_MODE_SENSE 1 */ +/* #define DEBUG */ +/* #define DEBUG_SCSI */ +#define __WEIRD_CHAR_SUPPRESS 1 + +/* zap the following define when we finally add real import/export support */ +#define IMPORT_EXPORT_HACK 1 /* for the moment, import/export == storage */ + +/* First, do some SCSI routines: */ + +/* the camlib is used on FreeBSD. */ +#if HAVE_CAMLIB_H +# include "scsi_freebsd.c" +#endif + +/* the scsi_ctl interface is used on HP/UX. */ +#if HAVE_SYS_SCSI_CTL_H +# include "scsi_hpux.c" +#endif + +/* the 'sg' interface is used on Linux. */ +#if HAVE_SCSI_SG_H +# include "scsi_linux.c" +#endif + +/* the IOCTL_SCSI_PASSTHROUGH interface is used on Windows. */ +#if HAVE_DDK_NTDDSCSI_H || defined(_MSC_VER) +# include "scsi_win32.c" +#endif + +/* The 'uscsi' interface is used on Solaris. */ +#if HAVE_SYS_SCSI_IMPL_USCSI_H +# include "scsi_sun.c" +#endif + +/* The 'gsc' interface, is used on AIX. */ +#if HAVE_SYS_GSCDDS_H +# include "scsi_aix.c" +#endif + +/* The 'dslib' interface is used on SGI. */ +#if HAVE_DSLIB_H +# include "scsi_sgi.c" +#endif + +/* Hmm, dunno what to do about Digital Unix at the moment. */ +#ifdef DIGITAL_UNIX +# include "du/scsi.c" +#endif + +#ifdef VMS +# include "[.vms]scsi.c" +#endif + +extern char *argv0; /* something to let us do good error messages. */ + +/* create a global RequestSenseT value. */ +RequestSense_T scsi_error_sense; + +/* Now for some low-level SCSI stuff: */ + +Inquiry_T *RequestInquiry(DEVICE_TYPE fd, RequestSense_T *RequestSense) +{ + Inquiry_T *Inquiry; + CDB_T CDB; + + Inquiry = (Inquiry_T *) xmalloc(sizeof(Inquiry_T)); + + CDB[0] = 0x12; /* INQUIRY */ + CDB[1] = 0; /* EVPD = 0 */ + CDB[2] = 0; /* Page Code */ + CDB[3] = 0; /* Reserved */ + CDB[4] = sizeof(Inquiry_T); /* Allocation Length */ + CDB[5] = 0; /* Control */ + + /* set us a very short timeout, sigh... */ + SCSI_Set_Timeout(30); /* 30 seconds, sigh! */ + + if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, Inquiry, sizeof(Inquiry_T), RequestSense) != 0) + { +#ifdef DEBUG + fprintf(stderr, "SCSI Inquiry Command failed\n"); +#endif + free(Inquiry); + return NULL; /* sorry! */ + } + return Inquiry; +} + + +#if defined(DEBUG_NSM) || defined(DEBUG_EXCHANGE) +/* DEBUG */ +static void dump_cdb(unsigned char *CDB, int len) +{ + fprintf(stderr,"CDB:"); + PrintHex(1, CDB, len); +} +#endif + + +#if defined(DEBUG_NSM) || defined(DEBUG_ADIC) +/* DEBUG */ +static void dump_data(unsigned char *data, int len) +{ + if (!len) + { + fprintf(stderr,"**NO DATA**\n"); + return; + } + + fprintf(stderr,"DATA:"); + PrintHex(1, data, len); +} +#endif + + +int BigEndian16(unsigned char *BigEndianData) +{ + return (BigEndianData[0] << 8) + BigEndianData[1]; +} + + +int BigEndian24(unsigned char *BigEndianData) +{ + return (BigEndianData[0] << 16) + (BigEndianData[1] << 8) + BigEndianData[2]; +} + + +void FatalError(char *ErrorMessage, ...) +{ +#define FORMAT_BUF_LEN 1024 + + char FormatBuffer[FORMAT_BUF_LEN]; + char *SourcePointer; + char *TargetPointer = FormatBuffer; + char Character, LastCharacter = '\0'; + int numchars = 0; + + va_list ArgumentPointer; + va_start(ArgumentPointer, ErrorMessage); + /* SourcePointer = "mtx: "; */ + sprintf(TargetPointer,"%s: ",argv0); + numchars=strlen(TargetPointer); + + while ((Character = *ErrorMessage++) != '\0') + { + if (LastCharacter == '%') + { + if (Character == 'm') + { + SourcePointer = strerror(errno); + while ((Character = *SourcePointer++) != '\0') + { + *TargetPointer++ = Character; + numchars++; + if (numchars == FORMAT_BUF_LEN - 1) + { + break; + } + } + if (numchars == FORMAT_BUF_LEN - 1) + { + break; /* break outer loop... */ + } + } + else + { + *TargetPointer++ = '%'; + *TargetPointer++ = Character; + numchars++; + if (numchars == FORMAT_BUF_LEN - 1) + { + break; + } + } + LastCharacter = '\0'; + } + else + { + if (Character != '%') + { + *TargetPointer++ = Character; + numchars++; + if (numchars == FORMAT_BUF_LEN-1) + { + break; + } + } + LastCharacter = Character; + } + } + + *TargetPointer = '\0'; /* works even if we had to break from above... */ + vfprintf(stderr, FormatBuffer, ArgumentPointer); + va_end(ArgumentPointer); + +#ifndef VMS + exit(1); +#else + sys$exit(VMS_ExitCode); +#endif +} + +/* This is a really slow and stupid 'bzero' implementation'... */ +void slow_bzero(char *buffer, int numchars) +{ + while (numchars--) + { + *buffer++ = 0; + } +} + +/* malloc some memory while checking for out-of-memory conditions. */ +void *xmalloc(size_t Size) +{ + void *Result = (void *) malloc(Size); + if (Result == NULL) + { + FatalError("cannot allocate %d bytes of memory\n", Size); + } + return Result; +} + +/* malloc some memory, zeroing it too: */ +void *xzmalloc(size_t Size) +{ + void *Result = (void *)xmalloc(Size); + + slow_bzero(Result, Size); + return Result; +} + + +int min(int x, int y) +{ + return (x < y ? x : y); +} + + +int max(int x, int y) +{ + return (x > y ? x : y); +} + + +/* Okay, this is a hack for the NSM modular jukebox series, which + * uses the "SEND DIAGNOSTIC" command to do shit. + */ + +int SendNSMHack(DEVICE_TYPE MediumChangerFD, NSM_Param_T *nsm_command, + int param_len, int timeout) +{ + CDB_T CDB; + int list_len = param_len + sizeof(NSM_Param_T) - 2048; + + /* Okay, now for the command: */ + CDB[0] = 0x1D; + CDB[1] = 0x10; + CDB[2] = 0; + CDB[3] = (unsigned char)(list_len >> 8); + CDB[4] = (unsigned char)list_len; + CDB[5] = 0; + +#ifdef DEBUG_NSM + dump_cdb(&CDB,6); + dump_data(nsm_command,list_len); +#endif + fflush(stderr); + /* Don't set us any timeout unless timeout is > 0 */ + if (timeout > 0) + { + SCSI_Set_Timeout(timeout); /* 30 minutes, sigh! */ + } + + /* Now send the command: */ + if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 6, nsm_command, list_len, &scsi_error_sense)) + { + return -1; /* we failed */ + } + return 0; /* Did it! */ +} + +NSM_Result_T *RecNSMHack( DEVICE_TYPE MediumChangerFD, + int param_len, int timeout) +{ + CDB_T CDB; + + NSM_Result_T *retval = (NSM_Result_T *)xzmalloc(sizeof(NSM_Result_T)); + + int list_len = param_len + sizeof(NSM_Result_T) - 0xffff; + + /* Okay, now for the command: */ + CDB[0] = 0x1C; + CDB[1] = 0x00; + CDB[2] = 0; + CDB[3] = (unsigned char)(list_len >> 8); + CDB[4] = (unsigned char)list_len; + CDB[5] = 0; + +#ifdef DEBUG_NSM + dump_cdb(&CDB,6); +#endif + + /* Don't set us any timeout unless timeout is > 0 */ + if (timeout > 0) + { + SCSI_Set_Timeout(timeout); + } + + /* Now send the command: */ + if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 6, retval, list_len, &scsi_error_sense)) + { + return NULL; /* we failed */ + } + +#ifdef DEBUG_NSM + fprintf(stderr, + "page_code=%02x page_len=%d command_code=%s\n", + retval->page_code, + (int) ((retval->page_len_msb << 8) + retval->page_len_lsb), + retval->command_code); +#endif + + return retval; /* Did it! (maybe!)*/ +} + +/* Routine to inventory the library. Needed by, e.g., some Breece Hill + * loaders. Sends an INITIALIZE_ELEMENT_STATUS command. This command + * has no parameters, such as a range to scan :-(. + */ + +int Inventory(DEVICE_TYPE MediumChangerFD) +{ + CDB_T CDB; + + /* okay, now for the command: */ + CDB[0] = 0x07; + CDB[1] = CDB[2] = CDB[3] = CDB[4] = CDB[5] = 0; + + /* set us a very long timeout, sigh... */ + SCSI_Set_Timeout(30 * 60); /* 30 minutes, sigh! */ + + if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,NULL,0,&scsi_error_sense) != 0) + { + /* If error is UNIT ATTENTION then retry the request */ + if (scsi_error_sense.ErrorCode != 0x70 || scsi_error_sense.SenseKey != 6 || + ClearUnitAttention(MediumChangerFD, &scsi_error_sense) != 0 || + SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,NULL,0,&scsi_error_sense) != 0) + { + PrintRequestSense(&scsi_error_sense); + fprintf(stderr, "Initialize Element Status (0x07) failed\n"); + return -1; /* could not do! */ + } + } + return 0; /* did do! */ +} + +/* Routine to read the Mode Sense Element Address Assignment Page */ +/* We try to read the page. If we can't read the page, we return NULL. + * Our caller really isn't too worried about why we could not read the + * page, it will simply default to some kind of default values. + */ +ElementModeSense_T *ReadAssignmentPage(DEVICE_TYPE MediumChangerFD) +{ + CDB_T CDB; + ElementModeSense_T *retval; /* processed SCSI. */ + unsigned char input_buffer[136]; + ElementModeSensePage_T *sense_page; /* raw SCSI. */ + + /* okay, now for the command: */ + CDB[0] = 0x1A; /* Mode Sense(6) */ + CDB[1] = 0x08; + CDB[2] = 0x1D; /* Mode Sense Element Address Assignment Page */ + CDB[3] = 0; + CDB[4] = 136; /* allocation_length... */ + CDB[5] = 0; + + /* clear the data buffer: */ + slow_bzero((char *)&scsi_error_sense, sizeof(RequestSense_T)); + slow_bzero((char *)input_buffer, sizeof(input_buffer)); + + if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 6, + &input_buffer, sizeof(input_buffer), &scsi_error_sense) != 0) + { + /* If error is UNIT ATTENTION then retry the request */ + if (scsi_error_sense.ErrorCode != 0x70 || scsi_error_sense.SenseKey != 6 || + ClearUnitAttention(MediumChangerFD, &scsi_error_sense) != 0 || + SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 6, + &input_buffer, sizeof(input_buffer), &scsi_error_sense) != 0) + { + PrintRequestSense(&scsi_error_sense); + fprintf(stderr,"Mode sense (0x1A) for Page 0x1D failed\n"); + fflush(stderr); + return NULL; /* sorry, couldn't do it. */ + } + } + + /* Could do it, now build return value: */ + +#ifdef DEBUG_MODE_SENSE + PrintHex(0, input_buffer, 30); +#endif + + /* first, skip past: mode data header, and block descriptor header if any */ + sense_page=(ElementModeSensePage_T *)(input_buffer+4+input_buffer[3]); + +#ifdef DEBUG_MODE_SENSE + fprintf(stderr,"*sense_page=%x %x\n",*((unsigned char *)sense_page),sense_page->PageCode); + fflush(stderr); +#endif + + retval = (ElementModeSense_T *)xzmalloc(sizeof(ElementModeSense_T)); + + /* Remember that all SCSI values are big-endian: */ + retval->MediumTransportStart = + (((int)sense_page->MediumTransportStartHi) << 8) + + sense_page->MediumTransportStartLo; + + retval->NumMediumTransport = + (((int)(sense_page->NumMediumTransportHi))<<8) + + sense_page->NumMediumTransportLo; + + /* HACK! Some HP autochangers don't report NumMediumTransport right! */ + /* ARG! TAKE OUT THE %#@!# HACK! */ +#ifdef STUPID_DUMB_IDIOTIC_HP_LOADER_HACK + if (!retval->NumMediumTransport) + { + retval->NumMediumTransport = 1; + } +#endif + +#ifdef DEBUG_MODE_SENSE + fprintf(stderr, "rawNumStorage= %d %d rawNumImportExport= %d %d\n", + sense_page->NumStorageHi, sense_page->NumStorageLo, + sense_page->NumImportExportHi, sense_page->NumImportExportLo); + fprintf(stderr, "rawNumTransport=%d %d rawNumDataTransfer=%d %d\n", + sense_page->NumMediumTransportHi, sense_page->NumMediumTransportLo, + sense_page->NumDataTransferHi, sense_page->NumDataTransferLo); + fflush(stderr); +#endif + + retval->StorageStart = + ((int)sense_page->StorageStartHi << 8) + sense_page->StorageStartLo; + + retval->NumStorage = + ((int)sense_page->NumStorageHi << 8) + sense_page->NumStorageLo; + + retval->ImportExportStart = + ((int)sense_page->ImportExportStartHi << 8) + sense_page->ImportExportStartLo; + + retval->NumImportExport = + ((int)sense_page->NumImportExportHi << 8) + sense_page->NumImportExportLo; + + retval->DataTransferStart = + ((int)sense_page->DataTransferStartHi << 8) + sense_page->DataTransferStartLo; + + retval->NumDataTransfer = + ((int)sense_page->NumDataTransferHi << 8) + sense_page->NumDataTransferLo; + + /* allocate a couple spares 'cause some HP autochangers and maybe others + * don't properly report the robotics arm(s) count here... + */ + retval->NumElements = + retval->NumStorage+retval->NumImportExport + + retval->NumDataTransfer+retval->NumMediumTransport; + + retval->MaxReadElementStatusData = + (sizeof(ElementStatusDataHeader_T) + + 4 * sizeof(ElementStatusPage_T) + + retval->NumElements * sizeof(TransportElementDescriptor_T)); + +#ifdef IMPORT_EXPORT_HACK + retval->NumStorage = retval->NumStorage+retval->NumImportExport; +#endif + +#ifdef DEBUG_MODE_SENSE + fprintf(stderr, "NumMediumTransport=%d\n", retval->NumMediumTransport); + fprintf(stderr, "NumStorage=%d\n", retval->NumStorage); + fprintf(stderr, "NumImportExport=%d\n", retval->NumImportExport); + fprintf(stderr, "NumDataTransfer=%d\n", retval->NumDataTransfer); + fprintf(stderr, "MaxReadElementStatusData=%d\n", retval->MaxReadElementStatusData); + fprintf(stderr, "NumElements=%d\n", retval->NumElements); + fflush(stderr); +#endif + + return retval; +} + +static void FreeElementData(ElementStatus_T *data) +{ + free(data->DataTransferElementAddress); + free(data->DataTransferElementSourceStorageElementNumber); + free(data->DataTransferPrimaryVolumeTag); + free(data->DataTransferAlternateVolumeTag); + free(data->PrimaryVolumeTag); + free(data->AlternateVolumeTag); + free(data->StorageElementAddress); + free(data->StorageElementIsImportExport); + free(data->StorageElementFull); + free(data->DataTransferElementFull); +} + + +/* allocate data */ + +static ElementStatus_T *AllocateElementData(ElementModeSense_T *mode_sense) +{ + ElementStatus_T *retval; + + retval = (ElementStatus_T *)xzmalloc(sizeof(ElementStatus_T)); + + /* now for the invidual component arrays.... */ + + retval->DataTransferElementAddress = + (int *)xzmalloc(sizeof(int) * (mode_sense->NumDataTransfer + 1)); + retval->DataTransferElementSourceStorageElementNumber = + (int *)xzmalloc(sizeof(int) * (mode_sense->NumDataTransfer + 1)); + retval->DataTransferPrimaryVolumeTag = + (barcode *)xzmalloc(sizeof(barcode) * (mode_sense->NumDataTransfer + 1)); + retval->DataTransferAlternateVolumeTag = + (barcode *)xzmalloc(sizeof(barcode) * (mode_sense->NumDataTransfer + 1)); + retval->PrimaryVolumeTag = + (barcode *)xzmalloc(sizeof(barcode) * (mode_sense->NumStorage + 1)); + retval->AlternateVolumeTag = + (barcode *)xzmalloc(sizeof(barcode) * (mode_sense->NumStorage + 1)); + retval->StorageElementAddress = + (int *)xzmalloc(sizeof(int) * (mode_sense->NumStorage + 1)); + retval->StorageElementIsImportExport = + (boolean *)xzmalloc(sizeof(boolean) * (mode_sense->NumStorage + 1)); + retval->StorageElementFull = + (boolean *)xzmalloc(sizeof(boolean) * (mode_sense->NumStorage + 1)); + retval->DataTransferElementFull = + (boolean *)xzmalloc(sizeof(boolean) * (mode_sense->NumDataTransfer + 1)); + + return retval; /* sigh! */ +} + + +void copy_barcode(unsigned char *src, unsigned char *dest) +{ + int i; + + for (i=0; i < 36; i++) + { + *dest = *src++; + + if ((*dest < 32) || (*dest > 127)) + { + *dest = '\0'; + } + + dest++; + } + *dest = 0; /* null-terminate */ +} + +/* This #%!@# routine has more parameters than I can count! */ +static unsigned char *SendElementStatusRequestActual( + DEVICE_TYPE MediumChangerFD, + RequestSense_T *RequestSense, + Inquiry_T *inquiry_info, + SCSI_Flags_T *flags, + int ElementStart, + int NumElements, + int NumBytes + ) +{ + CDB_T CDB; + boolean is_attached = false; + + unsigned char *DataBuffer; /* size of data... */ + +#ifdef HAVE_GET_ID_LUN + scsi_id_t *scsi_id; +#endif + if (inquiry_info->MChngr && + inquiry_info->PeripheralDeviceType != MEDIUM_CHANGER_TYPE) + { + is_attached = true; + } + + if (flags->no_attached) + { + /* override, sigh */ + is_attached = false; + } + + DataBuffer = (unsigned char *)xzmalloc(NumBytes + 1); + + slow_bzero((char *)RequestSense, sizeof(RequestSense_T)); + +#ifdef HAVE_GET_ID_LUN + scsi_id = SCSI_GetIDLun(MediumChangerFD); +#endif + + CDB[0] = 0xB8; /* READ ELEMENT STATUS */ + + if (is_attached) + { + CDB[0] = 0xB4; /* whoops, READ_ELEMENT_STATUS_ATTACHED! */ + } + +#ifdef HAVE_GET_ID_LUN + CDB[1] = (scsi_id->lun << 5) | ((flags->no_barcodes) ? + 0 : 0x10) | flags->elementtype; /* Lun + VolTag + Type code */ + free(scsi_id); +#else + /* Element Type Code = 0, VolTag = 1 */ + CDB[1] = (unsigned char)((flags->no_barcodes ? 0 : 0x10) | flags->elementtype); +#endif + /* Starting Element Address */ + CDB[2] = (unsigned char)(ElementStart >> 8); + CDB[3] = (unsigned char)ElementStart; + + /* Number Of Elements */ + CDB[4]= (unsigned char)(NumElements >> 8); + CDB[5]= (unsigned char)NumElements; + + CDB[6] = 0; /* Reserved */ + + /* allocation length */ + CDB[7]= (unsigned char)(NumBytes >> 16); + CDB[8]= (unsigned char)(NumBytes >> 8); + CDB[9]= (unsigned char)NumBytes; + + CDB[10] = 0; /* Reserved */ + CDB[11] = 0; /* Control */ + +#ifdef DEBUG_BARCODE + fprintf(stderr,"CDB:\n"); + PrintHex(2, CDB, 12); +#endif + + if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 12, + DataBuffer,NumBytes, RequestSense) != 0) + { + +#ifdef DEBUG + fprintf(stderr, "Read Element Status (0x%02X) failed\n", CDB[0]); +#endif + + /* + First see if we have sense key of 'illegal request', + additional sense code of '24', additional sense qualfier of + '0', and field in error of '4'. This means that we issued a request + w/bar code reader and did not have one, thus must re-issue the request + w/out barcode :-(. + */ + + /* + Most autochangers and tape libraries set a sense key here if + they do not have a bar code reader. For some reason, the ADIC DAT + uses a different sense key? Let's retry w/o bar codes for *ALL* + sense keys. + */ + + if (RequestSense->SenseKey > 1) + { + /* we issued a code requesting bar codes, there is no bar code reader? */ + /* clear out our sense buffer first... */ + slow_bzero((char *)RequestSense, sizeof(RequestSense_T)); + + CDB[1] &= ~0x10; /* clear bar code flag! */ + +#ifdef DEBUG_BARCODE + fprintf(stderr,"CDB:\n"); + PrintHex(2, CDB, 12); +#endif + + if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 12, + DataBuffer, NumBytes, RequestSense) != 0) + { + free(DataBuffer); + return NULL; + } + } + else + { + free(DataBuffer); + return NULL; + } + } + +#ifdef DEBUG_BARCODE + /* print a bunch of extra debug data :-(. */ + PrintRequestSense(RequestSense); /* see what it sez :-(. */ + fprintf(stderr,"Data:\n"); + PrintHex(2, DataBuffer, 40); +#endif + return DataBuffer; /* we succeeded! */ +} + + +unsigned char *SendElementStatusRequest(DEVICE_TYPE MediumChangerFD, + RequestSense_T *RequestSense, + Inquiry_T *inquiry_info, + SCSI_Flags_T *flags, + int ElementStart, + int NumElements, + int NumBytes + ) +{ + unsigned char *DataBuffer; /* size of data... */ + int real_numbytes; + + DataBuffer = SendElementStatusRequestActual(MediumChangerFD, + RequestSense, + inquiry_info, + flags, + ElementStart, + NumElements, + NumBytes + ); + /* + One weird loader wants either 8 or BYTE_COUNT_OF_REPORT + values for the ALLOCATION_LENGTH. Give it what it wants + if we get an Sense Key of 05 Illegal Request with a + CDB position of 7 as the field in error. + */ + + if (DataBuffer == NULL && + RequestSense->SenseKey == 5 && + RequestSense->CommandData && + RequestSense->BitPointer == 7) + { + NumBytes=8; /* send an 8 byte request */ + DataBuffer=SendElementStatusRequestActual( MediumChangerFD, + RequestSense, + inquiry_info, + flags, + ElementStart, + NumElements, + NumBytes + ); + } + + /* the above code falls thru into this: */ + if (DataBuffer != NULL) + { + /* see if we need to retry with a bigger NumBytes: */ + real_numbytes = ((int)DataBuffer[5] << 16) + + ((int)DataBuffer[6] << 8) + + (int)DataBuffer[7] + 8; + + if (real_numbytes > NumBytes) + { + /* uh-oh, retry! */ + free(DataBuffer); /* solve memory leak */ + DataBuffer = SendElementStatusRequestActual(MediumChangerFD, + RequestSense, + inquiry_info, + flags, + ElementStart, + NumElements, + real_numbytes + ); + } + } + + return DataBuffer; +} + + + +/******************* ParseElementStatus ***********************************/ +/* This does the actual grunt work of parsing element status data. It fills + * in appropriate pieces of its input data. It may be called multiple times + * while we are gathering element status. + */ + +static void ParseElementStatus( int *EmptyStorageElementAddress, + int *EmptyStorageElementCount, + unsigned char *DataBuffer, + ElementStatus_T *ElementStatus, + ElementModeSense_T *mode_sense, + int *pNextElement + ) +{ + unsigned char *DataPointer = DataBuffer; + TransportElementDescriptor_T TEBuf; + TransportElementDescriptor_T *TransportElementDescriptor; + ElementStatusDataHeader_T *ElementStatusDataHeader; + Element2StatusPage_T *ElementStatusPage; + Element2StatusPage_T ESBuf; + int ElementCount; + int TransportElementDescriptorLength; + int BytesAvailable; + int ImportExportIndex; + + ElementStatusDataHeader = (ElementStatusDataHeader_T *) DataPointer; + DataPointer += sizeof(ElementStatusDataHeader_T); + ElementCount = + BigEndian16(ElementStatusDataHeader->NumberOfElementsAvailable); + +#ifdef DEBUG + fprintf(stderr,"ElementCount=%d\n",ElementCount); + fflush(stderr); +#endif + + while (ElementCount > 0) + { +#ifdef DEBUG + int got_element_num=0; + + fprintf(stderr,"Working on element # %d Element Count %d\n",got_element_num,ElementCount); + got_element_num++; +#endif + + memcpy(&ESBuf, DataPointer, sizeof(ElementStatusPage_T)); + ElementStatusPage = &ESBuf; + DataPointer += sizeof(ElementStatusPage_T); + + TransportElementDescriptorLength = + BigEndian16(ElementStatusPage->ElementDescriptorLength); + + if (TransportElementDescriptorLength < + sizeof(TransportElementDescriptorShort_T)) + { + /* Foo, Storage Element Descriptors can be 4 bytes?! */ + if ((ElementStatusPage->ElementTypeCode != MediumTransportElement && + ElementStatusPage->ElementTypeCode != StorageElement && + ElementStatusPage->ElementTypeCode != ImportExportElement ) || + TransportElementDescriptorLength < 4) + { +#ifdef DEBUG + fprintf(stderr,"boom! ElementTypeCode=%d\n",ElementStatusPage->ElementTypeCode); +#endif + FatalError("Transport Element Descriptor Length too short: %d\n", TransportElementDescriptorLength); + } + } +#ifdef DEBUG + fprintf(stderr,"Transport Element Descriptor Length=%d\n",TransportElementDescriptorLength); +#endif + BytesAvailable = + BigEndian24(ElementStatusPage->ByteCountOfDescriptorDataAvailable); +#ifdef DEBUG + fprintf(stderr,"%d bytes of descriptor data available in descriptor\n", + BytesAvailable); +#endif + /* work around a bug in ADIC DAT loaders */ + if (BytesAvailable <= 0) + { + ElementCount--; /* sorry :-( */ + } + while (BytesAvailable > 0) + { + /* TransportElementDescriptor = + (TransportElementDescriptor_T *) DataPointer; */ + memcpy(&TEBuf, DataPointer, + (TransportElementDescriptorLength <= sizeof(TEBuf)) ? + TransportElementDescriptorLength : + sizeof(TEBuf)); + TransportElementDescriptor = &TEBuf; + + if (pNextElement != NULL) + { + if (BigEndian16(TransportElementDescriptor->ElementAddress) != 0 || *pNextElement == 0) + { + (*pNextElement) = BigEndian16(TransportElementDescriptor->ElementAddress) + 1; + } + else + { + return; + } + } + + DataPointer += TransportElementDescriptorLength; + BytesAvailable -= TransportElementDescriptorLength; + ElementCount--; + + switch (ElementStatusPage->ElementTypeCode) + { + case MediumTransportElement: + ElementStatus->TransportElementAddress = BigEndian16(TransportElementDescriptor->ElementAddress); +#ifdef DEBUG + fprintf(stderr,"TransportElementAddress=%d\n",ElementStatus->TransportElementAddress); +#endif + break; + + /* we treat ImportExport elements as if they were normal + * storage elements now, sigh... + */ + case ImportExportElement: +#ifdef DEBUG + fprintf(stderr,"ImportExportElement=%d\n",ElementStatus->StorageElementCount); +#endif + if (ElementStatus->ImportExportCount >= mode_sense->NumImportExport) + { + fprintf(stderr,"Warning:Too Many Import/Export Elements Reported (expected %d, now have %d\n", + mode_sense->NumImportExport, + ElementStatus->ImportExportCount + 1); + fflush(stderr); + return; /* we're done :-(. */ + } + + ImportExportIndex = mode_sense->NumStorage - mode_sense->NumImportExport + ElementStatus->ImportExportCount; + + ElementStatus->StorageElementAddress[ImportExportIndex] = + BigEndian16(TransportElementDescriptor->ElementAddress); + ElementStatus->StorageElementFull[ImportExportIndex] = + TransportElementDescriptor->Full; + + if ( (TransportElementDescriptorLength > 11) && + (ElementStatusPage->VolBits & E2_AVOLTAG)) + { + copy_barcode(TransportElementDescriptor->AlternateVolumeTag, + ElementStatus->AlternateVolumeTag[ImportExportIndex]); + } + else + { + ElementStatus->AlternateVolumeTag[ImportExportIndex][0] = 0; /* null string. */; + } + if ((TransportElementDescriptorLength > 11) && + (ElementStatusPage->VolBits & E2_PVOLTAG)) + { + copy_barcode(TransportElementDescriptor->PrimaryVolumeTag, + ElementStatus->PrimaryVolumeTag[ImportExportIndex]); + } + else + { + ElementStatus->PrimaryVolumeTag[ImportExportIndex][0]=0; /* null string. */ + } + + ElementStatus->StorageElementIsImportExport[ImportExportIndex] = 1; + + ElementStatus->ImportExportCount++; + break; + + case StorageElement: +#ifdef DEBUG + fprintf(stderr,"StorageElementCount=%d ElementAddress = %d ",ElementStatus->StorageElementCount,BigEndian16(TransportElementDescriptor->ElementAddress)); +#endif + /* ATL/Exabyte kludge -- skip slots that aren't installed :-( */ + if (TransportElementDescriptor->AdditionalSenseCode==0x83 && + TransportElementDescriptor->AdditionalSenseCodeQualifier==0x02) + continue; + + ElementStatus->StorageElementAddress[ElementStatus->StorageElementCount] = + BigEndian16(TransportElementDescriptor->ElementAddress); + ElementStatus->StorageElementFull[ElementStatus->StorageElementCount] = + TransportElementDescriptor->Full; +#ifdef DEBUG + if (TransportElementDescriptor->Except) + fprintf(stderr,"ASC,ASCQ = 0x%x,0x%x ",TransportElementDescriptor->AdditionalSenseCode,TransportElementDescriptor->AdditionalSenseCodeQualifier); + fprintf(stderr,"TransportElement->Full = %d\n",TransportElementDescriptor->Full); +#endif + if (!TransportElementDescriptor->Full) + { + EmptyStorageElementAddress[(*EmptyStorageElementCount)++] = + ElementStatus->StorageElementCount; /* slot idx. */ + /* ElementStatus->StorageElementAddress[ElementStatus->StorageElementCount]; */ + } + if ((TransportElementDescriptorLength > 11) && + (ElementStatusPage->VolBits & E2_AVOLTAG)) + { + copy_barcode(TransportElementDescriptor->AlternateVolumeTag, + ElementStatus->AlternateVolumeTag[ElementStatus->StorageElementCount]); + } + else + { + ElementStatus->AlternateVolumeTag[ElementStatus->StorageElementCount][0]=0; /* null string. */; + } + if ((TransportElementDescriptorLength > 11) && + (ElementStatusPage->VolBits & E2_PVOLTAG)) + { + copy_barcode(TransportElementDescriptor->PrimaryVolumeTag, + ElementStatus->PrimaryVolumeTag[ElementStatus->StorageElementCount]); + } + else + { + ElementStatus->PrimaryVolumeTag[ElementStatus->StorageElementCount][0]=0; /* null string. */ + } + + ElementStatus->StorageElementCount++; + /* + Note that the original mtx had no check here for + buffer overflow, though some drives might mistakingly + do one... + */ + + if (ElementStatus->StorageElementCount > mode_sense->NumStorage) + { + fprintf(stderr,"Warning:Too Many Storage Elements Reported (expected %d, now have %d\n", + mode_sense->NumStorage, + ElementStatus->StorageElementCount); + fflush(stderr); + return; /* we're done :-(. */ + } + break; + + case DataTransferElement: + /* tape drive not installed, go back to top of loop */ + + /* if (TransportElementDescriptor->Except) continue ; */ + + /* Note: This is for Exabyte tape libraries that improperly + report that they have a 2nd tape drive when they don't. We + could generalize this in an ideal world, but my attempt to + do so failed with dual-drive Exabyte tape libraries that + *DID* have the second drive. Sigh. + */ + if (TransportElementDescriptor->AdditionalSenseCode==0x83 && + TransportElementDescriptor->AdditionalSenseCodeQualifier==0x04) + { + continue; + } + + /* generalize it. Does it work? Let's try it! */ + /* + No, dammit, following does not work on dual-drive Exabyte + 'cause if a tape is in the drive, it sets the AdditionalSense + code to something (sigh). + */ + /* if (TransportElementDescriptor->AdditionalSenseCode!=0) + continue; + */ + + ElementStatus->DataTransferElementAddress[ElementStatus->DataTransferElementCount] = + BigEndian16(TransportElementDescriptor->ElementAddress); + ElementStatus->DataTransferElementFull[ElementStatus->DataTransferElementCount] = + TransportElementDescriptor->Full; + ElementStatus->DataTransferElementSourceStorageElementNumber[ElementStatus->DataTransferElementCount] = + BigEndian16(TransportElementDescriptor->SourceStorageElementAddress); + +#if DEBUG + fprintf(stderr, "%d: ElementAddress = %d, Full = %d, SourceElement = %d\n", + ElementStatus->DataTransferElementCount, + ElementStatus->DataTransferElementAddress[ElementStatus->DataTransferElementCount], + ElementStatus->DataTransferElementFull[ElementStatus->DataTransferElementCount], + ElementStatus->DataTransferElementSourceStorageElementNumber[ElementStatus->DataTransferElementCount]); +#endif + if (ElementStatus->DataTransferElementCount >= mode_sense->NumDataTransfer) + { + FatalError("Too many Data Transfer Elements Reported\n"); + } + + if (ElementStatusPage->VolBits & E2_PVOLTAG) + { + copy_barcode(TransportElementDescriptor->PrimaryVolumeTag, + ElementStatus->DataTransferPrimaryVolumeTag[ElementStatus->DataTransferElementCount]); + } + else + { + ElementStatus->DataTransferPrimaryVolumeTag[ElementStatus->DataTransferElementCount][0]=0; /* null string */ + } + + if (ElementStatusPage->VolBits & E2_AVOLTAG) + { + copy_barcode(TransportElementDescriptor->AlternateVolumeTag, + ElementStatus->DataTransferAlternateVolumeTag[ElementStatus->DataTransferElementCount]); + } + else + { + ElementStatus->DataTransferAlternateVolumeTag[ElementStatus->DataTransferElementCount][0]=0; /* null string */ + } + + ElementStatus->DataTransferElementCount++; + + /* 0 actually is a usable element address */ + /* if (DataTransferElementAddress == 0) */ + /* FatalError( */ + /* "illegal Data Transfer Element Address %d reported\n", */ + /* DataTransferElementAddress); */ + break; + + default: + FatalError("illegal Element Type Code %d reported\n", + ElementStatusPage->ElementTypeCode); + } + } + } + +#ifdef DEBUG + if (pNextElement) + fprintf(stderr,"Next start element will be %d\n",*pNextElement); +#endif +} + + +/********************* Real ReadElementStatus ********************* */ + +/* + * We no longer do the funky trick to figure out ALLOCATION_LENGTH. + * Instead, we use the SCSI Generic command rather than SEND_SCSI_COMMAND + * under Linux, which gets around the @#%@ 4k buffer size in Linux. + * We still have the restriction that Linux cuts off the last two + * bytes of the SENSE DATA (Q#@$%@#$^ Linux!). Which means that the + * verbose widget won't work :-(. + + * We now look for that "attached" bit in the inquiry_info to see whether + * to use READ_ELEMENT_ATTACHED or plain old READ_ELEMENT. In addition, we + * look at the device type in the inquiry_info to see whether it is a media + * changer or tape device, and if it's a media changer device, we ignore the + * attached bit (one beta tester found an old 4-tape DAT changer that set + * the attached bit for both the tape device AND the media changer device). + +*/ + +ElementStatus_T *ReadElementStatus(DEVICE_TYPE MediumChangerFD, RequestSense_T *RequestSense, Inquiry_T *inquiry_info, SCSI_Flags_T *flags) +{ + ElementStatus_T *ElementStatus; + + unsigned char *DataBuffer; /* size of data... */ + + int EmptyStorageElementCount=0; + int *EmptyStorageElementAddress; /* [MAX_STORAGE_ELEMENTS]; */ + + int empty_idx = 0; + boolean is_attached = false; + int i,j; + + ElementModeSense_T *mode_sense = NULL; + + if (inquiry_info->MChngr && inquiry_info->PeripheralDeviceType != MEDIUM_CHANGER_TYPE) + { + is_attached = true; + } + + if (flags->no_attached) + { + /* override, sigh */ + is_attached = false; + } + + if (!is_attached) + { + mode_sense = ReadAssignmentPage(MediumChangerFD); + } + + if (!mode_sense) + { + mode_sense = (ElementModeSense_T *)xmalloc(sizeof(ElementModeSense_T)); + mode_sense->NumMediumTransport = MAX_TRANSPORT_ELEMENTS; + mode_sense->NumStorage = MAX_STORAGE_ELEMENTS; + mode_sense->NumDataTransfer = MAX_TRANSFER_ELEMENTS; + mode_sense->MaxReadElementStatusData = + (sizeof(ElementStatusDataHeader_T) + 3 * sizeof(ElementStatusPage_T) + + (MAX_STORAGE_ELEMENTS+MAX_TRANSFER_ELEMENTS+MAX_TRANSPORT_ELEMENTS) * + sizeof(TransportElementDescriptor_T)); + + /* don't care about the others anyhow at the moment... */ + } + + ElementStatus = AllocateElementData(mode_sense); + + /* Now to initialize it (sigh). */ + ElementStatus->StorageElementCount = 0; + ElementStatus->DataTransferElementCount = 0; + + /* first, allocate some empty storage stuff: Note that we pass this + * down to ParseElementStatus (sigh!) + */ + + EmptyStorageElementAddress = (int *)xzmalloc((mode_sense->NumStorage+1)*sizeof(int)); + for (i = 0; i < mode_sense->NumStorage; i++) + { + EmptyStorageElementAddress[i] = -1; + } + + /* Okay, now to send some requests for the various types of stuff: */ + + /* -----------STORAGE ELEMENTS---------------- */ + /* Let's start with storage elements: */ + + for (i = 0; i < mode_sense->NumDataTransfer; i++) + { + /* initialize them to an illegal # so that we can fix later... */ + ElementStatus->DataTransferElementSourceStorageElementNumber[i] = -1; + } + + if (flags->querytype == MTX_ELEMENTSTATUS_ORIGINAL) + { +#ifdef DEBUG + fprintf(stderr,"Using original element status polling method (storage, import/export, drivers etc independantly)\n"); +#endif + flags->elementtype = StorageElement; /* sigh! */ + DataBuffer = SendElementStatusRequest( MediumChangerFD, RequestSense, + inquiry_info, flags, + mode_sense->StorageStart, + /* adjust for import/export. */ + mode_sense->NumStorage - mode_sense->NumImportExport, + mode_sense->MaxReadElementStatusData); + + if (!DataBuffer) + { +#ifdef DEBUG + fprintf(stderr,"Had no elements!\n"); +#endif + /* darn. Free up stuff and return. */ +#ifdef DEBUG_MODE_SENSE + PrintRequestSense(RequestSense); +#endif + FreeElementData(ElementStatus); + return NULL; + } + +#ifdef DEBUG + fprintf(stderr, "Parsing storage elements\n"); +#endif + ParseElementStatus(EmptyStorageElementAddress, &EmptyStorageElementCount, + DataBuffer,ElementStatus,mode_sense,NULL); + + free(DataBuffer); /* sigh! */ + + /* --------------IMPORT/EXPORT--------------- */ + /* Next let's see if we need to do Import/Export: */ + if (mode_sense->NumImportExport > 0) + { +#ifdef DEBUG + fprintf(stderr,"Sending request for Import/Export status\n"); +#endif + flags->elementtype = ImportExportElement; + DataBuffer = SendElementStatusRequest( MediumChangerFD,RequestSense, + inquiry_info, flags, + mode_sense->ImportExportStart, + mode_sense->NumImportExport, + mode_sense->MaxReadElementStatusData); + + if (!DataBuffer) + { +#ifdef DEBUG + fprintf(stderr,"Had no input/export element!\n"); +#endif + /* darn. Free up stuff and return. */ +#ifdef DEBUG_MODE_SENSE + PrintRequestSense(RequestSense); +#endif + FreeElementData(ElementStatus); + return NULL; + } +#ifdef DEBUG + fprintf(stderr,"Parsing inport/export element status\n"); +#endif +#ifdef DEBUG_ADIC + dump_data(DataBuffer, 100); /* dump some data :-(. */ +#endif + ParseElementStatus( EmptyStorageElementAddress, &EmptyStorageElementCount, + DataBuffer, ElementStatus, mode_sense, NULL); + + ElementStatus->StorageElementCount += ElementStatus->ImportExportCount; + } + + /* ----------------- DRIVES ---------------------- */ + +#ifdef DEBUG + fprintf(stderr,"Sending request for data transfer element (drive) status\n"); +#endif + flags->elementtype = DataTransferElement; /* sigh! */ + DataBuffer = SendElementStatusRequest( MediumChangerFD, RequestSense, + inquiry_info, flags, + mode_sense->DataTransferStart, + mode_sense->NumDataTransfer, + mode_sense->MaxReadElementStatusData); + if (!DataBuffer) + { +#ifdef DEBUG + fprintf(stderr,"No data transfer element status."); +#endif + /* darn. Free up stuff and return. */ +#ifdef DEBUG_MODE_SENSE + PrintRequestSense(RequestSense); +#endif + FreeElementData(ElementStatus); + return NULL; + } + +#ifdef DEBUG + fprintf(stderr,"Parsing data for data transfer element (drive) status\n"); +#endif + ParseElementStatus( EmptyStorageElementAddress, &EmptyStorageElementCount, + DataBuffer,ElementStatus, mode_sense, NULL); + + free(DataBuffer); /* sigh! */ + + /* ----------------- Robot Arm(s) -------------------------- */ + + /* grr, damned brain dead HP doesn't report that it has any! */ + if (!mode_sense->NumMediumTransport) + { + ElementStatus->TransportElementAddress = 0; /* default it sensibly :-(. */ + } + else + { +#ifdef DEBUG + fprintf(stderr,"Sending request for robot arm status\n"); +#endif + flags->elementtype = MediumTransportElement; /* sigh! */ + DataBuffer = SendElementStatusRequest( MediumChangerFD, RequestSense, + inquiry_info, flags, + mode_sense->MediumTransportStart, + 1, /* only get 1, sigh. */ + mode_sense->MaxReadElementStatusData); + if (!DataBuffer) + { +#ifdef DEBUG + fprintf(stderr,"Loader reports no robot arm!\n"); +#endif + /* darn. Free up stuff and return. */ +#ifdef DEBUG_MODE_SENSE + PrintRequestSense(RequestSense); +#endif + FreeElementData(ElementStatus); + return NULL; + } +#ifdef DEBUG + fprintf(stderr,"Parsing robot arm data\n"); +#endif + ParseElementStatus( EmptyStorageElementAddress, &EmptyStorageElementCount, + DataBuffer, ElementStatus, mode_sense, NULL); + + free(DataBuffer); + } + } + else + { + int nLastEl=-1, nNextEl=0; + +#ifdef DEBUG + fprintf(stderr,"Using alternative element status polling method (all elements)\n"); +#endif + /* ----------------- ALL Elements ---------------------- */ + /* Just keep asking for elements till no more are returned + - increment our starting address as we go acording to the + number of elements returned from the last call + */ + + while(nLastEl!=nNextEl) + { + flags->elementtype = AllElementTypes;//StorageElement; /* sigh! */ /*XL1B2 firewire changer does not seem to respond to specific types so just use all elements*/ + DataBuffer = SendElementStatusRequest( MediumChangerFD, + RequestSense, + inquiry_info, + flags, + nNextEl,//mode_sense->StorageStart, + /* adjust for import/export. */ + mode_sense->NumStorage - mode_sense->NumImportExport,//FIX ME:this should be a more sensible value + mode_sense->MaxReadElementStatusData); + if (!DataBuffer) + { + if (RequestSense->AdditionalSenseCode == 0x21 && + RequestSense->AdditionalSenseCodeQualifier == 0x01) + { + /* Error is invalid element address, we've probably just hit the end */ + break; + } + + /* darn. Free up stuff and return. */ + FreeElementData(ElementStatus); + return NULL; + } + + nLastEl = nNextEl; + + ParseElementStatus( EmptyStorageElementAddress, &EmptyStorageElementCount, + DataBuffer, ElementStatus, mode_sense, &nNextEl); + + free(DataBuffer); /* sigh! */ + } + + ElementStatus->StorageElementCount += ElementStatus->ImportExportCount; + } + + /*---------------------- Sanity Checking ------------------- */ + + if (ElementStatus->DataTransferElementCount == 0) + FatalError("no Data Transfer Element reported\n"); + + if (ElementStatus->StorageElementCount == 0) + FatalError("no Storage Elements reported\n"); + + + /* ---------------------- Reset SourceStorageElementNumbers ------- */ + + /* + * Re-write the SourceStorageElementNumber code *AGAIN*. + * + * Pass1: + * Translate from raw element # to our translated # (if possible). + * First, check the SourceStorageElementNumbers against the list of + * filled slots. If the slots indicated are empty, we accept that list as + * valid. Otherwise decide the SourceStorageElementNumbers are invalid. + * + * Pass2: + * If we had some invalid (or unknown) SourceStorageElementNumbers + * then we must search for free slots, and assign SourceStorageElementNumbers + * to those free slots. We happen to already built a list of free + * slots as part of the process of reading the storage element numbers + * from the tape. So that's easy enough to do! + */ + +#ifdef DEBUG_TAPELIST + fprintf(stderr, "empty slots: %d\n", EmptyStorageElementCount); + if (EmptyStorageElementCount) + { + for (i = 0; i < EmptyStorageElementCount; i++) + { + fprintf(stderr, "empty: %d\n", EmptyStorageElementAddress[i]); + } + } +#endif + + /* + * Now we re-assign origin slots if the "real" origin slot + * is obviously defective: + */ + /* pass one: */ + for (i = 0; i < ElementStatus->DataTransferElementCount; i++) + { + int elnum; + + /* if we have an element, then ... */ + if (ElementStatus->DataTransferElementFull[i]) + { + elnum = ElementStatus->DataTransferElementSourceStorageElementNumber[i]; + /* if we have an element number, then ... */ + if (elnum >= 0) + { + /* Now to translate the elnum: */ + ElementStatus->DataTransferElementSourceStorageElementNumber[i] = -1; + for (j = 0; j < ElementStatus->StorageElementCount; j++) + { + if (elnum == ElementStatus->StorageElementAddress[j]) + { + /* now see if the element # is already occupied:*/ + if (!ElementStatus->StorageElementFull[j]) + { + /* properly set the source... */ + ElementStatus->DataTransferElementSourceStorageElementNumber[i] = j; + } + } + } + } + } + } + + /* Pass2: */ + /* We have invalid sources, so let's see what they should be: */ + /* Note: If EmptyStorageElementCount is < # of drives, the leftover + * drives will be assigned a -1 (see the initialization loop for + * EmptyStorageElementAddress above), which will be reported as "slot 0" + * by the user interface. This is an invalid value, but more useful for us + * to have than just crapping out here :-(. + */ + empty_idx=0; + for (i = 0; i < ElementStatus->DataTransferElementCount; i++) + { + if (ElementStatus->DataTransferElementFull[i] && + ElementStatus->DataTransferElementSourceStorageElementNumber[i] < 0) + { +#ifdef DEBUG_TAPELIST + fprintf(stderr,"for drive %d, changing to %d (empty slot #%d)\n", + i, + EmptyStorageElementAddress[empty_idx], + empty_idx); +#endif + ElementStatus->DataTransferElementSourceStorageElementNumber[i] = + EmptyStorageElementAddress[empty_idx++]; + } + } + + /* and done! */ + free(mode_sense); + free(EmptyStorageElementAddress); + return ElementStatus; +} + +/*************************************************************************/ + +RequestSense_T *PositionElement(DEVICE_TYPE MediumChangerFD, + int DestinationAddress, + ElementStatus_T *ElementStatus) +{ + RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T)); + CDB_T CDB; + + CDB[0] = 0x2b; + CDB[1] = 0; + CDB[2] = (unsigned char)(ElementStatus->TransportElementAddress >> 8); + CDB[3] = (unsigned char)ElementStatus->TransportElementAddress; + CDB[4] = (unsigned char)(DestinationAddress >> 8); + CDB[5] = (unsigned char)DestinationAddress; + CDB[6] = 0; + CDB[7] = 0; + CDB[8] = 0; + CDB[9] = 0; + + if(SCSI_ExecuteCommand( MediumChangerFD, Output, &CDB, 10, + NULL, 0, RequestSense) != 0) + { + return RequestSense; + } + free(RequestSense); + return NULL; /* success */ +} + + +/* Now the actual media movement routine! */ +RequestSense_T *MoveMedium( DEVICE_TYPE MediumChangerFD, int SourceAddress, + int DestinationAddress, + ElementStatus_T *ElementStatus, + Inquiry_T *inquiry_info, SCSI_Flags_T *flags) +{ + RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T)); + CDB_T CDB; + + if (inquiry_info->MChngr && inquiry_info->PeripheralDeviceType != MEDIUM_CHANGER_TYPE) + { + /* if using the ATTACHED API */ + CDB[0] = 0xA7; /* MOVE_MEDIUM_ATTACHED */ + } + else + { + CDB[0] = 0xA5; /* MOVE MEDIUM */ + } + + CDB[1] = 0; /* Reserved */ + + /* Transport Element Address */ + CDB[2] = (unsigned char)(ElementStatus->TransportElementAddress >> 8); + CDB[3] = (unsigned char)ElementStatus->TransportElementAddress; + + /* Source Address */ + CDB[4] = (unsigned char)(SourceAddress >> 8); + CDB[5] = (unsigned char)SourceAddress; + + /* Destination Address */ + CDB[6] = (unsigned char)(DestinationAddress >> 8); + CDB[7] = (unsigned char)DestinationAddress; + + CDB[8] = 0; /* Reserved */ + CDB[9] = 0; /* Reserved */ + + if (flags->invert) + { + CDB[10] = 1; /* Reserved */ + } + else + { + CDB[10] = 0; + } + /* eepos controls the tray for import/export elements, sometimes. */ + CDB[11] = flags->eepos << 6; /* Control */ + + if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 12, + NULL, 0, RequestSense) != 0) + { +#ifdef DEBUG + fprintf(stderr, "Move Medium (0x%02X) failed\n", CDB[0]); +#endif + return RequestSense; + } + + free(RequestSense); + return NULL; /* success! */ +} + + +/* Now the actual Exchange Medium routine! */ +RequestSense_T *ExchangeMedium( DEVICE_TYPE MediumChangerFD, int SourceAddress, + int DestinationAddress, int Dest2Address, + ElementStatus_T *ElementStatus, + SCSI_Flags_T *flags) +{ + RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T)); + CDB_T CDB; + + CDB[0] = 0xA6; /* EXCHANGE MEDIUM */ + CDB[1] = 0; /* Reserved */ + + /* Transport Element Address */ + CDB[2] = (unsigned char)(ElementStatus->TransportElementAddress >> 8); + CDB[3] = (unsigned char)ElementStatus->TransportElementAddress; + + /* Source Address */ + CDB[4] = (unsigned char)(SourceAddress >> 8); + CDB[5] = (unsigned char)SourceAddress; + + /* Destination Address */ + CDB[6] = (unsigned char)(DestinationAddress >> 8); + CDB[7] = (unsigned char)DestinationAddress; + + /* move destination back to source? */ + CDB[8] = (unsigned char)(Dest2Address >> 8); + CDB[9] = (unsigned char)Dest2Address; + CDB[10] = 0; + + if (flags->invert) + { + CDB[10] |= 2; /* INV2 */ + } + + if (flags->invert2) + { + CDB[1] |= 1; /* INV1 */ + } + + /* eepos controls the tray for import/export elements, sometimes. */ + CDB[11] = flags->eepos << 6; /* Control */ + +#ifdef DEBUG_EXCHANGE + dump_cdb(&CDB,12); +#endif + + if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 12, + NULL, 0, RequestSense) != 0) + { + return RequestSense; + } + free(RequestSense); + return NULL; /* success! */ +} + + +/* + * for Linux, this creates a way to do a short erase... the @#$%@ st.c + * driver defaults to doing a long erase! + */ + +RequestSense_T *Erase(DEVICE_TYPE MediumChangerFD) +{ + RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T)); + CDB_T CDB; + + CDB[0] = 0x19; + CDB[1] = 0; /* Short! */ + CDB[2] = CDB[3] = CDB[4] = CDB[5] = 0; + + if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 6, NULL, 0, RequestSense) != 0) + { + /* If error is UNIT ATTENTION then retry the request */ + if (RequestSense->ErrorCode != 0x70 || RequestSense->SenseKey != 6 || + ClearUnitAttention(MediumChangerFD, RequestSense) != 0 || + SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 6, NULL, 0, RequestSense) != 0) + { +#ifdef DEBUG + fprintf(stderr, "Erase (0x19) failed\n"); +#endif + return RequestSense; + } + } + + free(RequestSense); + return NULL; /* Success! */ +} + +/* Routine to send an LOAD/UNLOAD from the MMC/SSC spec to a device. + * For tapes and changers this can be used either to eject a tape + * or to eject a magazine (on some Seagate changers, when sent to LUN 1 ). + * For CD/DVDs this is used to Load or Unload a disc which is required by + * some media changers. + */ + +int LoadUnload(DEVICE_TYPE fd, int bLoad) +{ + CDB_T CDB; + /* okay, now for the command: */ + + CDB[0] = 0x1B; + CDB[4] = bLoad ? 3 : 2; + CDB[1] = CDB[2] = CDB[3] = CDB[5] = 0; + + if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, NULL, 0, &scsi_error_sense) != 0) + { + /* If error is UNIT ATTENTION then retry the request */ + if (scsi_error_sense.ErrorCode != 0x70 || scsi_error_sense.SenseKey != 6 || + ClearUnitAttention(fd, &scsi_error_sense) != 0 || + SCSI_ExecuteCommand(fd, Input, &CDB, 6, NULL, 0, &scsi_error_sense) != 0) + { + PrintRequestSense(&scsi_error_sense); + fprintf(stderr, "Eject (0x1B) failed\n"); + return -1; /* could not do! */ + } + } + return 0; /* did do! */ +} + +/* Routine to send an START/STOP from the MMC/SSC spec to a device. + * For tape drives this may be required prior to using the changer + * Load or Unload commands. + * For CD/DVD drives this is used to Load or Unload a disc which may be + * required by some media changers. + */ + +int StartStop(DEVICE_TYPE fd, int bStart) +{ + CDB_T CDB; + /* okay, now for the command: */ + + CDB[0] = 0x1B; + CDB[4] = bStart ? 1 : 0; + CDB[1] = CDB[2] = CDB[3] = CDB[5] = 0; + + if (SCSI_ExecuteCommand(fd, Input, &CDB, 6,NULL, 0, &scsi_error_sense) != 0) + { + PrintRequestSense(&scsi_error_sense); + fprintf(stderr, "Eject (0x1B) failed\n"); + return -1; /* could not do! */ + } + return 0; /* did do! */ +} + +/* Routine to send a LOCK/UNLOCK from the SSC/MMC spec to a device. + * This can be used to prevent or allow the Tape or CD/DVD from being + * removed. + */ + +int LockUnlock(DEVICE_TYPE fd, int bLock) +{ + CDB_T CDB; + /* okay, now for the command: */ + + CDB[0] = 0x1E; + CDB[1] = CDB[2] = CDB[3] = CDB[5] = 0; + CDB[4] = (char)bLock; + + if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, NULL, 0, &scsi_error_sense) != 0) + { + PrintRequestSense(&scsi_error_sense); + fprintf(stderr, "Lock/Unlock (0x1E) failed\n"); + return -1; /* could not do! */ + } + return 0; /* did do! */ +} + +int ClearUnitAttention(DEVICE_TYPE fd, RequestSense_T *RequestSense) +{ + CDB_T CDB; + int RetryCount = 10; /* Unit Attentions may be stacked */ + RequestSense_T unit_attention_sense; + + CDB[0] = 0x03; /* Request Sense */ + CDB[4] = (char)sizeof(*RequestSense); + CDB[1] = CDB[2] = CDB[3] = CDB[5] = 0; + + while (RetryCount-- > 0) + { + if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, + &unit_attention_sense, sizeof(unit_attention_sense), + RequestSense) != 0) + { + fprintf(stderr, "RequestSense (0x03) failed\n"); + return -1; /* could not do! */ + } + + if (unit_attention_sense.SenseKey == 0) + { + /* If SenseKey is NO SENSE then we are done. */ + return 0; + } + } + return -1; /* did do! */ + +} + +static char Spaces[] = " "; + +void PrintHex(int Indent, unsigned char *Buffer, int Length) +{ + int idxBuffer; + int idxAscii; + int PadLength; + char cAscii; + + for (idxBuffer = 0; idxBuffer < Length; idxBuffer++) + { + if ((idxBuffer % 16) == 0) + { + if (idxBuffer > 0) + { + fputc('\'', stderr); + + for (idxAscii = idxBuffer - 16; idxAscii < idxBuffer; idxAscii++) + { + cAscii = Buffer[idxAscii] >= 0x20 && Buffer[idxAscii] < 0x7F ? Buffer[idxAscii] : '.'; + fputc(cAscii, stderr); + } + fputs("'\n", stderr); + } + fprintf(stderr, "%.*s%04X: ", Indent, Spaces, idxBuffer); + } + fprintf(stderr, "%02X ", (unsigned char)Buffer[idxBuffer]); + } + + PadLength = 16 - (Length % 16); + + if (PadLength > 0) + { + fprintf(stderr, "%.*s'", 3 * PadLength, Spaces); + + for (idxAscii = idxBuffer - (16 - PadLength); idxAscii < idxBuffer; idxAscii++) + { + cAscii = Buffer[idxAscii] >= 0x20 && Buffer[idxAscii] < 0x80 ? Buffer[idxAscii] : '.'; + fputc(cAscii, stderr); + } + fputs("'\n", stderr); + } + + fflush(stderr); +} + +static char *sense_keys[] = +{ + "No Sense", /* 00 */ + "Recovered Error", /* 01 */ + "Not Ready", /* 02 */ + "Medium Error", /* 03 */ + "Hardware Error", /* 04 */ + "Illegal Request", /* 05 */ + "Unit Attention", /* 06 */ + "Data Protect", /* 07 */ + "Blank Check", /* 08 */ + "0x09", /* 09 */ + "0x0a", /* 0a */ + "Aborted Command", /* 0b */ + "0x0c", /* 0c */ + "Volume Overflow", /* 0d */ + "Miscompare", /* 0e */ + "0x0f" /* 0f */ +}; + +static char Yes[] = "yes"; +static char No[] = "no"; + +void PrintRequestSense(RequestSense_T *RequestSense) +{ + char *msg; + + fprintf(stderr, "mtx: Request Sense: Long Report=yes\n"); + fprintf(stderr, "mtx: Request Sense: Valid Residual=%s\n", RequestSense->Valid ? Yes : No); + + if (RequestSense->ErrorCode == 0x70) + { + msg = "Current" ; + } + else if (RequestSense->ErrorCode == 0x71) + { + msg = "Deferred" ; + } + else + { + msg = "Unknown?!" ; + } + + fprintf(stderr, "mtx: Request Sense: Error Code=%0x (%s)\n", RequestSense->ErrorCode, msg); + fprintf(stderr, "mtx: Request Sense: Sense Key=%s\n", sense_keys[RequestSense->SenseKey]); + fprintf(stderr, "mtx: Request Sense: FileMark=%s\n", RequestSense->Filemark ? Yes : No); + fprintf(stderr, "mtx: Request Sense: EOM=%s\n", RequestSense->EOM ? Yes : No); + fprintf(stderr, "mtx: Request Sense: ILI=%s\n", RequestSense->ILI ? Yes : No); + + if (RequestSense->Valid) + { + fprintf(stderr, "mtx: Request Sense: Residual = %02X %02X %02X %02X\n",RequestSense->Information[0],RequestSense->Information[1],RequestSense->Information[2],RequestSense->Information[3]); + } + + fprintf(stderr,"mtx: Request Sense: Additional Sense Code = %02X\n", RequestSense->AdditionalSenseCode); + fprintf(stderr,"mtx: Request Sense: Additional Sense Qualifier = %02X\n", RequestSense->AdditionalSenseCodeQualifier); + + if (RequestSense->SKSV) + { + fprintf(stderr,"mtx: Request Sense: Field in Error = %02X\n", RequestSense->BitPointer); + } + + fprintf(stderr, "mtx: Request Sense: BPV=%s\n", RequestSense->BPV ? Yes : No); + fprintf(stderr, "mtx: Request Sense: Error in CDB=%s\n", RequestSense->CommandData ? Yes : No); + fprintf(stderr, "mtx: Request Sense: SKSV=%s\n", RequestSense->SKSV ? Yes : No); + + if (RequestSense->BPV || RequestSense -> SKSV) + { + fprintf(stderr, "mtx: Request Sense: Field Pointer = %02X %02X\n", + RequestSense->FieldData[0], RequestSense->FieldData[1]); + } + + fflush(stderr); +} diff --git a/mtxl.h b/mtxl.h new file mode 100644 index 0000000..073f4fa --- /dev/null +++ b/mtxl.h @@ -0,0 +1,109 @@ +/* + MTX -- SCSI Tape Attached Medium Changer Control Program + + Copyright 1997-1998 Leonard N. Zubkoff + Copyright 2007-2008 by Robert Nelson + This file created by Eric Lee Green + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for complete details. + + $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ + $Revision: 193 $ +*/ + +/* Much of the guts of mtx.c has been extracted to mtxl.c, a library file + * full of utility routines. This file is the header file for that library. + * -E + */ + +#ifndef MTXL_H +#define MTXL_H 1 + +#include "mtx.h" + +#undef min +#undef max + +void FatalError(char *ErrorMessage, ...); +void *xmalloc(size_t Size); +void *xzmalloc(size_t Size); +void slow_bzero(char *buffer, int numchars); + +DEVICE_TYPE SCSI_OpenDevice(char *DeviceName); +void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD); +int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD, + Direction_T Direction, + CDB_T *CDB, + int CDB_Length, + void *DataBuffer, + int DataBufferLength, + RequestSense_T *RequestSense); + +void PrintRequestSense(RequestSense_T *RequestSense); + +int BigEndian16(unsigned char *BigEndianData); +int BigEndian24(unsigned char *BigEndianData); +int min(int x, int y); +int max(int x, int y); + +void PrintHex(int Indent, unsigned char *Buffer, int Length); +int ClearUnitAttention(DEVICE_TYPE fd, RequestSense_T *RequestSense); + +ElementStatus_T *ReadElementStatus( DEVICE_TYPE MediumChangerFD, + RequestSense_T *RequestSense, + Inquiry_T *inquiry_info, + SCSI_Flags_T *flags); + +Inquiry_T *RequestInquiry( DEVICE_TYPE fd, + RequestSense_T *RequestSense); + +RequestSense_T *MoveMedium( DEVICE_TYPE MediumChangerFD, + int SourceAddress, + int DestinationAddress, + ElementStatus_T *ElementStatus, + Inquiry_T *inquiry_info, + SCSI_Flags_T *flags); + +RequestSense_T *ExchangeMedium( DEVICE_TYPE MediumChangerFD, + int SourceAddress, + int DestinationAddress, + int Dest2Address, + ElementStatus_T *ElementStatus, + SCSI_Flags_T *flags); + +RequestSense_T *PositionElement(DEVICE_TYPE MediumChangerFD, + int DestinationAddress, + ElementStatus_T *ElementStatus); + +int Inventory(DEVICE_TYPE MediumChangerFD); /* inventory library */ +int LoadUnload(DEVICE_TYPE fd, int bLoad); /* load/unload tape, magazine or disc */ +int StartStop(DEVICE_TYPE fd, int bStart); /* start/stop device */ +int LockUnlock(DEVICE_TYPE fd, int bLock); /* lock/unlock medium in device */ +RequestSense_T *Erase(DEVICE_TYPE fd); /* send SHORT erase to drive */ + +void SCSI_Set_Timeout(int secs); /* set the SCSI timeout */ +void SCSI_Default_Timeout(void); /* go back to default timeout */ + +/* we may not have this function :-(. */ +#ifdef HAVE_GET_ID_LUN + scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd); +#endif + +/* These two hacks are so that I can stick the tongue out on an + * NSM optical jukebox. + */ +NSM_Result_T *RecNSMHack(DEVICE_TYPE MediumChangerFD, + int param_len, int timeout); + +int SendNSMHack(DEVICE_TYPE MediumChangerFD, NSM_Param_T *nsm_command, + int param_len, int timeout); + +#endif + diff --git a/nsmhack.c b/nsmhack.c new file mode 100644 index 0000000..b2ac2c2 --- /dev/null +++ b/nsmhack.c @@ -0,0 +1,342 @@ +/* Copyright 2001 DISC Inc. + * Copyright 2007-2008 by Robert Nelson + * Released under terms of the GNU General Public License as required + * by the license on the file "mtxl.c". See file "LICENSE" for details. + */ + +#define DEBUG_NSM 1 + +/* This is a hack to make the NSM modular series jukeboxes stick out + * their tongue, then retract tongue, so we can import media. They + * automatically stick out their tongue when exporting media, but + * importing media is not working, you try to do a MOVE_MEDIUM and + * it says "What medium?" before even sticking out its tongue. + * My manager has turned in a change request to NSM engineering to direct + * their firmware guys to add EEPOS support to the NSM modular jukeboxes so + * that we have tongue firmware that's compatible with Exabyte, Sony, Breece + * Hill, etc., but until that new firmware is here, this hack will work. + */ + +/* Note: Perhaps "hack" is an overstatement, since this will also + * eventually add pack management and other things of that nature + * that are extremely loader dependent. + */ + +/* Commands: + -f + tongue_out + tongue_in + tongue_button_wait + tongue_button_enable + tongue_button_disable +*/ + + +#include "mtxl.h" /* get the SCSI routines out of the main file */ + +/****************************************************************/ +/* Variables: */ +/****************************************************************/ + +/* the device handle we're operating upon, sigh. */ +static char *device; /* the text of the device thingy. */ +static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) -1; +char *argv0; +int arg[4]; /* arguments for the command. */ +#define arg1 (arg[0]) /* for backward compatibility, sigh */ +static SCSI_Flags_T SCSI_Flags = { 0, 0, 0,0 }; + +static ElementStatus_T *ElementStatus = NULL; + +/* Okay, now let's do the main routine: */ + +void Usage(void) { + FatalError("Usage: nsmhack -f where is:\n [tongue_out] | [tongue_in] | [tongue_button_wait] | [tongue_button_enable]\n | tongue_button_disable. \n"); +} + +static int S_tongue_out(void); +static int S_tongue_in(void); +static int S_slotinfo(void); +static int S_jukeinfo(void); + +struct command_table_struct { + int num_args; + char *name; + int (*command)(void); +} command_table[] = { + { 1, "tongue_out", S_tongue_out }, + { 0, "tongue_in", S_tongue_in }, + { 0, "slotinfo", S_slotinfo }, + { 0, "jukeinfo", S_jukeinfo }, + { 0, NULL, NULL } +}; + + +/* open_device() -- set the 'fh' variable.... */ +void open_device(void) { + + if (MediumChangerFD != -1) { + SCSI_CloseDevice("Unknown",MediumChangerFD); /* close it, sigh... new device now! */ + } + + MediumChangerFD = SCSI_OpenDevice(device); + +} + +static int get_arg(char *arg) { + int retval=-1; + + if (*arg < '0' || *arg > '9') { + return -1; /* sorry! */ + } + + retval=atoi(arg); + return retval; +} + +/* we see if we've got a file open. If not, we open one :-(. Then + * we execute the actual command. Or not :-(. + */ +int execute_command(struct command_table_struct *command) { + + /* if the device is not already open, then open it from the + * environment. + */ + if (MediumChangerFD == -1) { + /* try to get it from STAPE or TAPE environment variable... */ + device=getenv("STAPE"); + if (device==NULL) { + device=getenv("TAPE"); + if (device==NULL) { + Usage(); + } + } + open_device(); + } + + + /* okay, now to execute the command... */ + return command->command(); +} + +/* parse_args(): + * Basically, we are parsing argv/argc. We can have multiple commands + * on a line now, such as "unload 3 0 load 4 0" to unload one tape and + * load in another tape into drive 0, and we execute these commands one + * at a time as we come to them. If we don't have a -f at the start, we + * barf. If we leave out a drive #, we default to drive 0 (the first drive + * in the cabinet). + */ + +int parse_args(int argc,char **argv) { + int i,cmd_tbl_idx,retval,arg_idx; + struct command_table_struct *command; + + i=1; + arg_idx=0; + while (i=argc) { + Usage(); + } + device=argv[i++]; + open_device(); /* open the device and do a status scan on it... */ + } else { + cmd_tbl_idx=0; + command=&command_table[0]; /* default to the first command... */ + command=&command_table[cmd_tbl_idx]; + while (command->name) { + if (!strcmp(command->name,argv[i])) { + /* we have a match... */ + break; + } + /* otherwise we don't have a match... */ + cmd_tbl_idx++; + command=&command_table[cmd_tbl_idx]; + } + /* if it's not a command, exit.... */ + if (!command->name) { + Usage(); + } + i++; /* go to the next argument, if possible... */ + /* see if we need to gather arguments, though! */ + arg1=-1; /* default it to something */ + for (arg_idx=0;arg_idx < command->num_args ; arg_idx++) { + if (i < argc) { + arg[arg_idx]=get_arg(argv[i]); + if (arg[arg_idx] != -1) { + i++; /* increment i over the next cmd. */ + } + } else { + arg[arg_idx]=0; /* default to 0 setmarks or whatever */ + } + } + retval=execute_command(command); /* execute_command handles 'stuff' */ + exit(retval); + } + } + return 0; /* should never get here */ +} + +static void init_param(NSM_Param_T *param, char *command, int paramlen, int resultlen) { + int i; + + /* zero it out first: */ + memset((char *)param,0,sizeof(NSM_Param_T)); + + resultlen=resultlen+sizeof(NSM_Result_T)-0xffff; + + + param->page_code=0x80; + param->reserved=0; + param->page_len_msb=((paramlen+8)>>8) & 0xff; + param->page_len_lsb=(paramlen+8) & 0xff; + param->allocation_msb=((resultlen + 10) >> 8) & 0xff; + param->allocation_lsb= (resultlen+10) & 0xff; + param->reserved2[0]=0; + param->reserved2[1]=0; + + for (i=0;i<4;i++) { + param->command_code[i]=command[i]; + } + +} + +static NSM_Result_T *SendRecHack(NSM_Param_T *param,int param_len, + int read_len) { + NSM_Result_T *result; + /* send the command: */ + if (SendNSMHack(MediumChangerFD,param,param_len,0)) { + PrintRequestSense(&scsi_error_sense); + FatalError("SendNSMHack failed.\n"); + } + + /* Now read the result: */ + result=RecNSMHack(MediumChangerFD,read_len,0); + if (!result) { + PrintRequestSense(&scsi_error_sense); + FatalError("RecNSMHack failed.\n"); + } + + return result; +} + + +/* Print some info about the NSM jukebox. */ +static int S_jukeinfo(void) { + NSM_Result_T *result; + NSM_Param_T param; + + if (!device) + Usage(); + + /* okay, we have a device: Let's get vendor ID: */ + init_param(¶m,"1010",0,8); + result=SendRecHack(¶m,0,8); + /* Okay, we got our result, print out the vendor ID: */ + result->return_data[8]=0; + printf("Vendor ID: %s\n",result->return_data); + free(result); + + /* Get our product ID: */ + init_param(¶m,"1011",0,16); + result=SendRecHack(¶m,0,16); + result->return_data[16]=0; + printf("Product ID: %s\n",result->return_data); + free(result); + + init_param(¶m,"1012",0,4); + result=SendRecHack(¶m,0,4); + result->return_data[4]=0; + printf("Product Revision: %s\n",result->return_data); + free(result); + + init_param(¶m,"1013",0,8); + result=SendRecHack(¶m,0,8); + result->return_data[8]=0; + printf("Production Date: %s\n",result->return_data); + free(result); + + init_param(¶m,"1014",0,8); + result=SendRecHack(¶m,0,8); + result->return_data[8]=0; + printf("Part Number: %s\n",result->return_data); + free(result); + + init_param(¶m,"1015",0,12); + result=SendRecHack(¶m,0,12); + result->return_data[12]=0; + printf("Serial Number: %s\n",result->return_data); + free(result); + + init_param(¶m,"1016",0,4); + result=SendRecHack(¶m,0,4); + result->return_data[4]=0; + printf("Firmware Release: %s\n",result->return_data); + free(result); + + init_param(¶m,"1017",0,8); + result=SendRecHack(¶m,0,8); + result->return_data[8]=0; + printf("Firmware Date: %s\n",result->return_data); + free(result); + + return 0; +} + +static int S_slotinfo(void) { + NSM_Result_T *result; + NSM_Param_T param; + + if (!device) + Usage(); + + /* Okay, let's see what I can get from slotinfo: */ + init_param(¶m,"1020",0,6); + result=SendRecHack(¶m,0,6); + result->return_data[6]=0; + printf("Layout: %s\n",result->return_data); + free(result); + + return 0; +} + +static int S_tongue_in(void) { + return 0; +} + +/* okay, stick our tongue out. We need a slot ID to grab a caddy from. */ +static int S_tongue_out(void) { + int slotnum=arg1; + Inquiry_T *inquiry_info; /* needed by MoveMedium etc... */ + RequestSense_T RequestSense; + + /* see if we have element status: */ + if (ElementStatus==NULL) { + inquiry_info=RequestInquiry(MediumChangerFD,&RequestSense); + if (!inquiry_info) { + PrintRequestSense(&RequestSense); + FatalError("INQUIRY Command Failed\n"); + } + ElementStatus = ReadElementStatus(MediumChangerFD,&RequestSense,inquiry_info,&SCSI_Flags); + if (!ElementStatus) { + PrintRequestSense(&RequestSense); + FatalError("READ ELEMENT STATUS Command Failed\n"); + } + } + + /* Okay, we have element status, so now let's assume that */ + return 0; +} + +/* See parse_args for the scoop. parse_args does all. */ +int main(int argc, char **argv) { + argv0=argv[0]; + parse_args(argc,argv); + + if (device) + SCSI_CloseDevice(device,MediumChangerFD); + + exit(0); +} diff --git a/scsi_aix.c b/scsi_aix.c new file mode 100644 index 0000000..4b77fa6 --- /dev/null +++ b/scsi_aix.c @@ -0,0 +1,159 @@ +/* Changes 2003 Steve Heck + Copyright 2007-2008 by Robert Nelson + +$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ +$Revision: 193 $ + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for complete details. + +*/ + + +/* This is the SCSI commands for AIX using GSC Generic SCSI Interface. */ + +#define LONG_PRINT_REQUEST_SENSE /* sigh! */ + +DEVICE_TYPE SCSI_OpenDevice(char *DeviceName) +{ + int DeviceFD = open(DeviceName, 0); + + if (DeviceFD < 0) + FatalError("cannot open SCSI device '%s' - %m\n", DeviceName); + return (DEVICE_TYPE) DeviceFD; +} + + +void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD) +{ + if (close(DeviceFD) < 0) + FatalError("cannot close SCSI device '%s' - %m\n", DeviceName); +} + + +#define HAS_SCSI_TIMEOUT + +static int timeout = 9 * 60; + +void SCSI_Set_Timeout(int to) +{ + timeout = to; +} + +void SCSI_Default_Timeout(void) +{ + timeout = 9 * 60; /* the default */ +} + +#ifdef DEBUG +int SCSI_DumpBuffer(int DataBufferLength, unsigned char *DataBuffer) +{ + int i, j; + j = 0; + + for (i = 0; i < DataBufferLength; i++) + { + if (j == 25) + { + fprintf(stderr, "\n"); + j = 0; + } + + if (j == 0) + { + fprintf(stderr, "%04x:", i); + } + + if (j > 0) + { + fprintf(stderr, " "); + } + + fprintf(stderr, "%02x", (int)DataBuffer[i]); + j++; + } + fprintf(stderr, "\n"); +} +#endif + + + +int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD, + Direction_T Direction, + CDB_T *CDB, + int CDB_Length, + void *DataBuffer, + int DataBufferLength, + RequestSense_T *RequestSense) +{ + int ioctl_result; + char sbyte; + scmd_t scmd; + +#ifdef DEBUG_SCSI + fprintf(stderr,"------CDB--------\n"); + SCSI_DumpBuffer(CDB_Length,(char *)CDB); +#endif + + /* memset(&scmd, 0, sizeof(struct scmd_t)); */ + /* memset(RequestSense, 0, sizeof(RequestSense_T)); */ + switch (Direction) + { + case Input: + scmd.rw = 1; + if (DataBufferLength > 0) + { + memset(DataBuffer, 0, DataBufferLength); + } + break; + + case Output: + scmd.rw = 2; + break; + } + /* Set timeout to 5 minutes. */ +#ifdef DEBUG_TIMEOUT + fprintf(stderr,"timeout=%d\n",timeout); + fflush(stderr); +#endif + + scmd.timeval = timeout; + + scmd.cdb = (caddr_t) CDB; + scmd.cdblen = CDB_Length; + scmd.data_buf = DataBuffer; + scmd.datalen = DataBufferLength; + scmd.sense_buf = (caddr_t) RequestSense; + scmd.senselen = sizeof(RequestSense_T); + scmd.statusp = &sbyte; + ioctl_result = ioctl(DeviceFD, GSC_CMD, (caddr_t) &scmd); + + SCSI_Default_Timeout(); /* set it back to default, sigh. */ + + if (ioctl_result < 0) + { +#ifdef DEBUG + perror("mtx"); +#endif + return ioctl_result; + } + + if (sbyte != 0) + { + return -1; + } +#ifdef DEBUG_SCSI + if (Direction==Input) + { + fprintf(stderr,"--------input data-----------\n"); + SCSI_DumpBuffer(DataBufferLength,DataBuffer); + } +#endif + return 0; +} diff --git a/scsi_freebsd.c b/scsi_freebsd.c new file mode 100644 index 0000000..4a085ec --- /dev/null +++ b/scsi_freebsd.c @@ -0,0 +1,116 @@ +/* Copyright 2000 Enhanced Software Technologies Inc. (http://www.estinc.com) + Copyright 2007-2008 by Robert Nelson + Written by Eric Lee Green + +$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ +$Revision: 193 $ + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for complete details. + +*/ + +/* This is the SCSI commands for FreeBSD */ +DEVICE_TYPE SCSI_OpenDevice(char *DeviceName) +{ + struct cam_device *DeviceFD = cam_open_pass(DeviceName, O_RDWR | O_EXCL, NULL); + if (DeviceFD == 0) + FatalError("cannot open SCSI device '%s' - %m\n", DeviceName); + return (DEVICE_TYPE) DeviceFD; +} + + +void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD) +{ + cam_close_device((struct cam_device *) DeviceFD); +} + +#define PASS_HZ 1000*60 +#define PASS_DEFAULT_TIMEOUT 5*PASS_HZ +static int pass_timeout = PASS_DEFAULT_TIMEOUT; + +void SCSI_Set_Timeout(int secs) +{ + pass_timeout=secs*PASS_HZ; +} + +void SCSI_Default_Timeout(void) { + pass_timeout=5*PASS_HZ; +} + +int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD, + Direction_T Direction, + CDB_T *CDB, + int CDB_Length, + void *DataBuffer, + int DataBufferLength, + RequestSense_T *RequestSense) +{ + struct cam_device *dsp = (struct cam_device *) DeviceFD; + int retval; + union ccb *ccb; + CDB_T *cdb; + int Result; + + ccb = cam_getccb(dsp); + cdb = (CDB_T *) &ccb->csio.cdb_io.cdb_bytes; /* pointer to actual cdb. */ + + /* cam_getccb() zeros the CCB header only. So now clear the + * payload portion of the ccb. + */ + bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); + + /* copy the CDB... */ + memcpy(cdb,CDB,CDB_Length); + + /* set the command control block stuff.... the rather involved + * conditional expression sets the direction to NONE if there is no + * data to go in or out, and IN or OUT if we want data. Movement + * commands will have no data buffer, just a CDB, while INQUIRY and + * READ_ELEMENT_STATUS will have input data, and we don't have any + * stuff that outputs data -- yet -- but we may eventually. + */ + cam_fill_csio( &ccb->csio, + 1, /* retries */ + NULL, /* cbfcnp*/ + (DataBufferLength ? + (Direction == Input ? CAM_DIR_IN : CAM_DIR_OUT) : + CAM_DIR_NONE), /* flags */ + MSG_SIMPLE_Q_TAG, /* tag action */ + DataBuffer, /* data ptr */ + DataBufferLength, /* xfer_len */ + SSD_FULL_SIZE, /* sense_len */ + CDB_Length, /* cdb_len */ + pass_timeout /* timeout */ /* should be 5 minutes or more?! */ + ); + + pass_timeout = PASS_DEFAULT_TIMEOUT; /* make sure it gets reset. */ + memset(RequestSense, 0, sizeof(RequestSense_T)); /* clear sense buffer... */ + + if (Direction == Input) + { + memset(DataBuffer, 0, DataBufferLength); + } + + Result = cam_send_ccb(DeviceFD,ccb); + if (Result < 0 || + (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) + { + /* copy our sense data, sigh... */ + memcpy(RequestSense,(void *) &ccb->csio.sense_data, + min(sizeof(RequestSense_T), sizeof(struct scsi_sense_data))); + + cam_freeccb(ccb); + return -1; /* sorry! */ + } + + /* okay, we did good, maybe? */ + cam_freeccb(ccb); + return 0; /* and done? */ +} diff --git a/scsi_hpux.c b/scsi_hpux.c new file mode 100644 index 0000000..880ce2c --- /dev/null +++ b/scsi_hpux.c @@ -0,0 +1,134 @@ +/* Copyright 1997, 1998 Leonard Zubkoff + Changes copyright 2000 Eric Green + Copyright 2007-2008 by Robert Nelson + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for complete details. + +struct sctl_io +{ + unsigned flags; // IN: SCTL_READ + unsigned cdb_length; // IN + unsigned char cdb[16]; // IN + void *data; // IN + unsigned data_length; // IN + unsigned max_msecs; // IN: milli-seconds before abort + unsigned data_xfer; // OUT + unsigned cdb_status; // OUT: SCSI status + unsigned char sense[256]; // OUT + unsigned sense_status; // OUT: SCSI status + unsigned sense_xfer; // OUT: bytes of sense data received + unsigned reserved[16]; // IN: Must be zero; OUT: undefined +}; + +*/ + + +/* Hockey Pux may define these. If so, *UN*define them. */ +#ifdef ILI +#undef ILI +#endif + +#ifdef EOM +#undef EOM +#endif + +/* This is the SCSI commands for HPUX. */ + +#define LONG_PRINT_REQUEST_SENSE /* Sigh! */ + +DEVICE_TYPE SCSI_OpenDevice(char *DeviceName) +{ + int DeviceFD = open(DeviceName, O_RDWR | O_NDELAY); + + if (DeviceFD < 0) + FatalError("cannot open SCSI device '%s' - %m\n", DeviceName); + + return (DEVICE_TYPE) DeviceFD; +} + + +void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD) +{ + if (close(DeviceFD) < 0) + FatalError("cannot close SCSI device '%s' - %m\n", DeviceName); +} + +#define MTX_HZ 1000 +#define DEFAULT_HZ (5*60*MTX_HZ) + +static int sctl_io_timeout=DEFAULT_HZ; /* default timeout is 5 minutes. */ + + +void SCSI_Set_Timeout(int to) +{ + sctl_io_timeout=to*60*MTX_HZ; +} + +void SCSI_Default_Timeout(void) +{ + sctl_io_timeout=DEFAULT_HZ; +} + + +int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD, + Direction_T Direction, + CDB_T *CDB, + int CDB_Length, + void *DataBuffer, + int DataBufferLength, + RequestSense_T *RequestSense) +{ + int ioctl_result; + struct sctl_io Command; + + int i; + + memset(&Command, 0, sizeof(struct sctl_io)); + memset(RequestSense, 0, sizeof(RequestSense_T)); + + switch (Direction) + { + case Input: + if (DataBufferLength > 0) + memset(DataBuffer, 0, DataBufferLength); + Command.flags = SCTL_READ | SCTL_INIT_SDTR; + break; + + case Output: + Command.flags = SCTL_INIT_WDTR | SCTL_INIT_SDTR; + break; + } + + Command.max_msecs = sctl_io_timeout; /* Set timeout to minutes. */ + memcpy(Command.cdb, CDB, CDB_Length); + Command.cdb_length = CDB_Length; + Command.data = DataBuffer; + Command.data_length = DataBufferLength; + ioctl_result=ioctl(DeviceFD, SIOC_IO, &Command); + SCSI_Default_Timeout(); /* change the default back to 5 minutes */ + + if (ioctl_result < 0) + { + perror("mtx"); + return ioctl_result; + } + + if (Command.sense_xfer > sizeof(RequestSense_T)) + { + Command.sense_xfer=sizeof(RequestSense_T); + } + + if (Command.sense_xfer) + { + memcpy(RequestSense, Command.sense, Command.sense_xfer); + } + + return Command.sense_status; +} diff --git a/scsi_linux.c b/scsi_linux.c new file mode 100644 index 0000000..cc14ebf --- /dev/null +++ b/scsi_linux.c @@ -0,0 +1,491 @@ +/* Copyright 1997, 1998 Leonard Zubkoff + Changes in Feb 2000 Eric Green + Copyright 2007-2008 by Robert Nelson + +$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ +$Revision: 193 $ + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for complete details. + +*/ + +/* this is the SCSI commands for Linux. Note that changed + * it from using SCSI_IOCTL_SEND_COMMAND to using the SCSI generic interface. + */ + +#ifndef HZ +#warning "HZ is not defined, mtx might not work correctly!" +#define HZ 100 /* Jiffys for SG_SET_TIMEOUT */ +#endif + +/* These are copied out of BRU 16.1, with all the boolean masks changed + * to our bitmasks. +*/ +#define S_NO_SENSE(s) ((s)->SenseKey == 0x0) +#define S_RECOVERED_ERROR(s) ((s)->SenseKey == 0x1) + +#define S_NOT_READY(s) ((s)->SenseKey == 0x2) +#define S_MEDIUM_ERROR(s) ((s)->SenseKey == 0x3) +#define S_HARDWARE_ERROR(s) ((s)->SenseKey == 0x4) +#define S_UNIT_ATTENTION(s) ((s)->SenseKey == 0x6) +#define S_BLANK_CHECK(s) ((s)->SenseKey == 0x8) +#define S_VOLUME_OVERFLOW(s) ((s)->SenseKey == 0xd) + +#define DEFAULT_TIMEOUT 3*60 /* 3 minutes here */ + +/* Sigh, the T-10 SSC spec says all of the following is needed to + * detect a short read while in variable block mode, and that even + * though we got a BLANK_CHECK or MEDIUM_ERROR, it's still a valid read. + */ + +#define HIT_FILEMARK(s) (S_NO_SENSE((s)) && (s)->Filemark && (s)->Valid) +#define SHORT_READ(s) (S_NO_SENSE((s)) && (s)->ILI && (s)->Valid && (s)->AdditionalSenseCode==0 && (s)->AdditionalSenseCodeQualifier==0) +#define HIT_EOD(s) (S_BLANK_CHECK((s)) && (s)->Valid) +#define HIT_EOP(s) (S_MEDIUM_ERROR((s)) && (s)->EOM && (s)->Valid) +#define HIT_EOM(s) ((s)->EOM && (s)->Valid) + +#define STILL_A_VALID_READ(s) (HIT_FILEMARK(s) || SHORT_READ(s) || HIT_EOD(s) || HIT_EOP(s) || HIT_EOM(s)) + +#define SG_SCSI_DEFAULT_TIMEOUT (HZ*60*5) /* 5 minutes? */ + +static int pack_id; +static int sg_timeout; + +DEVICE_TYPE SCSI_OpenDevice(char *DeviceName) +{ + int timeout = SG_SCSI_DEFAULT_TIMEOUT; +#ifdef SG_IO + int k; /* version */ +#endif + int DeviceFD = open(DeviceName, O_RDWR); + + if (DeviceFD < 0) + FatalError("cannot open SCSI device '%s' - %m\n", DeviceName); + + +#ifdef SG_IO + /* It is prudent to check we have a sg device by trying an ioctl */ + if ((ioctl(DeviceFD, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) + { + FatalError("%s is not an sg device, or old sg driver\n", DeviceName); + } +#endif + + if (ioctl(DeviceFD, SG_SET_TIMEOUT, &timeout)) + { + FatalError("failed to set sg timeout - %m\n"); + } + pack_id = 1; /* used for SG v3 interface if possible. */ + return (DEVICE_TYPE) DeviceFD; +} + +void SCSI_Set_Timeout(int secs) +{ + sg_timeout = secs * HZ; +} + +void SCSI_Default_Timeout(void) +{ + sg_timeout = SG_SCSI_DEFAULT_TIMEOUT; +} + +void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD) +{ + if (close(DeviceFD) < 0) + FatalError("cannot close SCSI device '%s' - %m\n", DeviceName); +} + + +/* Added by Eric Green to deal with burping + * Seagate autoloader (hopefully!). + */ +/* Get the SCSI ID and LUN... */ +scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd) +{ + int status; + scsi_id_t *retval; + + struct my_scsi_idlun + { + int word1; + int word2; + } idlun; + + status = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun); + if (status) + { + return NULL; /* sorry! */ + } + + retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t)); + retval->id = idlun.word1 & 0xff; + retval->lun = idlun.word1 >> 8 & 0xff; + +#ifdef DEBUG + fprintf(stderr, "SCSI:ID=%d LUN=%d\n", retval->id, retval->lun); +#endif + + return retval; +} + + +/* Changed January 2001 by Eric Green to + * use the Linux version 2.4 SCSI Generic facility if available. + * Liberally cribbed code from Doug Gilbert's sg3 utils. + */ + +#ifdef SG_IO +#include "sg_err.h" /* error stuff. */ +#include "sg_err.c" /* some of Doug Gilbert's routines */ + +/* Use the new SG_IO structure */ +int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD, + Direction_T Direction, + CDB_T *CDB, + int CDB_Length, + void *DataBuffer, + int DataBufferLength, + RequestSense_T *RequestSense) +{ + unsigned int status; + sg_io_hdr_t io_hdr; + + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + memset(RequestSense, 0, sizeof(RequestSense_T)); + + /* Fill in the common stuff... */ + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = CDB_Length; + io_hdr.mx_sb_len = sizeof(RequestSense_T); + io_hdr.dxfer_len = DataBufferLength; + io_hdr.cmdp = (unsigned char *) CDB; + io_hdr.sbp = (unsigned char *) RequestSense; + io_hdr.dxferp = DataBuffer; + io_hdr.timeout = sg_timeout * 10; /* Convert from Jiffys to milliseconds */ + + if (Direction==Input) + { + /* fprintf(stderr,"direction=input\n"); */ + io_hdr.dxfer_direction=SG_DXFER_FROM_DEV; + } + else + { + /* fprintf(stderr,"direction=output\n"); */ + io_hdr.dxfer_direction=SG_DXFER_TO_DEV; + } + + /* Now do it: */ + if ((status = ioctl(DeviceFD, SG_IO , &io_hdr)) || io_hdr.masked_status) + { + /* fprintf(stderr, "smt_scsi_cmd: Rval=%d Status=%d, errno=%d [%s]\n",status, io_hdr.masked_status, + errno, + strerror(errno)); */ + + switch (sg_err_category3(&io_hdr)) + { + case SG_ERR_CAT_CLEAN: + case SG_ERR_CAT_RECOVERED: + break; + + case SG_ERR_CAT_MEDIA_CHANGED: + return 2; + + default: + return -1; + } + + /* fprintf(stderr,"host_status=%d driver_status=%d residual=%d writelen=%d\n",io_hdr.host_status,io_hdr.driver_status,io_hdr.resid,io_hdr.sb_len_wr ); */ + + return -errno; + } + + /* Now check the returned statuses: */ + /* fprintf(stderr,"host_status=%d driver_status=%d residual=%d writelen=%d\n",io_hdr.host_status,io_hdr.driver_status,io_hdr.resid,io_hdr.sb_len_wr ); */ + + SCSI_Default_Timeout(); /* reset back to default timeout, sigh. */ + return 0; +} + +#else + +/* Changed February 2000 by Eric Green to + * use the SCSI generic interface rather than SCSI_IOCTL_SEND_COMMAND + * so that we can get more than PAGE_SIZE data.... + * + * Note that the SCSI generic interface abuses READ and WRITE calls to serve + * the same purpose as IOCTL calls, i.e., for "writes", the contents of the + * buffer that you send as the argument to the write() call are actually + * altered to fill in result status and sense data (if needed). + * Also note that this brain-dead interface does not have any sort of + * provisions for expanding the sg_header struct in a backward-compatible + * manner. This sucks. But sucks less than SCSI_IOCTL_SEND_COMMAND, sigh. + */ + + +#ifndef OLD_EXECUTE_COMMAND_STUFF + +static void slow_memcopy(unsigned char *src, unsigned char *dest, int numbytes) +{ + while (numbytes--) + { + *dest++ = *src++; + } +} + + +int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD, + Direction_T Direction, + CDB_T *CDB, + int CDB_Length, + void *DataBuffer, + int DataBufferLength, + RequestSense_T *RequestSense) +{ + unsigned char *Command=NULL; /* the command data struct sent to them... */ + unsigned char *ResultBuf=NULL; /* the data we read in return... */ + + unsigned char *src; /* for copying stuff, sigh. */ + unsigned char *dest; /* for copy stuff, again, sigh. */ + + int write_length = sizeof(struct sg_header)+CDB_Length; + int i; /* a random index... */ + int result; /* the result of the write... */ + + struct sg_header *Header; /* we actually point this into Command... */ + struct sg_header *ResultHeader; /* we point this into ResultBuf... */ + + /* First, see if we need to set our SCSI timeout to something different */ + if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT) + { + /* if not default, set it: */ +#ifdef DEBUG_TIMEOUT + fprintf(stderr,"Setting timeout to %d\n", sg_timeout); + fflush(stderr); +#endif + if(ioctl(DeviceFD, SG_SET_TIMEOUT, &sg_timeout)) + { + FatalError("failed to set sg timeout - %m\n"); + } + } + + if (Direction == Output) + { + /* if we're writing, our length is longer... */ + write_length += DataBufferLength; + } + + /* allocate some memory... enough for the command plus the header + + * any other data that we may need here... + */ + + Command = (unsigned char *)xmalloc(write_length); + Header = (struct sg_header *) Command; /* make it point to start of buf */ + + dest = Command; /* now to copy the CDB... from start of buffer,*/ + dest += sizeof(struct sg_header); /* increment it past the header. */ + + slow_memcopy((char *)CDB, dest, CDB_Length); + + /* if we are writing additional data, tack it on here! */ + if (Direction == Output) + { + dest += CDB_Length; + slow_memcopy(DataBuffer, dest, DataBufferLength); /* copy to end of command */ + } + + /* Now to fill in the Header struct: */ + Header->reply_len=DataBufferLength+sizeof(struct sg_header); +#ifdef DEBUG + fprintf(stderr,"sg:reply_len(sent)=%d\n",Header->reply_len); +#endif + Header->twelve_byte = CDB_Length == 12; + Header->result = 0; + Header->pack_len = write_length; /* # of bytes written... */ + Header->pack_id = 0; /* not used */ + Header->other_flags = 0; /* not used. */ + Header->sense_buffer[0]=0; /* used? */ + + /* Now to do the write... */ + result = write(DeviceFD,Command,write_length); + + /* Now to check the result :-(. */ + /* Note that we don't have any request sense here. So we have no + * idea what's going on. + */ + if (result < 0 || result != write_length || Header->result || Header->sense_buffer[0]) + { +#ifdef DEBUG_SCSI + fprintf(stderr,"scsi:result=%d Header->result=%d Header->sense_buffer[0]=%d\n", + result,Header->result,Header->sense_buffer[0]); +#endif + /* we don't have any real sense data, sigh :-(. */ + if (Header->sense_buffer[0]) + { + /* well, I guess we DID have some! eep! copy the sense data! */ + slow_memcopy((char *)Header->sense_buffer,(char *)RequestSense, + sizeof(Header->sense_buffer)); + } + else + { + dest=(unsigned char *)RequestSense; + *dest=(unsigned char)Header->result; /* may chop, sigh... */ + } + + /* okay, now, we may or may not need to find a non-zero value to return. + * For tape drives, we may get a BLANK_CHECK or MEDIUM_ERROR and find + * that it's *STILL* a good read! Use the STILL_A_VALID_READ macro + * that calls all those macros I cribbed from Richard. + */ + + if (!STILL_A_VALID_READ(RequestSense)) + { + free(Command); /* zap memory leak, sigh */ + /* okay, find us a non-zero value to return :-(. */ + if (result) + { + return result; + } + else if (Header->result) + { + return Header->result; + } + else + { + return -1; /* sigh */ + } + } + else + { + result=-1; + } + } + else + { + result=0; /* we're okay! */ + } + + /* now to allocate the new block.... */ + ResultBuf=(unsigned char *)xmalloc(Header->reply_len); + /* now to clear ResultBuf... */ + slow_bzero(ResultBuf,Header->reply_len); + + ResultHeader=(struct sg_header *)ResultBuf; + + /* copy the original Header... */ + ResultHeader->result=0; + ResultHeader->pack_id=0; + ResultHeader->other_flags=0; + ResultHeader->reply_len=Header->reply_len; + ResultHeader->twelve_byte = CDB_Length == 12; + ResultHeader->pack_len = write_length; /* # of bytes written... */ + ResultHeader->sense_buffer[0]=0; /* whoops! Zero that! */ +#ifdef DEBUG + fprintf(stderr,"sg:Reading %d bytes from DeviceFD\n",Header->reply_len); + fflush(stderr); +#endif + result=read(DeviceFD,ResultBuf,Header->reply_len); +#ifdef DEBUG + fprintf(stderr,"sg:result=%d ResultHeader->result=%d\n", + result,ResultHeader->result); + fflush(stderr); +#endif + /* New: added check to see if the result block is still all zeros! */ + if (result < 0 || + result != Header->reply_len || + ResultHeader->result || + ResultHeader->sense_buffer[0]) + { +#ifdef DEBUG + fprintf(stderr, + "scsi: result=%d Header->reply_len=%d ResultHeader->result=%d ResultHeader->sense_buffer[0]=%d\n", + result, + Header->reply_len, + ResultHeader->result, + ResultHeader->sense_buffer[0]); +#endif + /* eep! copy the sense data! */ + slow_memcopy((char *)ResultHeader->sense_buffer,(char *)RequestSense, + sizeof(ResultHeader->sense_buffer)); + /* sense data copied, now find us a non-zero value to return :-(. */ + /* NOTE: Some commands return sense data even though they validly + * executed! We catch a few of those with the macro STILL_A_VALID_READ. + */ + + if (!STILL_A_VALID_READ(RequestSense)) + { + free(Command); + if (result) + { + free(ResultBuf); + return result; + } + else if (ResultHeader->result) + { + free(ResultBuf); + return ResultHeader->result; + } + else + { + free(ResultBuf); + return -1; /* sigh! */ + } + } + else + { + result=-1; /* if it was a valid read, still have -1 result. */ + } + } + else + { + result=0; + } + + /* See if we need to reset our SCSI timeout */ + if (sg_timeout != SG_SCSI_DEFAULT_TIMEOUT) + { + sg_timeout = SG_SCSI_DEFAULT_TIMEOUT; /* reset it back to default */ + +#ifdef DEBUG_TIMEOUT + fprintf(stderr,"Setting timeout to %d\n", sg_timeout); + fflush(stderr); +#endif + /* if not default, set it: */ + if (ioctl(DeviceFD, SG_SET_TIMEOUT, &sg_timeout)) + { + FatalError("failed to set sg timeout - %m\n"); + } + } + + /* now for the crowning moment: copying any result into the DataBuffer! */ + /* (but only if it were an input command and not an output command :-} */ + if (Direction == Input) + { +#ifdef DEBUG + fprintf(stderr,"Header->reply_len=%d,ResultHeader->reply_len=%d\n", + Header->reply_len,ResultHeader->reply_len); +#endif + src=ResultBuf+sizeof(struct sg_header); + dest=DataBuffer; + for (i = 0; i < ResultHeader->reply_len; i++) + { + if (i >= DataBufferLength) + break; /* eep! */ + *dest++ = *src++; + } + } + + /* and return! */ + free(Command); /* clean up memory leak... */ + free(ResultBuf); + return result; /* good stuff ! */ +} + +#endif +#endif /* #ifdef SG_IO */ diff --git a/scsi_sgi.c b/scsi_sgi.c new file mode 100644 index 0000000..32c00a5 --- /dev/null +++ b/scsi_sgi.c @@ -0,0 +1,81 @@ +/* Copyright 1997, 1998 Leonard Zubkoff + Changes copyright 2000 Eric Green + Copyright 2007-2008 by Robert Nelson + +$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ +$Revision: 193 $ + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for complete details. + +*/ + +/* This is the SCSI commands for SGI Iris */ +DEVICE_TYPE SCSI_OpenDevice(char *DeviceName) +{ + dsreq_t *DeviceFD = dsopen(DeviceName, O_RDWR | O_EXCL); + if (DeviceFD == 0) + FatalError("cannot open SCSI device '%s' - %m\n", DeviceName); + return (DEVICE_TYPE) DeviceFD; +} + + +void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD) +{ + dsclose((dsreq_t *) DeviceFD); +} + +#define MTX_HZ 1000 +#define MTX_DEFAULT_SCSI_TIMEOUT 60*5*MTX_HZ /* 5 minutes! */ + +static int mtx_default_timeout = MTX_DEFAULT_SCSI_TIMEOUT ; +void SCSI_Set_Timeout(int sec) +{ + mtx_default_timeout=sec*MTX_HZ; +} + +void SCSI_Default_Timeout() +{ + mtx_default_timeout=MTX_DEFAULT_SCSI_TIMEOUT; +} + +int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD, + Direction_T Direction, + CDB_T *CDB, + int CDB_Length, + void *DataBuffer, + int DataBufferLength, + RequestSense_T *RequestSense) +{ + dsreq_t *dsp = (dsreq_t *) DeviceFD; + int Result; + memset(RequestSense, 0, sizeof(RequestSense_T)); + memcpy(CMDBUF(dsp), CDB, CDB_Length); + + if (Direction == Input) + { + memset(DataBuffer, 0, DataBufferLength); + filldsreq(dsp, (unsigned char *) DataBuffer, DataBufferLength, DSRQ_READ | DSRQ_SENSE); + } + else + filldsreq(dsp, (unsigned char *) DataBuffer, DataBufferLength, DSRQ_WRITE | DSRQ_SENSE); + + /* Set 5 minute timeout. */ + /* TIME(dsp) = 300 * 1000; */ + TIME(dsp) = mtx_default_timeout; + Result = doscsireq(getfd((dsp)), dsp); + + if (SENSESENT(dsp) > 0) + { + memcpy(RequestSense, SENSEBUF(dsp), min(sizeof(RequestSense_T), SENSESENT(dsp))); + } + + SCSI_Default_Timeout(); /* reset the mtx default timeout */ + return Result; +} diff --git a/scsi_sun.c b/scsi_sun.c new file mode 100644 index 0000000..7197e62 --- /dev/null +++ b/scsi_sun.c @@ -0,0 +1,156 @@ +/* Copyright 1997, 1998 Leonard Zubkoff + Changes copyright 2000 Eric Green + Copyright 2007-2008 by Robert Nelson + +$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ +$Revision: 193 $ + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for complete details. + +*/ + +/* This is the SCSI commands for Sun Solaris. */ + +#define LONG_PRINT_REQUEST_SENSE /* sigh! */ + +DEVICE_TYPE SCSI_OpenDevice(char *DeviceName) +{ + int DeviceFD = open(DeviceName, O_RDWR | O_NDELAY); + if (DeviceFD < 0) + FatalError("cannot open SCSI device '%s' - %m\n", DeviceName); + return (DEVICE_TYPE) DeviceFD; +} + + +void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD) +{ + if (close(DeviceFD) < 0) + FatalError("cannot close SCSI device '%s' - %m\n", DeviceName); +} + + +#define HAS_SCSI_TIMEOUT + +static int uscsi_timeout=5*60; + +void SCSI_Set_Timeout(int to) +{ + uscsi_timeout = to; +} + +void SCSI_Default_Timeout(void) +{ + uscsi_timeout=5*60; /* the default */ +} + +#ifdef DEBUG +int SCSI_DumpBuffer(int DataBufferLength, unsigned char *DataBuffer) +{ + int i,j; + j = 0; + + for (i = 0; i < DataBufferLength; i++) + { + if (j == 25) + { + fprintf(stderr,"\n"); + j = 0; + } + + if (j == 0) + { + fprintf(stderr, "%04x:", i); + } + + if (j > 0) + { + fprintf(stderr," "); + } + + fprintf(stderr, "%02x", (int)DataBuffer[i]); + j++; + } + fprintf(stderr, "\n"); +} +#endif + + +int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD, + Direction_T Direction, + CDB_T *CDB, + int CDB_Length, + void *DataBuffer, + int DataBufferLength, + RequestSense_T *RequestSense) +{ + int ioctl_result; + struct uscsi_cmd Command; + +#ifdef DEBUG_SCSI + fprintf(stderr,"------CDB--------\n"); + SCSI_DumpBuffer(CDB_Length,(char *)CDB); +#endif + + memset(&Command, 0, sizeof(struct uscsi_cmd)); + memset(RequestSense, 0, sizeof(RequestSense_T)); + switch (Direction) + { + case Input: + Command.uscsi_flags = USCSI_DIAGNOSE | USCSI_ISOLATE | USCSI_RQENABLE; + if (DataBufferLength > 0) + { + memset(DataBuffer, 0, DataBufferLength); + Command.uscsi_flags |= USCSI_READ; + } + break; + case Output: + Command.uscsi_flags = USCSI_DIAGNOSE | USCSI_ISOLATE | + USCSI_WRITE | USCSI_RQENABLE; + break; + } + /* Set timeout to 5 minutes. */ +#ifdef DEBUG_TIMEOUT + fprintf(stderr,"uscsi_timeout=%d\n",uscsi_timeout); + fflush(stderr); +#endif + Command.uscsi_timeout = uscsi_timeout; + + Command.uscsi_cdb = (caddr_t) CDB; + Command.uscsi_cdblen = CDB_Length; + Command.uscsi_bufaddr = DataBuffer; + Command.uscsi_buflen = DataBufferLength; + Command.uscsi_rqbuf = (caddr_t) RequestSense; + Command.uscsi_rqlen = sizeof(RequestSense_T); + ioctl_result = ioctl(DeviceFD, USCSICMD, &Command); + + SCSI_Default_Timeout(); /* set it back to default, sigh. */ + + if (ioctl_result < 0) + { +#ifdef DEBUG + perror("mtx"); +#endif + return ioctl_result; + } + + if (RequestSense->ErrorCode > 1) + { + return -1; + } + +#ifdef DEBUG_SCSI + if (Direction==Input) + { + fprintf(stderr,"--------input data-----------\n"); + SCSI_DumpBuffer(DataBufferLength, DataBuffer); + } +#endif + return 0; +} diff --git a/scsi_win32.c b/scsi_win32.c new file mode 100644 index 0000000..b913fd1 --- /dev/null +++ b/scsi_win32.c @@ -0,0 +1,355 @@ +/* Copyright 2006-2008 Robert Nelson + +$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ +$Revision: 193 $ + + This program is free software; you may redistribute and/or modify it under + the terms of the GNU General Public License Version 2 as published by the + Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for complete details. + +*/ + +/* + * This is the SCSI commands for Windows. + */ + +#include +#define WIN32_LEAN_AND_MEAN +#include + +#ifdef _MSC_VER +#include +#else +#include +#endif + +#define SCSI_DEFAULT_TIMEOUT 300 /* 1 minutes */ +#define SCSI_MAX_TIMEOUT 108000 /* 30 hours */ + +typedef struct _HANDLE_ENTRY +{ + HANDLE hDevice; + UCHAR PortId; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; +} HANDLE_ENTRY, *PHANDLE_ENTRY; + +PHANDLE_ENTRY HandleTable = NULL; +int nEntries = 0; + +DEVICE_TYPE SCSI_OpenDevice(char *DeviceName) +{ + int DeviceIndex; + TCHAR szDevicePath[256]; + + int nColons = 0; + int index; + + int port, path, target, lun; + + for (DeviceIndex = 0; DeviceIndex < nEntries; DeviceIndex++) + { + if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE) + break; + } + + if (DeviceIndex >= nEntries) + { + PHANDLE_ENTRY pNewTable; + + nEntries += 4; + + if (HandleTable == NULL) + { + pNewTable = (PHANDLE_ENTRY)malloc(nEntries * sizeof(HANDLE_ENTRY)); + } + else + { + pNewTable = (PHANDLE_ENTRY)realloc(HandleTable, nEntries * sizeof(HANDLE_ENTRY)); + } + + if (pNewTable == NULL) + { + FatalError("cannot open SCSI device '%s' - %m\n", DeviceName); + } + + HandleTable = pNewTable; + } + + for (index = 0; DeviceName[index] != '\0'; index++) + { + if (DeviceName[index] == ':') + nColons++; + else if (DeviceName[index] < '0' || DeviceName[index] > '9') + break; + } + + if (DeviceName[index] == '\0' && nColons == 3 && + sscanf(DeviceName, "%d:%d:%d:%d", &port, &path, &target, &lun) == 4) + { + HandleTable[DeviceIndex].PortId = (UCHAR)port; + HandleTable[DeviceIndex].PathId = (UCHAR)path; + HandleTable[DeviceIndex].TargetId = (UCHAR)target; + HandleTable[DeviceIndex].Lun = (UCHAR)lun; + + sprintf(szDevicePath, "\\\\.\\scsi%d:", port); + } + else + { + int nPrefixLength = 0; + + if (DeviceName[0] != '\\') { + memcpy(szDevicePath, "\\\\.\\", 4 * sizeof(TCHAR)); + nPrefixLength = 4; + } + + HandleTable[DeviceIndex].PortId = 0; + HandleTable[DeviceIndex].PathId = 0; + HandleTable[DeviceIndex].TargetId = 0; + HandleTable[DeviceIndex].Lun = 0; + + strncpy(&szDevicePath[nPrefixLength], + DeviceName, + sizeof(szDevicePath) / sizeof(TCHAR) - nPrefixLength - 1); + + szDevicePath[sizeof(szDevicePath) / sizeof(TCHAR) - 1] = '\0'; + } + + HandleTable[DeviceIndex].hDevice = CreateFile(szDevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE) + { + DWORD dwError = GetLastError(); + +#if DEBUG + LPSTR lpszMessage; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL); + fputs(lpszMessage, stderr); +#endif + + switch (dwError) + { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + errno = ENOENT; + break; + + case ERROR_TOO_MANY_OPEN_FILES: + errno = EMFILE; + break; + + default: + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + case ERROR_INVALID_NAME: + errno = EACCES; + break; + + case ERROR_FILE_EXISTS: + errno = EEXIST; + break; + + case ERROR_INVALID_PARAMETER: + errno = EINVAL; + break; + } + + FatalError("cannot open SCSI device '%s' - %m\n", DeviceName); + } + + return DeviceIndex; +} + +static int scsi_timeout = SCSI_DEFAULT_TIMEOUT; + +void SCSI_Set_Timeout(int secs) +{ + if (secs > SCSI_MAX_TIMEOUT) + { + secs = SCSI_MAX_TIMEOUT; + } + + scsi_timeout = secs; +} + +void SCSI_Default_Timeout(void) +{ + scsi_timeout = SCSI_DEFAULT_TIMEOUT; +} + +void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD) +{ + if (DeviceFD < nEntries) + { + CloseHandle(HandleTable[DeviceFD].hDevice); + HandleTable[DeviceFD].hDevice = INVALID_HANDLE_VALUE; + } + else + { + errno = EBADF; + FatalError("cannot close SCSI device '%s' - %m\n", DeviceName); + } +} + + +/* Get the SCSI ID and LUN... */ +scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd) +{ + scsi_id_t * retval; + + SCSI_ADDRESS ScsiAddress; + BOOL bResult; + DWORD dwBytesReturned; + + if (fd < nEntries) + { + retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t)); + retval->id = HandleTable[fd].TargetId; + retval->lun = HandleTable[fd].Lun; + +#ifdef DEBUG + fprintf(stderr,"SCSI:ID=%d LUN=%d\n", retval->id, retval->lun); +#endif + return retval; + } + else + { + errno = EBADF; + FatalError("cannot close SCSI device - %m\n"); + } + + memset(&ScsiAddress, 0, sizeof(ScsiAddress)); + + ScsiAddress.Length = sizeof(ScsiAddress); + + bResult = DeviceIoControl( HandleTable[fd].hDevice, + IOCTL_SCSI_GET_ADDRESS, + &ScsiAddress, sizeof(ScsiAddress), + &ScsiAddress, sizeof(ScsiAddress), + &dwBytesReturned, + NULL); + + if (!bResult) + { + return NULL; + } + + retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t)); + retval->id = ScsiAddress.TargetId; + retval->lun = ScsiAddress.Lun; + +#ifdef DEBUG + fprintf(stderr,"SCSI:ID=%d LUN=%d\n",retval->id,retval->lun); +#endif + return retval; +} + +int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD, + Direction_T Direction, + CDB_T *CDB, + int CDB_Length, + void *DataBuffer, + int DataBufferLength, + RequestSense_T *RequestSense) +{ + PSCSI_PASS_THROUGH ScsiPassThrough; + + const DWORD dwDataBufferOffset = sizeof(SCSI_PASS_THROUGH) + (sizeof(RequestSense_T) + 3) / 4 * 4; + const DWORD dwBufferSize = dwDataBufferOffset + DataBufferLength; + + BOOL bResult; + DWORD dwBytesReturned; + DWORD dwInputLength; + DWORD dwOutputLength; + + if (DeviceFD >= nEntries || HandleTable[DeviceFD].hDevice == INVALID_HANDLE_VALUE) + { + errno = EBADF; + return -1; + } + + ScsiPassThrough = (PSCSI_PASS_THROUGH)malloc(dwBufferSize); + + memset(ScsiPassThrough, 0, dwDataBufferOffset); + + ScsiPassThrough->Length = sizeof(SCSI_PASS_THROUGH); + + ScsiPassThrough->PathId = HandleTable[DeviceFD].PathId; + ScsiPassThrough->TargetId = HandleTable[DeviceFD].TargetId; + ScsiPassThrough->Lun = HandleTable[DeviceFD].Lun; + ScsiPassThrough->CdbLength = (UCHAR)CDB_Length; + ScsiPassThrough->DataIn = Direction == Input; + ScsiPassThrough->DataBufferOffset = dwDataBufferOffset; + ScsiPassThrough->DataTransferLength = DataBufferLength; + ScsiPassThrough->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH); + ScsiPassThrough->SenseInfoLength = sizeof(RequestSense_T); + ScsiPassThrough->TimeOutValue = scsi_timeout; + + memcpy(ScsiPassThrough->Cdb, CDB, CDB_Length); + dwBytesReturned = 0; + + if (Direction == Output) + { + memcpy((void *)(((char *)ScsiPassThrough) + dwDataBufferOffset), DataBuffer, DataBufferLength); + dwInputLength = dwBufferSize; + dwOutputLength = dwDataBufferOffset; + } + else + { + dwInputLength = sizeof(SCSI_PASS_THROUGH); + dwOutputLength = dwBufferSize; + } + + bResult = DeviceIoControl( HandleTable[DeviceFD].hDevice, + IOCTL_SCSI_PASS_THROUGH, + ScsiPassThrough, dwInputLength, + ScsiPassThrough, dwOutputLength, + &dwBytesReturned, + NULL); + if (bResult) + { + if (ScsiPassThrough->ScsiStatus != 0) + { + memcpy(RequestSense, &ScsiPassThrough[1], sizeof(RequestSense_T)); +#if DEBUG + fprintf(stderr, "Command failed - ScsiStatus = %d\n", ScsiPassThrough->ScsiStatus); + PrintRequestSense(RequestSense); +#endif + bResult = false; + } + else + { + if (Direction == Input) + { + memcpy( DataBuffer, + (void *)(((char *)ScsiPassThrough) + dwDataBufferOffset), + DataBufferLength); + } + } + } + else + { +#if DEBUG + DWORD dwError = GetLastError(); + LPSTR lpszMessage; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL); + fputs(lpszMessage, stderr); + LocalFree(lpszMessage); +#endif + + memset(RequestSense, 0, sizeof(RequestSense_T)); + } + + free(ScsiPassThrough); + + return bResult ? 0 : -1; +} diff --git a/scsieject.1 b/scsieject.1 new file mode 100644 index 0000000..52e309e --- /dev/null +++ b/scsieject.1 @@ -0,0 +1,116 @@ +.\" scsieject.1 Document Copyright 2007-2008 Robert Nelson +.\" +.\" This is free documentation; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License as +.\" published by the Free Software Foundation; either version 2 of +.\" the License, or (at your option) any later version. +.\" +.\" The GNU General Public License's references to "object code" +.\" and "executables" are to be interpreted as the output of any +.\" document formatting or typesetting system, including +.\" intermediate and printed output. +.\" +.\" This manual is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public +.\" License along with this manual; if not, write to the Free +.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +.\" USA. +.\" +.TH scsieject 1 scsieject1.0 +.SH NAME +scsieject \- control SCSI tape devices +.SH SYNOPSIS +scsieject [-f ] commands +.SH DESCRIPTION +The +.B scsieject +command controls SCSI devices in a platform-independent +manner. As long as 'mtx' works on the platform, so does 'scsieject'. +.SH OPTIONS +The first argument, given following +.B -f +, is the SCSI generic device corresponding to your tape drive. +Consult your operating system's documentation for more information (for +example, under Linux these are generally /dev/sg0 through /dev/sg15, +under FreeBSD these are /dev/pass0 through /dev/passX. Under Solaris +this is usually the same as your tape drive (Solaris has a SCSI passthrough +ioctl). You can set the STAPE or TAPE environment variable rather +than use -f. +.P +.SH COMMANDS +.TP 10 +.B load +Load the medium into the drive. When this command is issued to a CD/DVD drive +and the tray is extended the tray will be retracted if the drive is capable of it. + +.TP 10 +.B unload +Unload the medium from the drive (also known as eject). When this command is issued +to a CD/DVD drive or a tape drive the media will be ejected if the device supports it. + +.TP 10 +.B start +Start the device. Some devices require a start command after a media changer has +loaded new media into the device. + +.TP 10 +.B stop +Stop the device. Some devices require a stop command prior to unloading the medium +from the device when using a media changer. + +.TP 10 +.B lock +Lock the device. Locks the device so that the medium cannot be removed manually. + +.TP 10 +.B unlock +Unlock the device. Unlocks the device so that the medium can be removed manually. + +.SH AUTHORS +This program was written by Robert Nelson +based on the scsitape program written by Eric Lee Green . +Major portions of the 'mtxl.c' library used herein were written by +Leonard Zubkoff. +.P + +.SH HINTS +Under Linux, +.B cat /proc/scsi/scsi +will tell you what SCSI devices you have. +You can then refer to them as +.B /dev/sga, +.B /dev/sgb, +etc. by the order they +are reported. +.P +Under FreeBSD, +.B camcontrol devlist +will tell you what SCSI devices you +have, along with which +.B pass +device controls them. +.P +Under Solaris 7 and 8, +.B /usr/sbin/devfsadm -C +will clean up your /devices directory. Then +.B find /devices -name 'st@*' -print +will return a list of all tape drives. /dev on Solaris is apparently only +of historical interest. + +.SH BUGS AND LIMITATIONS +There are no known bugs or limitations. + +.SH AVAILABILITY +This version of +.B scsieject +is currently being maintained by Robert Nelson +as part of the 'mtx' suite of programs. The 'mtx' home page is +http://mtx.sourceforge.net and the actual code is currently available there and via +SVN from http://sourceforge.net/projects/mtx. + +.SH SEE ALSO +.BR loaderinfo (1), tapeinfo (1), mtx (1) diff --git a/scsieject.c b/scsieject.c new file mode 100644 index 0000000..c2c79b9 --- /dev/null +++ b/scsieject.c @@ -0,0 +1,255 @@ +/* Copyright 2007-2008, Robert Nelson + * Released under terms of the GNU General Public License as + * required by the license on 'mtxl.c'. + * $Date: 2007-01-28 19:23:33 -0800 (Sun, 28 Jan 2007) $ + * $Revision: 125 $ + */ + +/* This is a generic SCSI device control program. It operates by + * directly sending commands to the device. + */ + +/* + * Commands: + * load -- Load medium + * unload -- Unload medium + * start -- Start device + * stop -- Stop device + * lock -- Lock medium + * unlock -- Unlock medium + */ + +#include +#include + +#include "mtx.h" +#include "mtxl.h" + +#if HAVE_UNISTD_H +#include +#endif + +#if HAVE_SYS_TYPES_H +#include +#endif + +#ifdef _MSC_VER +#include +#endif + +char *argv0; + +/* the device handle we're operating upon. */ +static char *device; /* the device name. */ +static DEVICE_TYPE DeviceFD = (DEVICE_TYPE) -1; + +static int S_load(void); +static int S_unload(void); +static int S_start(void); +static int S_stop(void); +static int S_lock(void); +static int S_unlock(void); + +struct command_table_struct +{ + char *name; + int (*command)(void); +} + command_table[] = +{ + { "load", S_load }, + { "unload", S_unload }, + { "start", S_start }, + { "stop", S_stop }, + { "lock", S_lock }, + { "unlock", S_unlock }, + { NULL, NULL } /* terminate list */ +}; + +void Usage(void) +{ + FatalError("Usage: scsieject -f where is:\n load | unload | start | stop | lock | unlock\n"); +} + +/* open_device() -- set the 'DeviceFD' variable.... */ +void open_device(void) +{ + if (DeviceFD != -1) + { + SCSI_CloseDevice("Unknown", DeviceFD); + } + + DeviceFD = SCSI_OpenDevice(device); +} + +/* we see if we've got a file open. If not, we open one :-(. Then + * we execute the actual command. Or not :-(. + */ +int execute_command(struct command_table_struct *command) +{ + /* + * If the device is not already open, then open it from the + * environment. + */ + if (DeviceFD == -1) + { + /* try to get it from STAPE or TAPE environment variable... */ + if ((device = getenv("STAPE")) == NULL && + (device = getenv("TAPE")) == NULL) + { + Usage(); /* Doesn't return */ + } + + open_device(); + } + + /* okay, now to execute the command... */ + return command->command(); +} + + +/* parse_args(): + * Basically, we are parsing argv/argc. We can have multiple commands + * on a line, such as "load start" to load a tape and start the device. + * We execute these commands one at a time as we come to them. If we don't + * have a -f at the start and the default device isn't defined in a TAPE or + * STAPE environment variable, we exit. + */ + +int parse_args(int argc, char **argv) +{ + int index, retval; + struct command_table_struct *command; + + argv0 = argv[0]; + + for (index = 1; index < argc; index++) + { + if (strcmp(argv[index], "-f") == 0) + { + index++; + if (index >= argc) + { + Usage(); /* Doesn't return */ + } + device = argv[index]; + open_device(); + } + else + { + for (command = &command_table[0]; command->name != NULL; command++) + { + if (strcmp(command->name, argv[index]) == 0) + { + break; + } + } + + if (command->name == NULL) + { + Usage(); /* Doesn't return */ + } + + retval = execute_command(command); + + if (retval < 0) + { + /* Command failed, we probably shouldn't continue */ + return retval; + } + } + } + + return 0; +} + +int S_load(void) +{ + int result = LoadUnload(DeviceFD, 1); + + if (result < 0) + { + fputs("scsieject: load failed\n", stderr); + fflush(stderr); + } + + return result; +} + +int S_unload(void) +{ + int result = LoadUnload(DeviceFD, 0); + + if (result < 0) + { + fputs("scsieject: unload failed\n", stderr); + fflush(stderr); + } + + return result; +} + +int S_start(void) +{ + int result = StartStop(DeviceFD, 1); + + if (result < 0) + { + fputs("scsieject: start failed\n", stderr); + fflush(stderr); + } + + return result; +} + +int S_stop(void) +{ + int result = StartStop(DeviceFD, 0); + + if (result < 0) + { + fputs("scsieject: stop failed\n", stderr); + fflush(stderr); + } + + return result; +} + +int S_lock(void) +{ + int result = LockUnlock(DeviceFD, 1); + + if (result < 0) + { + fputs("scsieject: lock failed\n", stderr); + fflush(stderr); + } + + return result; +} + +int S_unlock(void) +{ + int result = LockUnlock(DeviceFD, 0); + + if (result < 0) + { + fputs("scsieject: unlock failed\n", stderr); + fflush(stderr); + } + + return result; +} + +/* See parse_args for the scoop. parse_args does all. */ +int main(int argc, char **argv) +{ + parse_args(argc, argv); + + if (device) + { + SCSI_CloseDevice(device, DeviceFD); + } + + exit(0); +} diff --git a/scsitape.1 b/scsitape.1 new file mode 100644 index 0000000..46906bc --- /dev/null +++ b/scsitape.1 @@ -0,0 +1,179 @@ +.\" scsitape.1 Document Copyright 2001 Eric Lee Green +.\" Copyright 2007-2008 by Robert Nelson +.\" +.\" This is free documentation; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License as +.\" published by the Free Software Foundation; either version 2 of +.\" the License, or (at your option) any later version. +.\" +.\" The GNU General Public License's references to "object code" +.\" and "executables" are to be interpreted as the output of any +.\" document formatting or typesetting system, including +.\" intermediate and printed output. +.\" +.\" This manual is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public +.\" License along with this manual; if not, write to the Free +.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +.\" USA. +.\" +.TH SCSITAPE 1 SCSITAPE1.0 +.SH NAME +scsitape \- control SCSI tape devices +.SH SYNOPSIS +scsitape [-f ] commands +.SH DESCRIPTION +The +.B scsitape +command controls SCSI tape drives in a platform-independent +manner. As long as 'mtx' works on the platform, so does 'scsitape'. +.P +Note that 'scsitape' and your OS's native tape driver may stomp on each +other. In particular, if you use 'setblk' and your OS's native tape +driver has a different notion of the block size, you may get evil results. +It is recommended to use 'scsitape' only for software where you've written +your own low-level READ and WRITE routines that use the SCSI command set +to directly talk to tape drives (i.e., you do not use the OS's native tape +driver at all). +.SH OPTIONS +The first argument, given following +.B -f +, is the SCSI generic device corresponding to your tape drive. +Consult your operating system's documentation for more information (for +example, under Linux these are generally /dev/sg0 through /dev/sg15, +under FreeBSD these are /dev/pass0 through /dev/passX. Under Solaris +this is usually the same as your tape drive (Solaris has a SCSI passthrough +ioctl). You can set the STAPE or TAPE environment variable rather +than use -f. +.P +.SH COMMANDS +.TP 10 +.B setblk +Set the tape drive's SCSI block size to bytes. (NOTE: if you are +using your OS's native tape driver, THIS IS EVIL!). + +.TP 10 +.B fsf +Go forward by tapemarks. +.TP 10 +.B bsf +Go to immediately previous the th previous tapemark. (WARNING: This +probably doesn't do what you expect -- e.g. if you are immediately +after a tapemark and type 'bfs 1', it moves to immediately *before* +that tape mark, for a sum total of zero effective movement!). +.TP 10 +.B eod +Go to end of data. +.TP 10 +.B rewind +Rewind the tape drive. +.TP 10 +.B eject +Eject the tape currently in the drive. +.TP 10 +.B erase +Does a *short* erase (warning: does NOT work on all drives!). +.TP 10 +.B mark + write filemarks ( 'mark 0' flushes the drive's buffers ). +.TP 10 +.B seek +Seek to a logical position that was reported by a previous 'tapeinfo' +command. +.TP 10 +.B write +write blocks from stdin to the tape. Chunk the data into -sized +chunks. *DOES NOT WRITE OUT A TAPEMARK!* (you will need to use a +subsequent +.B mark 1 +command to write out a tape mark). +.TP 10 +.B read [] [ <#blocks/#bytes> ] +read blocks from the tape, write them to stdout. If we are in variable +block mode, should be zero (note: The maximum block size +we currently support in variable block mode is 128K, MAX_READ_SIZE will +need to be turned into a settable variable to allow bigger reads). If + is ommitted, we assume that we're in variable block mode, and +that we are going to read from tape until we hit a tapemark or end of +partition or end of tape. + + +.SH AUTHORS +This program was written by Eric Lee Green . +Major portions of the 'mtxl.c' library used herein were written by +Leonard Zubkoff. +.P + +The SCSI read and write routines are based upon those that Richard +Fish wrote for Enhanced Software Technology's BRU 16.1 product, +substantially modified to work in our particular environment (in +particular, all the variable block stuff is new since BRU only does +fixed block reads and writes, and the BRU code uses bitmasks rather +than bitfields for the various flags and such in return values, as +well as the BRU code having a different SCSI API and having variable +names considerably shorter than the rather sesquipedalian 'mtx' +identifiers). As required by 'mtxl.c', these routines are licensed +under the GNU General Public License. + +.SH HINTS +Under Linux, +.B cat /proc/scsi/scsi +will tell you what SCSI devices you have. +You can then refer to them as +.B /dev/sga, +.B /dev/sgb, +etc. by the order they +are reported. +.P +Under FreeBSD, +.B camcontrol devlist +will tell you what SCSI devices you +have, along with which +.B pass +device controls them. +.P +Under Solaris 7 and 8, +.B /usr/sbin/devfsadm -C +will clean up your /devices directory. Then +.B find /devices -name 'st@*' -print +will return a list of all tape drives. /dev on Solaris is apparently only +of historical interest. + +.SH BUGS AND LIMITATIONS + +for +.B scsitape read 0 +where you are doing variable-block-size reads and wish for bytes, +it instead reads one and exactly one block from tape and prints that +(no matter what its size). Use 'dd' on the output of scsitape if you +want finer control. +.P +.B scsitape read 0 +attempts reads of MAX_READ_SIZE, which is currently 128K. If blocks on tape +are larger than 128K, only the first 128K will be read -- the remainder +will be silently dumped in the toilet. +.P +This program does not interact well (or at all :-) with your OS's +native tape driver. You will likely see weird things happen if you +attempt to intermingle scsitape commands with native tape driver +operations. Note that BRU 16.1 for Solaris (and possibly others, but +Solaris I know about) will have a 'scsi' keyword to bypass the +native tape driver and write via direct uscsi commands, so if you use +\'scsitape\' to bypass the flaws of the native Solaris driver, you can use +BRU 16.1 to write your actual tape archives. (Assuming that BRU 16.1 +has been released at the time that you read this). + +.SH AVAILABILITY +This version of +.B scsitape +is currently being maintained by Robert Nelson +as part of the 'mtx' suite of programs. The 'mtx' home page is +http://mtx.sourceforge.net and the actual code is currently available there and via +SVN from http://sourceforge.net/projects/mtx. + +.SH SEE ALSO +.BR loaderinfo (1), tapeinfo (1), mtx (1) diff --git a/scsitape.c b/scsitape.c new file mode 100644 index 0000000..dd52dd5 --- /dev/null +++ b/scsitape.c @@ -0,0 +1,941 @@ +/* Copyright 2001 Enhanced Software Technologies Inc. + * Copyright 2007-2008 by Robert Nelson + * Released under terms of the GNU General Public License as + * required by the license on 'mtxl.c'. + * $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ + * $Revision: 193 $ + */ + +/* This is a generic SCSI tape control program. It operates by + * directly sending commands to the tape drive. If you are going + * through your operating system's SCSI tape driver, do *NOT* use + * this program! If, on the other hand, you are using raw READ and WRITE + * commands through your operating system's generic SCSI interface (or + * through our built-in 'read' and 'write'), this is the place for you. + */ + +/*#define DEBUG_PARTITION */ +/*#define DEBUG 1 */ + +/* + Commands: + setblk -- set the block size to + fsf -- go forward by filemarks + bsf -- go backward by filemarks + eod -- go to end of data + rewind -- rewind back to start of data + eject -- rewind, then eject the tape. + erase -- (short) erase the tape (we have no long erase) + mark -- write filemarks. + seek -- seek to position . + + write <-- write blocks from stdin to the tape + read [] [<#blocks/#bytes>] -- read blocks from tape, write to stdout. + + See the 'tapeinfo' program for status info about the tape drive. + + */ + +#include +#include + +#include "mtx.h" +#include "mtxl.h" + +#if HAVE_UNISTD_H +#include +#endif + +#if HAVE_SYS_TYPES_H +#include +#endif + +#if HAVE_SYS_IOCTL_H +#include +#endif + +#if HAVE_SYS_MTIO_H +#include /* will try issuing some ioctls for Solaris, sigh. */ +#endif + +#ifdef _MSC_VER +#include +#endif + +void Usage(void) { + FatalError("Usage: scsitape -f where is:\n setblk | fsf | bsf | eod | rewind | eject | mark |\n seek | read [ [] \n"); +} + +#define arg1 (arg[0]) /* for backward compatibility, sigh */ +static int arg[4]; /* the argument for the command, sigh. */ + +/* the device handle we're operating upon, sigh. */ +static char *device; /* the text of the device thingy. */ +static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) -1; + + + +static int S_setblk(void); +static int S_fsf(void); +static int S_bsf(void); +static int S_eod(void); +static int S_rewind(void); +static int S_eject(void); +static int S_mark(void); +static int S_seek(void); +static int S_reten(void); +static int S_erase(void); + +static int S_read(void); +static int S_write(void); + + +struct command_table_struct { + int num_args; + char *name; + int (*command)(void); +} command_table[] = { + { 1, "setblk", S_setblk }, + { 1, "fsf", S_fsf }, + { 1, "bsf", S_bsf }, + { 0, "eod", S_eod }, + { 0, "rewind", S_rewind }, + { 0, "eject", S_eject }, + { 0, "reten", S_reten }, + { 0, "erase", S_erase }, + { 1, "mark", S_mark }, + { 1, "seek", S_seek }, + { 2, "read", S_read }, + { 2, "write",S_write }, + { 0, NULL, NULL } /* terminate list */ +}; + +char *argv0; + + +/* open_device() -- set the 'fh' variable.... */ +void open_device(void) +{ + if (MediumChangerFD != -1) + { + SCSI_CloseDevice("Unknown",MediumChangerFD); /* close it, sigh... new device now! */ + } + + MediumChangerFD = SCSI_OpenDevice(device); +} + +static int get_arg(char *arg) +{ + int retval=-1; + + if (*arg < '0' || *arg > '9') + { + return -1; /* sorry! */ + } + + retval=atoi(arg); + return retval; +} + + +/* we see if we've got a file open. If not, we open one :-(. Then + * we execute the actual command. Or not :-(. + */ +int execute_command(struct command_table_struct *command) +{ + /* if the device is not already open, then open it from the + * environment. + */ + if (!MediumChangerFD == -1) + { + /* try to get it from STAPE or TAPE environment variable... */ + device = getenv("STAPE"); + if (device == NULL) + { + device = getenv("TAPE"); + if (device == NULL) + { + Usage(); + } + } + open_device(); + } + + /* okay, now to execute the command... */ + return command->command(); +} + + +/* parse_args(): + * Basically, we are parsing argv/argc. We can have multiple commands + * on a line now, such as "unload 3 0 load 4 0" to unload one tape and + * load in another tape into drive 0, and we execute these commands one + * at a time as we come to them. If we don't have a -f at the start, we + * barf. If we leave out a drive #, we default to drive 0 (the first drive + * in the cabinet). + */ + +int parse_args(int argc, char **argv) +{ + int i, cmd_tbl_idx,retval,arg_idx; + struct command_table_struct *command; + + i=1; + arg_idx = 0; + while (i < argc) + { + if (strcmp(argv[i],"-f") == 0) + { + i++; + if (i >= argc) + { + Usage(); + } + device = argv[i++]; + open_device(); /* open the device and do a status scan on it... */ + } + else + { + cmd_tbl_idx=0; + command = &command_table[0]; /* default to the first command... */ + command = &command_table[cmd_tbl_idx]; + while (command->name) + { + if (strcmp(command->name,argv[i]) == 0) + { + /* we have a match... */ + break; + } + /* otherwise we don't have a match... */ + cmd_tbl_idx++; + command = &command_table[cmd_tbl_idx]; + } + /* if it's not a command, exit.... */ + if (command->name == NULL) + { + Usage(); + } + i++; /* go to the next argument, if possible... */ + /* see if we need to gather arguments, though! */ + arg1 = -1; /* default it to something */ + for (arg_idx=0;arg_idx < command->num_args ; arg_idx++) + { + if (i < argc) + { + arg[arg_idx] = get_arg(argv[i]); + if (arg[arg_idx] != -1) + { + i++; /* increment i over the next cmd. */ + } + } + else + { + arg[arg_idx] = 0; /* default to 0 setmarks or whatever */ + } + } + retval=execute_command(command); /* execute_command handles 'stuff' */ + exit(retval); + } + } + return 0; /* should never get here */ +} + +/* For Linux, this allows us to do a short erase on a tape (sigh!). + * Note that you'll need to do a 'mt status' on the tape afterwards in + * order to get the tape driver in sync with the tape drive again. Also + * note that on other OS's, this might do other evil things to the tape + * driver. Note that to do an erase, you must first rewind! + + */ +static int S_erase(void) +{ + int retval; + RequestSense_T *RequestSense; + + retval=S_rewind(); + if (retval) + { + return retval; /* we have an exit status :-(. */ + } + + RequestSense=Erase(MediumChangerFD); + if (RequestSense) + { + PrintRequestSense(RequestSense); + exit(1); /* exit with an error status. */ + } + return 0; +} + +/* This should eject a tape or magazine, depending upon the device sent + * to. + */ +static int S_eject(void) +{ + int i; + i = LoadUnload(MediumChangerFD, 0); + if ( i < 0) + { + fprintf(stderr,"scsitape:eject failed\n"); + fflush(stderr); + } + return i; +} + + + +/* We write a filemarks of 0 before going to grab position, in order + * to insure that data in the buffer is not a problem. + */ + +static int S_mark(void) +{ + RequestSense_T RequestSense; /* for result of ReadElementStatus */ + CDB_T CDB; + unsigned char buffer[6]; + int count = arg1; /* voila! */ + + CDB[0] = 0x10; /* SET_MARK */ + CDB[1] = 0; + CDB[2] = (unsigned char)(count >> 16); + CDB[3] = (unsigned char)(count >> 8); + CDB[4] = (unsigned char)count; + CDB[5] = 0; + + /* we really don't care if this command works or not, sigh. */ + slow_bzero((char *)&RequestSense, sizeof(RequestSense_T)); + + if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 6, buffer, 0, &RequestSense)!= 0) + { + PrintRequestSense(&RequestSense); + return 1; + } + return 0; +} +/* let's rewind to bod! + */ + +static int S_rewind(void) +{ + RequestSense_T sense; + CDB_T CDB; + unsigned char buffer[6]; + + CDB[0] = 0x01; /* REWIND */ + CDB[1] = 0; + CDB[2] = 0; + CDB[3] = 0; + CDB[4] = 0; + CDB[5] = 0; + + /* we really don't care if this command works or not, sigh. */ + slow_bzero((char *)&sense,sizeof(RequestSense_T)); + if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&sense)!=0) + { + PrintRequestSense(&sense); + return 1; + } + return 0; +} + + + + +/* This is used for fsf and bsf. */ +static int Space(int count, char code) +{ + RequestSense_T sense; + CDB_T CDB; + unsigned char buffer[6]; + + CDB[0] = 0x11; /* SET_MARK */ + CDB[1] = code; + CDB[2] = (unsigned char)(count >> 16); + CDB[3] = (unsigned char)(count >> 8); + CDB[4] = (unsigned char)count; + CDB[5] = 0; + + /* we really don't care if this command works or not, sigh. */ + slow_bzero((char *)&sense,sizeof(RequestSense_T)); + if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 6, buffer, 0, &sense) != 0) + { + PrintRequestSense(&sense); + return 1; + } + return 0; +} + + +/* Let's try a fsf: */ +/* We write a filemarks of 0 before going to grab position, in order + * to insure that data in the buffer is not a problem. + */ + +static int S_fsf(void) +{ + return Space(arg1,1); /* go forward! */ +} + +static int S_bsf(void) +{ + return Space(-arg1,1); /* go backward! */ +} + +static int S_eod(void) +{ + return Space(0,3); /* go to eod! */ +} + +/* sigh, abuse of the LOAD command... + + */ +static int S_reten(void) +{ + RequestSense_T sense; + CDB_T CDB; + unsigned char buffer[6]; + + CDB[0] = 0x1B; /* START_STOP */ + CDB[1] = 0; /* wait */ + CDB[2] = 0; + CDB[3] = 0; + CDB[4] = 3; /* reten. */ + CDB[5] = 0; + + /* we really don't care if this command works or not, sigh. */ + slow_bzero((char *)&sense, sizeof(RequestSense_T)); + if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 6, buffer, 0, &sense) != 0) + { + PrintRequestSense(&sense); + return 1; + } + return 0; +} + +/* seek a position on the tape (sigh!) */ +static int S_seek(void) +{ + RequestSense_T sense; + CDB_T CDB; + unsigned char buffer[6]; + int count = arg1; + + /* printf("count=%d\n",arg1); */ + + CDB[0] = 0x2B; /* LOCATE */ + CDB[1] = 0; /* Logical */ + CDB[2] = 0; /* padding */ + CDB[3] = (unsigned char)(count >> 24); + CDB[4] = (unsigned char)(count >> 16); + CDB[5] = (unsigned char)(count >> 8); + CDB[6] = (unsigned char)count; + CDB[7] = 0; + CDB[8] = 0; + CDB[9] = 0; + + /* we really don't care if this command works or not, sigh. */ + slow_bzero((char *)&sense,sizeof(RequestSense_T)); + if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 10, buffer, 0, &sense) != 0) + { + PrintRequestSense(&sense); + return 1; + } + return 0; +} + +#ifdef MTSRSZ +static int Solaris_setblk(int fh,int count) +{ + /* we get here only if we have a MTSRSZ, which means Solaris. */ + struct mtop mt_com; /* the struct used for the MTIOCTOP ioctl */ + int result; + + /* okay, we have fh and count.... */ + + /* Now to try the ioctl: */ + mt_com.mt_op=MTSRSZ; + mt_com.mt_count=count; + + /* surround the actual ioctl to enable threading, since fsf/etc. can be + * big time consumers and we want other threads to be able to run too. + */ + + result=ioctl(fh, MTIOCTOP, (char *)&mt_com); + + if (result < 0) + { + return errno; + } + + /* okay, we did okay. Return a value of None... */ + return 0; +} +#endif + + +/* okay, this is a write: we need to set the block size to something: */ +static int S_setblk(void) +{ + RequestSense_T sense; + CDB_T CDB; + char buffer[12]; + unsigned int count = (unsigned int) arg1; + + CDB[0] = 0x15; /* MODE SELECT */ + CDB[1] = 0x10; /* scsi2 */ + CDB[2] = 0; + CDB[3] = 0; + CDB[4] = 12; /* length of data */ + CDB[5] = 0; + + slow_bzero((char *)&sense, sizeof(RequestSense_T)); + slow_bzero(buffer, 12); + + /* Now to set the mode page header: */ + buffer[0] = 0; + buffer[1] = 0; + buffer[2] = 0x10; /* we are in buffered mode now, people! */ + buffer[3] = 8; /* block descriptor length. */ + buffer[4] = 0; /* reset to default density, sigh. */ /* 0 */ + buffer[5] = 0; /* 1 */ + buffer[6] = 0; /* 2 */ + buffer[7] = 0; /* 3 */ + buffer[8] = 0; /* 4 */ + buffer[9] = (unsigned char)(count >> 16); /* 5 */ + buffer[10] = (unsigned char)(count >> 8); /* 6 */ + buffer[11] = (unsigned char)count; /* 7 */ + + if (SCSI_ExecuteCommand(MediumChangerFD,Output,&CDB,6,buffer,12,&sense)!=0) + { + PrintRequestSense(&sense); + return 1; + } +#ifdef MTSRSZ + /* Solaris_setblk(MediumChangerFD,count); */ +#endif + + return 0; +} + +/*************************************************************************/ +/* SCSI read/write calls. These are mostly pulled out of BRU 16.1, + * modified to work within the mtxl.h framework rather than the + * scsi_lowlevel.h framework. + *************************************************************************/ + +#define MAX_READ_SIZE 128*1024 /* max size of a variable-block read */ + +#define READ_OK 0 +#define READ_FILEMARK 1 +#define READ_EOD 2 +#define READ_EOP 3 +#define READ_SHORT 5 +#define READ_ERROR 255 + +#define WRITE_OK 0 +#define WRITE_ERROR 1 +#define WRITE_EOM 2 +#define WRITE_EOV 3 + + +/* These are copied out of BRU 16.1, with all the boolean masks changed + * to our bitmasks. +*/ +#define S_NO_SENSE(s) ((s).SenseKey == 0x0) +#define S_RECOVERED_ERROR(s) ((s).SenseKey == 0x1) + +#define S_NOT_READY(s) ((s).SenseKey == 0x2) +#define S_MEDIUM_ERROR(s) ((s).SenseKey == 0x3) +#define S_HARDWARE_ERROR(s) ((s).SenseKey == 0x4) +#define S_UNIT_ATTENTION(s) ((s).SenseKey == 0x6) +#define S_BLANK_CHECK(s) ((s).SenseKey == 0x8) +#define S_VOLUME_OVERFLOW(s) ((s).SenseKey == 0xd) + +#define DEFAULT_TIMEOUT 3*60 /* 3 minutes here */ + +#define HIT_FILEMARK(s) (S_NO_SENSE((s)) && (s).Filemark && (s).Valid) +/* Sigh, the T-10 SSC spec says all of the following is needed to + * detect a short read while in variable block mode. We'll see. + */ +#define SHORT_READ(s) (S_NO_SENSE((s)) && (s).ILI && (s).Valid && (s).AdditionalSenseCode==0 && (s).AdditionalSenseCodeQualifier==0) + +#define HIT_EOD(s) (S_BLANK_CHECK((s)) && (s).Valid) +#define HIT_EOP(s) (S_MEDIUM_ERROR((s)) && (s).EOM && (s).Valid) +#define HIT_EOM(s) ((s).EOM && (s).Valid) +#define BECOMING_READY(s) (S_UNIT_ATTENTION((s)) && (s).AdditionalSenseCode == 0x28 && (s).AdditionalSenseCodeQualifier == 0) + +/* Reading is a problem. We can hit a filemark, hit an EOD, or hit an + * EOP. Our caller may do something about that. Note that we assume that + * our caller has already put us into fixed block mode. If he has not, then + * we are in trouble anyhow. + */ +int SCSI_readt(DEVICE_TYPE fd, char * buf, unsigned int bufsize, unsigned int *len, unsigned int timeout) { + int rtnval; + CDB_T cmd; + + int blockCount; + int info; + + RequestSense_T RequestSense; + + if (bufsize==0) + { + /* we are in variable block mode */ + blockCount=MAX_READ_SIZE; /* variable block size. */ + } + else + { + blockCount= *len / bufsize; + if ((*len % bufsize) != 0) + { + fprintf(stderr,"Error: Data (%d bytes) not even multiple of block size (%d bytes).\n",*len,bufsize); + exit(1); /* we're finished, sigh. */ + } + } + + if (timeout == 0) + { + timeout = 1 * 60; /* 1 minutes */ + } + + memset(&cmd, 0, sizeof(CDB_T)); + cmd[0] = 0x08; /* READ */ + cmd[1] = (bufsize) ? 1 : 0; /* fixed length or var length blocks */ + cmd[2] = (unsigned char)(blockCount >> 16); /* MSB */ + cmd[3] = (unsigned char)(blockCount >> 8); + cmd[4] = (unsigned char)blockCount; /* LSB */ + + /* okay, let's read, look @ the result code: */ + rtnval=READ_OK; + if (SCSI_ExecuteCommand(fd,Input,&cmd,6,buf,(bufsize) ? *len : MAX_READ_SIZE,&RequestSense)) + { + rtnval=READ_ERROR; + if (HIT_EOP(RequestSense)) + { + cmd[0]=0x08; + rtnval=READ_EOP; + } + + if (HIT_FILEMARK(RequestSense)) + { + rtnval=READ_FILEMARK; + } + + if (HIT_EOD(RequestSense)) + { + rtnval=READ_EOD; + } + + if ( (bufsize==0) && SHORT_READ(RequestSense)) + { + rtnval=READ_SHORT; /* we only do short reads for variable block mode */ + } + + if (rtnval != READ_ERROR) + { + /* info contains number of blocks or bytes *not* read. May be + negative if the block we were trying to read was too big. So + we will have to account for that and set it to zero if so, so that + we return the proper # of blocks read. + */ + info = ((RequestSense.Information[0] << 24) + + (RequestSense.Information[1] << 16) + + (RequestSense.Information[2] << 8) + + RequestSense.Information[3]); + + /* on 64-bit platforms, we may need to turn 'info' into a negative # */ + if (info > 0x7fffffff) + info = 0; + + if (info < 0) + info=0; /* make sure we don't return too big len read. */ + + /* Now set *len to # of bytes read. */ + *len= bufsize ? (blockCount-info) * bufsize : MAX_READ_SIZE-info ; + } + else + { + PrintRequestSense(&RequestSense); + exit(1); /* foo. */ + } + } + + return rtnval; +} + +/* Low level SCSI write. Modified from BRU 16.1, with much BRU smarts + * taken out and with the various types changed to mtx types rather than + * BRU types. + */ +int SCSI_write(DEVICE_TYPE fd, char * buf, unsigned int blocksize, + unsigned int *len) +{ + CDB_T cmd; + + int blockCount; + int rtnval=0; + RequestSense_T RequestSense; + + if (blocksize == 0) + { + /* we are in variable block mode */ + blockCount = *len; /* variable block size. */ + } + else + { + blockCount= *len / blocksize ; + if ((*len % blocksize) != 0) + { + fprintf(stderr,"Error: Data (%d bytes) not even multiple of block size (%d bytes).\n",*len,blocksize); + exit(1); /* we're finished, sigh. */ + } + } + + fprintf(stderr,"Writing %d blocks\n",blockCount); + + memset(&cmd, 0, sizeof(CDB_T)); + cmd[0] = 0x0a; /* WRITE */ + cmd[1] = (blocksize) ? 1 : 0; /* fixed length or var length blocks */ + cmd[2] = (unsigned char)(blockCount >> 16); /* MSB */ + cmd[3] = (unsigned char)(blockCount >> 8); + cmd[4] = (unsigned char)blockCount; /* LSB */ + + + if (SCSI_ExecuteCommand(fd,Output,&cmd,6,buf, *len, &RequestSense)) + { + if (HIT_EOM(RequestSense)) + { + /* we hit end of media. Return -1. */ + if (S_VOLUME_OVERFLOW(RequestSense)) + { + exit(WRITE_EOV); + } + exit(WRITE_EOM); /* end of media! */ + } + else + { + /* it was plain old write error: */ + PrintRequestSense(&RequestSense); + exit(WRITE_ERROR); + } + } + else + { + rtnval = *len; /* worked! */ + } + return rtnval; +} + +/* S_write is not implemented yet! */ +static int S_write(void) +{ + char *buffer; /* the buffer we're gonna read/write out of. */ + int buffersize; + int len; /* the length of the data in the buffer */ + int blocksize = arg[0]; + int numblocks = arg[1]; + int varsize=0; /* variable size block flag */ + int result; + int eof_input; + int infile=fileno(stdin); /* sigh */ + + if (blocksize == 0) + { + varsize = 1; + buffersize = MAX_READ_SIZE; + len = MAX_READ_SIZE; + } + else + { + varsize = 0; /* fixed block mode */ + buffersize = blocksize; + len = blocksize; + } + + /* sigh, make it oversized just to have some */ + buffer = malloc(buffersize+8); + + eof_input = 0; + while (!eof_input) + { + /* size_t could be 64 bit on a 32 bit platform, so do casts. */ + len=0; + /* If it is a pipe, we could read 4096 bytes rather than the full + * 128K bytes or whatever, so we must gather multiple reads into + * the buffer. + */ + while (len < buffersize) + { + result=(int)read(infile, buffer + len, (size_t)(buffersize - len)); + if (!result) + { + eof_input = 1; + if (!len) + { + /* if we have no deata in our buffer, exit */ + return 0; /* we're at end of file! */ + } + break; /* otherwise, break and write the data */ + } + len += result; /* add the result input to our length. */ + } + + result = SCSI_write(MediumChangerFD, buffer, blocksize, (unsigned int *)&len); + if (!result) + { + return 1; /* at end of tape! */ + } + + /* Now see if we have numbytes or numblocks. If so, we may wish to exit + this loop. + */ + if (arg[1]) + { + if (varsize) + { + /***BUG***/ + return 0; /* we will only write one block in variable size mode :-( */ + } + else + { + if (numblocks) + { + numblocks--; + } + else + { + return 0; /* we're done. */ + } + } + } + } + /* and done! */ + return 0; +} + +/* Okay, the read thingy: */ + +/* We have a device opened (we hope!) by the parser. + * we will have arg[0] and arg[1] being the blocksize and # of blocks + * (respectively). + */ + + +static int S_read(void) +{ + char *buffer; /* the buffer we're going to be reading out of */ + int buffersize; + unsigned int len; /* the length of the data in the buffer */ + int blocksize = arg[0]; + int numblocks = arg[1]; + int varsize = 0; /* variable size block flag. */ + + int result; + + int outfile=fileno(stdout); /* sigh. */ + + if (blocksize == 0) + { + varsize=1; + buffersize=MAX_READ_SIZE; + len=MAX_READ_SIZE; + } + else + { + varsize=0; /* fixed block mode */ + buffersize=blocksize; + len=blocksize; + } + + /* sigh, make it oversized just to have some */ + buffer = malloc(buffersize + 8); + + for ( ; ; ) + { + if (varsize) + { + /* it could have gotten reset by prior short read... */ + len=MAX_READ_SIZE; + } + result=SCSI_readt(MediumChangerFD,buffer,blocksize, &len, DEFAULT_TIMEOUT); + + if (result==READ_FILEMARK || result==READ_EOD || result==READ_EOP) + { + /* okay, normal end of file? */ + if (len > 0) + { + write(outfile,buffer,len); + } + +#ifdef NEED_TO_GO_PAST_FILEMARK + /* Now, let's try to go past the filemark if that's what we hit: */ + if (result==READ_FILEMARK) + { + arg1 = 1; /* arg for S_fsf. */ + S_fsf(); /* and go forward 1 filemark, we hope! */ + } +#endif + return 0; /* hit normal end of file. */ + } + else if (result == READ_SHORT) + { + /* short reads are only valid in variable block mode. */ + if (varsize) + { + if (len > 0) + { + write(outfile,buffer,len); + } + } + else + { + fprintf(stderr,"scsitape:Short Read encountered on input. Aborting.\n"); + fflush(stderr); + exit(1); /* error exit! */ + } + } + else if (result == READ_OK) + { + write(outfile,buffer,len); + } + else + { + fprintf(stderr,"scsitape:Read Error\n"); + fflush(stderr); + exit(1); + } + + /* Now see if we have numbytes or numblocks: if so, we may wish to + * exit this loop. + */ + if (arg[1]) + { + if (varsize) + { + /****BUG****/ + return 0; /* we're only reading one block in var size mode! */ + } + else if (numblocks) + { + numblocks--; + } + else + { + return 0; /* we're done. */ + } + } + } +} + + +/* See parse_args for the scoop. parse_args does all. */ +int main(int argc, char **argv) +{ + argv0 = argv[0]; + parse_args(argc, argv); + + if (device) + SCSI_CloseDevice(device,MediumChangerFD); + + exit(0); +} diff --git a/sg_err.c b/sg_err.c new file mode 100644 index 0000000..6c1570e --- /dev/null +++ b/sg_err.c @@ -0,0 +1,645 @@ + +/* This file is a huge cut, paste and hack from linux/drivers/scsi/constant.c +* which I guess was written by: +* Copyright (C) 1993, 1994, 1995 Eric Youngdale + +* The rest of this is: +* Copyright (C) 1999 - 2001 D. Gilbert +* Copyright 2007-2008 by Robert Nelson +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* ASCII values for a number of symbolic constants, printing functions, etc. +* +* Some of the tables have been updated for SCSI 2. +* +* Version 0.84 (20010115) +* Change output from stdout to stderr +*/ + +#define OUTP stderr + +static const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, + 12, 12, 10, 10 }; + +#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7] + +static const char unknown[] = "UNKNOWN"; + +static const char * group_0_commands[] = { +/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense", +/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks", +/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, +/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", +/* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve", +/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", +/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", +/* 1e-1f */ "Prevent/Allow Medium Removal", unknown, +}; + + +static const char *group_1_commands[] = { +/* 20-22 */ unknown, unknown, unknown, +/* 23-28 */ unknown, "Define window parameters", "Read Capacity", + unknown, unknown, "Read (10)", +/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase", + "Read updated block", +/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", +/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", +/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", +/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", + "Read Buffer", +/* 3d-3f */ "Update Block", "Read Long", "Write Long", +}; + +static const char *group_2_commands[] = { +/* 40-41 */ "Change Definition", "Write Same", +/* 42-48 */ "Read sub-channel", "Read TOC", "Read header", + "Play audio (10)", unknown, "Play audio msf", + "Play audio track/index", +/* 49-4f */ "Play track relative (10)", unknown, "Pause/resume", + "Log Select", "Log Sense", unknown, unknown, +/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)", +/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown, +/* 5c-5f */ unknown, unknown, unknown, +}; + + +/* The following are 12 byte commands in group 5 */ +static const char *group_5_commands[] = { +/* a0-a5 */ unknown, unknown, unknown, unknown, unknown, + "Move medium/play audio(12)", +/* a6-a9 */ "Exchange medium", unknown, "Read(12)", "Play track relative(12)", +/* aa-ae */ "Write(12)", unknown, "Erase(12)", unknown, + "Write and verify(12)", +/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)", +/* b2-b4 */ "Search data low(12)", "Set limits(12)", unknown, +/* b5-b6 */ "Request volume element address", "Send volume tag", +/* b7-b9 */ "Read defect data(12)", "Read element status", unknown, +/* ba-bf */ unknown, unknown, unknown, unknown, unknown, unknown, +}; + + + + +#define group(opcode) (((opcode) >> 5) & 7) + +#define RESERVED_GROUP 0 +#define VENDOR_GROUP 1 + +static const char **commands[] = { + group_0_commands, group_1_commands, group_2_commands, + (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, + group_5_commands, (const char **) VENDOR_GROUP, + (const char **) VENDOR_GROUP +}; + +static const char reserved[] = "RESERVED"; +static const char vendor[] = "VENDOR SPECIFIC"; + +static void print_opcode(int opcode) { + const char **table = commands[ group(opcode) ]; + switch ((unsigned long) table) { + case RESERVED_GROUP: + fprintf(OUTP, "%s(0x%02x) ", reserved, opcode); + break; + case VENDOR_GROUP: + fprintf(OUTP, "%s(0x%02x) ", vendor, opcode); + break; + default: + if (table[opcode & 0x1f] != unknown) + fprintf(OUTP, "%s ",table[opcode & 0x1f]); + else + fprintf(OUTP, "%s(0x%02x) ", unknown, opcode); + break; + } +} + +void sg_print_command (const unsigned char * command) { + int i,s; + print_opcode(command[0]); + for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + fprintf(OUTP, "%02x ", command[i]); + fprintf(OUTP, "\n"); +} + +static const char * statuses[] = { +/* 0-4 */ "Good", "Check Condition", "Condition Met", unknown, "Busy", +/* 5-9 */ unknown, unknown, unknown, "Intermediate", unknown, +/* a-c */ "Intermediate-Condition Met", unknown, "Reservation Conflict", +/* d-10 */ unknown, unknown, unknown, unknown, +/* 11-14 */ "Command Terminated", unknown, unknown, "Queue Full", +/* 15-1a */ unknown, unknown, unknown, unknown, unknown, unknown, +/* 1b-1f */ unknown, unknown, unknown, unknown, unknown, +}; + +void sg_print_status (int masked_status) { + /* status = (status >> 1) & 0xf; */ /* already done */ + fprintf(OUTP, "%s ",statuses[masked_status]); +} + +#define D 0x001 /* DIRECT ACCESS DEVICE (disk) */ +#define T 0x002 /* SEQUENTIAL ACCESS DEVICE (tape) */ +#define L 0x004 /* PRINTER DEVICE */ +#define P 0x008 /* PROCESSOR DEVICE */ +#define W 0x010 /* WRITE ONCE READ MULTIPLE DEVICE */ +#define R 0x020 /* READ ONLY (CD-ROM) DEVICE */ +#define S 0x040 /* SCANNER DEVICE */ +#define O 0x080 /* OPTICAL MEMORY DEVICE */ +#define M 0x100 /* MEDIA CHANGER DEVICE */ +#define C 0x200 /* COMMUNICATION DEVICE */ + +struct error_info{ + unsigned char code1, code2; + unsigned short int devices; + const char * text; +}; + +struct error_info2{ + unsigned char code1, code2_min, code2_max; + unsigned short int devices; + const char * text; +}; + +static struct error_info2 additional2[] = +{ + {0x40,0x00,0x7f,D,"Ram failure (%x)"}, + {0x40,0x80,0xff,D|T|L|P|W|R|S|O|M|C,"Diagnostic failure on component (%x)"}, + {0x41,0x00,0xff,D,"Data path failure (%x)"}, + {0x42,0x00,0xff,D,"Power-on or self-test failure (%x)"}, + {0, 0, 0, 0, NULL} +}; + +static struct error_info additional[] = +{ + {0x00,0x01,T,"Filemark detected"}, + {0x00,0x02,T|S,"End-of-partition/medium detected"}, + {0x00,0x03,T,"Setmark detected"}, + {0x00,0x04,T|S,"Beginning-of-partition/medium detected"}, + {0x00,0x05,T|S,"End-of-data detected"}, + {0x00,0x06,D|T|L|P|W|R|S|O|M|C,"I/O process terminated"}, + {0x00,0x11,R,"Audio play operation in progress"}, + {0x00,0x12,R,"Audio play operation paused"}, + {0x00,0x13,R,"Audio play operation successfully completed"}, + {0x00,0x14,R,"Audio play operation stopped due to error"}, + {0x00,0x15,R,"No current audio status to return"}, + {0x01,0x00,D|W|O,"No index/sector signal"}, + {0x02,0x00,D|W|R|O|M,"No seek complete"}, + {0x03,0x00,D|T|L|W|S|O,"Peripheral device write fault"}, + {0x03,0x01,T,"No write current"}, + {0x03,0x02,T,"Excessive write errors"}, + {0x04,0x00,D|T|L|P|W|R|S|O|M|C, + "Logical unit not ready, cause not reportable"}, + {0x04,0x01,D|T|L|P|W|R|S|O|M|C, + "Logical unit is in process of becoming ready"}, + {0x04,0x02,D|T|L|P|W|R|S|O|M|C, + "Logical unit not ready, initializing command required"}, + {0x04,0x03,D|T|L|P|W|R|S|O|M|C, + "Logical unit not ready, manual intervention required"}, + {0x04,0x04,D|T|L|O,"Logical unit not ready, format in progress"}, + {0x05,0x00,D|T|L|W|R|S|O|M|C,"Logical unit does not respond to selection"}, + {0x06,0x00,D|W|R|O|M,"No reference position found"}, + {0x07,0x00,D|T|L|W|R|S|O|M,"Multiple peripheral devices selected"}, + {0x08,0x00,D|T|L|W|R|S|O|M|C,"Logical unit communication failure"}, + {0x08,0x01,D|T|L|W|R|S|O|M|C,"Logical unit communication time-out"}, + {0x08,0x02,D|T|L|W|R|S|O|M|C,"Logical unit communication parity error"}, + {0x09,0x00,D|T|W|R|O,"Track following error"}, + {0x09,0x01,W|R|O,"Tracking servo failure"}, + {0x09,0x02,W|R|O,"Focus servo failure"}, + {0x09,0x03,W|R|O,"Spindle servo failure"}, + {0x0A,0x00,D|T|L|P|W|R|S|O|M|C,"Error log overflow"}, + {0x0C,0x00,T|S,"Write error"}, + {0x0C,0x01,D|W|O,"Write error recovered with auto reallocation"}, + {0x0C,0x02,D|W|O,"Write error - auto reallocation failed"}, + {0x10,0x00,D|W|O,"Id crc or ecc error"}, + {0x11,0x00,D|T|W|R|S|O,"Unrecovered read error"}, + {0x11,0x01,D|T|W|S|O,"Read retries exhausted"}, + {0x11,0x02,D|T|W|S|O,"Error too long to correct"}, + {0x11,0x03,D|T|W|S|O,"Multiple read errors"}, + {0x11,0x04,D|W|O,"Unrecovered read error - auto reallocate failed"}, + {0x11,0x05,W|R|O,"L-ec uncorrectable error"}, + {0x11,0x06,W|R|O,"Circ unrecovered error"}, + {0x11,0x07,W|O,"Data resynchronization error"}, + {0x11,0x08,T,"Incomplete block read"}, + {0x11,0x09,T,"No gap found"}, + {0x11,0x0A,D|T|O,"Miscorrected error"}, + {0x11,0x0B,D|W|O,"Unrecovered read error - recommend reassignment"}, + {0x11,0x0C,D|W|O,"Unrecovered read error - recommend rewrite the data"}, + {0x12,0x00,D|W|O,"Address mark not found for id field"}, + {0x13,0x00,D|W|O,"Address mark not found for data field"}, + {0x14,0x00,D|T|L|W|R|S|O,"Recorded entity not found"}, + {0x14,0x01,D|T|W|R|O,"Record not found"}, + {0x14,0x02,T,"Filemark or setmark not found"}, + {0x14,0x03,T,"End-of-data not found"}, + {0x14,0x04,T,"Block sequence error"}, + {0x15,0x00,D|T|L|W|R|S|O|M,"Random positioning error"}, + {0x15,0x01,D|T|L|W|R|S|O|M,"Mechanical positioning error"}, + {0x15,0x02,D|T|W|R|O,"Positioning error detected by read of medium"}, + {0x16,0x00,D|W|O,"Data synchronization mark error"}, + {0x17,0x00,D|T|W|R|S|O,"Recovered data with no error correction applied"}, + {0x17,0x01,D|T|W|R|S|O,"Recovered data with retries"}, + {0x17,0x02,D|T|W|R|O,"Recovered data with positive head offset"}, + {0x17,0x03,D|T|W|R|O,"Recovered data with negative head offset"}, + {0x17,0x04,W|R|O,"Recovered data with retries and/or circ applied"}, + {0x17,0x05,D|W|R|O,"Recovered data using previous sector id"}, + {0x17,0x06,D|W|O,"Recovered data without ecc - data auto-reallocated"}, + {0x17,0x07,D|W|O,"Recovered data without ecc - recommend reassignment"}, + {0x18,0x00,D|T|W|R|O,"Recovered data with error correction applied"}, + {0x18,0x01,D|W|R|O,"Recovered data with error correction and retries applied"}, + {0x18,0x02,D|W|R|O,"Recovered data - data auto-reallocated"}, + {0x18,0x03,R,"Recovered data with circ"}, + {0x18,0x04,R,"Recovered data with lec"}, + {0x18,0x05,D|W|R|O,"Recovered data - recommend reassignment"}, + {0x19,0x00,D|O,"Defect list error"}, + {0x19,0x01,D|O,"Defect list not available"}, + {0x19,0x02,D|O,"Defect list error in primary list"}, + {0x19,0x03,D|O,"Defect list error in grown list"}, + {0x1A,0x00,D|T|L|P|W|R|S|O|M|C,"Parameter list length error"}, + {0x1B,0x00,D|T|L|P|W|R|S|O|M|C,"Synchronous data transfer error"}, + {0x1C,0x00,D|O,"Defect list not found"}, + {0x1C,0x01,D|O,"Primary defect list not found"}, + {0x1C,0x02,D|O,"Grown defect list not found"}, + {0x1D,0x00,D|W|O,"Miscompare during verify operation"}, + {0x1E,0x00,D|W|O,"Recovered id with ecc correction"}, + {0x20,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid command operation code"}, + {0x21,0x00,D|T|W|R|O|M,"Logical block address out of range"}, + {0x21,0x01,M,"Invalid element address"}, + {0x22,0x00,D,"Illegal function (should use 20 00, 24 00, or 26 00)"}, + {0x24,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid field in cdb"}, + {0x25,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit not supported"}, + {0x26,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid field in parameter list"}, + {0x26,0x01,D|T|L|P|W|R|S|O|M|C,"Parameter not supported"}, + {0x26,0x02,D|T|L|P|W|R|S|O|M|C,"Parameter value invalid"}, + {0x26,0x03,D|T|L|P|W|R|S|O|M|C,"Threshold parameters not supported"}, + {0x27,0x00,D|T|W|O,"Write protected"}, + {0x28,0x00,D|T|L|P|W|R|S|O|M|C,"Not ready to ready transition (medium may have changed)"}, + {0x28,0x01,M,"Import or export element accessed"}, + {0x29,0x00,D|T|L|P|W|R|S|O|M|C,"Power on, reset, or bus device reset occurred"}, + {0x2A,0x00,D|T|L|W|R|S|O|M|C,"Parameters changed"}, + {0x2A,0x01,D|T|L|W|R|S|O|M|C,"Mode parameters changed"}, + {0x2A,0x02,D|T|L|W|R|S|O|M|C,"Log parameters changed"}, + {0x2B,0x00,D|T|L|P|W|R|S|O|C,"Copy cannot execute since host cannot disconnect"}, + {0x2C,0x00,D|T|L|P|W|R|S|O|M|C,"Command sequence error"}, + {0x2C,0x01,S,"Too many windows specified"}, + {0x2C,0x02,S,"Invalid combination of windows specified"}, + {0x2D,0x00,T,"Overwrite error on update in place"}, + {0x2F,0x00,D|T|L|P|W|R|S|O|M|C,"Commands cleared by another initiator"}, + {0x30,0x00,D|T|W|R|O|M,"Incompatible medium installed"}, + {0x30,0x01,D|T|W|R|O,"Cannot read medium - unknown format"}, + {0x30,0x02,D|T|W|R|O,"Cannot read medium - incompatible format"}, + {0x30,0x03,D|T,"Cleaning cartridge installed"}, + {0x31,0x00,D|T|W|O,"Medium format corrupted"}, + {0x31,0x01,D|L|O,"Format command failed"}, + {0x32,0x00,D|W|O,"No defect spare location available"}, + {0x32,0x01,D|W|O,"Defect list update failure"}, + {0x33,0x00,T,"Tape length error"}, + {0x36,0x00,L,"Ribbon, ink, or toner failure"}, + {0x37,0x00,D|T|L|W|R|S|O|M|C,"Rounded parameter"}, + {0x39,0x00,D|T|L|W|R|S|O|M|C,"Saving parameters not supported"}, + {0x3A,0x00,D|T|L|W|R|S|O|M,"Medium not present"}, + {0x3B,0x00,T|L,"Sequential positioning error"}, + {0x3B,0x01,T,"Tape position error at beginning-of-medium"}, + {0x3B,0x02,T,"Tape position error at end-of-medium"}, + {0x3B,0x03,L,"Tape or electronic vertical forms unit not ready"}, + {0x3B,0x04,L,"Slew failure"}, + {0x3B,0x05,L,"Paper jam"}, + {0x3B,0x06,L,"Failed to sense top-of-form"}, + {0x3B,0x07,L,"Failed to sense bottom-of-form"}, + {0x3B,0x08,T,"Reposition error"}, + {0x3B,0x09,S,"Read past end of medium"}, + {0x3B,0x0A,S,"Read past beginning of medium"}, + {0x3B,0x0B,S,"Position past end of medium"}, + {0x3B,0x0C,S,"Position past beginning of medium"}, + {0x3B,0x0D,M,"Medium destination element full"}, + {0x3B,0x0E,M,"Medium source element empty"}, + {0x3D,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid bits in identify message"}, + {0x3E,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit has not self-configured yet"}, + {0x3F,0x00,D|T|L|P|W|R|S|O|M|C,"Target operating conditions have changed"}, + {0x3F,0x01,D|T|L|P|W|R|S|O|M|C,"Microcode has been changed"}, + {0x3F,0x02,D|T|L|P|W|R|S|O|M|C,"Changed operating definition"}, + {0x3F,0x03,D|T|L|P|W|R|S|O|M|C,"Inquiry data has changed"}, + {0x43,0x00,D|T|L|P|W|R|S|O|M|C,"Message error"}, + {0x44,0x00,D|T|L|P|W|R|S|O|M|C,"Internal target failure"}, + {0x45,0x00,D|T|L|P|W|R|S|O|M|C,"Select or reselect failure"}, + {0x46,0x00,D|T|L|P|W|R|S|O|M|C,"Unsuccessful soft reset"}, + {0x47,0x00,D|T|L|P|W|R|S|O|M|C,"Scsi parity error"}, + {0x48,0x00,D|T|L|P|W|R|S|O|M|C,"Initiator detected error message received"}, + {0x49,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid message error"}, + {0x4A,0x00,D|T|L|P|W|R|S|O|M|C,"Command phase error"}, + {0x4B,0x00,D|T|L|P|W|R|S|O|M|C,"Data phase error"}, + {0x4C,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit failed self-configuration"}, + {0x4E,0x00,D|T|L|P|W|R|S|O|M|C,"Overlapped commands attempted"}, + {0x50,0x00,T,"Write append error"}, + {0x50,0x01,T,"Write append position error"}, + {0x50,0x02,T,"Position error related to timing"}, + {0x51,0x00,T|O,"Erase failure"}, + {0x52,0x00,T,"Cartridge fault"}, + {0x53,0x00,D|T|L|W|R|S|O|M,"Media load or eject failed"}, + {0x53,0x01,T,"Unload tape failure"}, + {0x53,0x02,D|T|W|R|O|M,"Medium removal prevented"}, + {0x54,0x00,P,"Scsi to host system interface failure"}, + {0x55,0x00,P,"System resource failure"}, + {0x57,0x00,R,"Unable to recover table-of-contents"}, + {0x58,0x00,O,"Generation does not exist"}, + {0x59,0x00,O,"Updated block read"}, + {0x5A,0x00,D|T|L|P|W|R|S|O|M,"Operator request or state change input (unspecified)"}, + {0x5A,0x01,D|T|W|R|O|M,"Operator medium removal request"}, + {0x5A,0x02,D|T|W|O,"Operator selected write protect"}, + {0x5A,0x03,D|T|W|O,"Operator selected write permit"}, + {0x5B,0x00,D|T|L|P|W|R|S|O|M,"Log exception"}, + {0x5B,0x01,D|T|L|P|W|R|S|O|M,"Threshold condition met"}, + {0x5B,0x02,D|T|L|P|W|R|S|O|M,"Log counter at maximum"}, + {0x5B,0x03,D|T|L|P|W|R|S|O|M,"Log list codes exhausted"}, + {0x5C,0x00,D|O,"Rpl status change"}, + {0x5C,0x01,D|O,"Spindles synchronized"}, + {0x5C,0x02,D|O,"Spindles not synchronized"}, + {0x60,0x00,S,"Lamp failure"}, + {0x61,0x00,S,"Video acquisition error"}, + {0x61,0x01,S,"Unable to acquire video"}, + {0x61,0x02,S,"Out of focus"}, + {0x62,0x00,S,"Scan head positioning error"}, + {0x63,0x00,R,"End of user area encountered on this track"}, + {0x64,0x00,R,"Illegal mode for this track"}, + {0, 0, 0, NULL} +}; + +static const char *snstext[] = { + "None", /* There is no sense information */ + "Recovered Error", /* The last command completed successfully + but used error correction */ + "Not Ready", /* The addressed target is not ready */ + "Medium Error", /* Data error detected on the medium */ + "Hardware Error", /* Controller or device failure */ + "Illegal Request", + "Unit Attention", /* Removable medium was changed, or + the target has been reset */ + "Data Protect", /* Access to the data is blocked */ + "Blank Check", /* Reached unexpected written or unwritten + region of the medium */ + "Key=9", /* Vendor specific */ + "Copy Aborted", /* COPY or COMPARE was aborted */ + "Aborted Command", /* The target aborted the command */ + "Equal", /* A SEARCH DATA command found data equal */ + "Volume Overflow", /* Medium full with still data to be written */ + "Miscompare", /* Source data and data on the medium + do not agree */ + "Key=15" /* Reserved */ +}; + +/* Print sense information */ +void sg_print_sense(const char * leadin, const unsigned char * sense_buffer, + int sb_len) +{ + int i, s; + int sense_class, valid, code; + const char * error = NULL; + + sense_class = (sense_buffer[0] >> 4) & 0x07; + code = sense_buffer[0] & 0xf; + valid = sense_buffer[0] & 0x80; + + if (sense_class == 7) { /* extended sense data */ + s = sense_buffer[7] + 8; + if(s > sb_len) + s = sb_len; + + if (!valid) + fprintf(OUTP, "[valid=0] "); + fprintf(OUTP, "Info fld=0x%x, ", (int)((sense_buffer[3] << 24) | + (sense_buffer[4] << 16) | (sense_buffer[5] << 8) | + sense_buffer[6])); + + if (sense_buffer[2] & 0x80) + fprintf(OUTP, "FMK "); /* current command has read a filemark */ + if (sense_buffer[2] & 0x40) + fprintf(OUTP, "EOM "); /* end-of-medium condition exists */ + if (sense_buffer[2] & 0x20) + fprintf(OUTP, "ILI "); /* incorrect block length requested */ + + switch (code) { + case 0x0: + error = "Current"; /* error concerns current command */ + break; + case 0x1: + error = "Deferred"; /* error concerns some earlier command */ + /* e.g., an earlier write to disk cache succeeded, but + now the disk discovers that it cannot write the data */ + break; + default: + error = "Invalid"; + } + + fprintf(OUTP, "%s ", error); + + if (leadin) + fprintf(OUTP, "%s: ", leadin); + fprintf(OUTP, "sense key: %s\n", snstext[sense_buffer[2] & 0x0f]); + + /* Check to see if additional sense information is available */ + if(sense_buffer[7] + 7 < 13 || + (sense_buffer[12] == 0 && sense_buffer[13] == 0)) goto done; + + for(i=0; additional[i].text; i++) + if(additional[i].code1 == sense_buffer[12] && + additional[i].code2 == sense_buffer[13]) + fprintf(OUTP, "Additional sense indicates: %s\n", + additional[i].text); + + for(i=0; additional2[i].text; i++) + if(additional2[i].code1 == sense_buffer[12] && + additional2[i].code2_min >= sense_buffer[13] && + additional2[i].code2_max <= sense_buffer[13]) { + fprintf(OUTP, "Additional sense indicates: "); + fprintf(OUTP, additional2[i].text, sense_buffer[13]); + fprintf(OUTP, "\n"); + }; + } else { /* non-extended sense data */ + + /* + * Standard says: + * sense_buffer[0] & 0200 : address valid + * sense_buffer[0] & 0177 : vendor-specific error code + * sense_buffer[1] & 0340 : vendor-specific + * sense_buffer[1..3] : 21-bit logical block address + */ + + if (leadin) + fprintf(OUTP, "%s: ", leadin); + if (sense_buffer[0] < 15) + fprintf(OUTP, + "old sense: key %s\n", snstext[sense_buffer[0] & 0x0f]); + else + fprintf(OUTP, "sns = %2x %2x\n", sense_buffer[0], sense_buffer[2]); + + fprintf(OUTP, "Non-extended sense class %d code 0x%0x ", + sense_class, code); + s = 4; + } + + done: + fprintf(OUTP, "Raw sense data (in hex):\n "); + for (i = 0; i < s; ++i) { + if ((i > 0) && (0 == (i % 24))) + fprintf(OUTP, "\n "); + fprintf(OUTP, "%02x ", sense_buffer[i]); + } + fprintf(OUTP, "\n"); + return; +} + +static const char * hostbyte_table[]={ +"DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", +"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", +"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL}; + +void sg_print_host_status(int host_status) +{ static int maxcode=0; + int i; + + if(! maxcode) { + for(i = 0; hostbyte_table[i]; i++) ; + maxcode = i-1; + } + fprintf(OUTP, "Host_status=0x%02x", host_status); + if(host_status > maxcode) { + fprintf(OUTP, "is invalid "); + return; + } + fprintf(OUTP, "(%s) ",hostbyte_table[host_status]); +} + +static const char * driverbyte_table[]={ +"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", +"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE", NULL}; + +static const char * driversuggest_table[]={"SUGGEST_OK", +"SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE", +unknown,unknown,unknown, "SUGGEST_SENSE",NULL}; + + +void sg_print_driver_status(int driver_status) +{ + static int driver_max =0 , suggest_max=0; + int i; + int dr = driver_status & SG_ERR_DRIVER_MASK; + int su = (driver_status & SG_ERR_SUGGEST_MASK) >> 4; + + if(! driver_max) { + for(i = 0; driverbyte_table[i]; i++) ; + driver_max = i; + for(i = 0; driversuggest_table[i]; i++) ; + suggest_max = i; + } + fprintf(OUTP, "Driver_status=0x%02x",driver_status); + fprintf(OUTP, " (%s,%s) ", + dr < driver_max ? driverbyte_table[dr]:"invalid", + su < suggest_max ? driversuggest_table[su]:"invalid"); +} + +#ifdef SG_IO +int sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp) +{ + return sg_chk_n_print(leadin, hp->masked_status, hp->host_status, + hp->driver_status, hp->sbp, hp->sb_len_wr); +} +#endif + +int sg_chk_n_print(const char * leadin, int masked_status, + int host_status, int driver_status, + const unsigned char * sense_buffer, int sb_len) +{ + int done_leadin = 0; + int done_sense = 0; + + if ((0 == masked_status) && (0 == host_status) && + (0 == driver_status)) + return 1; /* No problems */ + if (0 != masked_status) { + if (leadin) + fprintf(OUTP, "%s: ", leadin); + done_leadin = 1; + sg_print_status(masked_status); + fprintf(OUTP, "\n"); + if (sense_buffer && ((masked_status == CHECK_CONDITION) || + (masked_status == COMMAND_TERMINATED))) { + sg_print_sense(0, sense_buffer, sb_len); + done_sense = 1; + } + } + if (0 != host_status) { + if (leadin && (! done_leadin)) + fprintf(OUTP, "%s: ", leadin); + if (done_leadin) + fprintf(OUTP, "plus...: "); + else + done_leadin = 1; + sg_print_host_status(host_status); + fprintf(OUTP, "\n"); + } + if (0 != driver_status) { + if (leadin && (! done_leadin)) + fprintf(OUTP, "%s: ", leadin); + if (done_leadin) + fprintf(OUTP, "plus...: "); + else + done_leadin = 1; + sg_print_driver_status(driver_status); + fprintf(OUTP, "\n"); + if (sense_buffer && (! done_sense) && + (SG_ERR_DRIVER_SENSE & driver_status)) + sg_print_sense(0, sense_buffer, sb_len); + } + return 0; +} + +#ifdef SG_IO +int sg_err_category3(struct sg_io_hdr * hp) +{ + return sg_err_category(hp->masked_status, hp->host_status, + hp->driver_status, hp->sbp, hp->sb_len_wr); +} +#endif + +int sg_err_category(int masked_status, int host_status, + int driver_status, const unsigned char * sense_buffer, + int sb_len) +{ + if ((0 == masked_status) && (0 == host_status) && + (0 == driver_status)) + return SG_ERR_CAT_CLEAN; + if ((CHECK_CONDITION == masked_status) || + (COMMAND_TERMINATED == masked_status) || + (SG_ERR_DRIVER_SENSE & driver_status)) { + if (sense_buffer && (sb_len > 2)) { + if(RECOVERED_ERROR == sense_buffer[2]) + return SG_ERR_CAT_RECOVERED; + else if ((UNIT_ATTENTION == (0x0f & sense_buffer[2])) && + (sb_len > 12)) { + if (0x28 == sense_buffer[12]) + return SG_ERR_CAT_MEDIA_CHANGED; + if (0x29 == sense_buffer[12]) + return SG_ERR_CAT_RESET; + } + } + return SG_ERR_CAT_SENSE; + } + if (0 != host_status) { + if ((SG_ERR_DID_NO_CONNECT == host_status) || + (SG_ERR_DID_BUS_BUSY == host_status) || + (SG_ERR_DID_TIME_OUT == host_status)) + return SG_ERR_CAT_TIMEOUT; + } + if (0 != driver_status) { + if (SG_ERR_DRIVER_TIMEOUT == driver_status) + return SG_ERR_CAT_TIMEOUT; + } + return SG_ERR_CAT_OTHER; +} + +int sg_get_command_size(unsigned char opcode) +{ + return COMMAND_SIZE(opcode); +} diff --git a/sg_err.h b/sg_err.h new file mode 100644 index 0000000..fd59e3b --- /dev/null +++ b/sg_err.h @@ -0,0 +1,140 @@ +#ifndef SG_ERR_H +#define SG_ERR_H + +/* Feel free to copy and modify this GPL-ed code into your applications. */ + +/* Version 0.84 (20010115) + - all output now sent to stderr rather thatn stdout + - remove header files included in this file +*/ + + +/* Some of the following error/status codes are exchanged between the + various layers of the SCSI sub-system in Linux and should never + reach the user. They are placed here for completeness. What appears + here is copied from drivers/scsi/scsi.h which is not visible in + the user space. */ + +/* The following are 'host_status' codes */ +#ifndef DID_OK +#define DID_OK 0x00 +#endif +#ifndef DID_NO_CONNECT +#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ +#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ +#define DID_TIME_OUT 0x03 /* Timed out for some other reason */ +#define DID_BAD_TARGET 0x04 /* Bad target (id?) */ +#define DID_ABORT 0x05 /* Told to abort for some other reason */ +#define DID_PARITY 0x06 /* Parity error (on SCSI bus) */ +#define DID_ERROR 0x07 /* Internal error */ +#define DID_RESET 0x08 /* Reset by somebody */ +#define DID_BAD_INTR 0x09 /* Received an unexpected interrupt */ +#define DID_PASSTHROUGH 0x0a /* Force command past mid-level */ +#define DID_SOFT_ERROR 0x0b /* The low-level driver wants a retry */ +#endif + +/* These defines are to isolate applictaions from kernel define changes */ +#define SG_ERR_DID_OK DID_OK +#define SG_ERR_DID_NO_CONNECT DID_NO_CONNECT +#define SG_ERR_DID_BUS_BUSY DID_BUS_BUSY +#define SG_ERR_DID_TIME_OUT DID_TIME_OUT +#define SG_ERR_DID_BAD_TARGET DID_BAD_TARGET +#define SG_ERR_DID_ABORT DID_ABORT +#define SG_ERR_DID_PARITY DID_PARITY +#define SG_ERR_DID_ERROR DID_ERROR +#define SG_ERR_DID_RESET DID_RESET +#define SG_ERR_DID_BAD_INTR DID_BAD_INTR +#define SG_ERR_DID_PASSTHROUGH DID_PASSTHROUGH +#define SG_ERR_DID_SOFT_ERROR DID_SOFT_ERROR + +/* The following are 'driver_status' codes */ +#ifndef DRIVER_OK +#define DRIVER_OK 0x00 +#endif +#ifndef DRIVER_BUSY +#define DRIVER_BUSY 0x01 +#define DRIVER_SOFT 0x02 +#define DRIVER_MEDIA 0x03 +#define DRIVER_ERROR 0x04 +#define DRIVER_INVALID 0x05 +#define DRIVER_TIMEOUT 0x06 +#define DRIVER_HARD 0x07 +#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ + +/* Following "suggests" are "or-ed" with one of previous 8 entries */ +#define SUGGEST_RETRY 0x10 +#define SUGGEST_ABORT 0x20 +#define SUGGEST_REMAP 0x30 +#define SUGGEST_DIE 0x40 +#define SUGGEST_SENSE 0x80 +#define SUGGEST_IS_OK 0xff +#endif +#ifndef DRIVER_MASK +#define DRIVER_MASK 0x0f +#endif +#ifndef SUGGEST_MASK +#define SUGGEST_MASK 0xf0 +#endif + +/* These defines are to isolate applictaions from kernel define changes */ +#define SG_ERR_DRIVER_OK DRIVER_OK +#define SG_ERR_DRIVER_BUSY DRIVER_BUSY +#define SG_ERR_DRIVER_SOFT DRIVER_SOFT +#define SG_ERR_DRIVER_MEDIA DRIVER_MEDIA +#define SG_ERR_DRIVER_ERROR DRIVER_ERROR +#define SG_ERR_DRIVER_INVALID DRIVER_INVALID +#define SG_ERR_DRIVER_TIMEOUT DRIVER_TIMEOUT +#define SG_ERR_DRIVER_HARD DRIVER_HARD +#define SG_ERR_DRIVER_SENSE DRIVER_SENSE +#define SG_ERR_SUGGEST_RETRY SUGGEST_RETRY +#define SG_ERR_SUGGEST_ABORT SUGGEST_ABORT +#define SG_ERR_SUGGEST_REMAP SUGGEST_REMAP +#define SG_ERR_SUGGEST_DIE SUGGEST_DIE +#define SG_ERR_SUGGEST_SENSE SUGGEST_SENSE +#define SG_ERR_SUGGEST_IS_OK SUGGEST_IS_OK +#define SG_ERR_DRIVER_MASK DRIVER_MASK +#define SG_ERR_SUGGEST_MASK SUGGEST_MASK + + + +/* The following "print" functions send ACSII to stdout */ +extern void sg_print_command(const unsigned char * command); +extern void sg_print_sense(const char * leadin, + const unsigned char * sense_buffer, int sb_len); +extern void sg_print_status(int masked_status); +extern void sg_print_host_status(int host_status); +extern void sg_print_driver_status(int driver_status); + +/* sg_chk_n_print() returns 1 quietly if there are no errors/warnings + else it prints to standard output and returns 0. */ +extern int sg_chk_n_print(const char * leadin, int masked_status, + int host_status, int driver_status, + const unsigned char * sense_buffer, int sb_len); + +/* The following function declaration is for the sg version 3 driver. + Only version 3 sg_err.c defines it. */ +struct sg_io_hdr; +extern int sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp); + + +/* The following "category" function returns one of the following */ +#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */ +#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ +#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ +#define SG_ERR_CAT_TIMEOUT 3 +#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ +#define SG_ERR_CAT_SENSE 98 /* Something else is in the sense buffer */ +#define SG_ERR_CAT_OTHER 99 /* Some other error/warning has occurred */ + +extern int sg_err_category(int masked_status, int host_status, + int driver_status, const unsigned char * sense_buffer, + int sb_len); + +/* The following function declaration is for the sg version 3 driver. + Only version 3 sg_err.c defines it. */ +extern int sg_err_category3(struct sg_io_hdr * hp); + +/* Returns length of SCSI command given the opcode (first byte) */ +int sg_get_command_size(unsigned char opcode); + +#endif diff --git a/tapeinfo.1 b/tapeinfo.1 new file mode 100644 index 0000000..653042f --- /dev/null +++ b/tapeinfo.1 @@ -0,0 +1,72 @@ +.\" tapeinfo.1 Document copyright 2000 Eric Lee Green +.\" Program Copyright 2000 Eric Lee Green +.\" Copyright 2007-2008 by Robert Nelson +.\" +.\" This is free documentation; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License as +.\" published by the Free Software Foundation; either version 2 of +.\" the License, or (at your option) any later version. +.\" +.\" The GNU General Public License's references to "object code" +.\" and "executables" are to be interpreted as the output of any +.\" document formatting or typesetting system, including +.\" intermediate and printed output. +.\" +.\" This manual is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public +.\" License along with this manual; if not, write to the Free +.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +.\" USA. +.\" +.TH TAPEINFO 1 TAPEINFO1.0 +.SH NAME +tapeinfo \- report SCSI tape device info +.SH SYNOPSIS +tapeinfo -f +.SH DESCRIPTION +The +.B tapeinfo +command reads various information from SCSI tape drives that is not +generally available via most vendors' tape drivers. It issues raw +commands directly to the tape drive, using either the operating system's +SCSI generic device ( e.g. /dev/sg0 on Linux, /dev/pass0 on FreeBSD) or +the raw SCSI I/O ioctl on a tape device on some operating systems. +.P +One good time to use 'tapeinfo' is immediately after a tape i/o operation has +failed. On tape drives that support HP's 'tapealert' API, 'tapeinfo' will +report a more exact description of what went wrong. +.P +Do be aware that 'tapeinfo' is not a substitute for your operating system's +own 'mt' or similar tape driver control program. It is intended to supplement, +not replace, programs like 'mt' that access your operating system's tape +driver in order to report or set information. +.SH OPTIONS +The first argument, given following +.B -f +, is the SCSI generic device corresponding to your tape drive. +Consult your operating system's documentation for more information (for +example, under Linux these are generally start at /dev/sg0 +under FreeBSD these start at /dev/pass0). +.P +Under FreeBSD, 'camcontrol devlist' will tell you what SCSI devices you +have, along with which 'pass' device controls them. Under Linux, +"cat /proc/scsi/scsi" will tell you what SCSI devices you have. + +.SH BUGS AND LIMITATIONS +.P +This program has only been tested on Linux with a limited number of +tape drives (HP DDS4, Seagate AIT). +.P +.SH AVAILABILITY +.B tapeinfo +is currently being maintained by Robert Nelson +as part of the 'mtx' suite of programs. The 'mtx' home page is +http://mtx.sourceforge.net and the actual code is currently available there and via +SVN from http://sourceforge.net/projects/mtx. + +.SH SEE ALSO +.BR mt (1), mtx (1), scsitape (1), scsieject (1), loaderinfo (1) diff --git a/tapeinfo.c b/tapeinfo.c new file mode 100644 index 0000000..1a5a0cb --- /dev/null +++ b/tapeinfo.c @@ -0,0 +1,969 @@ +/* Copyright 2000 Enhanced Software Technologies Inc. + * Copyright 2007-2008 by Robert Nelson + * Released under terms of the GNU General Public License as + * required by the license on 'mtxl.c'. + * $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ + * $Revision: 193 $ + */ + +/*#define DEBUG_PARTITION */ +/*#define DEBUG 1 */ + +/* What this does: This basically dumps out the contents of the following + * pages: + * + * Inquiry -- prints full inquiry info. If it's not a tape drive, this is + * the end of things. + * DeviceType: + * Manufacturer: + * ProdID: + * ProdRevision: + * + * Log Sense: TapeAlert Page (if supported): + * TapeAlert:[message#] e.g. "TapeAlert:[22]Cleaning Cartridge Worn Out" + * + * Mode Sense: + * Data Compression Page: + * DataCompEnabled: + * DataCompCapable: + * DataDeCompEnabled: + * CompType: + * DeCompType: + * + * Device Configuration Page: + * ActivePartition:<#> + * DevConfigComp:<#> -- the compression byte in device config page. + * EarlyWarningSize:<#> -- size of early warning buffer? + * + * Medium Partition Page: + * NumPartitions:<#> + * MaxPartitions:<#> + * Partition[0]: + * Partition[1]:... + * + * Read Block Limits command: + * MinBlock:<#> -- Minimum block size. + * MaxBlock:<#> -- Maximum block size. + */ + +#include +#include +#include "mtx.h" +#include "mtxl.h" + +char *argv0; + +void usage(void) +{ + FatalError("Usage: tapeinfo -f \n"); +} + +/* A table for printing out the peripheral device type as ASCII. */ +static char *PeripheralDeviceType[32] = +{ + "Disk Drive", + "Tape Drive", + "Printer", + "Processor", + "Write-once", + "CD-ROM", + "Scanner", + "Optical", + "Medium Changer", + "Communications", + "ASC IT8", + "ASC IT8", + "RAID Array", + "Enclosure Services", + "OCR/W", + "Bridging Expander", /* 0x10 */ + "Reserved", /* 0x11 */ + "Reserved", /* 0x12 */ + "Reserved", /* 0x13 */ + "Reserved", /* 0x14 */ + "Reserved", /* 0x15 */ + "Reserved", /* 0x16 */ + "Reserved", /* 0x17 */ + "Reserved", /* 0x18 */ + "Reserved", /* 0x19 */ + "Reserved", /* 0x1a */ + "Reserved", /* 0x1b */ + "Reserved", /* 0x1c */ + "Reserved", /* 0x1d */ + "Reserved", /* 0x1e */ + "Unknown" /* 0x1f */ +}; + + + +/* we call it MediumChangerFD for history reasons, sigh. */ + +/* now to print inquiry information: Copied from other one.... */ + +static void ReportInquiry(DEVICE_TYPE MediumChangerFD) +{ + RequestSense_T RequestSense; + Inquiry_T *Inquiry; + int i; + + Inquiry = RequestInquiry(MediumChangerFD, &RequestSense); + if (Inquiry == NULL) + { + PrintRequestSense(&RequestSense); + FatalError("INQUIRY Command Failed\n"); + } + + printf("Product Type: %s\n", PeripheralDeviceType[Inquiry->PeripheralDeviceType]); + + printf("Vendor ID: '"); + for (i = 0; i < sizeof(Inquiry->VendorIdentification); i++) + printf("%c", Inquiry->VendorIdentification[i]); + + printf("'\nProduct ID: '"); + for (i = 0; i < sizeof(Inquiry->ProductIdentification); i++) + printf("%c", Inquiry->ProductIdentification[i]); + + printf("'\nRevision: '"); + for (i = 0; i < sizeof(Inquiry->ProductRevisionLevel); i++) + printf("%c", Inquiry->ProductRevisionLevel[i]); + printf("'\n"); + + if (Inquiry->MChngr) + { + /* check the attached-media-changer bit... */ + printf("Attached Changer API: Yes\n"); + } + else + { + printf("Attached Changer API: No\n"); + } + + free(Inquiry); /* well, we're about to exit, but ... */ +} + + + + +/* Okay, now for the Log Sense Tape Alert Page (if supported): */ +#define TAPEALERT_SIZE 2048 /* max size of tapealert buffer. */ +#define MAX_TAPE_ALERT 0x41 + +static char *tapealert_messages[] = +{ + "Undefined", /* 0 */ + " Read: Having problems reading (slowing down)", /* 1 */ + " Write: Having problems writing (losing capacity)", /* 2 */ + " Hard Error: Uncorrectable read/write error", /* 3 */ + " Media: Media Performance Degraded, Data Is At Risk", /* 4 */ + " Read Failure: Tape faulty or tape drive broken", /* 5 */ + "Write Failure: Tape faulty or tape drive broken", /* 6 */ + " Media Life: The tape has reached the end of its useful life", /* 7 */ + "Not Data Grade:Replace cartridge with one containing data grade tape",/*8*/ + "Write Protect: Attempted to write to a write-protected cartridge",/*9 */ + " No Removal: Cannot unload, initiator is preventing media removal", /*a*/ + "Cleaning Media:Cannot back up or restore to a cleaning cartridge", /* b */ + " Bad Format: The loaded tape contains data in an unsupported format", /*c */ + " Snapped Tape: The data cartridge contains a broken tape", /* d */ + "Undefined", /* e */ + "Undefined", /* f */ + "Undefined", /* 10 */ + "Undefined", /* 11 */ + "Undefined", /* 12 */ + "Undefined", /* 13 */ + " Clean Now: The tape drive neads cleaning NOW", /* 0x14 */ + "Clean Periodic:The tape drive needs to be cleaned at next opportunity", /* 0x15 */ + "Cleaning Media:Cannot clean because cleaning cartridge used up, insert new cleaning cartridge to clean the drive", /* 0x16 */ + "Undefined", /* 0x17 */ + "Undefined", /* 0x18 */ + "Undefined", /* 0x19 */ + "Undefined", /* 0x1a */ + "Undefined", /* 0x1b */ + "Undefined", /* 0x1c */ + "Undefined", /* 0x1d */ + " Hardware A: Tape drive has a problem not read/write related", /* 0x1e */ + " Hardware B: Tape drive has a problem not read/write related", /* 0x1f */ + " Interface: Problem with SCSI interface between tape drive and initiator", /* 0x20 */ + " Eject Media: The current operation has failed. Eject and reload media", /* 0x21 */ + "Download Fail: Attempt to download new firmware failed", /* 0x22 */ + "Undefined", /* 0x23 */ + "Undefined", /* 0x24 */ + "Undefined", /* 0x25 */ + "Undefined", /* 0x26 */ + "Undefined", /* 0x27 */ + "Loader Hardware A: Changer having problems communicating with tape drive", /* 0x28 40 */ + "Loader Stray Tape: Stray tape left in drive from prior error", /* 0x29 41 */ + "Loader Hardware B: Autoloader mechanism has a fault", /* 0x2a 42 */ + " Loader Door: Loader door is open, please close it", /* 0x2b 43 */ + "Undefined", /* 0x2c */ + "Undefined", /* 0x2d */ + "Undefined", /* 0x2e */ + "Undefined", /* 0x2f */ + "Undefined", /* 0x30 */ + "Undefined", /* 0x31 */ + "Undefined", /* 0x32 */ + "Undefined", /* 0x33 */ + "Undefined", /* 0x34 */ + "Undefined", /* 0x35 */ + "Undefined", /* 0x36 */ + "Undefined", /* 0x37 */ + "Undefined", /* 0x38 */ + "Undefined", /* 0x39 */ + "Undefined", /* 0x3a */ + "Undefined", /* 0x3b */ + "Undefined", /* 0x3c */ + "Undefined", /* 0x3d */ + "Undefined", /* 0x3e */ + "Undefined", /* 0x3f */ + "Undefined" /* 0x40 */ +}; + +typedef struct TapeCapacityStruct +{ + unsigned int partition0_remaining; + unsigned int partition1_remaining; + unsigned int partition0_size; + unsigned int partition1_size; +} TapeCapacity; + +#if defined(DEBUG) +/* DEBUG */ +static void dump_data(unsigned char *data, int len) +{ + if (len != 0) + { + fprintf(stderr,"DATA:"); + PrintHex(1, data, len); + } + else + { + fprintf(stderr, "**NO DATA**\n"); + } +} +#endif + + +/* Request the tape capacity page defined by some DAT autoloaders. */ + +static TapeCapacity *RequestTapeCapacity(DEVICE_TYPE fd, RequestSense_T *sense) +{ + CDB_T CDB; + TapeCapacity *result; + int result_len; + + unsigned char buffer[TAPEALERT_SIZE]; /* Overkill, but ... */ + + slow_bzero((char *)buffer,TAPEALERT_SIZE); /*zero it... */ + + /* now to create the CDB block: */ + CDB[0] = 0x4d; /* Log Sense */ + CDB[1] = 0; + CDB[2] = 0x31; /* Tape Capacity Page. */ + CDB[3] = 0; + CDB[4] = 0; + CDB[5] = 0; + CDB[6] = 0; + CDB[7] = TAPEALERT_SIZE >> 8 & 0xff; /* hi byte, allocation size */ + CDB[8] = TAPEALERT_SIZE & 0xff; /* lo byte, allocation size */ + CDB[9] = 0; /* reserved */ + + if (SCSI_ExecuteCommand(fd, Input, &CDB, 10, buffer, TAPEALERT_SIZE, sense) != 0) + { + /* fprintf(stderr,"RequestTapeCapacity: Command failed: Log Sense\n"); */ + return NULL; + } + + /* dump_data(buffer,64); */ + + /* okay, we have stuff in the result buffer: the first 4 bytes are a header: + * byte 0 should be 0x31, byte 1 == 0, bytes 2,3 tell how long the + * log page is. + */ + if ((buffer[0]&0x3f) != 0x31) + { + /* fprintf(stderr,"RequestTapeCapacity: Invalid header for page (not 0x31).\n"); */ + return NULL; + } + + result_len = ((int)buffer[2] << 8) + buffer[3]; + + if (result_len != 32) + { + /* fprintf(stderr,"RequestTapeCapacity: Page was %d bytes long, not 32 bytes\n",result_len); */ + return NULL; /* This Is Not The Page You're Looking For */ + } + + result = xmalloc(sizeof(TapeCapacity)); + + /* okay, now allocate data and move the buffer over there: */ + + /* 0 1 2 3 4 5 6 7 8 9 + DATA: 31 00 00 20 00 01 4c 04 01 3a + 10 11 12 13 14 15 16 17 18 19 + DATA: 81 0c 00 02 4c 04 00 00 00 00 + 20 21 22 23 24 25 26 27 28 29 + DATA: 00 03 4c 04 01 3f 4b 1f 00 04 + 30 31 32 33 34 35 + DATA: 4c 04 00 00 00 00 00 00 00 00 + DATA: 00 00 00 00 00 00 00 00 00 00 + DATA: 00 00 00 00 00 00 00 00 00 00 + DATA: 00 00 00 00 + */ + + result->partition0_remaining = + ((unsigned int)buffer[8] << 24) + + ((unsigned int)buffer[9] << 16) + + ((unsigned int)buffer[10] << 8) + + buffer[11]; + + result->partition1_remaining = + ((unsigned int)buffer[16] << 24) + + ((unsigned int)buffer[17] << 16) + + ((unsigned int)buffer[18] << 8) + + buffer[19]; + + result->partition0_size = + ((unsigned int)buffer[24] << 24) + + ((unsigned int)buffer[25] << 16) + + ((unsigned int)buffer[26] << 8) + + buffer[27]; + + result->partition1_size = + ((unsigned int)buffer[32] << 24) + + ((unsigned int)buffer[33] << 16) + + ((unsigned int)buffer[34] << 8) + + buffer[35]; + + return result; +} + + + +struct tapealert_struct +{ + int length; + unsigned char *data; +}; + +static struct tapealert_struct *RequestTapeAlert(DEVICE_TYPE fd, RequestSense_T *sense) +{ + CDB_T CDB; + + struct tapealert_struct *result; + int i, tapealert_len, result_idx; + + unsigned char buffer[TAPEALERT_SIZE]; + unsigned char *walkptr; + + slow_bzero((char *)buffer, TAPEALERT_SIZE); /*zero it... */ + + /* now to create the CDB block: */ + CDB[0] = 0x4d; /* Log Sense */ + CDB[1] = 0; + CDB[2] = 0x2e; /* Tape Alert Page. */ + CDB[3] = 0; + CDB[4] = 0; + CDB[5] = 0; + CDB[6] = 0; + CDB[7] = TAPEALERT_SIZE >> 8 & 0xff; /* hi byte, allocation size */ + CDB[8] = TAPEALERT_SIZE & 0xff; /* lo byte, allocation size */ + CDB[9] = 0; /* reserved */ + + if (SCSI_ExecuteCommand(fd,Input,&CDB,10,buffer,TAPEALERT_SIZE,sense)!=0) + { + return NULL; + } + + result = xmalloc(sizeof(struct tapealert_struct)); + + /* okay, we have stuff in the result buffer: the first 4 bytes are a header: + * byte 0 should be 0x2e, byte 1 == 0, bytes 2,3 tell how long the + * tapealert page is. + */ + if ((buffer[0]&0x3f) != 0x2e) + { + result->data = NULL; + result->length = 0; + return result; + } + + tapealert_len = ((int)buffer[2] << 8) + buffer[3]; + + if (!tapealert_len) + { + result->length = 0; + result->data = NULL; + return result; + } + + /* okay, now allocate data and move the buffer over there: */ + result->length = MAX_TAPE_ALERT; + result->data = xzmalloc(MAX_TAPE_ALERT); /* alloc & zero. */ + + walkptr = &buffer[4]; + i = 0; + + while (i < tapealert_len) + { + result_idx=(((int)walkptr[0])<<8) + walkptr[1]; /* the parameter #. */ + if (result_idx > 0 && result_idx < MAX_TAPE_ALERT) + { + if (walkptr[4]) + { + result->data[result_idx] = 1; + } + else + { + result->data[result_idx] = 0; + } +#ifdef DEBUGOLD1 + fprintf(stderr,"Alert[0x%x]=%d\n",result_idx,result->data[result_idx]); + fflush(stderr); +#endif + } + else + { + FatalError("Invalid tapealert page: %d\n",result_idx); + } + + i = i + 4 + walkptr[3]; /* length byte! */ + walkptr = walkptr + 4 + walkptr[3]; /* next! */ + } + return result; +} + +static void ReportTapeCapacity(DEVICE_TYPE fd) +{ + /* we actually ignore a bad sense reading, like might happen if the + * tape drive does not support the tape capacity page. + */ + + RequestSense_T RequestSense; + + TapeCapacity *result; + + result=RequestTapeCapacity(fd,&RequestSense); + + if (!result) + return; + + printf("Partition 0 Remaining Kbytes: %d\n", result->partition0_remaining); + printf("Partition 0 Size in Kbytes: %d\n", result->partition0_size); + + if (result->partition1_size) + { + printf("Partition 1 Remaining Kbytes: %d\n", result->partition1_remaining); + printf("Partition 1 Size in Kbytes: %d\n", result->partition1_size); + } + + free(result); +} + + + +static void ReportTapeAlert(DEVICE_TYPE fd) +{ + /* we actually ignore a bad sense reading, like might happen if the + * tape drive does not support the tapealert page. + */ + + RequestSense_T RequestSense; + + struct tapealert_struct *result; + int i; + + result=RequestTapeAlert(fd,&RequestSense); + + if (!result) + return; /* sorry. Don't print sense here. */ + + if (!result->length) + return; /* sorry, no alerts valid. */ + + for (i = 0; i < result->length; i++) + { + if (result->data[i]) + { + printf("TapeAlert[%d]: %s.\n", i, tapealert_messages[i]); + } + } + + free(result->data); + free(result); +} + +static unsigned char +*mode_sense(DEVICE_TYPE fd, char pagenum, int alloc_len, RequestSense_T *RequestSense) +{ + CDB_T CDB; + + unsigned char *input_buffer; + unsigned char *tmp; + unsigned char *retval; + int i, pagelen; + + if (alloc_len > 255) + { + FatalError("mode_sense(6) can only read up to 255 characters!\n"); + } + + input_buffer = (unsigned char *)xzmalloc(256); /* overdo it, eh? */ + + /* clear the sense buffer: */ + slow_bzero((char *)RequestSense, sizeof(RequestSense_T)); + + /* returns an array of bytes in the page, or, if not possible, NULL. */ + CDB[0] = 0x1a; /* Mode Sense(6) */ + CDB[1] = 0; + CDB[2] = pagenum; /* the page to read. */ + CDB[3] = 0; + CDB[4] = 255; /* allocation length. This does max of 256 bytes! */ + CDB[5] = 0; + + if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, input_buffer, 255, RequestSense) != 0) + { +#ifdef DEBUG_MODE_SENSE + fprintf(stderr,"Could not execute mode sense...\n"); + fflush(stderr); +#endif + return NULL; /* sorry, couldn't do it. */ + } + + /* Oh hell, write protect is the only thing I have: always print + * it if our mode page was 0x0fh, before skipping past buffer: + * if the media is *NOT* write protected, just skip, sigh. + * + * Oh poops, the blocksize is reported in the block descriptor header + * < * too. Again, just print if our mode page was 0x0f... + */ + if (pagenum == 0x0f) + { + int blocklen; + + if (input_buffer[2] & 0x80) + { + printf("WriteProtect: yes\n"); + } + + if (input_buffer[2] & 0x70) + { + printf("BufferedMode: yes\n"); + } + + if (input_buffer[1] ) + { + printf("Medium Type: 0x%x\n", input_buffer[1]); + } + else + { + printf("Medium Type: Not Loaded\n"); + } + + printf("Density Code: 0x%x\n", input_buffer[4]); + /* Put out the block size: */ + + blocklen = ((int)input_buffer[9] << 16)+ + ((int)input_buffer[10] << 8)+ + input_buffer[11]; + + printf("BlockSize: %d\n", blocklen); + } + + /* First skip past any header.... */ + tmp = input_buffer + 4 + input_buffer[3]; + + /* now find out real length of page... */ + pagelen = tmp[1] + 2; + retval = xmalloc(pagelen); + + /* and copy our data to the new page. */ + for (i=0;i> 16); + CDB[3] = (unsigned char)(count >> 8); + CDB[4] = (unsigned char)count; + CDB[5] = 0; + + /* we really don't care if this command works or not, sigh. */ + slow_bzero((char *)&sense, sizeof(RequestSense_T)); + if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, buffer, 0, &sense) != 0) + { + return 1; + } + + return 0; +} + + +/* This will get the SCSI ID and LUN of the target device, if such + * is available from the OS. Currently only Linux supports this, + * but other drivers could, if someone wants to write a + * SCSI_GetIDLun function for them. + */ +#ifdef HAVE_GET_ID_LUN + +static void ReportIDLun(DEVICE_TYPE fd) +{ + scsi_id_t *scsi_id; + + scsi_id = SCSI_GetIDLun(fd); + printf("SCSI ID: %d\nSCSI LUN: %d\n", scsi_id->id, scsi_id->lun); +} + +#endif + +/* we only have one argument: "-f ". */ +int main(int argc, char **argv) +{ + DEVICE_TYPE fd; + char *filename; + + argv0=argv[0]; + + if (argc != 3) + { + fprintf(stderr,"argc=%d",argc); + usage(); + } + + if (strcmp(argv[1],"-f")!=0) + { + usage(); + } + filename=argv[2]; + + fd=SCSI_OpenDevice(filename); + + /* Now to call the various routines: */ + ReportInquiry(fd); + ReportSerialNumber(fd); + ReportTapeAlert(fd); + ReportBlockLimits(fd); + +#ifdef HAVE_GET_ID_LUN + ReportIDLun(fd); +#endif + + /* okay, we should only report position if the unit is ready :-(. */ + if (TestUnitReady(fd)) + { + ReportCompressionPage(fd); + ReadPosition(fd); + ReportTapeCapacity(fd); /* only if we have it */ + ReportConfigPage(fd); /* only valid if unit is ready. */ + ReportPartitionPage(fd); + } + + exit(0); +} diff --git a/vms/000readme b/vms/000readme new file mode 100644 index 0000000..854d58a --- /dev/null +++ b/vms/000readme @@ -0,0 +1,175 @@ +MTX -- SCSI Tape Attached Medium Changer Control Program + +Copyright 1997 by Leonard N. Zubkoff + +VMS port, April 1998, by TECSys Development, Inc. + +SECTION I - Disclaimer + + These programs / ports are distributed in the hopes that they + will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + While a significant amount of testing has been performed, and while + TDI believes that this utility is safe, ONLY YOU can make that + determination with respect to your environment. There are NO + GUARANTEES WHATSOEVER that use of this program will not CRASH + YOUR SYSTEM or worse. TDI disclaims any responsibility for any + losses or damages from the use of this program. + +SECTION II - MTX program + +***CAUTIONS*** + * Attempting to check the status of the drive with 1 tape manually + inserted in the drive, and no magazine results in an unexpected + SCSI status message. During porting of this program on a VS4000/90a, + it is believed that the handling of this status message caused + some sort of scsi state problem wherein subsequent accesses to + the changer from normal MKDRIVER activity resulted in SCSI bus + phase errors and an ultimate system failure. Power cycles of both + the drive and the host were required to rectify the problem. + +Instructions: + Read instructions (particularly section III below on the LDRSET utility). + Compile (DEC C) and link image, copy to an appropriate install location + Define a foreign symbol to access the program + Use UNIX syntax to operate program per documentation (MTX.DOC) + + A descrip.mms file is provided if you have MMS or MMK installed. + You can build everything from scratch by doing a MMK/FROM_SOURCE. This + includes the LDRSET utility described below. You should be in the mtx + root directory before you do this, NOT [.vms]. + + If you do not have or use MMS or MMK, I can highly recommend MMK as + a great tool. It is available from www.madgoat.com. If you still do + not have mmk or mms, a build.com is provided. Again, you should be in + the mtx root directory before you do this, NOT [.vms]. + + Note: If you are on an alpha, the mms[k]-built exe files will be called + .alpha_exe, not .exe. Adjust following instructions accordingly. + +Example: + $ MMS/DESCRIP=[.VMS] !Or MMK, or @[.VMS]BUILD + $ copy mtx.exe DISK$USERDISK:[USERS.FRED.UTILS]MTX + $ MTX:==$DISK$USERDISK:[USERS.FRED.UTILS]MTX.EXE + $ MTX -f MKA500 status + --or-- + $ DEFINE TAPE MKA500 + $ MTX status + +Notes: + * This code does NOT compile under VAX C... the only issue is VAX C's + incorrect assertion that a 'boolean' is not an acceptable "expression" + on either side of a || operator. If you are on VAX C - upgrade. If you + really must... then use a ((int)...) around the left-hand-side + of the lines where the compiler complains.... like so: + if (((int)StorageElementFull[FirstStorageElementNumber]) || + + * The following symbols result from 'status' or element movement commands: + MTX_DTE (Data Transfer Element) + FULL:n (Full, with element 'n'... if n=0, then unknown ele) + EMPTY + MTX_MSZ (Magazine SiZe) + n (Number of magazine slots) + MTX_STE01 thru MTX_STExx (STorage Element, Max is MTX_MSZ) + FULL + EMPTY + These will allow a DCL program to process the results + of the status command + + * PHY_IO and DIAGNOSE are required to run the program as it stands + today. Yes, the GKdriver dox say PHY_IO or LOG_IO.... MKdriver + thinks otherwise. It wins. + + * The program IS equipped to handle being installed with DIAGNOSE + and PHY_IO. A certain level of checking is done to see that the + right type of device is being targeted for the autoloader manipulation + SCSI commands. [see next item] + + * There is an indicator bit in DEVCHAR2 that indicates the presence of + a loader on a tape. Unfortunately, it appears that the "knowledge" of + whether a loader is present or not is hard-coded into mkdriver. This + means that if you don't have the magic DEC rom's in your Archive + loader, then the LDR bit is not set. This makes the LDR bit effectively + useless unless you want to write a kernel dinker program you could + run from startup to "fix" the DEVCHAR2 longword. (Incidentally, + if you ship the autoloader commands at a TZ30 (a non-loader drive), + the tz30 blows it off w/o any adverse side-effects - I would hope + that other drives are as tolerant.) + + Because of this misfeature, the code to check the LDR flag in DEVCHAR2 + is commented out. + + *See section below on LDRSET utility if you want to use this + feature anyway (recommended). + + * This program has been tested under: + VAX C V2.2, VAX/VMS 6.1, VS 4000/90A **with code modifications + DEC C V5.2, VAX/VMS 6.1, VS 4000/90A + DEC C V5.3, AXP/VMS 6.2, DEC3000-300X + + +SECTION III - LDRSET Utility + +Description: + This is a small KERNEL MODE utility program to go set or reset + the DEV$M_LDR flag in UCB$L_DEVCHAR2 for a specified device. While + a certain amount of checking is performed, and while the author + believes that this utility is safe, ONLY YOU can make that + determination with respect to your environment. There are NO + GUARANTEES WHATSOEVER that use of this program will not CRASH + YOUR SYSTEM or worse. TDI disclaims any responsibility for any + losses or damages from the use of this program. + + With all that said... this utility can be used [example: system + startup] to set the LDR flag for the autoloader tape device. + With the loader flag properly set, you can re-enable the LDR + check section in MTX and be fairly well certain that the MTX + utility will not be used against a drive that is not a SCSI + MAGTAPE with a LOADER attached. + +Instructions: + Compile (DEC C ***ONLY***) the LDRSET C program + + Alpha: + MACRO/MIGRATE the LDRUTIL.MAR program + LINK LDRSET,LDRUTIL/SYSEXE to generate the image + + Vax + MACRO the LDRUTIL.MAR program + LINK LDRSET,LDRUTIL to generate the image + + [NOTE!!! ---> DO NOT USE RESULTING IMAGE IF THERE ARE ANY COMPILE OR LINK + ERRORS!!!] + + Copy to an appropriate install location. + + Edit provided CLD file to reflect the installed location + + Use the following syntax: + $ SET COMMAND LDRSET + $ LDRSET MKA500: /SET !Sets the loader present flag on MKA500 + $ LDRSET MKA500: /RESET !Clears the loader present flag on MKA500 + +Alpha example: + $ CC/DECC/DEBUG/NOOPT LDRSET + $ MACRO/MIGRATE LDRUTIL + $ LINK LDRSET,LDRUTIL/SYSEXE + +Vax example: + $ CC/DECC/DEBUG/NOOPT LDRSET + $ MACRO LDRUTIL + $ LINK LDRSET,LDRUTIL + +Common: + $ copy LDRSET.EXE DISK$USERDISK:[USERS.FRED.UTILS]LDRSET.EXE + $ copy LDRSET.CLD DISK$USERDISK:[USERS.FRED.UTILS]LDRSET.CLD + $ EDIT DISK$USERDISK:[USERS.FRED.UTILS]LDRSET.CLD + ...change image sys$disk:[]ldrset line to : + image DISK$USERDISK:[USERS.FRED.UTILS]LDRSET.EXE + $ LDRSET MKA500 /SET + + * This program has been tested under: + DEC C V5.2, VAX/VMS 6.1, VS 4000/90A + DEC C V5.6, AXP/VMS 7.1, AS 1000A + diff --git a/vms/build.com b/vms/build.com new file mode 100644 index 0000000..2f6308d --- /dev/null +++ b/vms/build.com @@ -0,0 +1,34 @@ +$!x='f$ver(0) +$ if f$parse("[.VMS]A.A").eqs."" +$ then +$ write sys$output "?Error: Use $ @[.VMS]BUILD from the mtx directory" +$ exit 44 +$ endif +$ alpha = f$getsyi("hw_model").ge.1024 +$ vax = .not.alpha +$ exe = "EXE" +$ obj = "OBJ" +$ sysexe="" +$ migrate="" +$ if alpha then exe="ALPHA_EXE" +$ if alpha then obj="ALPHA_OBJ" +$ if alpha then sysexe="/SYSEXE" +$ if alpha then migrate="/MIGRATION/NOOPT" +$ set verify +$ if "''p1'".eqs."LINK" then goto do_link +$ CC /DECC/DEB/NOOP MTX.C/DEB/NOOP/OBJECT=MTX.'obj' +$ if f$search("MTX.''obj';-1").nes."" then - + purge/log MTX.'obj' +$ CC /DECC/DEB/NOOP [.VMS]LDRSET.C/DEB/NOOP/OBJECT=[.VMS]LDRSET.'obj' +$ if f$search("[.VMS]LDRSET.''obj';-1").nes."" then - + purge/log [.VMS]LDRSET.'obj' +$ MACRO'migrate' /DEB [.VMS]LDRUTIL.MAR - + /OBJECT=[.VMS]LDRUTIL.'obj' +$ if f$search("[.VMS]LDRUTIL.''obj';-1").nes."" then - + purge/log [.VMS]LDRUTIL.'obj' +$! +$ do_link: +$ link/notrace mtx.'obj'/exe=mtx.'exe' +$ link [.vms]ldrset.'obj',[.vms]ldrutil.'obj' - + /exe=ldrset.'exe' 'sysexe' +$ exit diff --git a/vms/defs.h b/vms/defs.h new file mode 100644 index 0000000..68dd7d7 --- /dev/null +++ b/vms/defs.h @@ -0,0 +1,42 @@ +#ifdef __DECC +#pragma module MTX "V01-00" +#else +#module MTX "V01-00" +#endif + +typedef int DEVICE_TYPE; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__DECC) +#pragma member_alignment save +#pragma nomember_alignment +#endif + +/* + Define either of the following symbols as 1 to enable checking of + the LDR flag for specified devices. DO NOT set these bits if you + do not 1) have a DEC-recognized autoloader, or 2) use the LDRSET + utility to set the LDR flag for the target devices. +*/ + +#define USING_DEC_DRIVE 0 +#define USING_LDRSET 0 + +static unsigned long VMS_ExitCode = SS$_ABORT; diff --git a/vms/descrip.mms b/vms/descrip.mms new file mode 100644 index 0000000..fb08467 --- /dev/null +++ b/vms/descrip.mms @@ -0,0 +1,77 @@ +! +! MMS System build for MTX and LDRSET utility +! +!Global build flag macros +! +CDEBUG = /DEB/NOOP +MDEBUG = /DEB + +CFLAGS = /DECC$(CDEBUG) +MFLAGS = $(MDEBUG) + +.IFDEF __AXP__ +.SUFFIXES .ALPHA_OBJ +MFLAGS = /MIGRATE$(MFLAGS)/NOOP +DBG = .ALPHA_DBG +EXE = .ALPHA_EXE +OBJ = .ALPHA_OBJ +OPT = .ALPHA_OPT +SYSEXE=/SYSEXE + +.ELSE +DBG = .DBG +EXE = .EXE +OPT = .OPT +OBJ = .OBJ +SYSEXE= + +.ENDIF + +PURGEOBJ = if f$search("$(MMS$TARGET_NAME)$(OBJ);-1").nes."" then purge/log $(MMS$TARGET_NAME)$(OBJ) + +! +!Bend the default build rules for C, MACRO, and MESSAGE +! +.C$(OBJ) : + $(CC) $(CFLAGS) $(MMS$SOURCE)$(CDEBUG)/OBJECT=$(MMS$TARGET_NAME)$(OBJ) + $(PURGEOBJ) +.MAR$(OBJ) : + $(MACRO) $(MFLAGS) $(MMS$SOURCE)$(MDEBUG)/OBJECT=$(MMS$TARGET_NAME)$(OBJ) + $(PURGEOBJ) +.CLD$(OBJ) : + SET COMMAND/OBJECT=$(MMS$TARGET_NAME)$(OBJ) $(MMS$SOURCE) + $(PURGEOBJ) +.MSG$(OBJ) : + MESSAGE $(MMS$SOURCE)/OBJECT=$(MMS$TARGET_NAME)$(OBJ) + $(PURGEOBJ) + + +DEFAULT : ERROR,- + MTX,- + LDRSET + @ ! + +ERROR : + @ if f$parse("[.VMS]A.A").eqs."" then write sys$output "?Error: Use $ MMS/DESCRIP=[.VMS] from the mtx directory" + +MTX : mtx$(EXE) + @ ! + +mtx$(EXE) : mtx$(OBJ) + $ link/notrace mtx$(OBJ)/exe=mtx$(EXE) + +mtx$(OBJ) : mtx.c,[.vms]scsi.c,[.vms]defs.h + +LDRSET : ldrset$(EXE),ldrset.cld + @ ! + +ldrset.cld : [.vms]ldrset.cld + $ copy [.vms]ldrset.cld []/log + +ldrset$(EXE) : [.vms]ldrset$(OBJ),[.vms]ldrutil$(OBJ) + $ link [.vms]ldrset$(OBJ),[.vms]ldrutil$(OBJ)/exe=ldrset$(EXE)$(SYSEXE) + +[.vms]ldrset$(OBJ) : [.vms]ldrset.c + +[.vms]ldrutil$(OBJ) : [.vms]ldrutil.mar + diff --git a/vms/ldrset.c b/vms/ldrset.c new file mode 100644 index 0000000..c0efd0c --- /dev/null +++ b/vms/ldrset.c @@ -0,0 +1,183 @@ +/* LDRSET - Set the state of the LDR flag in UCB$L_DEVCHAR2 for a +** SCSI magtape. REQUIRES CMKRNL privilege. +** +** Copyright 1999 by TECSys Development, Inc. http://www.tditx.com +** +** This program is free software; you may redistribute and/or modify it under +** the terms of the GNU General Public License Version 2 as published by the +** Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, but +** WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY +** or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +** for complete details. +** +** Description: +** This is a small KERNEL MODE utility program to go set or reset +** the DEV$M_LDR flag in UCB$L_DEVCHAR2 for a specified device. While +** a certain amount of checking is performed, and while the author +** believes that this utility is safe, ONLY YOU can make that +** determination with respect to your environment. There are NO +** GUARANTEES WHATSOEVER that use of this program will not CRASH +** YOUR SYSTEM or worse. TDI disclaims any responsibility for any +** losses or damages from the use of this program. +** +** With all that said... this utility can be used [example: system +** startup] to set the LDR flag for the autoloader tape device. +** With the loader flag properly set, you can re-enable the LDR +** check section in MTX and be fairly well certain that the MTX +** utility will not be used against a drive that is not a SCSI +** MAGTAPE with a LOADER attached. +** +** +** LDRSET.CLD: +** define verb LDRSET +** image sys$disk:[]ldrset.exe +** parameter p1, label=device, +** prompt="Device", +** value(required,type=$FILE) +** qualifier SET, nonnegatable +** qualifier RESET, nonnegatable +** disallow any2 (SET, RESET) +** disallow NOT SET AND NOT RESET +*/ +#ifdef __DECC +#pragma module LDRSET "V01-00" +#else +#module LDRSET "V01-00" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef DESCR_CNT +#define DESCR_CNT 16 +/* MUST BE of the form 2^N!, big enough for max concurrent usage */ +#endif + +static struct dsc$descriptor_s * +descr( + char *str) +{ +static struct dsc$descriptor_s d_descrtbl[DESCR_CNT]; /* MAX usage! */ +static unsigned short int descridx=0; + struct dsc$descriptor_s *d_ret = &d_descrtbl[descridx]; + + descridx = (descridx+1)&(DESCR_CNT-1); + + d_ret->dsc$w_length = strlen((const char *)str); + d_ret->dsc$a_pointer = (char *)str; + + d_ret->dsc$b_class = + d_ret->dsc$b_dtype = 0; + return(d_ret); +} + +extern unsigned long int finducb(); +extern unsigned long int _setldr(); +extern unsigned long int _clrldr(); + +unsigned long int +set_ldrstate( + int devch, + int setstate) +{ + unsigned long int ret; + struct ucbdef *ucb; + + if (~(ret=finducb(devch,&ucb))&1) + return(ret); + + if (setstate) + return(_setldr(ucb)); + else + return(_clrldr(ucb)); +} + +extern unsigned long int CLI$PRESENT(); +extern unsigned long int CLI$GET_VALUE(); + +static unsigned long int +cld_special( + char *kwd_name) +{ + lib$establish(lib$sig_to_ret); + return(CLI$PRESENT(descr(kwd_name))); +} + +int +main(){ + unsigned long int ret; + unsigned long int ismnt = 0; + unsigned long int dvcls = 0; + unsigned long int dchr2 = 0; + struct itmlst_3 { + unsigned short int ilen; + unsigned short int code; + unsigned long int *returnP; + unsigned long int ignored; + } dvi_itmlst[] = { + {4, DVI$_MNT, 0/*&ismnt*/, 0}, + {4, DVI$_DEVCLASS, 0/*&dvcls*/, 0}, + {4, DVI$_DEVCHAR2, 0/*&dchr2*/, 0}, + {0,0,0,0} }; + unsigned long int iosb[2]; + struct dsc$descriptor_s *dp_tmp; + struct dsc$descriptor_d dy_devn = { 0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0 }; + unsigned long int devch=0; + + dvi_itmlst[0].returnP = &ismnt; + dvi_itmlst[1].returnP = &dvcls; + dvi_itmlst[2].returnP = &dchr2; + + if (~(ret=CLI$PRESENT(dp_tmp=descr("DEVICE")))&1) { + printf("?Error obtaining CLD DEVICE parameter\n"); + return(ret); } + if (~(ret=CLI$GET_VALUE(dp_tmp,&dy_devn,0))&1) { + printf("?Error obtaining CLD DEVICE value\n"); + return(ret); } + + if (~(ret=sys$alloc(&dy_devn,0,0,0,0))&1) { + printf("?Error allocating specified device\n"); + return(ret); } + + if (~(ret=sys$assign(&dy_devn,&devch,0,0))&1) { + printf("?Error assigning a channel to specified device\n"); + return(ret); } + + if (~(ret=sys$getdviw(0,devch,0,&dvi_itmlst,&iosb,0,0,0))&1) { + printf("?Error obtaining device information(1)\n"); + return(ret); } + if (~(ret=iosb[0])&1) { + printf("?Error obtaining device information(2)\n"); + return(ret); } + + if (dvcls != DC$_TAPE) { + printf("?Device is not a tape drive\n"); + return(SS$_IVDEVNAM); } + + if (~dchr2 & DEV$M_SCSI) { + printf("?Device is not a SCSI device\n"); + return(SS$_IVDEVNAM); } + + if (ismnt) { + printf("?Device is mounted\n"); + return(SS$_DEVMOUNT); } + + if (cld_special("SET")&1) + return(set_ldrstate(devch,1)); + + if (cld_special("RESET")&1) + return(set_ldrstate(devch,0)); + + /* Either SET or RESET above must be present to win */ + printf("?CLD structural error - see source\n"); + return(SS$_BADPARAM); +} diff --git a/vms/ldrset.cld b/vms/ldrset.cld new file mode 100644 index 0000000..0dfc543 --- /dev/null +++ b/vms/ldrset.cld @@ -0,0 +1,9 @@ +define verb LDRSET + image sys$disk:[]ldrset.exe + parameter p1, label=device, + prompt="Device", + value(required,type=$FILE) + qualifier SET, nonnegatable + qualifier RESET, nonnegatable + disallow any2 (SET, RESET) + disallow NOT SET AND NOT RESET diff --git a/vms/ldrutil.mar b/vms/ldrutil.mar new file mode 100644 index 0000000..9d0ea31 --- /dev/null +++ b/vms/ldrutil.mar @@ -0,0 +1,104 @@ + .title LDRUTIL - Obtain ucb for assigned channel + .ident /LDRUTIL V1.0/ +; LDRUTIL - VMS UCB LDR bit utility library +; +; TECSys Development, Inc., April 1998 +; +; This file may be copied under the terms and conditions of version 2 +; of the GNU General Public License, as published by the Free +; Software Foundation (Cambridge, Massachusetts). +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, write to the Free Software +; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +; +; + .link "sys$system:sys.stb"/selective_search + .library /sys$share:lib/ + + .NTYPE ...IS_IT_ALPHA,R22 ;Get the type of R22 + ...IS_IT_ALPHA = <...IS_IT_ALPHA@-4&^XF>-5 + .IIF EQ,...IS_IT_ALPHA, ALPHA=1 + + $ssdef + $ucbdef + $ccbdef + $chfdef + $dcdef + $devdef + $pcbdef + + .psect $$code,exe,rd,nowrt,shr +.IF NDF,ALPHA +.entry finducb,^m ;Find UCB address from channel +.IFF +.call_entry, 2,home_args=TRUE,- + preserve=,- + output=,- + label=finducb +.endc + movzwl 4(AP),r0 ;prep to find UCB + jsb g^IOC$VERIFYCHAN ;callable from user mode! + blbc r0,20$ + movl CCB$L_UCB(r1),@8(AP) ;save UCB address + movzbl #1,r0 +20$: ret + +.IF NDF,ALPHA +.entry __setldr,^m ;Find UCB address from channel +.IFF +.call_entry, 2,home_args=TRUE,- + preserve=,- + output=,- + label=__setldr +.endc + movl 4(AP),r1 + bisl #DEV$M_LDR,UCB$L_DEVCHAR2(r1) + movzbl #1,r0 + ret + +.IF NDF,ALPHA +.entry _setldr,^m ;Find UCB address from channel +.IFF +.call_entry, 2,home_args=TRUE,- + preserve=,- + output=,- + label=_setldr +.endc + $cmkrnl_s - + routin = __setldr,- + arglst = (AP) + ret + +.IF NDF,ALPHA +.entry __clrldr,^m ;Find UCB address from channel +.IFF +.call_entry, 2,home_args=TRUE,- + preserve=,- + output=,- + label=__clrldr +.endc + movl 4(AP),r1 + bicl #DEV$M_LDR,UCB$L_DEVCHAR2(r1) + movzbl #1,r0 + ret + +.IF NDF,ALPHA +.entry _clrldr,^m ;Find UCB address from channel +.IFF +.call_entry, 2,home_args=TRUE,- + preserve=,- + output=,- + label=_clrldr +.endc + $cmkrnl_s - + routin = __clrldr,- + arglst = (AP) + ret + + .end diff --git a/vms/scsi.c b/vms/scsi.c new file mode 100644 index 0000000..5b32572 --- /dev/null +++ b/vms/scsi.c @@ -0,0 +1,400 @@ +/* SCSI.C - VMS-specific SCSI routines. +** +** TECSys Development, Inc., April 1998 +** +** This module began life as a program called CDWRITE20, a CD-R control +** program for VMS. No real functionality from the original CDWRITE20 +** is present in this module, but in the interest of making certain that +** proper credit is given where it may be due, the copyrights and inclusions +** from the CDWRITE20 program are included below. +** +** The portions of coding in this module ascribable to TECSys Development +** are hereby also released under the terms and conditions of version 2 +** of the GNU General Public License as described below.... +*/ + +/* The remainder of these credits are included directly from the CDWRITE20 +** sources. */ + +/* Copyright 1994 Yggdrasil Computing, Inc. */ +/* Written by Adam J. Richter (adam@yggdrasil.com) */ + +/* Rewritten February 1997 by Eberhard Heuser-Hofmann*/ +/* using the OpenVMS generic scsi-interface */ +/* see the README-file, how to setup your machine */ + +/* +** Modified March 1997 by John Vottero to use overlapped, async I/O +** and lots of buffers to help prevent buffer underruns. +** Also improved error reporting. +*/ + +/* This file may be copied under the terms and conditions of version 2 + of the GNU General Public License, as published by the Free + Software Foundation (Cambridge, Massachusetts). + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* The second notice comes from sys$examples:gktest.c (OpenVMS 7.0)*/ + +/* +** COPYRIGHT (c) 1993 BY +** DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS. +** ALL RIGHTS RESERVED. +** +** THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED +** ONLY IN ACCORDANCE OF THE TERMS OF SUCH LICENSE AND WITH THE +** INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER +** COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY +** OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY +** TRANSFERRED. +** +** THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE +** AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT +** CORPORATION. +** +** DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS +** SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL. +*/ + +/* + Define the Generic SCSI Command Descriptor. +*/ + +typedef struct scsi$desc +{ + unsigned int SCSI$L_OPCODE; /* SCSI Operation Code */ + unsigned int SCSI$L_FLAGS; /* SCSI Flags Bit Map */ + unsigned char *SCSI$A_CMD_ADDR; /* ->SCSI Command Buffer */ + unsigned int SCSI$L_CMD_LEN; /* SCSI Command Length (bytes) */ + unsigned char *SCSI$A_DATA_ADDR; /* ->SCSI Data Buffer */ + unsigned int SCSI$L_DATA_LEN; /* SCSI Data Length (bytes) */ + unsigned int SCSI$L_PAD_LEN; /* SCSI Pad Length (bytes) */ + unsigned int SCSI$L_PH_CH_TMOUT; /* SCSI Phase Change Timeout (seconds) */ + unsigned int SCSI$L_DISCON_TMOUT; /* SCSI Disconnect Timeout (seconds) */ + unsigned int SCSI$L_RES_1; /* Reserved */ + unsigned int SCSI$L_RES_2; /* Reserved */ + unsigned int SCSI$L_RES_3; /* Reserved */ + unsigned int SCSI$L_RES_4; /* Reserved */ + unsigned int SCSI$L_RES_5; /* Reserved */ + unsigned int SCSI$L_RES_6; /* Reserved */ +} +SCSI$DESC; + + +/* + Define the SCSI Input/Output Status Block. +*/ + +typedef struct scsi$iosb +{ + unsigned short SCSI$W_VMS_STAT; /* VMS Status Code */ + unsigned long SCSI$L_IOSB_TFR_CNT; /* Actual Byte Count Transferred */ + unsigned char SCSI$B_IOSB_FILL_1; /* Unused */ + unsigned char SCSI$B_IOSB_STS; /* SCSI Device Status */ +} +SCSI$IOSB; + + +/* + Define the VMS symbolic representation for a successful SCSI command. +*/ + +#define SCSI$K_GOOD 0 + + +/* + Define the SCSI Flag Field Constants. +*/ + +#define SCSI$K_WRITE 0x0 /* Data Transfer Direction: Write */ +#define SCSI$K_READ 0x1 /* Data Transfer Direction: Read */ +#define SCSI$K_FL_ENAB_DIS 0x2 /* Enable Disconnect/Reconnect */ + + +/* + Define DESCR_CNT. It must be a power of two and large enough + for the maximum concurrent usage of descriptors. +*/ + +#define DESCR_CNT 16 + + +#define MK_EFN 0 /* Event Flag Number */ +#define FailureStatusP(Status) (~(Status) & 1) + + +static struct dsc$descriptor_s *descr(char *String) +{ + static struct dsc$descriptor_s d_descrtbl[DESCR_CNT]; + static unsigned short descridx = 0; + struct dsc$descriptor_s *d_ret = &d_descrtbl[descridx]; + descridx = (descridx + 1) & (DESCR_CNT - 1); + d_ret->dsc$w_length = strlen((const char *) String); + d_ret->dsc$a_pointer = String; + d_ret->dsc$b_class = 0; + d_ret->dsc$b_dtype = 0; + + return d_ret; +} + + +static int SCSI_OpenDevice(char *DeviceName) +{ + unsigned long d_dev[2], iosb[2], Status; + union prvdef setprivs, newprivs; + unsigned long ismnt = 0; + unsigned long dvcls = 0; + unsigned long dchr2 = 0; + int DeviceFD = 0; + struct itmlst_3 + { + unsigned short ilen; + unsigned short code; + unsigned long *returnP; + unsigned long ignored; + } + dvi_itmlst[] = { + { 4, DVI$_MNT, 0 /*&ismnt*/, 0 }, + { 4, DVI$_DEVCLASS, 0 /*&dvcls*/, 0 }, + { 4, DVI$_DEVCHAR2, 0 /*&dchr2*/, 0 }, + { 0, 0, 0, 0 } + }; + + dvi_itmlst[0].returnP = &ismnt; + dvi_itmlst[1].returnP = &dvcls; + dvi_itmlst[2].returnP = &dchr2; + + Status = sys$alloc(descr(DeviceName), 0, 0, 0, 0); + + if (FailureStatusP(Status)) + { + VMS_ExitCode = Status; + FatalError("cannot allocate device '%s' - %X\n", DeviceName, Status); + } + + Status = sys$assign(descr(DeviceName), &DeviceFD, 0, 0); + if (FailureStatusP(Status)) + { + VMS_ExitCode = Status; + FatalError("cannot open device '%s' - %X\n", DeviceName, Status); + } + + Status = sys$getdviw(0, DeviceFD, 0, &dvi_itmlst, &iosb, 0, 0, 0); + if (FailureStatusP(Status)) + { + VMS_ExitCode = Status; + FatalError("cannot $getdvi(1) on device '%s' - %X\n", DeviceName, Status); + } + + if (FailureStatusP(Status = iosb[0])) + { + VMS_ExitCode = Status; + FatalError("cannot $getdvi(2) on device '%s' - %X\n", DeviceName, Status); + } + + if (dvcls != DC$_TAPE) + { + VMS_ExitCode = SS$_IVDEVNAM; + FatalError("specified device is NOT a magtape: operation denied\n"); + } +#ifndef __DECC +#ifndef DEV$M_SCSI +#define DEV$M_SCSI 0x1000000 +#endif +#endif + if (~dchr2 & DEV$M_SCSI) + { + VMS_ExitCode = SS$_IVDEVNAM; + FatalError("specified magtape is NOT a SCSI device: operation denied\n"); + } +#if USING_DEC_DRIVE | USING_LDRSET +#ifndef __DECC +#ifndef DEV$M_LDR +#define DEV$M_LDR 0x100000 +#endif +#endif + if (~dchr2 & DEV$M_LDR) + { + VMS_ExitCode = SS$_IVDEVNAM; + FatalError("specified SCSI magtape does not have a loader: operation denied\n"); + } +#endif + if (ismnt) + { + VMS_ExitCode = SS$_DEVMOUNT; + FatalError("specified device is mounted: operation denied\n"); + } + + ots$move5(0, 0, 0, sizeof(newprivs), &newprivs); + newprivs.prv$v_diagnose = 1; + newprivs.prv$v_log_io = 1; + newprivs.prv$v_phy_io = 1; + Status = sys$setprv(1, &newprivs, 0, 0); + + if (FailureStatusP(Status)) + { + VMS_ExitCode = Status; + FatalError("error enabling privs (diagnose,log_io,phy_io): operation denied\n"); + } + + Status = sys$setprv(1, 0, 0, &setprivs); + if (FailureStatusP(Status)) + { + VMS_ExitCode = Status; + FatalError("error retrieving current privs: operation denied\n"); + } + + if (!setprivs.prv$v_diagnose) + { + VMS_ExitCode = SS$_NODIAGNOSE; + FatalError("DIAGNOSE privilege is required: operation denied\n"); + } + + if (!setprivs.prv$v_phy_io && !setprivs.prv$v_log_io) + { + VMS_ExitCode = SS$_NOPHY_IO; + FatalError("PHY_IO or LOG_IO privilege is required: operation denied\n"); + } + + return DeviceFD; +} + + +static void SCSI_CloseDevice(char *DeviceName, int DeviceFD) +{ + unsigned long Status; + + Status = sys$dassgn(DeviceFD); + if (FailureStatusP(Status)) + FatalError("cannot close SCSI device '%s' - %X\n", DeviceName, Status); +} + + +static int SCSI_ExecuteCommand( int DeviceFD, + Direction_T Direction, + CDB_T *CDB, + int CDB_Length, + void *DataBuffer, + int DataBufferLength, + RequestSense_T *RequestSense) +{ + SCSI$DESC cmd_desc; + SCSI$IOSB cmd_iosb; + unsigned long Status; + int Result; + memset(RequestSense, 0, sizeof(RequestSense_T)); + /* Issue the QIO to send the SCSI Command. */ + ots$move5(0, 0, 0, sizeof(cmd_desc), &cmd_desc); + cmd_desc.SCSI$L_OPCODE = 1; /* Only defined SCSI opcode... a VMS thing */ + cmd_desc.SCSI$A_CMD_ADDR = CDB; + cmd_desc.SCSI$L_CMD_LEN = CDB_Length; + cmd_desc.SCSI$A_DATA_ADDR = DataBuffer; + cmd_desc.SCSI$L_DATA_LEN = DataBufferLength; + cmd_desc.SCSI$L_PAD_LEN = 0; + cmd_desc.SCSI$L_PH_CH_TMOUT = 180; /* SCSI Phase Change Timeout (seconds) */ + cmd_desc.SCSI$L_DISCON_TMOUT = 180; /* SCSI Disconnect Timeout (seconds) */ + + switch (Direction) + { + /* + NOTE: Do NOT include flag SCSI$K_FL_ENAB_SYNC. + It does NOT work for this case. + */ + case Input: + cmd_desc.SCSI$L_FLAGS = SCSI$K_READ | SCSI$K_FL_ENAB_DIS; + break; + + case Output: + cmd_desc.SCSI$L_FLAGS = SCSI$K_WRITE | SCSI$K_FL_ENAB_DIS; + break; + } + + /* Issue the SCSI Command. */ + Status = sys$qiow(MK_EFN, DeviceFD, IO$_DIAGNOSE, &cmd_iosb, 0, 0, + &cmd_desc, sizeof(cmd_desc), 0, 0, 0, 0); + Result = SCSI$K_GOOD; + + if (Status & 1) + Status = cmd_iosb.SCSI$W_VMS_STAT; + + if (Status & 1) + Result = cmd_iosb.SCSI$B_IOSB_STS; + + if (Result != SCSI$K_GOOD) + { + unsigned char RequestSenseCDB[6] = + { 0x03 /* REQUEST_SENSE */, 0, 0, 0, sizeof(RequestSense_T), 0 }; + + printf("SCSI command error: %d - requesting sense data\n", Result); + + /* Execute Request Sense to determine the failure reason. */ + ots$move5(0, 0, 0, sizeof(cmd_desc), &cmd_desc); + cmd_desc.SCSI$L_OPCODE = 1; /* Only defined SCSI opcode... a VMS thing */ + cmd_desc.SCSI$L_FLAGS = SCSI$K_READ | SCSI$K_FL_ENAB_DIS; + cmd_desc.SCSI$A_CMD_ADDR = RequestSenseCDB; + cmd_desc.SCSI$L_CMD_LEN = 6; + cmd_desc.SCSI$A_DATA_ADDR = RequestSense; + cmd_desc.SCSI$L_DATA_LEN = sizeof(RequestSense_T); + cmd_desc.SCSI$L_PH_CH_TMOUT = 180; + cmd_desc.SCSI$L_DISCON_TMOUT = 180; + + /* Issue the QIO to send the Request Sense Command. */ + Status = sys$qiow(MK_EFN, DeviceFD, IO$_DIAGNOSE, &cmd_iosb, 0, 0, + &cmd_desc, sizeof(cmd_desc), 0, 0, 0, 0); + if (FailureStatusP(Status)) + { + printf("?Error returned from REQUEST_SENSE(1): %%X%08lX\n", Status); + sys$exit(Status); + } + + /* Check the VMS Status from QIO. */ + Status = cmd_iosb.SCSI$W_VMS_STAT; + if (FailureStatusP(Status)) + { + printf("?Error returned from REQUEST_SENSE(2): %%X%08lX\n", Status); + sys$exit(Status); + } + } + return Result; +} + + +static void VMS_DefineStatusSymbols(void) +{ + char SymbolName[32], SymbolValue[32]; + int StorageElementNumber; + + if (DataTransferElementFull) + { + /* Define MTX_DTE Symbol (environment variable) as 'FULL:n'. */ + sprintf(SymbolValue, "FULL:%d", + DataTransferElementSourceStorageElementNumber); + lib$set_symbol(descr("MTX_DTE"), descr(SymbolValue), &2); + } + else + { + /* Define MTX_DTE Symbol (environment variable) as 'EMPTY'. */ + lib$set_symbol(descr("MTX_DTE"), descr("EMPTY"), &2); + } + + /* Define MTX_MSZ Symbol (environment variable) "Magazine SiZe" as 'n'. */ + sprintf(SymbolValue, "%d", StorageElementCount); + lib$set_symbol(descr("MTX_MSZ"), descr(SymbolValue), &2); + for (StorageElementNumber = 1; + StorageElementNumber <= StorageElementCount; + StorageElementNumber++) + { + sprintf(SymbolName, "MTX_STE%02d", StorageElementNumber); + strcpy(SymbolValue, + (StorageElementFull[StorageElementNumber] ? "FULL" : "EMPTY")); + lib$set_symbol(descr(SymbolName), descr(SymbolValue), &2); + } +} -- cgit v1.2.3 From 91419886f3040d252b1a90ef90c34cae97e17bcb Mon Sep 17 00:00:00 2001 From: Carsten Leonhardt Date: Thu, 28 Feb 2019 11:49:03 +0100 Subject: Import mtx_1.3.12-12.debian.tar.xz [dgit import tarball mtx 1.3.12-12 mtx_1.3.12-12.debian.tar.xz] --- changelog | 241 +++++++++++++++++++++++++++++++ control | 21 +++ copyright | 15 ++ dirs | 1 + examples | 1 + gitlab-ci.yml | 6 + mtx.maintscript | 1 + patches/001-bug728142_many_slots.patch | 107 ++++++++++++++ patches/002-fix-configure-for-autoreconf | 28 ++++ patches/003-fix-spelling | 25 ++++ patches/004-fix-destdir | 35 +++++ patches/005-remove-argc-output | 30 ++++ patches/series | 5 + rules | 8 + source/format | 1 + watch | 3 + 16 files changed, 528 insertions(+) create mode 100644 changelog create mode 100644 control create mode 100644 copyright create mode 100644 dirs create mode 100644 examples create mode 100644 gitlab-ci.yml create mode 100644 mtx.maintscript create mode 100644 patches/001-bug728142_many_slots.patch create mode 100644 patches/002-fix-configure-for-autoreconf create mode 100644 patches/003-fix-spelling create mode 100644 patches/004-fix-destdir create mode 100644 patches/005-remove-argc-output create mode 100644 patches/series create mode 100755 rules create mode 100644 source/format create mode 100644 watch diff --git a/changelog b/changelog new file mode 100644 index 0000000..a36b495 --- /dev/null +++ b/changelog @@ -0,0 +1,241 @@ +mtx (1.3.12-12) unstable; urgency=medium + + * Apply patches from Fedora. + + -- Carsten Leonhardt Thu, 28 Feb 2019 11:49:03 +0100 + +mtx (1.3.12-11) unstable; urgency=medium + + * Adopt this package. Closes: #920519 + * Add Gitlab CI integration. + * Switch to debhelper 12, patch configure.in to fix errors on autoreconf + execution. + * Update standards-version to 4.3.0. + * Enable all hardening options. + + -- Carsten Leonhardt Thu, 28 Feb 2019 01:21:59 +0100 + +mtx (1.3.12-10) unstable; urgency=medium + + * Remove bash completions, they are also in the bash-completion package. + Closes: #847940 + * Update standards-version to 3.9.8 (no changes). + + -- Ivo De Decker Sun, 22 Jan 2017 23:39:33 +0100 + +mtx (1.3.12-9) unstable; urgency=medium + + * Update standards-version to 3.9.6 (no changes). + * Add patch to support autochangers with many slots. + Thanks to Wayne Keseberg for the report and the original patch. + Closes: #728142 + + -- Ivo De Decker Fri, 24 Oct 2014 18:45:47 +0200 + +mtx (1.3.12-8) unstable; urgency=low + + * Upload to unstable. + + -- Ivo De Decker Mon, 13 May 2013 20:40:38 +0200 + +mtx (1.3.12-7) experimental; urgency=low + + * Switch to debhelper 9. + * Switch to source format 3.0 (quilt). + * Don't build on hurd. Closes: #677616 + * Update standards-version to 3.9.4 (no changes). + + -- Ivo De Decker Sun, 10 Mar 2013 18:42:35 +0100 + +mtx (1.3.12-6) unstable; urgency=low + + * Adopt this package. Closes: #701030 + Thanks to Bdale for maintaining it all these years. + * Update upstream URL. Closes: #701121 + + -- Ivo De Decker Tue, 26 Feb 2013 20:38:14 +0100 + +mtx (1.3.12-5) unstable; urgency=low + + * orphan this package + + -- Bdale Garbee Wed, 20 Feb 2013 10:26:00 -0700 + +mtx (1.3.12-4) unstable; urgency=low + + * add Vcs-Browser entry to the control file + * change Build-Depends to use kfreebsd-any, closes: #634500 + + -- Bdale Garbee Sun, 20 Nov 2011 17:18:50 -0700 + +mtx (1.3.12-3) unstable; urgency=low + + * add Homepage field to control file, closes: #556747 + + -- Bdale Garbee Sat, 20 Mar 2010 01:39:17 -0600 + +mtx (1.3.12-2) unstable; urgency=low + + * patch from David Paleino to improve bash completions, closes: #522739 + * switch to using dh_bash-completion + + -- Bdale Garbee Mon, 06 Apr 2009 10:20:08 -0600 + +mtx (1.3.12-1) unstable; urgency=low + + * new upstream version, closes: #500590 + * clean up lintian warnings + * incorporate two changes suggested by a patch from Adam Cécile (Le_Vert): + * add debian/watch + * move config.* update to configure target, yields a smaller diff that + doesn't clash with git-buildpackage... already had autotools-dev build dep! + + -- Bdale Garbee Sun, 15 Feb 2009 10:17:54 -0700 + +mtx (1.3.11-1) unstable; urgency=low + + * new upstream version, closes: #425687, #425688 + * don't let Makefile.in strip binaries, let dh_strip do it, closes: #437589 + + -- Bdale Garbee Tue, 15 Apr 2008 14:34:32 -0600 + +mtx (1.2.17rel-2) unstable; urgency=low + + * update config.sub and config.guess in rules clean target using the + autotools-dev package, closes: #367467 + + -- Bdale Garbee Sat, 19 Aug 2006 18:44:54 -0600 + +mtx (1.2.17rel-1) unstable; urgency=low + + * new upstream version + + -- Bdale Garbee Wed, 28 Jun 2006 23:57:44 -0400 + +mtx (1.2.16rel-5) unstable; urgency=low + + * add build-deps needed for GNU/kFreeBSD, closes: #367467 + * update debhelper build dependency + + -- Bdale Garbee Wed, 28 Jun 2006 23:42:00 -0400 + +mtx (1.2.16rel-4) unstable; urgency=medium + + * revert SG_SCSI_DEFAULT_TIMEOUT to 5 minutes since at least the Sony + TLS-9000 takes more than a minute to load sometimes, closes: #229169 + * remove 'previous' from command summary, since it's not actually + implemented in the program, closes: #230041 + * include bash_completion file from Jon Middleton, closes: #227456 + + -- Bdale Garbee Sat, 14 Feb 2004 22:36:23 -0700 + +mtx (1.2.16rel-3) unstable; urgency=low + + * apply patch from Torsten Werner that elminates + hard-coding of the value of HZ, closes: #224147 + + -- Bdale Garbee Tue, 16 Dec 2003 10:04:26 -0700 + +mtx (1.2.16rel-2) unstable; urgency=low + + * apply patch from R.A.Owen that fixes the "staggered" + output from the status command on some changers, closes: #129910 + + -- Bdale Garbee Tue, 9 Apr 2002 19:30:06 -0600 + +mtx (1.2.16rel-1) unstable; urgency=low + + * new upstream version, bug-fixing release, reportedly fixes timeout + problem with some drives, closes: #113947 + + -- Bdale Garbee Mon, 4 Mar 2002 01:27:48 -0700 + +mtx (1.2.15-1) unstable; urgency=low + + * new upstream source + * update standards version, rebuild rules file + * man pages all included now, mtx-changer and other pieces from contrib + provided as examples, though chg-mtx in the amanda package is probably + a better choice for use with amanda, closes: #113728 + * apply diffs to correct "spelling errors" (actually hyphenation) in the + descriptions in the control file, closes: #125160 + + -- Bdale Garbee Sun, 30 Dec 2001 21:28:46 -0700 + +mtx (1.2.10-1) unstable; urgency=low + + * new upstream source + + -- Bdale Garbee Mon, 11 Dec 2000 17:34:13 -0700 + +mtx (1.0-10) frozen unstable; urgency=low + + * deliver mtx.doc, lost when the package was made FHS compliant, + closes: #56276 Target frozen since including the documentation + is worthwhile for potato, and there is no added risk. + + -- Bdale Garbee Wed, 9 Feb 2000 12:27:58 -0700 + +mtx (1.0-9) unstable; urgency=low + + * fix postinst/postrm scripts to be executable again + + -- Bdale Garbee Tue, 11 Jan 2000 23:00:17 -0700 + +mtx (1.0-8) unstable; urgency=low + + * update to latest standards revision, add Build-Depends + * fix all the lintian errors that aren't intentional, override the two + permissions warnings since they're precisely what is needed + + -- Bdale Garbee Fri, 7 Jan 2000 02:47:08 -0700 + +mtx (1.0-7) unstable; urgency=low + + * grab a local copy of scsi_ioctl.h from the 2.2.10 kernel source tree. This + doesn't change often in any way we care about, and this is much simpler + than having to reference a live kernel tree somewhere... + * move to debhelper and CVS + + -- Bdale Garbee Sun, 20 Jun 1999 10:42:39 -0600 + +mtx (1.0-6) unstable; urgency=low + + * put mtx in group backup, setuid root, perms set so that only members of + group backup can run mtx. This makes mtx compatible with amanda. + + -- Bdale Garbee Tue, 27 Jan 1998 15:06:13 -0700 + +mtx (1.0-5) unstable; urgency=low + + * explicit include path to find in the + /usr/src/linux/include tree. closes bug 16877 + + -- Bdale Garbee Sun, 25 Jan 1998 23:02:46 -0700 + +mtx (1.0-4) unstable; urgency=low + + * actually install the mtx.doc file that's referenced in the man page /o\ + + -- Bdale Garbee Sun, 21 Sep 1997 02:38:50 -0600 + +mtx (1.0-3) unstable; urgency=low + + * libc6 + + -- Bdale Garbee Thu, 4 Sep 1997 02:56:39 -0600 + +mtx (1.0-2) unstable; urgency=low + + * Add an 'mtx-changer' wrapper script from the amanda-users mailing list + to make this more useful with Amanda. + * Hack mtx-changer to report 6 slots instead of 4, since I have an HP + SureStore 12000e. Should make it configurable, someday. + + -- Bdale Garbee Sun, 10 Aug 1997 03:50:42 -0600 + +mtx (1.0-1) unstable; urgency=low + + * Initial Release. + + -- Bdale Garbee Sun, 10 Aug 1997 03:05:18 -0600 diff --git a/control b/control new file mode 100644 index 0000000..d538f05 --- /dev/null +++ b/control @@ -0,0 +1,21 @@ +Source: mtx +Section: admin +Priority: optional +Maintainer: Debian Bacula Team +Uploaders: Carsten Leonhardt +Build-Depends: debhelper-compat (= 12), libcam-dev [kfreebsd-any] +Standards-Version: 4.3.0 +Rules-Requires-Root: no +Vcs-Browser: https://salsa.debian.org/bacula-team/mtx +Vcs-Git: https://salsa.debian.org/bacula-team/mtx.git +Homepage: https://sourceforge.net/projects/mtx/ + +Package: mtx +# does not build on hurd: see http://bugs.debian.org/677616 +Architecture: linux-any kfreebsd-any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: controls tape autochangers + MTX can be used to manipulate tape auto-changers, also known as "jukeboxes", + such that backup software can make use of the multiple tape capabilities of + the auto-changer. In particular, this is necessary glue for using a backup + system like Amanda with a DDS auto-changer like the HP Surestore 12000e. diff --git a/copyright b/copyright new file mode 100644 index 0000000..d39b500 --- /dev/null +++ b/copyright @@ -0,0 +1,15 @@ +This package was debianized by Bdale Garbee bdale@gag.com on +Sun, 10 Aug 1997 03:05:18 -0600. + +mtx was downloaded from http://mtx.sourceforge.net/ + +Copyright: + + Copyright 1997, 1998 Leonard Zubkoff + Changes copyright 2000, 2001 Eric Green + Changes copyright 2007-2008 by Robert Nelson + + GPL, version 2 + +On Debian GNU/Linux systems, the complete text of the GNU General +Public License can be found in `/usr/share/common-licenses/GPL-2'. diff --git a/dirs b/dirs new file mode 100644 index 0000000..236670a --- /dev/null +++ b/dirs @@ -0,0 +1 @@ +usr/sbin diff --git a/examples b/examples new file mode 100644 index 0000000..86071d7 --- /dev/null +++ b/examples @@ -0,0 +1 @@ +contrib/* diff --git a/gitlab-ci.yml b/gitlab-ci.yml new file mode 100644 index 0000000..5c575a1 --- /dev/null +++ b/gitlab-ci.yml @@ -0,0 +1,6 @@ +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml + +variables: + RELEASE: 'unstable' diff --git a/mtx.maintscript b/mtx.maintscript new file mode 100644 index 0000000..713d81d --- /dev/null +++ b/mtx.maintscript @@ -0,0 +1 @@ +rm_conffile /etc/bash_completion.d/mtx 1.3.12-10~ diff --git a/patches/001-bug728142_many_slots.patch b/patches/001-bug728142_many_slots.patch new file mode 100644 index 0000000..b6d9f71 --- /dev/null +++ b/patches/001-bug728142_many_slots.patch @@ -0,0 +1,107 @@ +Description: Add support for large autochangers + For large autochangers, the buffer needed for the ReadElementStatus call can + be too large. This patch works around this by doing multiple smaller calls. + The maximum value of 10000 seems to be OK for this. Based on tests, the + maximum value seems to be between 24000 and 25000, but this might + depend on the autochanger. + . + This patch is based on the changes by Wayne Keseberg + in http://bugs.debian.org/728142 +Author: Ivo De Decker +Bug-Debian: http://bugs.debian.org/728142 + +Index: mtx/mtxl.c +=================================================================== +--- mtx.orig/mtxl.c ++++ mtx/mtxl.c +@@ -39,6 +39,8 @@ + /* zap the following define when we finally add real import/export support */ + #define IMPORT_EXPORT_HACK 1 /* for the moment, import/export == storage */ + ++#define ReadElementStatusMaxElements 10000 ++ + /* First, do some SCSI routines: */ + + /* the camlib is used on FreeBSD. */ +@@ -500,7 +502,7 @@ ElementModeSense_T *ReadAssignmentPage(D + retval->MaxReadElementStatusData = + (sizeof(ElementStatusDataHeader_T) + + 4 * sizeof(ElementStatusPage_T) + +- retval->NumElements * sizeof(TransportElementDescriptor_T)); ++ (retval->NumElements > ReadElementStatusMaxElements?ReadElementStatusMaxElements:retval->NumElements) * sizeof(TransportElementDescriptor_T)); + + #ifdef IMPORT_EXPORT_HACK + retval->NumStorage = retval->NumStorage+retval->NumImportExport; +@@ -1141,6 +1143,7 @@ ElementStatus_T *ReadElementStatus(DEVIC + int empty_idx = 0; + boolean is_attached = false; + int i,j; ++ int FirstElement, NumElements, NumThisTime; + + ElementModeSense_T *mode_sense = NULL; + +@@ -1207,33 +1210,47 @@ ElementStatus_T *ReadElementStatus(DEVIC + fprintf(stderr,"Using original element status polling method (storage, import/export, drivers etc independantly)\n"); + #endif + flags->elementtype = StorageElement; /* sigh! */ +- DataBuffer = SendElementStatusRequest( MediumChangerFD, RequestSense, +- inquiry_info, flags, +- mode_sense->StorageStart, +- /* adjust for import/export. */ +- mode_sense->NumStorage - mode_sense->NumImportExport, +- mode_sense->MaxReadElementStatusData); + +- if (!DataBuffer) ++ NumElements = mode_sense->NumStorage - mode_sense->NumImportExport; ++ FirstElement = mode_sense->StorageStart; ++ ++ do + { ++ ++ NumThisTime = NumElements; ++ if (NumThisTime > ReadElementStatusMaxElements) NumThisTime=ReadElementStatusMaxElements; ++ ++ DataBuffer = SendElementStatusRequest( MediumChangerFD, RequestSense, ++ inquiry_info, flags, ++ FirstElement, ++ /* adjust for import/export. */ ++ NumThisTime, ++ mode_sense->MaxReadElementStatusData); ++ ++ if (!DataBuffer) ++ { + #ifdef DEBUG +- fprintf(stderr,"Had no elements!\n"); ++ fprintf(stderr,"Had no elements!\n"); + #endif +- /* darn. Free up stuff and return. */ ++ /* darn. Free up stuff and return. */ + #ifdef DEBUG_MODE_SENSE +- PrintRequestSense(RequestSense); ++ PrintRequestSense(RequestSense); + #endif +- FreeElementData(ElementStatus); +- return NULL; +- } ++ FreeElementData(ElementStatus); ++ return NULL; ++ } + + #ifdef DEBUG +- fprintf(stderr, "Parsing storage elements\n"); ++ fprintf(stderr, "Parsing storage elements\n"); + #endif +- ParseElementStatus(EmptyStorageElementAddress, &EmptyStorageElementCount, +- DataBuffer,ElementStatus,mode_sense,NULL); ++ ParseElementStatus(EmptyStorageElementAddress, &EmptyStorageElementCount, ++ DataBuffer,ElementStatus,mode_sense,NULL); ++ ++ free(DataBuffer); /* sigh! */ ++ FirstElement += NumThisTime; ++ NumElements -= NumThisTime; + +- free(DataBuffer); /* sigh! */ ++ } while ( NumElements > 0 ); + + /* --------------IMPORT/EXPORT--------------- */ + /* Next let's see if we need to do Import/Export: */ diff --git a/patches/002-fix-configure-for-autoreconf b/patches/002-fix-configure-for-autoreconf new file mode 100644 index 0000000..5195a77 --- /dev/null +++ b/patches/002-fix-configure-for-autoreconf @@ -0,0 +1,28 @@ +Description: Fix configure.in for autoreconf + autoreconf complains about AC_DEFINE with only one argument, fix those. +Author: Carsten Leonhardt +Last-Update: 2019-02-28 +--- a/configure.in ++++ b/configure.in +@@ -10,10 +10,10 @@ + AC_PREFIX_DEFAULT(/usr/local) + + case "$host_os" in +- *linux*) AC_DEFINE(LINUX) ++ *linux*) AC_DEFINE([LINUX], [1], [Linux]) + TARGET=linux + ;; +- *solaris*) AC_DEFINE(SOLARIS) ++ *solaris*) AC_DEFINE([SOLARIS], [1], [Solaris]) + TARGET=solarissparc + ;; + *sunos*) TARGET=solarissparc +@@ -28,7 +28,7 @@ + ;; + *HP*) TARGET=hpux + ;; +- *sequent*) AC_DEFINE(SEQUENT) ++ *sequent*) AC_DEFINE([SEQUENT], [1], [Sequent]) + ;; + *MINGW*) TARGET=mingw + ;; diff --git a/patches/003-fix-spelling b/patches/003-fix-spelling new file mode 100644 index 0000000..4d3a32f --- /dev/null +++ b/patches/003-fix-spelling @@ -0,0 +1,25 @@ +Description: Fix spelling errors found by lintian +Author: Carsten Leonhardt +Last-Update: 2019-02-28 +--- a/loaderinfo.1 ++++ b/loaderinfo.1 +@@ -55,7 +55,7 @@ + .B Inquiry Page + Aside from the normal inquiry info, will also print out whether we have + a bar code reader (for loaders that support the Exabyte extension for +-reporting presense of said reader). ++reporting presence of said reader). + + + .SH OPTIONS +--- a/scsitape.1 ++++ b/scsitape.1 +@@ -97,7 +97,7 @@ + block mode, should be zero (note: The maximum block size + we currently support in variable block mode is 128K, MAX_READ_SIZE will + need to be turned into a settable variable to allow bigger reads). If +- is ommitted, we assume that we're in variable block mode, and ++ is omitted, we assume that we're in variable block mode, and + that we are going to read from tape until we hit a tapemark or end of + partition or end of tape. + diff --git a/patches/004-fix-destdir b/patches/004-fix-destdir new file mode 100644 index 0000000..6a26395 --- /dev/null +++ b/patches/004-fix-destdir @@ -0,0 +1,35 @@ +Description: Fix spelling errors found by lintian +Author: Dan Horák +Date: Sat, 24 Jan 2009 18:06:43 +0100 +Description: add support for DESTDIR + This patch is taken from Fedora: + https://src.fedoraproject.org/rpms/mtx/tree/master + +--- a/Makefile.in ++++ b/Makefile.in +@@ -33,6 +33,7 @@ + INSTALL_BIN = $(INSTALL) -m 755 + INSTALL_DIR = $(INSTALL) -m 755 -d + ++DESTDIR = + prefix = @prefix@ + exec_prefix = @exec_prefix@ + sbindir = @sbindir@ +@@ -109,13 +110,13 @@ + dbgs: $(DBGS) + + install: $(BINS) +- $(INSTALL_DIR) $(sbindir) ++ $(INSTALL_DIR) $(DESTDIR)$(sbindir) + for file in $(BINS); do \ +- $(INSTALL_BIN) "$$file" $(sbindir) ; \ ++ $(INSTALL_BIN) "$$file" $(DESTDIR)$(sbindir) ; \ + done +- $(INSTALL_DIR) $(mandir) $(mandir)/man1 ++ $(INSTALL_DIR) $(DESTDIR)$(mandir) $(DESTDIR)$(mandir)/man1 + for file in mtx.1 tapeinfo.1 scsitape.1 scsieject.1 loaderinfo.1 ; do \ +- $(INSTALL_DOC) "$$file" $(mandir)/man1 ; \ ++ $(INSTALL_DOC) "$$file" $(DESTDIR)$(mandir)/man1 ; \ + done + + clean: diff --git a/patches/005-remove-argc-output b/patches/005-remove-argc-output new file mode 100644 index 0000000..6850b1b --- /dev/null +++ b/patches/005-remove-argc-output @@ -0,0 +1,30 @@ +Author: Dan Horák +Description: remove the weird debugging-like info + The loaderinfo and tapeinfo utilities print a debugging-like + information about the number of arguments on command line when + started with wrong number of arguments. + . + This patch is taken from Fedora: + https://src.fedoraproject.org/rpms/mtx/tree/master +Date: Thu, 19 Nov 2009 15:45:54 +0100 + +--- a/loaderinfo.c ++++ b/loaderinfo.c +@@ -488,7 +488,6 @@ + argv0=argv[0]; + if (argc != 3) + { +- fprintf(stderr,"argc=%d",argc); + usage(); + } + +--- a/tapeinfo.c ++++ b/tapeinfo.c +@@ -933,7 +933,6 @@ + + if (argc != 3) + { +- fprintf(stderr,"argc=%d",argc); + usage(); + } + diff --git a/patches/series b/patches/series new file mode 100644 index 0000000..2ef608e --- /dev/null +++ b/patches/series @@ -0,0 +1,5 @@ +001-bug728142_many_slots.patch +002-fix-configure-for-autoreconf +003-fix-spelling +004-fix-destdir +005-remove-argc-output diff --git a/rules b/rules new file mode 100755 index 0000000..5abdca5 --- /dev/null +++ b/rules @@ -0,0 +1,8 @@ +#!/usr/bin/make -f + +# enable bindnow +# https://wiki.debian.org/HardeningWalkthrough +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +%: + dh $@ diff --git a/source/format b/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/watch b/watch new file mode 100644 index 0000000..ab1ee98 --- /dev/null +++ b/watch @@ -0,0 +1,3 @@ +version=3 +opts=dversionmangle=s/~debian$// \ +http://sf.net/mtx/mtx-([0-9\.]+)\.tar\.gz -- cgit v1.2.3 From b9e922dedc39ddec651ef9afd97c2b2118ee2fb7 Mon Sep 17 00:00:00 2001 From: Ivo De Decker Date: Thu, 28 Feb 2019 11:49:03 +0100 Subject: Add support for large autochangers Bug-Debian: http://bugs.debian.org/728142 For large autochangers, the buffer needed for the ReadElementStatus call can be too large. This patch works around this by doing multiple smaller calls. The maximum value of 10000 seems to be OK for this. Based on tests, the maximum value seems to be between 24000 and 25000, but this might depend on the autochanger. This patch is based on the changes by Wayne Keseberg in http://bugs.debian.org/728142 Gbp-Pq: Name 001-bug728142_many_slots.patch --- mtxl.c | 53 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/mtxl.c b/mtxl.c index 3ae77a6..7106a47 100644 --- a/mtxl.c +++ b/mtxl.c @@ -39,6 +39,8 @@ /* zap the following define when we finally add real import/export support */ #define IMPORT_EXPORT_HACK 1 /* for the moment, import/export == storage */ +#define ReadElementStatusMaxElements 10000 + /* First, do some SCSI routines: */ /* the camlib is used on FreeBSD. */ @@ -500,7 +502,7 @@ ElementModeSense_T *ReadAssignmentPage(DEVICE_TYPE MediumChangerFD) retval->MaxReadElementStatusData = (sizeof(ElementStatusDataHeader_T) + 4 * sizeof(ElementStatusPage_T) + - retval->NumElements * sizeof(TransportElementDescriptor_T)); + (retval->NumElements > ReadElementStatusMaxElements?ReadElementStatusMaxElements:retval->NumElements) * sizeof(TransportElementDescriptor_T)); #ifdef IMPORT_EXPORT_HACK retval->NumStorage = retval->NumStorage+retval->NumImportExport; @@ -1141,6 +1143,7 @@ ElementStatus_T *ReadElementStatus(DEVICE_TYPE MediumChangerFD, RequestSense_T * int empty_idx = 0; boolean is_attached = false; int i,j; + int FirstElement, NumElements, NumThisTime; ElementModeSense_T *mode_sense = NULL; @@ -1207,33 +1210,47 @@ ElementStatus_T *ReadElementStatus(DEVICE_TYPE MediumChangerFD, RequestSense_T * fprintf(stderr,"Using original element status polling method (storage, import/export, drivers etc independantly)\n"); #endif flags->elementtype = StorageElement; /* sigh! */ - DataBuffer = SendElementStatusRequest( MediumChangerFD, RequestSense, - inquiry_info, flags, - mode_sense->StorageStart, - /* adjust for import/export. */ - mode_sense->NumStorage - mode_sense->NumImportExport, - mode_sense->MaxReadElementStatusData); - if (!DataBuffer) + NumElements = mode_sense->NumStorage - mode_sense->NumImportExport; + FirstElement = mode_sense->StorageStart; + + do { + + NumThisTime = NumElements; + if (NumThisTime > ReadElementStatusMaxElements) NumThisTime=ReadElementStatusMaxElements; + + DataBuffer = SendElementStatusRequest( MediumChangerFD, RequestSense, + inquiry_info, flags, + FirstElement, + /* adjust for import/export. */ + NumThisTime, + mode_sense->MaxReadElementStatusData); + + if (!DataBuffer) + { #ifdef DEBUG - fprintf(stderr,"Had no elements!\n"); + fprintf(stderr,"Had no elements!\n"); #endif - /* darn. Free up stuff and return. */ + /* darn. Free up stuff and return. */ #ifdef DEBUG_MODE_SENSE - PrintRequestSense(RequestSense); + PrintRequestSense(RequestSense); #endif - FreeElementData(ElementStatus); - return NULL; - } + FreeElementData(ElementStatus); + return NULL; + } #ifdef DEBUG - fprintf(stderr, "Parsing storage elements\n"); + fprintf(stderr, "Parsing storage elements\n"); #endif - ParseElementStatus(EmptyStorageElementAddress, &EmptyStorageElementCount, - DataBuffer,ElementStatus,mode_sense,NULL); + ParseElementStatus(EmptyStorageElementAddress, &EmptyStorageElementCount, + DataBuffer,ElementStatus,mode_sense,NULL); - free(DataBuffer); /* sigh! */ + free(DataBuffer); /* sigh! */ + FirstElement += NumThisTime; + NumElements -= NumThisTime; + + } while ( NumElements > 0 ); /* --------------IMPORT/EXPORT--------------- */ /* Next let's see if we need to do Import/Export: */ -- cgit v1.2.3 From 93b037f057191883037072d50c9cba10540d0102 Mon Sep 17 00:00:00 2001 From: Carsten Leonhardt Date: Thu, 28 Feb 2019 11:49:03 +0100 Subject: Fix configure.in for autoreconf Last-Update: 2019-02-28 autoreconf complains about AC_DEFINE with only one argument, fix those. Gbp-Pq: Name 002-fix-configure-for-autoreconf --- configure.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.in b/configure.in index 10aa09d..b3102ec 100755 --- a/configure.in +++ b/configure.in @@ -10,10 +10,10 @@ AC_CANONICAL_SYSTEM AC_PREFIX_DEFAULT(/usr/local) case "$host_os" in - *linux*) AC_DEFINE(LINUX) + *linux*) AC_DEFINE([LINUX], [1], [Linux]) TARGET=linux ;; - *solaris*) AC_DEFINE(SOLARIS) + *solaris*) AC_DEFINE([SOLARIS], [1], [Solaris]) TARGET=solarissparc ;; *sunos*) TARGET=solarissparc @@ -28,7 +28,7 @@ case "$host_os" in ;; *HP*) TARGET=hpux ;; - *sequent*) AC_DEFINE(SEQUENT) + *sequent*) AC_DEFINE([SEQUENT], [1], [Sequent]) ;; *MINGW*) TARGET=mingw ;; -- cgit v1.2.3 From 3cebef2668cfb6923ce8653f1d8cd17ee509c47d Mon Sep 17 00:00:00 2001 From: Carsten Leonhardt Date: Thu, 28 Feb 2019 11:49:03 +0100 Subject: Fix spelling errors found by lintian Last-Update: 2019-02-28 Gbp-Pq: Name 003-fix-spelling --- loaderinfo.1 | 2 +- scsitape.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/loaderinfo.1 b/loaderinfo.1 index ea6da04..6463704 100644 --- a/loaderinfo.1 +++ b/loaderinfo.1 @@ -55,7 +55,7 @@ whether 'mtx transfer' works). .B Inquiry Page Aside from the normal inquiry info, will also print out whether we have a bar code reader (for loaders that support the Exabyte extension for -reporting presense of said reader). +reporting presence of said reader). .SH OPTIONS diff --git a/scsitape.1 b/scsitape.1 index 46906bc..0e5a6d4 100644 --- a/scsitape.1 +++ b/scsitape.1 @@ -97,7 +97,7 @@ read blocks from the tape, write them to stdout. If we are in variable block mode, should be zero (note: The maximum block size we currently support in variable block mode is 128K, MAX_READ_SIZE will need to be turned into a settable variable to allow bigger reads). If - is ommitted, we assume that we're in variable block mode, and + is omitted, we assume that we're in variable block mode, and that we are going to read from tape until we hit a tapemark or end of partition or end of tape. -- cgit v1.2.3 From 7124950c42605975977cf46e7d98af727bd17179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Hor=C3=A1k?= Date: Sat, 24 Jan 2009 18:06:43 +0100 Subject: Fix spelling errors found by lintian add support for DESTDIR This patch is taken from Fedora: https://src.fedoraproject.org/rpms/mtx/tree/master Gbp-Pq: Name 004-fix-destdir --- Makefile.in | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile.in b/Makefile.in index 6b967cf..05894d2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -33,6 +33,7 @@ INSTALL_DOC = $(INSTALL) -m 644 INSTALL_BIN = $(INSTALL) -m 755 INSTALL_DIR = $(INSTALL) -m 755 -d +DESTDIR = prefix = @prefix@ exec_prefix = @exec_prefix@ sbindir = @sbindir@ @@ -109,13 +110,13 @@ all: $(BINS) dbgs: $(DBGS) install: $(BINS) - $(INSTALL_DIR) $(sbindir) + $(INSTALL_DIR) $(DESTDIR)$(sbindir) for file in $(BINS); do \ - $(INSTALL_BIN) "$$file" $(sbindir) ; \ + $(INSTALL_BIN) "$$file" $(DESTDIR)$(sbindir) ; \ done - $(INSTALL_DIR) $(mandir) $(mandir)/man1 + $(INSTALL_DIR) $(DESTDIR)$(mandir) $(DESTDIR)$(mandir)/man1 for file in mtx.1 tapeinfo.1 scsitape.1 scsieject.1 loaderinfo.1 ; do \ - $(INSTALL_DOC) "$$file" $(mandir)/man1 ; \ + $(INSTALL_DOC) "$$file" $(DESTDIR)$(mandir)/man1 ; \ done clean: -- cgit v1.2.3 From 4810f89e5bc8ec487e68e8b576d661819088742c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Hor=C3=A1k?= Date: Thu, 19 Nov 2009 15:45:54 +0100 Subject: remove the weird debugging-like info The loaderinfo and tapeinfo utilities print a debugging-like information about the number of arguments on command line when started with wrong number of arguments. This patch is taken from Fedora: https://src.fedoraproject.org/rpms/mtx/tree/master Gbp-Pq: Name 005-remove-argc-output --- loaderinfo.c | 1 - tapeinfo.c | 1 - 2 files changed, 2 deletions(-) diff --git a/loaderinfo.c b/loaderinfo.c index b23867e..11aaeac 100644 --- a/loaderinfo.c +++ b/loaderinfo.c @@ -488,7 +488,6 @@ int main(int argc, char **argv) argv0=argv[0]; if (argc != 3) { - fprintf(stderr,"argc=%d",argc); usage(); } diff --git a/tapeinfo.c b/tapeinfo.c index 1a5a0cb..276abc2 100644 --- a/tapeinfo.c +++ b/tapeinfo.c @@ -933,7 +933,6 @@ int main(int argc, char **argv) if (argc != 3) { - fprintf(stderr,"argc=%d",argc); usage(); } -- cgit v1.2.3 From bb23a3cc702b1a19d5776497d31310bb089eb429 Mon Sep 17 00:00:00 2001 From: Ivo De Decker Date: Sun, 1 Nov 2020 12:19:03 +0100 Subject: Add support for large autochangers Bug-Debian: http://bugs.debian.org/728142 For large autochangers, the buffer needed for the ReadElementStatus call can be too large. This patch works around this by doing multiple smaller calls. The maximum value of 10000 seems to be OK for this. Based on tests, the maximum value seems to be between 24000 and 25000, but this might depend on the autochanger. This patch is based on the changes by Wayne Keseberg in http://bugs.debian.org/728142 Gbp-Pq: Name 001-bug728142_many_slots.patch --- mtxl.c | 53 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/mtxl.c b/mtxl.c index 3ae77a6..7106a47 100644 --- a/mtxl.c +++ b/mtxl.c @@ -39,6 +39,8 @@ /* zap the following define when we finally add real import/export support */ #define IMPORT_EXPORT_HACK 1 /* for the moment, import/export == storage */ +#define ReadElementStatusMaxElements 10000 + /* First, do some SCSI routines: */ /* the camlib is used on FreeBSD. */ @@ -500,7 +502,7 @@ ElementModeSense_T *ReadAssignmentPage(DEVICE_TYPE MediumChangerFD) retval->MaxReadElementStatusData = (sizeof(ElementStatusDataHeader_T) + 4 * sizeof(ElementStatusPage_T) + - retval->NumElements * sizeof(TransportElementDescriptor_T)); + (retval->NumElements > ReadElementStatusMaxElements?ReadElementStatusMaxElements:retval->NumElements) * sizeof(TransportElementDescriptor_T)); #ifdef IMPORT_EXPORT_HACK retval->NumStorage = retval->NumStorage+retval->NumImportExport; @@ -1141,6 +1143,7 @@ ElementStatus_T *ReadElementStatus(DEVICE_TYPE MediumChangerFD, RequestSense_T * int empty_idx = 0; boolean is_attached = false; int i,j; + int FirstElement, NumElements, NumThisTime; ElementModeSense_T *mode_sense = NULL; @@ -1207,33 +1210,47 @@ ElementStatus_T *ReadElementStatus(DEVICE_TYPE MediumChangerFD, RequestSense_T * fprintf(stderr,"Using original element status polling method (storage, import/export, drivers etc independantly)\n"); #endif flags->elementtype = StorageElement; /* sigh! */ - DataBuffer = SendElementStatusRequest( MediumChangerFD, RequestSense, - inquiry_info, flags, - mode_sense->StorageStart, - /* adjust for import/export. */ - mode_sense->NumStorage - mode_sense->NumImportExport, - mode_sense->MaxReadElementStatusData); - if (!DataBuffer) + NumElements = mode_sense->NumStorage - mode_sense->NumImportExport; + FirstElement = mode_sense->StorageStart; + + do { + + NumThisTime = NumElements; + if (NumThisTime > ReadElementStatusMaxElements) NumThisTime=ReadElementStatusMaxElements; + + DataBuffer = SendElementStatusRequest( MediumChangerFD, RequestSense, + inquiry_info, flags, + FirstElement, + /* adjust for import/export. */ + NumThisTime, + mode_sense->MaxReadElementStatusData); + + if (!DataBuffer) + { #ifdef DEBUG - fprintf(stderr,"Had no elements!\n"); + fprintf(stderr,"Had no elements!\n"); #endif - /* darn. Free up stuff and return. */ + /* darn. Free up stuff and return. */ #ifdef DEBUG_MODE_SENSE - PrintRequestSense(RequestSense); + PrintRequestSense(RequestSense); #endif - FreeElementData(ElementStatus); - return NULL; - } + FreeElementData(ElementStatus); + return NULL; + } #ifdef DEBUG - fprintf(stderr, "Parsing storage elements\n"); + fprintf(stderr, "Parsing storage elements\n"); #endif - ParseElementStatus(EmptyStorageElementAddress, &EmptyStorageElementCount, - DataBuffer,ElementStatus,mode_sense,NULL); + ParseElementStatus(EmptyStorageElementAddress, &EmptyStorageElementCount, + DataBuffer,ElementStatus,mode_sense,NULL); - free(DataBuffer); /* sigh! */ + free(DataBuffer); /* sigh! */ + FirstElement += NumThisTime; + NumElements -= NumThisTime; + + } while ( NumElements > 0 ); /* --------------IMPORT/EXPORT--------------- */ /* Next let's see if we need to do Import/Export: */ -- cgit v1.2.3 From 799b2efe844c9b534ff7eedb933172784e8ae646 Mon Sep 17 00:00:00 2001 From: Carsten Leonhardt Date: Sun, 1 Nov 2020 12:19:03 +0100 Subject: Fix configure.in for autoreconf Last-Update: 2019-02-28 autoreconf complains about AC_DEFINE with only one argument, fix those. Gbp-Pq: Name 002-fix-configure-for-autoreconf --- configure.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.in b/configure.in index 10aa09d..b3102ec 100755 --- a/configure.in +++ b/configure.in @@ -10,10 +10,10 @@ AC_CANONICAL_SYSTEM AC_PREFIX_DEFAULT(/usr/local) case "$host_os" in - *linux*) AC_DEFINE(LINUX) + *linux*) AC_DEFINE([LINUX], [1], [Linux]) TARGET=linux ;; - *solaris*) AC_DEFINE(SOLARIS) + *solaris*) AC_DEFINE([SOLARIS], [1], [Solaris]) TARGET=solarissparc ;; *sunos*) TARGET=solarissparc @@ -28,7 +28,7 @@ case "$host_os" in ;; *HP*) TARGET=hpux ;; - *sequent*) AC_DEFINE(SEQUENT) + *sequent*) AC_DEFINE([SEQUENT], [1], [Sequent]) ;; *MINGW*) TARGET=mingw ;; -- cgit v1.2.3 From 93fa3a56bb78b81a515ab5e523aea092e0dcf9ae Mon Sep 17 00:00:00 2001 From: Carsten Leonhardt Date: Sun, 1 Nov 2020 12:19:03 +0100 Subject: Fix spelling errors found by lintian Last-Update: 2019-02-28 Gbp-Pq: Name 003-fix-spelling --- loaderinfo.1 | 2 +- scsitape.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/loaderinfo.1 b/loaderinfo.1 index ea6da04..6463704 100644 --- a/loaderinfo.1 +++ b/loaderinfo.1 @@ -55,7 +55,7 @@ whether 'mtx transfer' works). .B Inquiry Page Aside from the normal inquiry info, will also print out whether we have a bar code reader (for loaders that support the Exabyte extension for -reporting presense of said reader). +reporting presence of said reader). .SH OPTIONS diff --git a/scsitape.1 b/scsitape.1 index 46906bc..0e5a6d4 100644 --- a/scsitape.1 +++ b/scsitape.1 @@ -97,7 +97,7 @@ read blocks from the tape, write them to stdout. If we are in variable block mode, should be zero (note: The maximum block size we currently support in variable block mode is 128K, MAX_READ_SIZE will need to be turned into a settable variable to allow bigger reads). If - is ommitted, we assume that we're in variable block mode, and + is omitted, we assume that we're in variable block mode, and that we are going to read from tape until we hit a tapemark or end of partition or end of tape. -- cgit v1.2.3 From f695107c3b551855de5104d46931e4e390b4a4ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Hor=C3=A1k?= Date: Sat, 24 Jan 2009 18:06:43 +0100 Subject: add support for DESTDIR This patch is taken from Fedora: https://src.fedoraproject.org/rpms/mtx/tree/master Gbp-Pq: Name 004-fix-destdir --- Makefile.in | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile.in b/Makefile.in index 6b967cf..05894d2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -33,6 +33,7 @@ INSTALL_DOC = $(INSTALL) -m 644 INSTALL_BIN = $(INSTALL) -m 755 INSTALL_DIR = $(INSTALL) -m 755 -d +DESTDIR = prefix = @prefix@ exec_prefix = @exec_prefix@ sbindir = @sbindir@ @@ -109,13 +110,13 @@ all: $(BINS) dbgs: $(DBGS) install: $(BINS) - $(INSTALL_DIR) $(sbindir) + $(INSTALL_DIR) $(DESTDIR)$(sbindir) for file in $(BINS); do \ - $(INSTALL_BIN) "$$file" $(sbindir) ; \ + $(INSTALL_BIN) "$$file" $(DESTDIR)$(sbindir) ; \ done - $(INSTALL_DIR) $(mandir) $(mandir)/man1 + $(INSTALL_DIR) $(DESTDIR)$(mandir) $(DESTDIR)$(mandir)/man1 for file in mtx.1 tapeinfo.1 scsitape.1 scsieject.1 loaderinfo.1 ; do \ - $(INSTALL_DOC) "$$file" $(mandir)/man1 ; \ + $(INSTALL_DOC) "$$file" $(DESTDIR)$(mandir)/man1 ; \ done clean: -- cgit v1.2.3 From 4abbabed5bd26e793d17709e7040a8b10f69a498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Hor=C3=A1k?= Date: Thu, 19 Nov 2009 15:45:54 +0100 Subject: remove the weird debugging-like info The loaderinfo and tapeinfo utilities print a debugging-like information about the number of arguments on command line when started with wrong number of arguments. This patch is taken from Fedora: https://src.fedoraproject.org/rpms/mtx/tree/master Gbp-Pq: Name 005-remove-argc-output --- loaderinfo.c | 1 - tapeinfo.c | 1 - 2 files changed, 2 deletions(-) diff --git a/loaderinfo.c b/loaderinfo.c index b23867e..11aaeac 100644 --- a/loaderinfo.c +++ b/loaderinfo.c @@ -488,7 +488,6 @@ int main(int argc, char **argv) argv0=argv[0]; if (argc != 3) { - fprintf(stderr,"argc=%d",argc); usage(); } diff --git a/tapeinfo.c b/tapeinfo.c index 1a5a0cb..276abc2 100644 --- a/tapeinfo.c +++ b/tapeinfo.c @@ -933,7 +933,6 @@ int main(int argc, char **argv) if (argc != 3) { - fprintf(stderr,"argc=%d",argc); usage(); } -- cgit v1.2.3 From c52b77353cee2f42392f4f400ca016ce2520d079 Mon Sep 17 00:00:00 2001 From: Carsten Leonhardt Date: Sun, 1 Nov 2020 12:19:03 +0100 Subject: Fix manpage quotation found by lintian Last-Update: 2020-10-31 An apostrophe at the beginning of the line is a command for (g)roff, so it must be either escaped or moved away from the beginning of the line to have a real apostrophe. The sequence \' doesn't stand for an apostrophe, however, but an acute accent. There are escaped sequences for an apostrophe, but they don't seem to be portable. Therefore, the easiest solution is to move the apostrophe away from the beginning of the line. Gbp-Pq: Name 006-fix-quotation-in-manpage --- scsitape.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scsitape.1 b/scsitape.1 index 0e5a6d4..db4c220 100644 --- a/scsitape.1 +++ b/scsitape.1 @@ -162,8 +162,8 @@ native tape driver. You will likely see weird things happen if you attempt to intermingle scsitape commands with native tape driver operations. Note that BRU 16.1 for Solaris (and possibly others, but Solaris I know about) will have a 'scsi' keyword to bypass the -native tape driver and write via direct uscsi commands, so if you use -\'scsitape\' to bypass the flaws of the native Solaris driver, you can use +native tape driver and write via direct uscsi commands, so if you +use 'scsitape' to bypass the flaws of the native Solaris driver, you can use BRU 16.1 to write your actual tape archives. (Assuming that BRU 16.1 has been released at the time that you read this). -- cgit v1.2.3 From c60b8d8cf77aaecff76d87a4dc869a33e5a5a540 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 6 May 2016 21:00:58 +0200 Subject: [PATCH] man: Document mtx eject and previous operations Gbp-Pq: Name 007-man-Document-mtx-eject-and-previous-operations --- mtx.1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mtx.1 b/mtx.1 index a5e6cc6..108836e 100644 --- a/mtx.1 +++ b/mtx.1 @@ -131,13 +131,16 @@ may need to eject the tape using your OS's tape control commands first). Note that this command may not be what you want on large tape libraries -- e.g. on Exabyte 220, the first slot is usually a cleaning tape. If is omitted, defaults to first drive. - .TP 10 .B last [] Loads drive from the last slot in the media changer. Unloads the drive if there is already a tape in it. (Note: you may need to eject the tape using your OS's tape control commands first). .TP 10 +.B previous [] +Unloads the drive and loads the previous tape in sequence. If the drive +was empty, loads the first tape into the drive. +.TP 10 .B next [] Unloads the drive and loads the next tape in sequence. If the drive was empty, loads the first tape into the drive. @@ -145,6 +148,9 @@ empty, loads the first tape into the drive. .B position Positions the robot at a specific slot. Needed by some changers to move to and open the import/export, or mailbox, slot. +.TP 10 +.B eject +Eject the tape currently in the drive. .SH AUTHORS The original 'mtx' program was written by Leonard Zubkoff and extensively -- cgit v1.2.3 From ab0aeeaec45cefbc76f9547e99c83ae70fba68ef Mon Sep 17 00:00:00 2001 From: Carsten Leonhardt Date: Sun, 1 Nov 2020 12:19:03 +0100 Subject: Fix scsitape usage message Last-Update: 2020-11-01 Add the "erase" operation to the usage message of scsitape. (Hint found at Rosa Linux) Gbp-Pq: Name 008-fix-scsitape-usage-message --- scsitape.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scsitape.c b/scsitape.c index dd52dd5..b55ca7c 100644 --- a/scsitape.c +++ b/scsitape.c @@ -63,7 +63,7 @@ #endif void Usage(void) { - FatalError("Usage: scsitape -f where is:\n setblk | fsf | bsf | eod | rewind | eject | mark |\n seek | read [ [] \n"); + FatalError("Usage: scsitape -f where is:\n setblk | fsf | bsf | eod | rewind | eject | erase |\n mark | seek | read [ []\n"); } #define arg1 (arg[0]) /* for backward compatibility, sigh */ -- cgit v1.2.3