From 0343893f093449bf41dafd8aac4a7f2d590cac59 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Wed, 19 Apr 2017 13:33:37 +0200 Subject: [PATCH] Imported Upstream version 1.05 --- CHANGES | 1 + LICENSE | 341 ++++++++++++++++++++++++ Makefile | 54 ++++ README | 131 ++++++++++ cvsenv.sh | 3 + debian/changelog | 70 +++++ debian/compat | 1 + debian/control | 34 +++ debian/copyright | 34 +++ debian/docs | 1 + debian/hd-idle.default | 30 +++ debian/hd-idle.init | 53 ++++ debian/rules | 13 + debian/source/format | 1 + hd-idle.1 | 101 ++++++++ hd-idle.c | 575 +++++++++++++++++++++++++++++++++++++++++ 16 files changed, 1443 insertions(+) create mode 100644 CHANGES create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README create mode 100644 cvsenv.sh create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/docs create mode 100644 debian/hd-idle.default create mode 100755 debian/hd-idle.init create mode 100755 debian/rules create mode 100644 debian/source/format create mode 100644 hd-idle.1 create mode 100644 hd-idle.c diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..fc9a06b --- /dev/null +++ b/CHANGES @@ -0,0 +1 @@ +Please refer to debian/changelog diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..86fd703 --- /dev/null +++ b/LICENSE @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + 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 + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..130afd8 --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +############################################################################### +# +# General Definitions +# +############################################################################### + +ifdef DESTDIR +# dh_auto_install (Debian) sets this variable + TARGET_DIR = $(DESTDIR)/usr +else + TARGET_DIR ?= /usr/local +endif + +LIB_DIRS = + +INC_DIRS = + +CC ?= gcc +CFLAGS += $(INC_DIRS) -Wall + +LD = $(CC) +LDFLAGS += $(LIB_DIRS) + +############################################################################### +# +# Main Dependencies +# +############################################################################### + +TARGET = hd-idle + +LIBS = + +SRCS = hd-idle.c + +OBJS = $(SRCS:.c=.o) + +all: $(TARGET) + +distclean: clean + +clean: + rm -f $(OBJS) $(TARGET) + +install: $(TARGET) + install -D -g root -o root $(TARGET) $(TARGET_DIR)/sbin/$(TARGET) + install -D -g root -o root $(TARGET).1 $(TARGET_DIR)/share/man/man1/$(TARGET).1 + +hd-idle.o: hd-idle.c + +$(TARGET): $(OBJS) + $(LD) $(LDFLAGS) -o $(TARGET) $(OBJS) $(LIB_DIRS) $(LIBS) + + diff --git a/README b/README new file mode 100644 index 0000000..c89275b --- /dev/null +++ b/README @@ -0,0 +1,131 @@ +Hard Disk Idle Spin-Down Utility +============================================================================== + +hd-idle is a utility program for spinning-down external disks after a period +of idle time. Since most external IDE disk enclosures don't support setting +the IDE idle timer, a program like hd-idle is required to spin down idle +disks automatically. + +A word of caution: hard disks don't like spinning up too often. Laptop disks +are more robust in this respect than desktop disks but if you set your disks +to spin down after a few seconds you may damage the disk over time due to the +stress the spin-up causes on the spindle motor and bearings. It seems that +manufacturers recommend a minimum idle time of 3-5 minutes, the default in +hd-idle is 10 minutes. + +One more word of caution: hd-idle will spin down any disk accessible via the +SCSI layer (USB, IEEE1394, ...) but it will NOT work with real SCSI disks +because they don't spin up automatically. Thus it's not called scsi-idle and +I don't recommend using it on a real SCSI system unless you have a kernel +patch that automatically starts the SCSI disks after receiving a sense buffer +indicating the disk has been stopped. Without such a patch, real SCSI disks +won't start again and you can as well pull the plug. + +You have been warned... + +The latest version of hd-idle can be found on SourceForge: + + http://hd-idle.sf.net + +hd-idle is not public domain software. It's copyrighted by myself, +Christian Mueller, according to the terms of the GNU General Public +License (GPL). Please see the file LICENSE for additional information. + +Copyright (c) Christian Mueller 2007 + +============================================================================== + +Installation +------------ + +The compile process is rather simple, thus there's no automake or configure +script at this point, just a makefile for Linux. Since hd-idle is using the +Linux generic SCSI layer, it requires the include files scsi/sg.h and +scsi/scsi.h which should come with libc6-dev (at least on Debian they do). + +Non-Debian Systems: + * In order to compile the program, type "make". + * In order to install the program into /usr/local/sbin, type "make install" + (this will also install the manpage into /usr/local/share/man/man1) + +Debian Systems: + * Run "dpkg-buildpackage -rfakeroot" + * Run "dpkg -i ../hd-idle_*.deb" to install the package + + NOTE: The build framework has been changed to be compatible to the Debian + package management with the intention of making hd-idle an official + Debian package. Once this effort has completed, hd-idle can be + installed with "apt-get install hd-idle". The changes to the Debian + build instructions as outlined above (previous releases used "make + install_debian") are a side effect of this effort. + + Once completed, please check /etc/default/hd-idle for configuration + information. The default settings will *not* start hd-idle automatically. + +Running hd-idle +--------------- + +In order to run hd-idle, type "hd-idle". This will start hd-idle with the +default options, causing all SCSI (read: USB, Firewire, SCSI, ...) hard disks +to spin down after 10 minutes of inactivity. + +On a Debian system, after editing /etc/default/hd-idle and enabling it, +use "/etc/init.d/hd-idle start" to run hd-idle. + +Please note that hd-idle uses /proc/diskstats to read disk statistics. If +this file is not present, hd-idle won't work. + +In case of problems, use the debug option (-d) tp get further information. + +Command line options: + + -a Set device name of disks for subsequent idle-time + parameters (-i). This parameter is optional in the + sense that there's a default entry for all disks + which are not named otherwise by using this + parameter. This can also be a symlink + (e.g. /dev/disk/by-uuid/...) + -i Idle time in seconds for the currently named disk(s) + (-a ) or for all disks. + -l Name of logfile (written only after a disk has spun + up). Please note that this option might cause the + disk which holds the logfile to spin up just because + another disk had some activity. This option should + not be used on systems with more than one disk + except for tuning purposes. On single-disk systems, + this option should not cause any additional spinups. + +Miscellaneous options: + -t Spin-down the specfified disk immediately and exit. + -d Debug mode. This will prevent hd-idle from + becoming a daemon and print debugging info to + stdout/stderr + -h Print usage information. + +Regarding the parameter "-a": + + Users of hd-idle have asked for means to set idle-time parameters for + individual disks. This makes a lot of sense, not only because some [SCSI] + disks may not react well to being stopped. Originally, hd-idle had one idle + time for all disks. The parameter "-a" can now be used to set a filter on + the disk's device name (omit /dev/) for subsequent idle-time settings. + + 1) A -i option before the first -a option will set the default idle time; + hence, compatibility with previous releases of hd-idle is maintained. + + 2) In order to disable spin-down of disks per default, and then re-enable + spin-down on selected disks, set the default idle time to 0. + + Example: + hd-idle -i 0 -a sda -i 300 -a sdb -i 1200 + + This example sets the default idle time to 0 (meaning hd-idle will never + try to spin down a disk), then sets explicit idle times for disks which + have the string "sda" or "sdb" in their device name. + +Stopping hd-idle +---------------- + +Use "killall hd-idle" to stop hd-idle. On a Debian system, use +"/etc/init.d/hd-idle stop". + diff --git a/cvsenv.sh b/cvsenv.sh new file mode 100644 index 0000000..6340890 --- /dev/null +++ b/cvsenv.sh @@ -0,0 +1,3 @@ +export CVS_RSH=ssh +export CVSROOT=cjmueller@hd-idle.cvs.sourceforge.net:/cvsroot/hd-idle + diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..d58c848 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,70 @@ +hd-idle (1.05) unstable; urgency=low + + * Allow SCSI device names with more than one character (e.g. sdaa) in case + there are more than 26 SCSI targets. + + -- Christian Mueller Sun, 6 Apr 2014 22:02:00 +0200 + +hd-idle (1.04) unstable; urgency=low + + * Make hd-idle's build environment compatible to Debian package management; + this effort is meant to allow hd-idle to become an official Debian package + * Man page for hd-idle + + -- Christian Mueller Fri, 30 Sep 2011 22:35:12 +0200 + +hd-idle (1.03) unstable; urgency=low + + * Use %u in dprintf() when reporting number of reads and writes (the + corresponding variable is an unsigned int). + * Fix example in README where the parameter "-a" was written as "-n". + + -- Christian Mueller Sun, 5 Dec 2010 19:25:51 +0100 + +hd-idle (1.02) unstable; urgency=low + + * In case the SCSI stop unit command fails with "check condition", print a + hex dump of the sense buffer to stderr. This is supposed to help + debugging. + + -- Christian Mueller Sat, 6 Nov 2010 15:47:00 +0100 + +hd-idle (1.01) unstable; urgency=low + + * The parameter "-a" now also supports symlinks for disk names. Thus, disks + can be specified using something like /dev/disk/by-uuid/... Use "-d" to + verify that the resulting disk name is what you want. + + Please note that disk names are resolved to device nodes at startup. Also, + since many entries in /dev/disk/by-xxx are actually partitions, partition + numbers are automatically removed from the resulting device node. + + * Not really a bug, but the disk name comparison used strstr which is a bit + useless because only disks starting with "sd" and a single letter after + that are currently considered. Replaced the comparison with strcmp() + + -- Christian Mueller Fri, 26 Feb 2010 14:03:44 +0100 + +hd-idle (1.00) unstable; urgency=low + + * New parameter "-a" to allow selecting idle timeouts for individual disks; + compatibility to previous releases is maintained by having an implicit + default which matches all SCSI disks + + * Changed comparison operator for idle periods from '>' to '>=' to prevent + adding one polling interval to idle time + + * Changed sleep time before calling sync after updating the log file to 1s + (from 3s) to accumulate fewer dirty blocks before synching. It's still + a compromize but the log file is for debugging purposes, anyway. A test + with fsync() was unsuccessful because the next bdflush-initiated sync + still caused spin-ups. + + -- Christian Mueller Wed, 18 Nov 2009 20:53:17 +0100 + +hd-idle (0.99) unstable; urgency=low + + * Initial Release. + + -- Christian Mueller Mon, 23 Apr 2007 22:03:10 +0100 + diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +7 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..9ac40d2 --- /dev/null +++ b/debian/control @@ -0,0 +1,34 @@ +Source: hd-idle +Section: utils +Priority: extra +Maintainer: Christian Mueller +Build-Depends: debhelper (>= 7.0.50~), libc6-dev +Standards-Version: 3.8.4 +Homepage: http://hd-idle.sf.net +#Vcs-Git: git://git.debian.org/collab-maint/hd-idle.git +#Vcs-Browser: http://git.debian.org/?p=collab-maint/hd-idle.git;a=summary + +Package: hd-idle +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Spin down idle [USB] hard disks + hd-idle is a utility program for spinning-down external disks after a period + of idle time. Since most external IDE disk enclosures don't support setting + the IDE idle timer, a program like hd-idle is required to spin down idle disks + automatically. + . + A word of caution: hard disks don't like spinning up too often. Laptop disks + are more robust in this respect than desktop disks but if you set your disks + to spin down after a few seconds you may damage the disk over time due to the + stress the spin-up causes on the spindle motor and bearings. It seems that + manufacturers recommend a minimum idle time of 3-5 minutes, the default in + hd-idle is 10 minutes. + . + One more word of caution: hd-idle will spin down any disk accessible via the + SCSI layer (USB, IEEE1394, ...) but it will not work with real SCSI disks + because they don't spin up automatically. Thus it's not called scsi-idle and + I don't recommend using it on a real SCSI system unless you have a kernel + patch that automatically starts the SCSI disks after receiving a sense buffer + indicating the disk has been stopped. Without such a patch, real SCSI disks + won't start again and you can as well pull the plug. + diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..7a7733b --- /dev/null +++ b/debian/copyright @@ -0,0 +1,34 @@ +This work was written and packaged by Christian Mueller + +It was downloaded from: + +Upstream Author(s): Christian Mueller + +Copyright: + + + +License: + + 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 3 of the License, or + (at your option) any later version. + + This package 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, see . + +On Debian systems, the complete text of the GNU General +Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". + +The Debian packaging is: + + Copyright (C) 2011 Christian Mueller + +and is licensed under the GPL version 3, see above. + diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..e845566 --- /dev/null +++ b/debian/docs @@ -0,0 +1 @@ +README diff --git a/debian/hd-idle.default b/debian/hd-idle.default new file mode 100644 index 0000000..a575c55 --- /dev/null +++ b/debian/hd-idle.default @@ -0,0 +1,30 @@ +# defaults file for hd-idle + +# start hd-idle automatically? +START_HD_IDLE=false + +# hd-idle command line options +# Options are: +# -a Set device name of disks for subsequent idle-time +# parameters (-i). This parameter is optional in the +# sense that there's a default entry for all disks +# which are not named otherwise by using this +# parameter. This can also be a symlink +# (e.g. /dev/disk/by-uuid/...) +# -i Idle time in seconds. +# -l Name of logfile (written only after a disk has spun +# up). Please note that this option might cause the +# disk which holds the logfile to spin up just because +# another disk had some activity. This option should +# not be used on systems with more than one disk +# except for tuning purposes. On single-disk systems, +# this option should not cause any additional spinups. +# +# Options not exactly useful here: +# -t Spin-down the specfified disk immediately and exit. +# -d Debug mode. This will prevent hd-idle from +# becoming a daemon and print debugging info to +# stdout/stderr +# -h Print usage information. +#HD_IDLE_OPTS="-i 180 -l /var/log/hd-idle.log" + diff --git a/debian/hd-idle.init b/debian/hd-idle.init new file mode 100755 index 0000000..d0d8263 --- /dev/null +++ b/debian/hd-idle.init @@ -0,0 +1,53 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: hd-idle +# Required-Start: $local_fs +# Required-Stop: $local_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: start hd-idle daemon (spin down idle hard disks) +### END INIT INFO + + +PATH=/sbin:/bin:/usr/sbin:/usr/bin + +DAEMON=/usr/sbin/hd-idle +HD_IDLE_OPTS="-i 600" +START_HD_IDLE=false + +[ -r /etc/default/hd-idle ] && . /etc/default/hd-idle + +if [ "$START_HD_IDLE" != "true" ] ; then + exit 0 +fi + +# See if the daemon is there +test -x $DAEMON || exit 0 + +. /lib/lsb/init-functions + +case "$1" in + start) + log_daemon_msg "Starting the hd-idle daemon" "hd-idle" + + start-stop-daemon --start --quiet --oknodo --exec $DAEMON -- $HD_IDLE_OPTS + + log_end_msg $? + ;; + + stop) + log_daemon_msg "Stopping the hd-idle daemon" "hd-idle" + start-stop-daemon --stop --quiet --oknodo --exec $DAEMON + log_end_msg $? + ;; + + restart|force-reload) + $0 stop && sleep 2 && $0 start + ;; + + *) + echo "Usage: /etc/init.d/hd-idle start/stop/restart/force-reload" + exit 1 + ;; +esac diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..68449f2 --- /dev/null +++ b/debian/rules @@ -0,0 +1,13 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +# Uncomment this to turn on verbose mode. +# export DH_VERBOSE=1 + +%: + dh $@ diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..89ae9db --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/hd-idle.1 b/hd-idle.1 new file mode 100644 index 0000000..a77e863 --- /dev/null +++ b/hd-idle.1 @@ -0,0 +1,101 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" First parameter, NAME, should be all caps +.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection +.\" other parameters are allowed: see man(7), man(1) +.TH HD-IDLE 1 "September 29, 2011" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +hd-idle \- spin down idle hard disks +.SH SYNOPSIS +.B hd-idle +.RI [ options ] +.P +.SH DESCRIPTION +hd-idle is a utility program for spinning down external disks after a period +of idle time. Since most external IDE disk enclosures don't support setting +the IDE idle timer, a program like hd-idle is required to spin down idle +disks automatically. +.P +A word of caution: hard disks don't like spinning up too often. Laptop disks +are more robust in this respect than desktop disks but if you set your disks +to spin down after a few seconds you may damage the disk over time due to the +stress the spin-up causes on the spindle motor and bearings. It seems that +manufacturers recommend a minimum idle time of 3-5 minutes, the default in +hd-idle is 10 minutes. +.P +One more word of caution: hd-idle will spin down any disk accessible via the +SCSI layer (USB, IEEE1394, ...) but it will NOT work with real SCSI disks +because they won't spin up automatically. Thus it's not called scsi-idle and +I don't recommend using it on a real SCSI system unless you have a kernel +patch that automatically starts the SCSI disks after receiving a sense buffer +indicating the disk has been stopped. Without such a patch, real SCSI disks +won't start again and you can as well pull the plug. +.SH OPTIONS +.TP +.B \-a name +Set device name of disks for subsequent idle-time parameters +.B (-i). +This parameter is optional in the sense that there's a default entry for +all disks which are not named otherwise by using this parameter. This can +also be a symlink (e.g. /dev/disk/by-uuid/...) +.TP +.B \-i idle_time +Idle time in seconds for the currently named disk(s) (-a ) or for +all disks. +.TP +.B \-l logfile +Name of logfile (written only after a disk has spun up). Please note that +this option might cause the disk which holds the logfile to spin up just +because another disk had some activity. This option should not be used on +systems with more than one disk except for tuning purposes. On single-disk +systems, this option should not cause any additional spinups. +.TP +.B \-t disk +Spin-down the specfified disk immediately and exit. +.TP +.B \-d +Debug mode. This will prevent hd-idle from becoming a daemon and print +debugging info to stdout/stderr +.TP +.B \-h +Print usage information. +.SH "DISK SELECTION" +The parameter +.B \-a +can be used to set a filter on the disk's device name (omit /dev/) for +subsequent idle-time settings. The default is all disks: +.P +.TP +.B \1) +A +.B \-i +option before the first +.B \-a +option will set the default idle time; hence, compatibility with previous +releases of hd-idle is maintained. +.TP +.B \2) +In order to disable spin-down of disks per default, and then re-enable +spin-down on selected disks, set the default idle time to 0. +.SH EXAMPLE +hd-idle -i 0 -a sda -i 300 -a sdb -i 1200 +.P +This example sets the default idle time to 0 (meaning hd-idle will never +try to spin down a disk), then sets explicit idle times for disks which +have the string "sda" or "sdb" in their device name. +.SH AUTHOR +hd-idle was written by Chistian Mueller +.PP +This manual page was written by Christian Mueller , +for the Debian project (and may be used by others). diff --git a/hd-idle.c b/hd-idle.c new file mode 100644 index 0000000..ec9c7d2 --- /dev/null +++ b/hd-idle.c @@ -0,0 +1,575 @@ +/* + * hd-idle.c - external disk idle daemon + * + * Copyright (c) 2007 Christian Mueller. + * + * 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 + */ + +/* + * hd-idle is a utility program for spinning-down external disks after a period + * of idle time. Since most external IDE disk enclosures don't support setting + * the IDE idle timer, a program like hd-idle is required to spin down idle + * disks automatically. + * + * A word of caution: hard disks don't like spinning-up too often. Laptop disks + * are more robust in this respect than desktop disks but if you set your disks + * to spin down after a few seconds you may damage the disk over time due to the + * stress the spin-up causes on the spindle motor and bearings. It seems that + * manufacturers recommend a minimum idle time of 3-5 minutes, the default in + * hd-idle is 10 minutes. + * + * Please note that hd-idle can spin down any disk accessible via the SCSI + * layer (USB, IEEE1394, ...) but it will NOT work with real SCSI disks because + * they don't spin up automatically. Thus it's not called scsi-idle and I don't + * recommend using it on a real SCSI system unless you have a kernel patch that + * automatically starts the SCSI disks after receiving a sense buffer indicating + * the disk has been stopped. Without such a patch, real SCSI disks won't start + * again and you can as well pull the plug. + * + * You have been warned... + * + * CVS Change Log: + * --------------- + * + * $Log: hd-idle.c,v $ + * Revision 1.7 2014/04/06 19:53:51 cjmueller + * Version 1.05 + * ------------ + * + * Bugs: + * - Allow SCSI device names with more than one character (e.g. sdaa) in case + * there are more than 26 SCSI targets. + * + * Revision 1.6 2010/12/05 19:25:51 cjmueller + * Version 1.03 + * ------------ + * + * Bugs + * - Use %u in dprintf() when reporting number of reads and writes (the + * corresponding variable is an unsigned int). + * - Fix example in README where the parameter "-a" was written as "-n". + * + * Revision 1.5 2010/11/06 15:30:04 cjmueller + * Version 1.02 + * ------------ + * + * Features + * - In case the SCSI stop unit command fails with "check condition", print a + * hex dump of the sense buffer to stderr. This is supposed to help + * debugging. + * + * Revision 1.4 2010/02/26 14:03:44 cjmueller + * Version 1.01 + * ------------ + * + * Features + * - The parameter "-a" now also supports symlinks for disk names. Thus, disks + * can be specified using something like /dev/disk/by-uuid/... Use "-d" to + * verify that the resulting disk name is what you want. + * + * Please note that disk names are resolved to device nodes at startup. Also, + * since many entries in /dev/disk/by-xxx are actually partitions, partition + * numbers are automatically removed from the resulting device node. + * + * Bugs + * - Not really a bug, but the disk name comparison used strstr which is a bit + * useless because only disks starting with "sd" and a single letter after + * that are currently considered. Replaced the comparison with strcmp() + * + * Revision 1.3 2009/11/18 20:53:17 cjmueller + * Features + * - New parameter "-a" to allow selecting idle timeouts for individual disks; + * compatibility to previous releases is maintained by having an implicit + * default which matches all SCSI disks + * + * Bugs + * - Changed comparison operator for idle periods from '>' to '>=' to prevent + * adding one polling interval to idle time + * - Changed sleep time before calling sync after updating the log file to 1s + * (from 3s) to accumulate fewer dirty blocks before synching. It's still + * a compromize but the log file is for debugging purposes, anyway. A test + * with fsync() was unsuccessful because the next bdflush-initiated sync + * still caused spin-ups. + * + * Revision 1.2 2007/04/23 22:14:27 cjmueller + * Bug fixes + * - Comment changes; no functionality changes... + * + * Revision 1.1.1.1 2007/04/23 21:49:43 cjmueller + * initial import into CVS + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define STAT_FILE "/proc/diskstats" +#define DEFAULT_IDLE_TIME 600 + +#define dprintf if (debug) printf + +/* typedefs and structures */ +typedef struct IDLE_TIME { + struct IDLE_TIME *next; + char *name; + int idle_time; +} IDLE_TIME; + +typedef struct DISKSTATS { + struct DISKSTATS *next; + char name[50]; + int idle_time; + time_t last_io; + time_t spindown; + time_t spinup; + unsigned int spun_down : 1; + unsigned int reads; + unsigned int writes; +} DISKSTATS; + +/* function prototypes */ +static void daemonize (void); +static DISKSTATS *get_diskstats (const char *name); +static void spindown_disk (const char *name); +static void log_spinup (DISKSTATS *ds); +static char *disk_name (char *name); +static void phex (const void *p, int len, + const char *fmt, ...); + +/* global/static variables */ +IDLE_TIME *it_root; +DISKSTATS *ds_root; +char *logfile = "/dev/null"; +int debug; + +/* main function */ +int main(int argc, char *argv[]) +{ + IDLE_TIME *it; + int have_logfile = 0; + int min_idle_time; + int sleep_time; + int opt; + + /* create default idle-time parameter entry */ + if ((it = malloc(sizeof(*it))) == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + it->next = NULL; + it->name = NULL; + it->idle_time = DEFAULT_IDLE_TIME; + it_root = it; + + /* process command line options */ + while ((opt = getopt(argc, argv, "t:a:i:l:dh")) != -1) { + switch (opt) { + + case 't': + /* just spin-down the specified disk and exit */ + spindown_disk(optarg); + return(0); + + case 'a': + /* add a new set of idle-time parameters for this particular disk */ + if ((it = malloc(sizeof(*it))) == NULL) { + fprintf(stderr, "out of memory\n"); + return(2); + } + it->name = disk_name(optarg); + it->idle_time = DEFAULT_IDLE_TIME; + it->next = it_root; + it_root = it; + break; + + case 'i': + /* set idle-time parameters for current (or default) disk */ + it->idle_time = atoi(optarg); + break; + + case 'l': + logfile = optarg; + have_logfile = 1; + break; + + case 'd': + debug = 1; + break; + + case 'h': + printf("usage: hd-idle [-t ] [-a ] [-i ] [-l ] [-d] [-h]\n"); + return(0); + + case ':': + fprintf(stderr, "error: option -%c requires an argument\n", optopt); + return(1); + + case '?': + fprintf(stderr, "error: unknown option -%c\n", optopt); + return(1); + } + } + + /* set sleep time to 1/10th of the shortest idle time */ + min_idle_time = 1 << 30; + for (it = it_root; it != NULL; it = it->next) { + if (it->idle_time != 0 && it->idle_time < min_idle_time) { + min_idle_time = it->idle_time; + } + } + if ((sleep_time = min_idle_time / 10) == 0) { + sleep_time = 1; + } + + /* daemonize unless we're running in debug mode */ + if (!debug) { + daemonize(); + } + + /* main loop: probe for idle disks and stop them */ + for (;;) { + DISKSTATS tmp; + FILE *fp; + char buf[200]; + + if ((fp = fopen(STAT_FILE, "r")) == NULL) { + perror(STAT_FILE); + return(2); + } + + memset(&tmp, 0x00, sizeof(tmp)); + + while (fgets(buf, sizeof(buf), fp) != NULL) { + if (sscanf(buf, "%*d %*d %s %*u %*u %u %*u %*u %*u %u %*u %*u %*u %*u", + tmp.name, &tmp.reads, &tmp.writes) == 3) { + DISKSTATS *ds; + time_t now = time(NULL); + const char *s; + + /* make sure this is a SCSI disk (sd[a-z]+) without partition number */ + if (tmp.name[0] != 's' || tmp.name[1] != 'd') { + continue; + } + for (s = tmp.name + 2; isalpha(*s); s++); + if (*s != '\0') { + /* ignore disk partitions */ + continue; + } + + dprintf("probing %s: reads: %u, writes: %u\n", tmp.name, tmp.reads, tmp.writes); + + /* get previous statistics for this disk */ + ds = get_diskstats(tmp.name); + + if (ds == NULL) { + /* new disk; just add it to the linked list */ + if ((ds = malloc(sizeof(*ds))) == NULL) { + fprintf(stderr, "out of memory\n"); + return(2); + } + memcpy(ds, &tmp, sizeof(*ds)); + ds->last_io = now; + ds->spinup = ds->last_io; + ds->next = ds_root; + ds_root = ds; + + /* find idle time for this disk (falling-back to default; default means + * 'it->name == NULL' and this entry will always be the last due to the + * way this single-linked list is built when parsing command line + * arguments) + */ + for (it = it_root; it != NULL; it = it->next) { + if (it->name == NULL || !strcmp(ds->name, it->name)) { + ds->idle_time = it->idle_time; + break; + } + } + + } else if (ds->reads == tmp.reads && ds->writes == tmp.writes) { + if (!ds->spun_down) { + /* no activity on this disk and still running */ + if (ds->idle_time != 0 && now - ds->last_io >= ds->idle_time) { + spindown_disk(ds->name); + ds->spindown = now; + ds->spun_down = 1; + } + } + + } else { + /* disk had some activity */ + if (ds->spun_down) { + /* disk was spun down, thus it has just spun up */ + if (have_logfile) { + log_spinup(ds); + } + ds->spinup = now; + } + ds->reads = tmp.reads; + ds->writes = tmp.writes; + ds->last_io = now; + ds->spun_down = 0; + } + } + } + + fclose(fp); + sleep(sleep_time); + } + + return(0); +} + +/* become a daemon */ +static void daemonize(void) +{ + int maxfd; + int i; + + /* fork #1: exit parent process and continue in the background */ + if ((i = fork()) < 0) { + perror("couldn't fork"); + exit(2); + } else if (i > 0) { + _exit(0); + } + + /* fork #2: detach from terminal and fork again so we can never regain + * access to the terminal */ + setsid(); + if ((i = fork()) < 0) { + perror("couldn't fork #2"); + exit(2); + } else if (i > 0) { + _exit(0); + } + + /* change to root directory and close file descriptors */ + chdir("/"); + maxfd = getdtablesize(); + for (i = 0; i < maxfd; i++) { + close(i); + } + + /* use /dev/null for stdin, stdout and stderr */ + open("/dev/null", O_RDONLY); + open("/dev/null", O_WRONLY); + open("/dev/null", O_WRONLY); +} + +/* get DISKSTATS entry by name of disk */ +static DISKSTATS *get_diskstats(const char *name) +{ + DISKSTATS *ds; + + for (ds = ds_root; ds != NULL; ds = ds->next) { + if (!strcmp(ds->name, name)) { + return(ds); + } + } + + return(NULL); +} + +/* spin-down a disk */ +static void spindown_disk(const char *name) +{ + struct sg_io_hdr io_hdr; + unsigned char sense_buf[255]; + char dev_name[100]; + int fd; + + dprintf("spindown: %s\n", name); + + /* fabricate SCSI IO request */ + memset(&io_hdr, 0x00, sizeof(io_hdr)); + io_hdr.interface_id = 'S'; + io_hdr.dxfer_direction = SG_DXFER_NONE; + + /* SCSI stop unit command */ + io_hdr.cmdp = (unsigned char *) "\x1b\x00\x00\x00\x00\x00"; + + io_hdr.cmd_len = 6; + io_hdr.sbp = sense_buf; + io_hdr.mx_sb_len = (unsigned char) sizeof(sense_buf); + + /* open disk device (kernel 2.4 will probably need "sg" names here) */ + snprintf(dev_name, sizeof(dev_name), "/dev/%s", name); + if ((fd = open(dev_name, O_RDONLY)) < 0) { + perror(dev_name); + return; + } + + /* execute SCSI request */ + if (ioctl(fd, SG_IO, &io_hdr) < 0) { + char buf[100]; + snprintf(buf, sizeof(buf), "ioctl on %s:", name); + perror(buf); + + } else if (io_hdr.masked_status != 0) { + fprintf(stderr, "error: SCSI command failed with status 0x%02x\n", + io_hdr.masked_status); + if (io_hdr.masked_status == CHECK_CONDITION) { + phex(sense_buf, io_hdr.sb_len_wr, "sense buffer:\n"); + } + } + + close(fd); +} + +/* write a spin-up event message to the log file */ +static void log_spinup(DISKSTATS *ds) +{ + FILE *fp; + + if ((fp = fopen(logfile, "a")) != NULL) { + /* Print statistics to logfile + * + * Note: This doesn't work too well if there are multiple disks + * because the I/O we're dealing with might be on another + * disk so we effectively wake up the disk the log file is + * stored on as well. Then again the logfile is a debugging + * option, so what... + */ + time_t now = time(NULL); + char tstr[20]; + char dstr[20]; + + strftime(dstr, sizeof(dstr), "%Y-%m-%d", localtime(&now)); + strftime(tstr, sizeof(tstr), "%H:%M:%S", localtime(&now)); + fprintf(fp, + "date: %s, time: %s, disk: %s, running: %ld, stopped: %ld\n", + dstr, tstr, ds->name, + (long) ds->spindown - (long) ds->spinup, + (long) time(NULL) - (long) ds->spindown); + + /* Sync to make sure writing to the logfile won't cause another + * spinup in 30 seconds (or whatever bdflush uses as flush interval). + */ + fclose(fp); + sleep(1); + sync(); + } +} + +/* Resolve disk names specified as "/dev/disk/by-xxx" or some other symlink. + * Please note that this function is only called during command line parsing + * and hd-idle per se does not support dynamic disk additions or removals at + * runtime. + * + * This might change in the future but would require some fiddling to avoid + * needless overhead -- after all, this was designed to run on tiny embedded + * devices, too. + */ +static char *disk_name(char *path) +{ + ssize_t len; + char buf[256]; + char *s; + + if (*path != '/') { + /* just a disk name without /dev prefix */ + return(path); + } + + if ((len = readlink(path, buf, sizeof(buf) - 1)) <= 0) { + if (errno != EINVAL) { + /* couldn't resolve disk name */ + return(path); + } + + /* 'path' is not a symlink */ + strncpy(buf, path, sizeof(buf) - 1); + buf[sizeof(buf)-1] = '\0'; + len = strlen(buf); + } + buf[len] = '\0'; + + /* remove partition numbers, if any */ + for (s = buf + strlen(buf) - 1; s >= buf && isdigit(*s); s--) { + *s = '\0'; + } + + /* Extract basename of the disk in /dev. Note that this assumes that the + * final target of the symlink (if any) resolves to /dev/sd* + */ + if ((s = strrchr(buf, '/')) != NULL) { + s++; + } else { + s = buf; + } + + if ((s = strdup(s)) == NULL) { + fprintf(stderr, "out of memory"); + exit(2); + } + + if (debug) { + printf("using %s for %s\n", s, path); + } + return(s); +} + +/* print hex dump to stderr (e.g. sense buffers) */ +static void phex(const void *p, int len, const char *fmt, ...) +{ + va_list va; + const unsigned char *buf = p; + int pos = 0; + int i; + + /* print header */ + va_start(va, fmt); + vfprintf(stderr, fmt, va); + + /* print hex block */ + while (len > 0) { + fprintf(stderr, "%08x ", pos); + + /* print hex block */ + for (i = 0; i < 16; i++) { + if (i < len) { + fprintf(stderr, "%c%02x", ((i == 8) ? '-' : ' '), buf[i]); + } else { + fprintf(stderr, " "); + } + } + + /* print ASCII block */ + fprintf(stderr, " "); + for (i = 0; i < ((len > 16) ? 16 : len); i++) { + fprintf(stderr, "%c", (buf[i] >= 32 && buf[i] < 128) ? buf[i] : '.'); + } + fprintf(stderr, "\n"); + + pos += 16; + buf += 16; + len -= 16; + } +} +