Imported Upstream version 1.05
This commit is contained in:
commit
0343893f09
341
LICENSE
Normal file
341
LICENSE
Normal file
@ -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.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
||||||
|
|
54
Makefile
Normal file
54
Makefile
Normal file
@ -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)
|
||||||
|
|
||||||
|
|
131
README
Normal file
131
README
Normal file
@ -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 <name> 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> Idle time in seconds for the currently named disk(s)
|
||||||
|
(-a <name>) or for all disks.
|
||||||
|
-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.
|
||||||
|
|
||||||
|
Miscellaneous options:
|
||||||
|
-t <disk> 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".
|
||||||
|
|
3
cvsenv.sh
Normal file
3
cvsenv.sh
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export CVS_RSH=ssh
|
||||||
|
export CVSROOT=cjmueller@hd-idle.cvs.sourceforge.net:/cvsroot/hd-idle
|
||||||
|
|
70
debian/changelog
vendored
Normal file
70
debian/changelog
vendored
Normal file
@ -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 <cm1@mumac.de> 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 <cm1@mumac.de> 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 <cm1@mumac.de> 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 <cm1@mumac.de> 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 <cm1@mumac.de> 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 <cm1@mumac.de> Wed, 18 Nov 2009 20:53:17 +0100
|
||||||
|
|
||||||
|
hd-idle (0.99) unstable; urgency=low
|
||||||
|
|
||||||
|
* Initial Release.
|
||||||
|
|
||||||
|
-- Christian Mueller <cm1@mumac.de> Mon, 23 Apr 2007 22:03:10 +0100
|
||||||
|
|
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
7
|
34
debian/control
vendored
Normal file
34
debian/control
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
Source: hd-idle
|
||||||
|
Section: utils
|
||||||
|
Priority: extra
|
||||||
|
Maintainer: Christian Mueller <cm1@mumac.de>
|
||||||
|
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.
|
||||||
|
|
34
debian/copyright
vendored
Normal file
34
debian/copyright
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
This work was written and packaged by Christian Mueller <cm1@mumac.de>
|
||||||
|
|
||||||
|
It was downloaded from: <http://hd-idle.sf.net>
|
||||||
|
|
||||||
|
Upstream Author(s): Christian Mueller <cm1@mumac.de>
|
||||||
|
|
||||||
|
Copyright:
|
||||||
|
|
||||||
|
<Copyright (C) 2007 Christian Mueller>
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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 <cm1@mumac.de>
|
||||||
|
|
||||||
|
and is licensed under the GPL version 3, see above.
|
||||||
|
|
1
debian/docs
vendored
Normal file
1
debian/docs
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
README
|
30
debian/hd-idle.default
vendored
Normal file
30
debian/hd-idle.default
vendored
Normal file
@ -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 <name> 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> Idle time in seconds.
|
||||||
|
# -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.
|
||||||
|
#
|
||||||
|
# Options not exactly useful here:
|
||||||
|
# -t <disk> 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"
|
||||||
|
|
53
debian/hd-idle.init
vendored
Executable file
53
debian/hd-idle.init
vendored
Executable file
@ -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
|
13
debian/rules
vendored
Executable file
13
debian/rules
vendored
Executable file
@ -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 $@
|
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.0 (native)
|
101
hd-idle.1
Normal file
101
hd-idle.1
Normal file
@ -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 <n> 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 <name>) 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 <chris@mumac.de>
|
||||||
|
.PP
|
||||||
|
This manual page was written by Christian Mueller <chris@mumac.de>,
|
||||||
|
for the Debian project (and may be used by others).
|
575
hd-idle.c
Normal file
575
hd-idle.c
Normal file
@ -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 <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <scsi/sg.h>
|
||||||
|
#include <scsi/scsi.h>
|
||||||
|
|
||||||
|
#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 <disk>] [-a <name>] [-i <idle_time>] [-l <logfile>] [-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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user