diff options
author | Bdale Garbee <bdale@gag.com> | 2009-02-15 18:17:54 +0100 |
---|---|---|
committer | Bdale Garbee <bdale@gag.com> | 2009-02-15 18:17:54 +0100 |
commit | 1c3607e4d1f94869e7887568fb40d16bb0d2407d (patch) | |
tree | f7a37bbbea5791814281affed9da11b47fbd080b |
Import mtx_1.3.12.orig.tar.gz
[dgit import orig mtx_1.3.12.orig.tar.gz]
-rw-r--r-- | CHANGES | 373 | ||||
-rw-r--r-- | COMPATABILITY | 163 | ||||
-rw-r--r-- | FAQ | 144 | ||||
-rw-r--r-- | LICENSE | 280 | ||||
-rw-r--r-- | LICENSE.html | 515 | ||||
-rw-r--r-- | Makefile.in | 176 | ||||
-rw-r--r-- | README | 38 | ||||
-rw-r--r-- | README.win32 | 45 | ||||
-rw-r--r-- | TODO | 15 | ||||
-rwxr-xr-x | build.win32 | 15 | ||||
-rwxr-xr-x | config.guess | 1500 | ||||
-rw-r--r-- | config.h.in | 37 | ||||
-rwxr-xr-x | config.sub | 1616 | ||||
-rwxr-xr-x | configure | 6545 | ||||
-rwxr-xr-x | configure.in | 113 | ||||
-rw-r--r-- | contrib/MTX.html | 209 | ||||
-rw-r--r-- | contrib/README | 3 | ||||
-rw-r--r-- | contrib/TapeChanger-MTX-0.71b.tar.gz | bin | 0 -> 6179 bytes | |||
-rwxr-xr-x | contrib/config_sgen_solaris.sh | 151 | ||||
-rwxr-xr-x | contrib/mtx-changer | 431 | ||||
-rw-r--r-- | contrib/mtx.py | 306 | ||||
-rw-r--r-- | contrib/mtxctl-0.0.2.tar.gz | bin | 0 -> 5688 bytes | |||
-rw-r--r-- | contrib/qdback.tar.gz | bin | 0 -> 11072 bytes | |||
-rw-r--r-- | contrib/tapechanger.html | 209 | ||||
-rw-r--r-- | contrib/tapeinfo.py | 55 | ||||
-rw-r--r-- | contrib/tapeload.pl | 118 | ||||
-rw-r--r-- | contrib/tapeunload.pl | 98 | ||||
-rw-r--r-- | debian/bash_completion | 45 | ||||
-rw-r--r-- | debian/changelog | 159 | ||||
-rw-r--r-- | debian/compat | 1 | ||||
-rw-r--r-- | debian/control | 16 | ||||
-rw-r--r-- | debian/copyright | 15 | ||||
-rw-r--r-- | debian/dirs | 2 | ||||
-rwxr-xr-x | debian/rules | 69 | ||||
-rw-r--r-- | du/defs.h | 25 | ||||
-rw-r--r-- | du/scsi.c | 214 | ||||
-rwxr-xr-x | install-sh | 253 | ||||
-rw-r--r-- | loaderinfo.1 | 90 | ||||
-rw-r--r-- | loaderinfo.c | 510 | ||||
-rwxr-xr-x | makedist | 19 | ||||
-rw-r--r-- | mam2debug.c | 124 | ||||
-rw-r--r-- | mam2debug2.c | 124 | ||||
-rw-r--r-- | msvc/config.h | 37 | ||||
-rw-r--r-- | msvc/loaderinfo/loaderinfo.vcproj | 205 | ||||
-rw-r--r-- | msvc/mtx.sln | 50 | ||||
-rw-r--r-- | msvc/mtx/Distributions.txt | 49 | ||||
-rw-r--r-- | msvc/mtx/mtx.vcproj | 247 | ||||
-rw-r--r-- | msvc/nsmhack/nsmhack.vcproj | 213 | ||||
-rw-r--r-- | msvc/scsieject/scsieject.vcproj | 203 | ||||
-rw-r--r-- | msvc/scsitape/scsitape.vcproj | 203 | ||||
-rw-r--r-- | msvc/tapeinfo/tapeinfo.vcproj | 213 | ||||
-rw-r--r-- | mtx.1 | 257 | ||||
-rw-r--r-- | mtx.c | 1075 | ||||
-rw-r--r-- | mtx.doc | 209 | ||||
-rw-r--r-- | mtx.h | 607 | ||||
-rw-r--r-- | mtx.spec | 109 | ||||
-rw-r--r-- | mtx.spec.in | 109 | ||||
-rw-r--r-- | mtxl.README.html | 165 | ||||
-rw-r--r-- | mtxl.c | 1907 | ||||
-rw-r--r-- | mtxl.h | 109 | ||||
-rw-r--r-- | nsmhack.c | 342 | ||||
-rw-r--r-- | scsi_aix.c | 159 | ||||
-rw-r--r-- | scsi_freebsd.c | 116 | ||||
-rw-r--r-- | scsi_hpux.c | 134 | ||||
-rw-r--r-- | scsi_linux.c | 491 | ||||
-rw-r--r-- | scsi_sgi.c | 81 | ||||
-rw-r--r-- | scsi_sun.c | 156 | ||||
-rw-r--r-- | scsi_win32.c | 355 | ||||
-rw-r--r-- | scsieject.1 | 116 | ||||
-rw-r--r-- | scsieject.c | 255 | ||||
-rw-r--r-- | scsitape.1 | 179 | ||||
-rw-r--r-- | scsitape.c | 941 | ||||
-rw-r--r-- | sg_err.c | 645 | ||||
-rw-r--r-- | sg_err.h | 140 | ||||
-rw-r--r-- | tapeinfo.1 | 72 | ||||
-rw-r--r-- | tapeinfo.c | 969 | ||||
-rw-r--r-- | vms/000readme | 175 | ||||
-rw-r--r-- | vms/build.com | 34 | ||||
-rw-r--r-- | vms/defs.h | 42 | ||||
-rw-r--r-- | vms/descrip.mms | 77 | ||||
-rw-r--r-- | vms/ldrset.c | 183 | ||||
-rw-r--r-- | vms/ldrset.cld | 9 | ||||
-rw-r--r-- | vms/ldrutil.mar | 104 | ||||
-rw-r--r-- | vms/scsi.c | 400 |
84 files changed, 26963 insertions, 0 deletions
@@ -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 + @@ -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. + @@ -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 @@ +<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN"> +<HTML> +<HEAD> +<TITLE>GNU General Public License - GNU Project - Free Software Foundation (FSF)</TITLE> +<LINK REV="made" HREF="mailto:webmasters@www.gnu.org"> +</HEAD> +<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#1F00FF" ALINK="#FF0000" VLINK="#9900DD"> +<H1>GNU General Public License</H1> + +<P> +<HR> + +<P> + +<H2>Table of Contents</H2> +<UL> + + <LI><A NAME="TOC1" HREF="gpl.html#SEC1">GNU GENERAL PUBLIC LICENSE</A> +<UL> +<LI><A NAME="TOC2" HREF="gpl.html#SEC2">Preamble</A> +<LI><A NAME="TOC3" HREF="gpl.html#SEC3">TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</A> +<LI><A NAME="TOC4" HREF="gpl.html#SEC4">How to Apply These Terms to Your New Programs</A> + +</UL> +</UL> + +<P> + +<HR> + +<P> + + + +<H2><A NAME="SEC1" HREF="gpl.html#TOC1">GNU GENERAL PUBLIC LICENSE</A></H2> +<P> +Version 2, June 1991 + +</P> + +<PRE> +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. +</PRE> + + + +<H2><A NAME="SEC2" HREF="gpl.html#TOC2">Preamble</A></H2> + +<P> + 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. + +</P> +<P> + 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. + +</P> +<P> + 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. + +</P> +<P> + 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. + +</P> +<P> + 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. + +</P> +<P> + 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. + +</P> +<P> + 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. + +</P> +<P> + The precise terms and conditions for copying, distribution and +modification follow. + +</P> + + +<H2><A NAME="SEC3" HREF="gpl.html#TOC3">TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</A></H2> + + +<P> + +<STRONG>0.</STRONG> + 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". +<P> + +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. + +<P> + +<STRONG>1.</STRONG> + 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. +<P> + +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. +<P> + +<STRONG>2.</STRONG> + 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: +<P> + +<UL> + +<LI><STRONG>a)</STRONG> + You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + +<P> +<LI><STRONG>b)</STRONG> + 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. + +<P> +<LI><STRONG>c)</STRONG> + 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.) +</UL> + +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. +<P> + +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. +<P> + +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. + +<P> + +<STRONG>3.</STRONG> + 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: + + +<!-- we use this doubled UL to get the sub-sections indented, --> +<!-- while making the bullets as unobvious as possible. --> +<UL> + +<LI><STRONG>a)</STRONG> + 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, + +<P> +<LI><STRONG>b)</STRONG> + 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, + +<P> +<LI><STRONG>c)</STRONG> + 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.) +</UL> + +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. +<P> + +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. +<P> + +<STRONG>4.</STRONG> + 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. + +<P> + +<STRONG>5.</STRONG> + 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. + +<P> + +<STRONG>6.</STRONG> + 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. + +<P> + +<STRONG>7.</STRONG> + 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. +<P> + +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. +<P> + +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. +<P> + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +<P> + +<STRONG>8.</STRONG> + 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. + +<P> + +<STRONG>9.</STRONG> + 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. +<P> + +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. + +<P> + + +<STRONG>10.</STRONG> + 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. + + + +<P><STRONG>NO WARRANTY</STRONG></P> + +<P> + +<STRONG>11.</STRONG> + 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. + +<P> + +<STRONG>12.</STRONG> + 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. + +<P> + + +<H2>END OF TERMS AND CONDITIONS</H2> + + + +<H2><A NAME="SEC4" HREF="gpl.html#TOC4">How to Apply These Terms to Your New Programs</A></H2> + +<P> + 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. + +</P> +<P> + 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. + +</P> + +<PRE> +<VAR>one line to give the program's name and an idea of what it does.</VAR> +Copyright (C) <VAR>yyyy</VAR> <VAR>name of author</VAR> + +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. +</PRE> + +<P> +Also add information on how to contact you by electronic and paper mail. + +</P> +<P> +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + +</P> + +<PRE> +Gnomovision version 69, Copyright (C) <VAR>year</VAR> <VAR>name of author</VAR> +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. +</PRE> + +<P> +The hypothetical commands <SAMP>`show w'</SAMP> and <SAMP>`show c'</SAMP> should show +the appropriate parts of the General Public License. Of course, the +commands you use may be called something other than <SAMP>`show w'</SAMP> and +<SAMP>`show c'</SAMP>; they could even be mouse-clicks or menu items--whatever +suits your program. + +</P> +<P> +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: + +</P> + +<PRE> +Yoyodyne, Inc., hereby disclaims all copyright +interest in the program `Gnomovision' +(which makes passes at compilers) written +by James Hacker. + +<VAR>signature of Ty Coon</VAR>, 1 April 1989 +Ty Coon, President of Vice +</PRE> + +<P> +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. + +<HR> + +<P> +FSF & GNU inquiries & questions to +<A HREF="mailto:gnu@gnu.org"><EM>gnu@gnu.org</EM></A>. +send other questions to +<A HREF="mailto:gnu@gnu.org"><EM>gnu@gnu.org</EM></A>. +<P> +Copyright notice above.<BR> +Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111, USA +<P> +<HR> +</BODY> +</HTML> 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 @@ -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 +<lnz@dandelion.com>. This version was modified for multi-drive, +optical changer, and tape library support by Eric Lee Green +<eric@badtux.org>. 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 <eric@badtux.org> 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<N>, on Windows you use Changer<N>. + +On Linux the tape drive is referenced using /dev/nst<N>, on Windows you use Tape<N>. + +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>:<bus>:<target>:<lun> + + 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 @@ -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 <per@bothner.com>. +# Please send patches to <config-patches@gnu.org>. 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 <config-patches@gnu.org>." + +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 <stdio.h> /* 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 <sys/systemcfg.h> + + 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 <stdlib.h> + #include <unistd.h> + + 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 <unistd.h> + 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 <features.h> + #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' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/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 <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # 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 <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#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 <sys/param.h> + 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 <sys/param.h> +# 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 <<EOF +$0: unable to guess system type + +This script, last modified $timestamp, has failed to recognize +the operating system you are using. It is advised that you +download the most up to date version of the config scripts from + + http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess +and + http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub + +If the version you run ($0) is already up to date, please +send the following data and any information you think might be +pertinent to <config-patches@gnu.org> 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 <config-patches@gnu.org>. 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 <config-patches@gnu.org>." + +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 </dev/null 6>&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 <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#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<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + 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 <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* 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 <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> 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 <limits.h> +#else +# include <assert.h> +#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 <ac_nonexistent.h> +_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 <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> 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 <limits.h> +#else +# include <assert.h> +#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 <ac_nonexistent.h> +_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 <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.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_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 <string.h> + +_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 <stdlib.h> + +_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 <ctype.h> +#include <stdlib.h> +#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 <sys/types.h> +#include <sys/time.h> +#include <time.h> + +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 <sys/types.h> +#include <time.h> + +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 <stdio.h> +#include <stdlib.h> +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 <stdio.h> +#include <stdlib.h> +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 <sys/types.h> +#include <sys/param.h> + +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 <sys/types.h> +#include <sys/param.h> + +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 <sys/types.h> +#include <signal.h> + +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 <limits.h> declares $ac_func. + For example, HP-UX 11i <limits.h> 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 <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#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 <limits.h> declares _doprnt. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define _doprnt innocuous__doprnt + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _doprnt (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#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 <bug-autoconf@gnu.org>." + +_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 <conf$$subs.sed +rm -f conf$$subs.sed +cat >>$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 @@ +<HTML> +<HEAD> +<TITLE>TapeChanger::MTX - use 'mtx' to manipulate a tape library</TITLE> +<LINK REV="made" HREF="mailto:none"> +</HEAD> + +<BODY> + +<A NAME="__index__"></A> +<!-- INDEX BEGIN --> + +<UL> + + <LI><A HREF="#name">NAME</A></LI> + <LI><A HREF="#synopsis">SYNOPSIS</A></LI> + <LI><A HREF="#description">DESCRIPTION</A></LI> + <LI><A HREF="#variables">VARIABLES</A></LI> + <LI><A HREF="#usage">USAGE</A></LI> + <LI><A HREF="#notes">NOTES</A></LI> + <LI><A HREF="#requirements">REQUIREMENTS</A></LI> + <LI><A HREF="#todo">TODO</A></LI> + <LI><A HREF="#see also">SEE ALSO</A></LI> + <LI><A HREF="#author">AUTHOR</A></LI> + <LI><A HREF="#copyright">COPYRIGHT</A></LI> +</UL> +<!-- INDEX END --> + +<HR> +<P> +<H1><A NAME="name">NAME</A></H1> +<P>TapeChanger::MTX - use 'mtx' to manipulate a tape library</P> +<P> +<HR> +<H1><A NAME="synopsis">SYNOPSIS</A></H1> +<PRE> + use TapeChanger::MTX;</PRE> +<PRE> + my $loaded = TapeChanger::MTX->loadedtape; + print "Currently loaded: $loaded\n" if ($loaded);</PRE> +<PRE> + TapeChanger::MTX->loadtape('next'); + my $nowloaded = TapeChanger::MTX->loadedtape; + print "Currently loaded: $nowloaded\n" if ($nowloaded); +</PRE> +<PRE> + +See below for more available functions.</PRE> +<P> +<HR> +<H1><A NAME="description">DESCRIPTION</A></H1> +<P>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.</P> +<P> +<HR> +<H1><A NAME="variables">VARIABLES</A></H1> +<DL> +<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3AMT_%3Ditem_%24TapeCha">$TapeChanger::MTX::MT +=item $TapeChanger::MTX::MTX</A></STRONG><BR> +<DD> +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'. +<P></P> +<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3ADRIVE">$TapeChanger::MTX::DRIVE</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3ACONTROL">$TapeChanger::MTX::CONTROL</A></STRONG><BR> +<DD> +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. +<P></P> +<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3AEJECT">$TapeChanger::MTX::EJECT</A></STRONG><BR> +<DD> +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'. +<P></P> +<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3AREADY_TIME">$TapeChanger::MTX::READY_TIME</A></STRONG><BR> +<DD> +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. +<P></P> +<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3ADEBUG">$TapeChanger::MTX::DEBUG</A></STRONG><BR> +<DD> +Print debugging information? Set to '0' for normal verbosity, '1' for +debugging information, or '-1' for 'quiet mode' (be as quiet as possible). +<P></P></DL> +<P> +<HR> +<H1><A NAME="usage">USAGE</A></H1> +<P>This module uses the following functions:</P> +<DL> +<DT><STRONG><A NAME="item_tape_cmd">tape_cmd ( COMMAND )</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_mt_cmd">mt_cmd ( COMMAND )</A></STRONG><BR> +<DD> +Runs 'mtx' and 'mt' as appropriate. <CODE>COMMAND</CODE> 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. +<P></P> +<DT><STRONG><A NAME="item_numdrives">numdrives ()</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_numslots">numslots ()</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_loadedtape">loadedtape ()</A></STRONG><BR> +<DD> +Returns the number of drives, number of slots, and currently loaded tape +values, respectively, by parsing <STRONG>tape_cmd('status')</STRONG>. +<P></P> +<DT><STRONG><A NAME="item_loadtape">loadtape ( SLOT [, DRIVE] )</A></STRONG><BR> +<DD> +Loads a tape into the tape changer, and waits until the drive is again +ready to be written to. <CODE>SLOT</CODE> can be any of the following (with the +relevant function indicated): +<PRE> + 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.</PRE> +<P><CODE>DRIVE</CODE> is the drive to load, and defaults to 0. Returns 0 if +successful, an error string otherwise.</P> +<P></P> +<DT><STRONG><A NAME="item_loadnexttape">loadnexttape ()</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_loadprevtape">loadprevtape ()</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_loadfirsttape">loadfirsttape ()</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_loadlasttape">loadlasttape ()</A></STRONG><BR> +<DD> +Loads the next, previous, first, and last tapes in the changer +respectively. Use <STRONG>tape_cmd('next')</STRONG>, <STRONG>tape_cmd('previous')</STRONG>, +<STRONG>tape_cmd('first')</STRONG>, and <STRONG>tape_cmd('last')</STRONG>, respectively. +<P></P> +<DT><STRONG><A NAME="item_ejecttape">ejecttape ()</A></STRONG><BR> +<DD> +Ejects the tape, by first ejecting the tape from the drive +(<STRONG>mt_cmd(rewind)</STRONG> then <STRONG>mt_cmd(offline)</STRONG>) and then returning it to its +slot (<STRONG>tape_cmd(unload)</STRONG>). Returns 1 if successful, 0 otherwise. +<P></P> +<DT><STRONG><A NAME="item_resetchanger">resetchanger ()</A></STRONG><BR> +<DD> +Resets the changer, ejecting the tape and loading the first one from the +changer. +<P></P> +<DT><STRONG><A NAME="item_checkdrive">checkdrive ()</A></STRONG><BR> +<DD> +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 <STRONG>mt_cmd(status)</STRONG>. Returns 1 if so, 0 otherwise. +<P></P> +<DT><STRONG><A NAME="item_reportstatus">reportstatus</A></STRONG><BR> +<DD> +Returns a string containing the loaded tape and the drive that it's +mounted on. +<P></P> +<DT><STRONG><A NAME="item_cannot_run">cannot_run ()</A></STRONG><BR> +<DD> +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. +<P></P></DL> +<P> +<HR> +<H1><A NAME="notes">NOTES</A></H1> +<P>~/.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 <CODE>setuid()</CODE> 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.</P> +<P> +<HR> +<H1><A NAME="requirements">REQUIREMENTS</A></H1> +<P>Perl 5.6.0 or better, an installed 'mtx' binary, and a tape changer and +reader connected to the system.</P> +<P> +<HR> +<H1><A NAME="todo">TODO</A></H1> +<P>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).</P> +<P> +<HR> +<H1><A NAME="see also">SEE ALSO</A></H1> +<P><STRONG>mtx</STRONG>, <STRONG>mt</STRONG>, <STRONG>tapechanger</STRONG>. Inspired by <STRONG>stc-changer</STRONG>, which comes +with the AMANDA tape backup package (http://www.amanda.org), and MTX, +available at <A HREF="http://mtx.sourceforge.net.">http://mtx.sourceforge.net.</A></P> +<P> +<HR> +<H1><A NAME="author">AUTHOR</A></H1> +<P>Tim Skirvin <<A HREF="mailto:tskirvin@uiuc.edu">tskirvin@uiuc.edu</A>></P> +<P> +<HR> +<H1><A NAME="copyright">COPYRIGHT</A></H1> +<P>Copyright 2001-2002 by the University of Illinois Board of Trustees and +Tim Skirvin <<A HREF="mailto:tskirvin@ks.uiuc.edu">tskirvin@ks.uiuc.edu</A>>.</P> + +</BODY> + +</HTML> 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 Binary files differnew file mode 100644 index 0000000..a42a2e0 --- /dev/null +++ b/contrib/TapeChanger-MTX-0.71b.tar.gz 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 <command> [arg...]" + echo " -info reports capability and loaded tape" + echo " -slot <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: <tape#> 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: <tape#> reason + echo "$ct $CommandResStr" + exit 1 + else + # success; output: <tape#> 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 Binary files differnew file mode 100644 index 0000000..de41b7d --- /dev/null +++ b/contrib/mtxctl-0.0.2.tar.gz diff --git a/contrib/qdback.tar.gz b/contrib/qdback.tar.gz Binary files differnew file mode 100644 index 0000000..761a216 --- /dev/null +++ b/contrib/qdback.tar.gz 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 @@ +<HTML> +<HEAD> +<TITLE>TapeChanger::MTX - use 'mtx' to manipulate a tape library</TITLE> +<LINK REV="made" HREF="mailto:none"> +</HEAD> + +<BODY> + +<A NAME="__index__"></A> +<!-- INDEX BEGIN --> + +<UL> + + <LI><A HREF="#name">NAME</A></LI> + <LI><A HREF="#synopsis">SYNOPSIS</A></LI> + <LI><A HREF="#description">DESCRIPTION</A></LI> + <LI><A HREF="#variables">VARIABLES</A></LI> + <LI><A HREF="#usage">USAGE</A></LI> + <LI><A HREF="#notes">NOTES</A></LI> + <LI><A HREF="#requirements">REQUIREMENTS</A></LI> + <LI><A HREF="#todo">TODO</A></LI> + <LI><A HREF="#see also">SEE ALSO</A></LI> + <LI><A HREF="#author">AUTHOR</A></LI> + <LI><A HREF="#copyright">COPYRIGHT</A></LI> +</UL> +<!-- INDEX END --> + +<HR> +<P> +<H1><A NAME="name">NAME</A></H1> +<P>TapeChanger::MTX - use 'mtx' to manipulate a tape library</P> +<P> +<HR> +<H1><A NAME="synopsis">SYNOPSIS</A></H1> +<PRE> + use TapeChanger::MTX;</PRE> +<PRE> + my $loaded = TapeChanger::MTX->loadedtape; + print "Currently loaded: $loaded\n" if ($loaded);</PRE> +<PRE> + TapeChanger::MTX->loadtape('next'); + my $nowloaded = TapeChanger::MTX->loadedtape; + print "Currently loaded: $nowloaded\n" if ($nowloaded); +</PRE> +<PRE> + +See below for more available functions.</PRE> +<P> +<HR> +<H1><A NAME="description">DESCRIPTION</A></H1> +<P>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.</P> +<P> +<HR> +<H1><A NAME="variables">VARIABLES</A></H1> +<DL> +<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3AMT_%3Ditem_%24TapeCha">$TapeChanger::MTX::MT +=item $TapeChanger::MTX::MTX</A></STRONG><BR> +<DD> +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'. +<P></P> +<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3ADRIVE">$TapeChanger::MTX::DRIVE</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3ACONTROL">$TapeChanger::MTX::CONTROL</A></STRONG><BR> +<DD> +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. +<P></P> +<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3AEJECT">$TapeChanger::MTX::EJECT</A></STRONG><BR> +<DD> +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'. +<P></P> +<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3AREADY_TIME">$TapeChanger::MTX::READY_TIME</A></STRONG><BR> +<DD> +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. +<P></P> +<DT><STRONG><A NAME="item_%24TapeChanger%3A%3AMTX%3A%3ADEBUG">$TapeChanger::MTX::DEBUG</A></STRONG><BR> +<DD> +Print debugging information? Set to '0' for normal verbosity, '1' for +debugging information, or '-1' for 'quiet mode' (be as quiet as possible). +<P></P></DL> +<P> +<HR> +<H1><A NAME="usage">USAGE</A></H1> +<P>This module uses the following functions:</P> +<DL> +<DT><STRONG><A NAME="item_tape_cmd">tape_cmd ( COMMAND )</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_mt_cmd">mt_cmd ( COMMAND )</A></STRONG><BR> +<DD> +Runs 'mtx' and 'mt' as appropriate. <CODE>COMMAND</CODE> 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. +<P></P> +<DT><STRONG><A NAME="item_numdrives">numdrives ()</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_numslots">numslots ()</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_loadedtape">loadedtape ()</A></STRONG><BR> +<DD> +Returns the number of drives, number of slots, and currently loaded tape +values, respectively, by parsing <STRONG>tape_cmd('status')</STRONG>. +<P></P> +<DT><STRONG><A NAME="item_loadtape">loadtape ( SLOT [, DRIVE] )</A></STRONG><BR> +<DD> +Loads a tape into the tape changer, and waits until the drive is again +ready to be written to. <CODE>SLOT</CODE> can be any of the following (with the +relevant function indicated): +<PRE> + 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.</PRE> +<P><CODE>DRIVE</CODE> is the drive to load, and defaults to 0. Returns 0 if +successful, an error string otherwise.</P> +<P></P> +<DT><STRONG><A NAME="item_loadnexttape">loadnexttape ()</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_loadprevtape">loadprevtape ()</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_loadfirsttape">loadfirsttape ()</A></STRONG><BR> +<DD> +<DT><STRONG><A NAME="item_loadlasttape">loadlasttape ()</A></STRONG><BR> +<DD> +Loads the next, previous, first, and last tapes in the changer +respectively. Use <STRONG>tape_cmd('next')</STRONG>, <STRONG>tape_cmd('previous')</STRONG>, +<STRONG>tape_cmd('first')</STRONG>, and <STRONG>tape_cmd('last')</STRONG>, respectively. +<P></P> +<DT><STRONG><A NAME="item_ejecttape">ejecttape ()</A></STRONG><BR> +<DD> +Ejects the tape, by first ejecting the tape from the drive +(<STRONG>mt_cmd(rewind)</STRONG> then <STRONG>mt_cmd(offline)</STRONG>) and then returning it to its +slot (<STRONG>tape_cmd(unload)</STRONG>). Returns 1 if successful, 0 otherwise. +<P></P> +<DT><STRONG><A NAME="item_resetchanger">resetchanger ()</A></STRONG><BR> +<DD> +Resets the changer, ejecting the tape and loading the first one from the +changer. +<P></P> +<DT><STRONG><A NAME="item_checkdrive">checkdrive ()</A></STRONG><BR> +<DD> +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 <STRONG>mt_cmd(status)</STRONG>. Returns 1 if so, 0 otherwise. +<P></P> +<DT><STRONG><A NAME="item_reportstatus">reportstatus</A></STRONG><BR> +<DD> +Returns a string containing the loaded tape and the drive that it's +mounted on. +<P></P> +<DT><STRONG><A NAME="item_cannot_run">cannot_run ()</A></STRONG><BR> +<DD> +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. +<P></P></DL> +<P> +<HR> +<H1><A NAME="notes">NOTES</A></H1> +<P>~/.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 <CODE>setuid()</CODE> 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.</P> +<P> +<HR> +<H1><A NAME="requirements">REQUIREMENTS</A></H1> +<P>Perl 5.6.0 or better, an installed 'mtx' binary, and a tape changer and +reader connected to the system.</P> +<P> +<HR> +<H1><A NAME="todo">TODO</A></H1> +<P>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).</P> +<P> +<HR> +<H1><A NAME="see also">SEE ALSO</A></H1> +<P><STRONG>mtx</STRONG>, <STRONG>mt</STRONG>, <STRONG>tapechanger</STRONG>. Inspired by <STRONG>stc-changer</STRONG>, which comes +with the AMANDA tape backup package (http://www.amanda.org), and MTX, +available at <A HREF="http://mtx.sourceforge.net.">http://mtx.sourceforge.net.</A></P> +<P> +<HR> +<H1><A NAME="author">AUTHOR</A></H1> +<P>Tim Skirvin <<A HREF="mailto:tskirvin@uiuc.edu">tskirvin@uiuc.edu</A>></P> +<P> +<HR> +<H1><A NAME="copyright">COPYRIGHT</A></H1> +<P>Copyright 2001-2002 by the University of Illinois Board of Trustees and +Tim Skirvin <<A HREF="mailto:tskirvin@ks.uiuc.edu">tskirvin@ks.uiuc.edu</A>>.</P> + +</BODY> + +</HTML> 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= <FD>; # 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= <FD>; # 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 <jjm@ixtab.org.uk> +# +# $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 <robertn@the-nelsons.org> 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 <bdale@gag.com> 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 <bdale@gag.com> Sat, 19 Aug 2006 18:44:54 -0600 + +mtx (1.2.17rel-1) unstable; urgency=low + + * new upstream version + + -- Bdale Garbee <bdale@gag.com> 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 <bdale@gag.com> 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 <bdale@gag.com> Sat, 14 Feb 2004 22:36:23 -0700 + +mtx (1.2.16rel-3) unstable; urgency=low + + * apply patch from Torsten Werner <twerner@debian.org> that elminates + hard-coding of the value of HZ, closes: #224147 + + -- Bdale Garbee <bdale@gag.com> Tue, 16 Dec 2003 10:04:26 -0700 + +mtx (1.2.16rel-2) unstable; urgency=low + + * apply patch from R.A.Owen <rao3@leicester.ac.uk> that fixes the "staggered" + output from the status command on some changers, closes: #129910 + + -- Bdale Garbee <bdale@gag.com> 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 <bdale@gag.com> 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 <bdale@gag.com> Sun, 30 Dec 2001 21:28:46 -0700 + +mtx (1.2.10-1) unstable; urgency=low + + * new upstream source + + -- Bdale Garbee <bdale@gag.com> 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 <bdale@gag.com> 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 <bdale@gag.com> 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 <bdale@gag.com> 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 <bdale@gag.com> 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 <bdale@gag.com> Tue, 27 Jan 1998 15:06:13 -0700 + +mtx (1.0-5) unstable; urgency=low + + * explicit include path to find <scsi/scsi_ioctl.h> in the + /usr/src/linux/include tree. closes bug 16877 + + -- Bdale Garbee <bdale@gag.com> 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 <bdale@gag.com> Sun, 21 Sep 1997 02:38:50 -0600 + +mtx (1.0-3) unstable; urgency=low + + * libc6 + + -- Bdale Garbee <bdale@gag.com> 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 <bdale@gag.com> Sun, 10 Aug 1997 03:50:42 -0600 + +mtx (1.0-1) unstable; urgency=low + + * Initial Release. + + -- Bdale Garbee <bdale@gag.com> 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 <robertn@the-nelsons.org> +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 <lnz@dandelion.com> + Changes copyright 2000, 2001 Eric Green <eric@badtux.org> + Changes copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org> + + 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 <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +typedef int DEVICE_TYPE; + +#ifdef __osf__ +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <io/common/iotypes.h> +#else /* must be ultrix */ +#include <sys/devio.h> +#endif +#include <io/cam/cam.h> +#include <io/cam/uagt.h> +#include <io/cam/dec_cam.h> +#include <io/cam/scsi_all.h> +#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 <eric@badtux.org> +.\" Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org> +.\" +.\" 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 <scsi-generic-device> +.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 <robertnelson@users.sourceforge.net> +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 <robertn@the-nelsons.org> + * 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 <stdio.h> +#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 <generic-device>\n"); +} + + +/* we only have one argument: "-f <device>". */ +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.in >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 <robertn@the-nelsons.org> + +$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ +$Revision: 193 $ + + Written by Eric Lee Green <eric@badtux.org> + 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 <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#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 <robertn@the-nelsons.org> + +$Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ +$Revision: 193 $ + + Written by Eric Lee Green <eric@badtux.org> + 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 <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#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 @@ +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="loaderinfo"
+ ProjectGUID="{13712060-F1FC-4498-97A7-5DA5A38F04DD}"
+ RootNamespace="loaderinfo"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".."
+ PreprocessorDefinitions="WIN32;_DEBUG;DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4214"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=".."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4214"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\loaderinfo.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\mtxl.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
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 <bgmilne@linux-mandrake.com> +Stable Version: 1.2.18-1mdk + +Merged: No changes + + +Redhat +====== + +Maintainer: Jesse Keating <jkeating@redhat.com> (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 @@ +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="mtx"
+ ProjectGUID="{7DD926F5-30EA-47D4-B67B-E32C0E221440}"
+ RootNamespace="mtx"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="VERSION=\"1.3.9-rbn\";LONG_PRINT_REQUEST_SENSE;WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4214"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="VERSION=\"1.3.11\";WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4214"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\mtx.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ CompileAs="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ CompileAs="1"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\mtxl.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ CompileAs="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ CompileAs="1"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\mtx.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\mtxl.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <File
+ RelativePath=".\Distributions.txt"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
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 @@ +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="nsmhack"
+ ProjectGUID="{1B3C0A23-4021-4928-92FA-76743B7F7F76}"
+ RootNamespace="nsmhack"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".."
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4214"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=".."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4214"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\mtxl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\nsmhack.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\mtx.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\mtxl.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
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 @@ +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="scsieject"
+ ProjectGUID="{E3B77A78-FD72-4AD7-933A-0503FB21551D}"
+ RootNamespace="scsieject"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4214;4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4214;4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\mtxl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\scsieject.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
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 @@ +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="scsitape"
+ ProjectGUID="{D19E95BD-87C6-4C91-A208-FB8338580F75}"
+ RootNamespace="scsitape"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4214;4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4214;4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\mtxl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\scsitape.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
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 @@ +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="tapeinfo"
+ ProjectGUID="{A1C8D34F-66EC-4F74-8261-C96B97727218}"
+ RootNamespace="tapeinfo"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=".."
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4214"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=".."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4214"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\mtxl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\tapeinfo.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\..\mtx.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\mtxl.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
@@ -0,0 +1,257 @@ +.\" mtx.1 Document copyright 2000 Eric Lee Green +.\" Program Copyright 1996, 1997 Leonard Zubkoff +.\" Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org> +.\" Extensive changes 2000 by Eric Lee Green <eric@badtux.org> +.\" +.\" 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 <scsi-generic-device>] [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 <slotnum> [ <drivenum> ] +Load media from slot <slotnum> into drive <drivenum>. Drive 0 is assumed +if the drive number is omitted. +.TP 10 +.B unload [<slotnum>] [ <drivenum> ] +Unloads media from drive <drivenum> into slot <slotnum>. If <drivenum> is +omitted, defaults to drive 0 (as do all commands). +If <slotnum> 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 <operation>] transfer <slotnum> <slotnum> +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 <operation> +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 <operation>] [invert] [invert2] exchange <slotnum> <slotnum> [<slotnum>] +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 [<drivenum>] +Loads drive <drivenum> 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 <drivenum> is omitted, defaults to first drive. + +.TP 10 +.B last [<drivenum>] +Loads drive <drivenum> 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 [<drivenum>] +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 <slotnum> +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 <eric@badtux.org>. 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 <robertnelson@users.sourceforge.net> . +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) @@ -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 <robertn@the-nelsons.org> + + 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 <philipp@enteka.com> of Enteka Enterprise + Technology Service for porting MTX to Solaris/SPARC. + + Thanks to Carsten Koch <Carsten.Koch@icem.de> 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 <eric@badtux.org> 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 <loader-dev> ] noattach <more commands>\n\ + mtx [ -f <loader-dev> ] inquiry | inventory \n\ + mtx [ -f <loader-dev> ] [altres] [nobarcode] status\n\ + mtx [ -f <loader-dev> ] [altres] first [<drive#>]\n\ + mtx [ -f <loader-dev> ] [altres] last [<drive#>]\n\ + mtx [ -f <loader-dev> ] [altres] previous [<drive#>]\n\ + mtx [ -f <loader-dev> ] [altres] next [<drive#>]\n\ + mtx [ -f <loader-dev> ] [altres] [invert] load <storage-element-number> [<drive#>]\n\ + mtx [ -f <loader-dev> ] [altres] [invert] unload [<storage-element-number>][<drive#>]\n\ + mtx [ -f <loader-dev> ] [altres] [eepos eepos-number] transfer <storage-element-number> <storage-element-number>\n\ + mtx [ -f <loader-dev> ] [altres] [eepos eepos-number][invert][invert2] exchange <storage-element-number> <storage-element-number>\n\ + mtx [ -f <loader-dev> ] [altres] position <storage-element-number>\n\ + mtx [ -f <loader-dev> ] 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 <storage-element-number> argument '%d' to 'load' command\n", + arg1 + 1); + } + + if (arg2 < 0 || arg2 >= ElementStatus->DataTransferElementCount) + { + FatalError( "illegal <drive-number> 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 <storage-element-number> argument '%d' to 'unload' command\n", + arg1 + 1); + } + + if (arg2 < 0 || arg2 >= ElementStatus->DataTransferElementCount) + { + FatalError( "illegal <drive-number> 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 +} @@ -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 <lnz@dandelion.com> + + + 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<N>. +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<N>. 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<N>. 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 <tape-device>" 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 <tape-device> ] 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 <tape-device> ] 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 <tape-device> ] load <storage-element-number> + +The "load" command loads the volume in Storage Element <storage-element-number> +into the Data Transfer Element. An error is signaled if the Data Transfer +Element is already full. + + +mtx [ -f <tape-device> ] unload [ <storage-element-number> ] + +The "unload" command unloads the volume in the Data Transfer Element into +Storage Element <storage-element-number>. If <storage-element-number> 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 <tape-device> ] 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 <tape-device> ] 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 <tape-device> ] 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 <tape-device> ] 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 / <wherever> + +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. @@ -0,0 +1,607 @@ +/* MTX -- SCSI Tape Attached Medium Control Program + + Copyright 1997-1998 Leonard N. Zubkoff <lnz@dandelion.com> + + Changes 1999 Eric Lee Green to add support for multi-drive tape changers. + Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org> + + $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 <stdio.h> +#include <errno.h> + +#if HAVE_STDLIB_H +# include <stdlib.h> +#endif + +#if HAVE_FCNTL_H +# include <fcntl.h> +#endif + +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#if HAVE_STRING_H +# include <string.h> +#else +# include <strings.h> +#endif + +#if HAVE_UNISTD_H +# include <unistd.h> +#endif + +#if HAVE_STDARG_H +# include <stdarg.h> +#endif + +#if HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif + +#if HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif + +#if HAVE_SYS_PARAM_H +# include <sys/param.h> +#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 <scsi/scsi.h> +# include <scsi/scsi_ioctl.h> +# include <scsi/sg.h> +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 <windows.h> +# include <ddk/ntddscsi.h> +# 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 <windows.h> +# include <winioctl.h> +# include <ntddscsi.h> +# undef DEVICE_TYPE + +typedef int DEVICE_TYPE; +#endif + +/* The 'cam' interface, like FreeBSD: */ +#if HAVE_CAMLIB_H +# include <camlib.h> /* easy (?) access to the CAM user library. */ +# include <cam/cam_ccb.h> +# include <cam/scsi/scsi_message.h> /* 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 <sys/scsi/impl/uscsi.h> +typedef int DEVICE_TYPE; +#endif + +/* the scsi_ctl interface, as used on HP/UX: */ +#if HAVE_SYS_SCSI_CTL_H +# include <sys/wsio.h> +# include <sys/spinlock.h> +# include <sys/scsi.h> +# include <sys/scsi_ctl.h> + 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 <sys/gscdds.h> + typedef int DEVICE_TYPE; +#endif + + /* the 'dslib' interface, as used on SGI. */ +#if HAVE_DSLIB_H +#include <dslib.h> +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 <eric@badtux.org> +- 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 <shiva@well.com> +- 1.2.12pre1 +- Need to create usr/sbin for install + +* Fri Mar 02 2001 Eric Green <eric@estinc.com> +- 1.2.11pre6 +- Move tapeinfo,loaderinfo, scsitape to /usr/sbin rather than /sbin + +* Wed Feb 28 2001 Kenneth Porter <shiva@well.com> +- 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 <eric@estinc.com> +- 1.2.11pre3 +- Removed patch, now use ./configure. + +* Mon Nov 27 2000 Eric Green <eric@estinc.com> +- 1.2.10 +- Fixed patching to use the portable.patch. + +* Tue Jul 25 2000 Eric Green <eric@estinc.com> +- 1.2.8 +- Added portability patch to mtx.spec so should compile on Red Hat Alpha etc. + +* Thu Jun 6 2000 Eric Green <eric@estinc.com> +- 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 <shiva@well.com> +- 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 <shiva@well.com> +- Spell sourceforge right so the link at rpmfind.net will work. + +* Thu May 4 2000 Kenneth Porter <shiva@well.com> +- 1.2.5 + +* Thu Oct 29 1998 Ian Macdonald <ianmacd@xs4all.nl> +- moved mtx from /sbin to /bin, seeing as mt is also located there + +* Fri Oct 23 1998 Ian Macdonald <ianmacd@xs4all.nl> +- 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 <eric@badtux.org> +- 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 <shiva@well.com> +- 1.2.12pre1 +- Need to create usr/sbin for install + +* Fri Mar 02 2001 Eric Green <eric@estinc.com> +- 1.2.11pre6 +- Move tapeinfo,loaderinfo, scsitape to /usr/sbin rather than /sbin + +* Wed Feb 28 2001 Kenneth Porter <shiva@well.com> +- 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 <eric@estinc.com> +- 1.2.11pre3 +- Removed patch, now use ./configure. + +* Mon Nov 27 2000 Eric Green <eric@estinc.com> +- 1.2.10 +- Fixed patching to use the portable.patch. + +* Tue Jul 25 2000 Eric Green <eric@estinc.com> +- 1.2.8 +- Added portability patch to mtx.spec so should compile on Red Hat Alpha etc. + +* Thu Jun 6 2000 Eric Green <eric@estinc.com> +- 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 <shiva@well.com> +- 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 <shiva@well.com> +- Spell sourceforge right so the link at rpmfind.net will work. + +* Thu May 4 2000 Kenneth Porter <shiva@well.com> +- 1.2.5 + +* Thu Oct 29 1998 Ian Macdonald <ianmacd@xs4all.nl> +- moved mtx from /sbin to /bin, seeing as mt is also located there + +* Fri Oct 23 1998 Ian Macdonald <ianmacd@xs4all.nl> +- 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 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<html> + <head> + + <title>SCSI Media Changer and Backup Device Control System</title> + + </head> + + <body> +<center> + <h1>SCSI Media Changer and Backup Device Control System</h1> +</center> +<p> +[Also see the SourceForge <a href="http://sourceforge.net/projects/mtx"> +project page</a>.] +<p> +<i>mtx</i> 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). <i>mtx</i> is designed to be a low level driver in a larger +scripted backup solution, such as <a +href="http://amanda.sourceforge.net">Amanda</a>. +<i>mtx</i> is not +supposed to itself be a high level interface to the SCSI devices that +it controls. +<p> +This version has the following features: + + <ul> + <li> Will deal with LARGE media libraries (over a hundred elements). + <li> Supports multi-drive media changers such as the Exabyte 220 dual- +drive tape library. + <li> Supports the 'invert' bit for optical jukeboxes that need that in +order to flip their media. + <li> Supports the 'eepos' bits for libraries that need this to extend/retract +their import/export tray. + <li> Now supports import/export elements! + <li> Reports volume tags (bar codes) and "alternate volume tags" +(whatever those are!) for those tape libraries +that support them. +<li> Now runs under FreeBSD and at least Solaris 8. + +<li> Now has a 'man' page! +<li> 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). +</ul> + +<p> + 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. +</ul> +<h2> Source Code </h2> +The current source code is: +<ul> +<li> <a href="http://mtx.sourceforge.net/mtx-1.2.13.tar.gz">http://mtx.sourceforge.net/mtx-1.2.13.tar.gz</a> +</ul> +RPMs may be available from the following place: +<ul> +<li> <a href="http://rpmfind.net/linux/RPM/mtx.html">RPMfind's 'mtx' page</a> +</ul> +A .spec file is now included in the 'mtx' distribution for building your +own RPM's. +<p> +Note that RPMs +are courtesy of <a href="http://www.sewingwitch.com/ken/">Kenneth Porter</a>, +who should be contacted regarding rpm-related problems. +<p> + +<h2> Known Bugs And Limitations </h2> +<ul> +<li> + 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. +<li> +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. + <li> + 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. + +<li> + 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. + +<li> 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). + +<li> VMS and Tru64 support are probably irretrievably busted. + + +<li> This program will only use the first arm of multiple-arm robots unless +the robot re-maps all arms to one element ID. + +<li> 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 +<a href="http://download.sourceforge.net/amanda/">http://download.sourceforge.net/amanda</a>. + +</ul> + +<h2> Philosophy </h2> +The Unix philosophy is "many small tools chained together". <i>mtx</i> supplies +those small tools so that you can create your own backup and +recovery tools by chaining +<i>mtx</i> pieces together, whether it be with /bin/sh, Perl, Python, or +CAML. + + +<h2> Support </h2> +<ul> +<li>There is now a 'mtx' mailing list at <a href="http://sourceforge.net/projects/mtx/">http://sourceforge.net/projects/mtx/</a>. +<li>There is now a 'mtx' home page at <a href="http://mtx.sourceforge.net">http://mtx.sourceforge.net</a>. +<li> There is now a FAQ that is part of the source code. Please read the +FAQ first. +<li>Report problems to Eric Lee Green (<a +href="mailto:eric@badtux.org">eric@badtux.org</a>). READ THE FAQ FIRST! +</ul> + +<h2> See Also: </h2> +<ul> +<li>The man page for 'mtx'! (once you get it installed). +<li>T-10 SCSI Working Group home page at <a href="http://www.t10.org">www.t10.org</a>. +<li>The Linux 'sg' SCSI generic driver home page at <a href="http://www.torque.net/sg/">http://www.torque.net/sg/</a>. +<li> <a href="http://badtux.org/eric">The Home Page Of <UL> Tags Anonymous</a> Hi, my name is Eric, and I am addicted to the <UL> tag... +</ul> + <hr> + <address>Maintained by <a href="mailto:eric@badtux.org">Eric Lee Green</a><br> + Hosted by <a href="http://www.valinux.com">VA Linux</a>'s <a href="http://www.sourceforge.net">SourceForge</a></address><br> + + +<!-- Created: Fri Mar 3 12:19:38 MST 2000 --> +<!-- hhmts start --> +Last modified: Mon Jun 25 15:37:22 MST 2001 +<!-- hhmts end --> + </body> +</html> @@ -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 <robertn@the-nelsons.org> + + $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $ + $Revision: 193 $ + + This file created Feb 2000 by Eric Lee Green <eric@badtux.org> 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); +} @@ -0,0 +1,109 @@ +/* + MTX -- SCSI Tape Attached Medium Changer Control Program + + Copyright 1997-1998 Leonard N. Zubkoff <lnz@dandelion.com> + Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org> + This file created by Eric Lee Green <eric@badtux.org> + + 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 <robertn@the-nelsons.org> + * 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 <devicenode> + tongue_out <sourceslot> + 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 <generic-device> <command> where <command> 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) { + 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])) { + /* 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 <steve.heck@am.sony.com> + Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org> + +$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 <robertn@the-nelsons.org> + Written by Eric Lee Green <eric@badtux.org> + +$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 <lnz@dandelion.com> + Changes copyright 2000 Eric Green <eric@badtux.org> + Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org> + + 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 <n> 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 <lnz@dandelion.com> + Changes in Feb 2000 Eric Green <eric@badtux.org> + Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org> + +$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 <eric@badtux.org> 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 <eric@estinc.com> 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 <eric@badtux.org> 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 <eric@estinc.com> 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 <lnz@dandelion.com> + Changes copyright 2000 Eric Green <eric@badtux.org> + Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org> + +$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 <lnz@dandelion.com> + Changes copyright 2000 Eric Green <eric@badtux.org> + Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org> + +$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 <robertn@the-nelsons.org> + +$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 <stdio.h> +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +#ifdef _MSC_VER +#include <ntddscsi.h> +#else +#include <ddk/ntddscsi.h> +#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 <scsi-generic-device>] 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 <robertnelson@users.sourceforge.net> +based on the scsitape program written by Eric Lee Green <eric@badtux.org>. +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 <robertnelson@users.sourceforge.net> +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 <robertn@the-nelsons.org>
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "mtx.h"
+#include "mtxl.h"
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef _MSC_VER
+#include <io.h>
+#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 <generic-device> <command> where <command> 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 <robertn@the-nelsons.org> +.\" +.\" 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 <scsi-generic-device>] 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 <n> +Set the tape drive's SCSI block size to <n> bytes. (NOTE: if you are +using your OS's native tape driver, THIS IS EVIL!). + +.TP 10 +.B fsf <n> +Go forward by <n> tapemarks. +.TP 10 +.B bsf <n> +Go to immediately previous the <n>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 <n> + write <n> filemarks ( 'mark 0' flushes the drive's buffers ). +.TP 10 +.B seek <n> +Seek to a logical position <n> that was reported by a previous 'tapeinfo' +command. +.TP 10 +.B write <blocksize> +write blocks from stdin to the tape. Chunk the data into <blocksize>-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 [<blocksize>] [ <#blocks/#bytes> ] +read blocks from the tape, write them to stdout. If we are in variable +block mode, <blocksize> 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 +<blocksize> 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 <eric@badtux.org>. +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 <n> +where you are doing variable-block-size reads and wish for <n> 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 <robertnelson@users.sourceforge.net> +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 <robertn@the-nelsons.org> + * 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 <n> -- set the block size to <n> + fsf <n> -- go forward by <n> filemarks + bsf <n> -- go backward by <n> 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 <n> -- write <n> filemarks. + seek <n> -- seek to position <n>. + + write <blksize> <-- write blocks from stdin to the tape + read [<blksize>] [<#blocks/#bytes>] -- read blocks from tape, write to stdout. + + See the 'tapeinfo' program for status info about the tape drive. + + */ + +#include <stdio.h> +#include <string.h> + +#include "mtx.h" +#include "mtxl.h" + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#if HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#if HAVE_SYS_MTIO_H +#include <sys/mtio.h> /* will try issuing some ioctls for Solaris, sigh. */ +#endif + +#ifdef _MSC_VER +#include <io.h> +#endif + +void Usage(void) { + FatalError("Usage: scsitape -f <generic-device> <command> where <command> is:\n setblk <n> | fsf <n> | bsf <n> | eod | rewind | eject | mark <n> |\n seek <n> | read [<blksize> [<numblocks]] | write [<blocksize>] \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 <robertn@the-nelsons.org> +* +* 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 <eric@badtux.org> +.\" Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org> +.\" +.\" 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 <scsi-generic-device> +.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 <robertnelson@users.sourceforge.net> +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 <robertn@the-nelsons.org> + * 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#]<Message> e.g. "TapeAlert:[22]Cleaning Cartridge Worn Out" + * + * Mode Sense: + * Data Compression Page: + * DataCompEnabled:<yes|no> + * DataCompCapable:<yes|no> + * DataDeCompEnabled:<yes|no> + * CompType:<number> + * DeCompType:<number> + * + * 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]:<size> + * Partition[1]:<size>... + * + * Read Block Limits command: + * MinBlock:<#> -- Minimum block size. + * MaxBlock:<#> -- Maximum block size. + */ + +#include <stdio.h> +#include <string.h> +#include "mtx.h" +#include "mtxl.h" + +char *argv0; + +void usage(void) +{ + FatalError("Usage: tapeinfo -f <generic-device>\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<pagelen;i++) + { + retval[i]=tmp[i]; + } + + /* okay, free our input buffer: */ + free(input_buffer); + return retval; +} + + +#define DCE_MASK 0x80 +#define DCC_MASK 0x40 +#define DDE_MASK 0x80 + +static void ReportCompressionPage(DEVICE_TYPE fd) +{ + /* actually ignore a bad sense reading, like might happen if the tape + * drive does not support the mode sense compression page. + */ + + RequestSense_T RequestSense; + + unsigned char *compression_page; + + compression_page=mode_sense(fd,0x0f,16,&RequestSense); + + if (!compression_page) + { + return; /* sorry! */ + } + + /* Okay, we now have the compression page. Now print stuff from it: */ + printf("DataCompEnabled: %s\n", (compression_page[2] & DCE_MASK)? "yes" : "no"); + printf("DataCompCapable: %s\n", (compression_page[2] & DCC_MASK)? "yes" : "no"); + printf("DataDeCompEnabled: %s\n", (compression_page[3] & DDE_MASK)? "yes" : "no"); + printf("CompType: 0x%x\n", + (compression_page[4] << 24) + + (compression_page[5] << 16) + + (compression_page[6] << 8) + + compression_page[7]); + + printf("DeCompType: 0x%x\n", + (compression_page[8] << 24) + + (compression_page[9] << 16) + + (compression_page[10] << 8) + + compression_page[11]); + + free(compression_page); +} + +/* Now for the device configuration mode page: */ + +static void ReportConfigPage(DEVICE_TYPE fd) +{ + RequestSense_T RequestSense; + unsigned char *config_page; + + config_page = mode_sense(fd, 0x10, 16, &RequestSense); + if (!config_page) + return; + + /* Now to print the stuff: */ + printf("ActivePartition: %d\n", config_page[3]); + + /* The following does NOT work accurately on any tape drive I know of... */ + /* printf("DevConfigComp: %s\n", config_page[14] ? "yes" : "no"); */ + printf("EarlyWarningSize: %d\n", + (config_page[11] << 16) + + (config_page[12] << 8) + + config_page[13]); +} + +/* *************************************** + * Medium Partition Page: + * + * The problem here, as we oh so graphically demonstrated during debugging + * of the Linux 'st' driver :-), is that there are actually *TWO* formats for + * the Medium Partition Page: There is the "long" format, where there is a + * partition size word for each partition on the page, and there is a "short" + * format, beloved of DAT drives, which only has a partition size word for + * partition #1 (and no partition size word for partition #0, and no + * provisions for any more partitions). So we must look at the size and + * # of partitions defined to know what to report as what. + * + ********************************************/ + +static void ReportPartitionPage(DEVICE_TYPE fd) +{ + RequestSense_T RequestSense; + unsigned char *partition_page; + + int num_parts,max_parts; + int i; + + partition_page=mode_sense(fd,0x11,255,&RequestSense); + if (!partition_page) + return; + + /* Okay, now we have either old format or new format: */ + num_parts = partition_page[3]; + max_parts = partition_page[2]; + + printf("NumPartitions: %d\n", num_parts); + printf("MaxPartitions: %d\n", max_parts); + + if (!num_parts) + { + /* if no additional partitions, then ... */ + free(partition_page); + return; + } + + /* we know we have at least one partition if we got here. Check the + * page size field. If it is 8 or below, then we are the old format.... + */ + +#ifdef DEBUG_PARTITION + fprintf(stderr,"partition_page[1]=%d\n",partition_page[1]); + fflush(stderr); +#endif + if (partition_page[1]==8) + { + /* old-style! */ + printf("Partition1: %d\n",(partition_page[8]<<8)+partition_page[9]); + } + else + { + /* new-style! */ + for (i=0;i<=max_parts;i++) + { +#ifdef DEBUG_PARTITION + fprintf(stderr,"partition%d:[%d]%d [%d]%d\n", i, 8 + i * 2, + partition_page[8+i*2]<<8, 9+i*2,partition_page[9 + i * 2]); + fflush(stderr); +#endif + printf("Partition%d: %d\n", i, + (partition_page[8 + i * 2] << 8) + partition_page[9 + i * 2]); + } + } + free(partition_page); +} + +static void ReportSerialNumber(DEVICE_TYPE fd) +{ + /* Actually ignore a bad sense reading, like might happen if the + tape drive does not support the inquiry page 0x80. + */ + + RequestSense_T sense; + CDB_T CDB; + +#define WILD_SER_SIZE 30 +unsigned char buffer[WILD_SER_SIZE]; /* just wildly overestimate serial# length! */ + + int i, lim; + char *bufptr; + + CDB[0] = 0x12; /* INQUIRY */ + CDB[1] = 1; /* EVPD = 1 */ + CDB[2] = 0x80; /* The serial # page, hopefully. */ + CDB[3] = 0; /* reserved */ + CDB[4] = WILD_SER_SIZE; + CDB[5] = 0; + + if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, &buffer, sizeof(buffer), &sense) != 0) + { + /* PrintRequestSense(&sense); */ /* zap debugging output :-) */ + /* printf("No Serial Number: None\n"); */ + return; + } + + /* okay, we have something in our buffer. Byte 3 should be the length of + the sernum field, and bytes 4 onward are the serial #. */ + + lim = (int)buffer[3]; + bufptr = (char *)&(buffer[4]); + + printf("SerialNumber: '"); + for (i=0;i<lim;i++) + { + putchar(*bufptr++); + } + printf("'\n"); +} + +/* Read Block Limits! */ + +void ReportBlockLimits(DEVICE_TYPE fd) +{ + RequestSense_T sense; + CDB_T CDB; + unsigned char buffer[6]; + + CDB[0] = 0x05; /* READ_BLOCK_LIMITS */ + CDB[1] = 0; + CDB[2] = 0; + CDB[3] = 0; /* 1-5 all unused. */ + CDB[4] = 0; + CDB[5] = 0; + + slow_bzero((char *)&sense,sizeof(RequestSense_T)); + if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, buffer, 6, &sense) != 0) + { + return; + } + + /* okay, but if we did get a result, print it: */ + printf("MinBlock: %d\n", (buffer[4] << 8) + buffer[5]); + printf("MaxBlock: %d\n", (buffer[1] << 16) + (buffer[2]<<8) + buffer[3]); +} + +/* Do a READ_POSITION. This may not be always valid, but (shrug). */ +void ReadPosition(DEVICE_TYPE fd) +{ + RequestSense_T sense; + CDB_T CDB; + unsigned char buffer[20]; + unsigned int position; + + CDB[0] = 0x34; /* READ_POSITION */ + CDB[1] = 0; + CDB[2] = 0; + CDB[3] = 0; /* 1-9 all unused. */ + CDB[4] = 0; + CDB[5] = 0; + CDB[6] = 0; + CDB[7] = 0; + CDB[8] = 0; + CDB[9] = 0; + + slow_bzero((char *)&sense, sizeof(RequestSense_T)); + + SCSI_Set_Timeout(2); /* set timeout to 2 seconds! */ + + /* if we don't get a result (e.g. we issue this to a disk drive), punt. */ + if (SCSI_ExecuteCommand(fd, Input, &CDB, 10, buffer, 20, &sense) != 0) + { + return; + } + + SCSI_Default_Timeout(); /* reset it to 5 minutes, sigh! */ + /* okay, but if we did get a result, print it: */ + +#define RBL_BOP 0x80 +#define RBL_EOP 0x40 +#define RBL_BCU 0x20 +#define RBL_BYCU 0x10 +#define RBL_R1 0x08 +#define RBL_BPU 0x04 +#define RBL_PERR 0x02 + + /* If we have BOP, go ahead and print that. */ + if (buffer[0]&RBL_BOP) + { + printf("BOP: yes\n"); + } + + /* if we have valid data, print it: */ + if (buffer[0]&RBL_BPU) + { + printf("Block Position: -1"); + } + else + { + position = (unsigned int)(((unsigned int)buffer[4] << 24) + + ((unsigned int)buffer[5] << 16) + + ((unsigned int)buffer[6] << 8) + + buffer[7]); + + printf("Block Position: %d\n",position); + } +} + +/* Test unit ready: This will tell us whether the tape drive + * is currently ready to read or write. + */ + +int TestUnitReady(DEVICE_TYPE fd) +{ + RequestSense_T sense; + CDB_T CDB; + unsigned char buffer[6]; + + CDB[0] = 0x00; /* TEST_UNIT_READY */ + CDB[1] = 0; + CDB[2] = 0; + CDB[3] = 0; /* 1-5 all unused. */ + CDB[4] = 0; + CDB[5] = 0; + + slow_bzero((char *)&sense,sizeof(RequestSense_T)); + if (SCSI_ExecuteCommand(fd,Input,&CDB,6,buffer,0,&sense)!=0) + { + printf("Ready: no\n"); + return 0; + } + + printf("Ready: yes\n"); + return 1; +} + +/* We write a filemarks of 0 before going to grab position, in order + * to insure that data in the buffer is not a problem. + */ + +int WriteFileMarks(DEVICE_TYPE fd,int count) +{ + RequestSense_T sense; + CDB_T CDB; + unsigned char buffer[6]; + + CDB[0] = 0x10; /* WRITE_FILE_MARKS */ + 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 *)&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 <device>". */ +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 <lnz@dandelion.com> + +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 <ssdef.h> +#include <lib$routines.h> +#include <ots$routines.h> +#include <stdio.h> +#include <ctype.h> +#include <iodef.h> +#include <descrip.h> +#include <dcdef.h> +#include <devdef.h> +#include <dvidef.h> +#include <starlet.h> +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <prvdef.h> + +#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 <ssdef.h> +#include <dcdef.h> +#include <devdef.h> +#include <dvidef.h> +#include <descrip.h> +#include <stdio.h> +#include <string.h> +#include <lib$routines.h> +#include <starlet.h> + +#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<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel +.IFF +.call_entry, 2,home_args=TRUE,- + preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,- + output=<r0,r1>,- + 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<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel +.IFF +.call_entry, 2,home_args=TRUE,- + preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,- + output=<r0,r1>,- + 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<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel +.IFF +.call_entry, 2,home_args=TRUE,- + preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,- + output=<r0,r1>,- + label=_setldr +.endc + $cmkrnl_s - + routin = __setldr,- + arglst = (AP) + ret + +.IF NDF,ALPHA +.entry __clrldr,^m<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel +.IFF +.call_entry, 2,home_args=TRUE,- + preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,- + output=<r0,r1>,- + 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<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel +.IFF +.call_entry, 2,home_args=TRUE,- + preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,- + output=<r0,r1>,- + 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); + } +} |