2 * Copyright (C) 19?? Christer Weinigel
3 * Copyright (C) 1999 Trent Piepho <xyzzy@speakeasy.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 * Daniel Sterling (dan@lost-habit.com):
23 added #include <unistd.h>
24 removed unused variables
25 down variable set when hd is down instead of vice versa
26 don't go into daemon mode if timeout is 30 seconds or less
27 warn if timeout is less than 60 seconds.... that's still very low--
28 I recommend timeouts of at least 20 minutes
29 fixed daemon to spin down drive more than just one time (oops!!)
37 #include <sys/ioctl.h>
39 #include <linux/major.h>
40 #include <linux/kdev_t.h>
41 #include <scsi/scsi_ioctl.h>
43 /* Kernel 2.0 and 2.2 differ on how SCSI_DISK_MAJOR works */
44 #ifdef SCSI_DISK0_MAJOR
45 #define IS_SCSI_DISK(rdev) SCSI_DISK_MAJOR(MAJOR(rdev))
47 #define IS_SCSI_DISK(rdev) (MAJOR(rdev)==SCSI_DISK_MAJOR)
51 #define SD_IOCTL_IDLE 4746 /* get idle time */
64 int main(int argc
, char *argv
[])
70 if (argc
< 2 || argc
> 3) {
72 "usage: %s device [timeout]\n"
73 " where timeout is the time until motor off in seconds\n"
74 " to idle the disk immediately, use a timeout of zero\n",
78 if ((fd
= open(argv
[1], O_RDWR
)) < 0) {
82 if ((fstat(fd
, &statbuf
)) < 0) {
87 if (!S_ISBLK(statbuf
.st_mode
)
88 || !IS_SCSI_DISK(statbuf
.st_rdev
)) {
89 fprintf(stderr
, "%s is not a SCSI disk device\n", argv
[1]);
96 /* Report idle time */
98 if ((last
= ioctl(fd
, SD_IOCTL_IDLE
, &last
)) < 0) {
104 printf("%s has not been accessed yet\n", argv
[1]);
106 printf("%s has been idle for %i second%s\n", argv
[1],
107 (int) last
, (last
== 1 ? "" : "s"));
111 if ((timeout
= atol(argv
[2])) < 0) {
112 fprintf(stderr
, "timeout may not be negative\n");
117 if (timeout
!= 0) fprintf(stderr
,
118 "Really low timeouts are a bad, "
119 "bad idea.\nI'll spin down immediately for you. Use a higher "
120 "timeout for daemon mode.");
121 /* Spin down disk immediately */
123 if (ioctl(fd
, SCSI_IOCTL_STOP_UNIT
) < 0) {
135 /* Spin down disk after an idle period */
138 "Warning: timeouts less than 60 seconds are really "
139 "not such a good idea..\n");
141 /* This is ugly, but I guess there is no portable way to do this */
142 dev
= ((statbuf
.st_rdev
>> 4) & 15) + 'a';
144 sprintf(lockfn
, "/var/run/scsi-idle.sd%c.pid", dev
);
146 if ((fp
= fopen(lockfn
, "r")) != NULL
) {
147 fscanf(fp
, "%i", &pid
);
156 perror("fork failed");
161 signal(SIGINT
, handler
);
162 signal(SIGTERM
, handler
);
164 if ((fp
= fopen(lockfn
, "w")) == NULL
) {
169 fprintf(fp
, "%i\n", (int)getpid());
176 * have we shut down the drive already?
177 * IF yes: has the idle time reset since the last check?
178 * IF yes: reset our drive status variable
179 * IF the drive is running AND idle time > user-specified timeout,
180 send STOP_UNIT and set our status variable.
181 * IF idle time < timeout, sleep until idle time would be > timeout.
182 * ELSE sleep for timeout.
185 if ((last
= ioctl(fd
, SD_IOCTL_IDLE
, &last
)) < 0) {
192 printf("%s has not been accessed\n", argv
[1]);
194 printf("%s has been idle for %d second%s\n", argv
[1],
195 last
, (last
== 1 ? "" : "s"));
197 if (down
== 1 && llast
>= last
)
200 if (last
>= timeout
) {
202 (ioctl(fd
, SCSI_IOCTL_STOP_UNIT
) != 0)) {
211 printf("sleeping for %d seconds\n", timeout
- last
);
213 sleep(timeout
- last
);
218 printf("%s: idle daemon started, timeout is %ld seconds\n",