Compare commits
No commits in common. "master" and "pristine-tar" have entirely different histories.
master
...
pristine-t
341
LICENSE
341
LICENSE
@ -1,341 +0,0 @@
|
||||
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
54
Makefile
@ -1,54 +0,0 @@
|
||||
###############################################################################
|
||||
#
|
||||
# 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
131
README
@ -1,131 +0,0 @@
|
||||
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".
|
||||
|
@ -1,3 +0,0 @@
|
||||
export CVS_RSH=ssh
|
||||
export CVSROOT=cjmueller@hd-idle.cvs.sourceforge.net:/cvsroot/hd-idle
|
||||
|
70
debian/changelog
vendored
70
debian/changelog
vendored
@ -1,70 +0,0 @@
|
||||
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
1
debian/compat
vendored
@ -1 +0,0 @@
|
||||
7
|
34
debian/control
vendored
34
debian/control
vendored
@ -1,34 +0,0 @@
|
||||
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
34
debian/copyright
vendored
@ -1,34 +0,0 @@
|
||||
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
1
debian/docs
vendored
@ -1 +0,0 @@
|
||||
README
|
30
debian/hd-idle.default
vendored
30
debian/hd-idle.default
vendored
@ -1,30 +0,0 @@
|
||||
# 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
53
debian/hd-idle.init
vendored
@ -1,53 +0,0 @@
|
||||
#!/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
13
debian/rules
vendored
@ -1,13 +0,0 @@
|
||||
#!/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
1
debian/source/format
vendored
@ -1 +0,0 @@
|
||||
3.0 (native)
|
101
hd-idle.1
101
hd-idle.1
@ -1,101 +0,0 @@
|
||||
.\" 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
575
hd-idle.c
@ -1,575 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
BIN
hd-idle_1.05.orig.tar.gz.delta
Normal file
BIN
hd-idle_1.05.orig.tar.gz.delta
Normal file
Binary file not shown.
1
hd-idle_1.05.orig.tar.gz.id
Normal file
1
hd-idle_1.05.orig.tar.gz.id
Normal file
@ -0,0 +1 @@
|
||||
7f1d28ec3f71d8ef1a9a10136bd215095351153f
|
Loading…
Reference in New Issue
Block a user