1*3ca9760fSShuah Khan /*
2*3ca9760fSShuah Khan * dslm.c
3*3ca9760fSShuah Khan * Simple Disk Sleep Monitor
4*3ca9760fSShuah Khan * by Bartek Kania
5*3ca9760fSShuah Khan * Licensed under the GPL
6*3ca9760fSShuah Khan */
7*3ca9760fSShuah Khan #include <unistd.h>
8*3ca9760fSShuah Khan #include <stdlib.h>
9*3ca9760fSShuah Khan #include <stdio.h>
10*3ca9760fSShuah Khan #include <fcntl.h>
11*3ca9760fSShuah Khan #include <errno.h>
12*3ca9760fSShuah Khan #include <time.h>
13*3ca9760fSShuah Khan #include <string.h>
14*3ca9760fSShuah Khan #include <signal.h>
15*3ca9760fSShuah Khan #include <sys/ioctl.h>
16*3ca9760fSShuah Khan #include <linux/hdreg.h>
17*3ca9760fSShuah Khan
18*3ca9760fSShuah Khan #ifdef DEBUG
19*3ca9760fSShuah Khan #define D(x) x
20*3ca9760fSShuah Khan #else
21*3ca9760fSShuah Khan #define D(x)
22*3ca9760fSShuah Khan #endif
23*3ca9760fSShuah Khan
24*3ca9760fSShuah Khan int endit = 0;
25*3ca9760fSShuah Khan
26*3ca9760fSShuah Khan /* Check if the disk is in powersave-mode
27*3ca9760fSShuah Khan * Most of the code is stolen from hdparm.
28*3ca9760fSShuah Khan * 1 = active, 0 = standby/sleep, -1 = unknown */
check_powermode(int fd)29*3ca9760fSShuah Khan static int check_powermode(int fd)
30*3ca9760fSShuah Khan {
31*3ca9760fSShuah Khan unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
32*3ca9760fSShuah Khan int state;
33*3ca9760fSShuah Khan
34*3ca9760fSShuah Khan if (ioctl(fd, HDIO_DRIVE_CMD, &args)
35*3ca9760fSShuah Khan && (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
36*3ca9760fSShuah Khan && ioctl(fd, HDIO_DRIVE_CMD, &args)) {
37*3ca9760fSShuah Khan if (errno != EIO || args[0] != 0 || args[1] != 0) {
38*3ca9760fSShuah Khan state = -1; /* "unknown"; */
39*3ca9760fSShuah Khan } else
40*3ca9760fSShuah Khan state = 0; /* "sleeping"; */
41*3ca9760fSShuah Khan } else {
42*3ca9760fSShuah Khan state = (args[2] == 255) ? 1 : 0;
43*3ca9760fSShuah Khan }
44*3ca9760fSShuah Khan D(printf(" drive state is: %d\n", state));
45*3ca9760fSShuah Khan
46*3ca9760fSShuah Khan return state;
47*3ca9760fSShuah Khan }
48*3ca9760fSShuah Khan
state_name(int i)49*3ca9760fSShuah Khan static char *state_name(int i)
50*3ca9760fSShuah Khan {
51*3ca9760fSShuah Khan if (i == -1) return "unknown";
52*3ca9760fSShuah Khan if (i == 0) return "sleeping";
53*3ca9760fSShuah Khan if (i == 1) return "active";
54*3ca9760fSShuah Khan
55*3ca9760fSShuah Khan return "internal error";
56*3ca9760fSShuah Khan }
57*3ca9760fSShuah Khan
myctime(time_t time)58*3ca9760fSShuah Khan static char *myctime(time_t time)
59*3ca9760fSShuah Khan {
60*3ca9760fSShuah Khan char *ts = ctime(&time);
61*3ca9760fSShuah Khan ts[strlen(ts) - 1] = 0;
62*3ca9760fSShuah Khan
63*3ca9760fSShuah Khan return ts;
64*3ca9760fSShuah Khan }
65*3ca9760fSShuah Khan
measure(int fd)66*3ca9760fSShuah Khan static void measure(int fd)
67*3ca9760fSShuah Khan {
68*3ca9760fSShuah Khan time_t start_time;
69*3ca9760fSShuah Khan int last_state;
70*3ca9760fSShuah Khan time_t last_time;
71*3ca9760fSShuah Khan int curr_state;
72*3ca9760fSShuah Khan time_t curr_time = 0;
73*3ca9760fSShuah Khan time_t time_diff;
74*3ca9760fSShuah Khan time_t active_time = 0;
75*3ca9760fSShuah Khan time_t sleep_time = 0;
76*3ca9760fSShuah Khan time_t unknown_time = 0;
77*3ca9760fSShuah Khan time_t total_time = 0;
78*3ca9760fSShuah Khan int changes = 0;
79*3ca9760fSShuah Khan float tmp;
80*3ca9760fSShuah Khan
81*3ca9760fSShuah Khan printf("Starting measurements\n");
82*3ca9760fSShuah Khan
83*3ca9760fSShuah Khan last_state = check_powermode(fd);
84*3ca9760fSShuah Khan start_time = last_time = time(0);
85*3ca9760fSShuah Khan printf(" System is in state %s\n\n", state_name(last_state));
86*3ca9760fSShuah Khan
87*3ca9760fSShuah Khan while(!endit) {
88*3ca9760fSShuah Khan sleep(1);
89*3ca9760fSShuah Khan curr_state = check_powermode(fd);
90*3ca9760fSShuah Khan
91*3ca9760fSShuah Khan if (curr_state != last_state || endit) {
92*3ca9760fSShuah Khan changes++;
93*3ca9760fSShuah Khan curr_time = time(0);
94*3ca9760fSShuah Khan time_diff = curr_time - last_time;
95*3ca9760fSShuah Khan
96*3ca9760fSShuah Khan if (last_state == 1) active_time += time_diff;
97*3ca9760fSShuah Khan else if (last_state == 0) sleep_time += time_diff;
98*3ca9760fSShuah Khan else unknown_time += time_diff;
99*3ca9760fSShuah Khan
100*3ca9760fSShuah Khan last_state = curr_state;
101*3ca9760fSShuah Khan last_time = curr_time;
102*3ca9760fSShuah Khan
103*3ca9760fSShuah Khan printf("%s: State-change to %s\n", myctime(curr_time),
104*3ca9760fSShuah Khan state_name(curr_state));
105*3ca9760fSShuah Khan }
106*3ca9760fSShuah Khan }
107*3ca9760fSShuah Khan changes--; /* Compensate for SIGINT */
108*3ca9760fSShuah Khan
109*3ca9760fSShuah Khan total_time = time(0) - start_time;
110*3ca9760fSShuah Khan printf("\nTotal running time: %lus\n", curr_time - start_time);
111*3ca9760fSShuah Khan printf(" State changed %d times\n", changes);
112*3ca9760fSShuah Khan
113*3ca9760fSShuah Khan tmp = (float)sleep_time / (float)total_time * 100;
114*3ca9760fSShuah Khan printf(" Time in sleep state: %lus (%.2f%%)\n", sleep_time, tmp);
115*3ca9760fSShuah Khan tmp = (float)active_time / (float)total_time * 100;
116*3ca9760fSShuah Khan printf(" Time in active state: %lus (%.2f%%)\n", active_time, tmp);
117*3ca9760fSShuah Khan tmp = (float)unknown_time / (float)total_time * 100;
118*3ca9760fSShuah Khan printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
119*3ca9760fSShuah Khan }
120*3ca9760fSShuah Khan
ender(int s)121*3ca9760fSShuah Khan static void ender(int s)
122*3ca9760fSShuah Khan {
123*3ca9760fSShuah Khan endit = 1;
124*3ca9760fSShuah Khan }
125*3ca9760fSShuah Khan
usage(void)126*3ca9760fSShuah Khan static void usage(void)
127*3ca9760fSShuah Khan {
128*3ca9760fSShuah Khan puts("usage: dslm [-w <time>] <disk>");
129*3ca9760fSShuah Khan exit(0);
130*3ca9760fSShuah Khan }
131*3ca9760fSShuah Khan
main(int argc,char ** argv)132*3ca9760fSShuah Khan int main(int argc, char **argv)
133*3ca9760fSShuah Khan {
134*3ca9760fSShuah Khan int fd;
135*3ca9760fSShuah Khan char *disk = 0;
136*3ca9760fSShuah Khan int settle_time = 60;
137*3ca9760fSShuah Khan
138*3ca9760fSShuah Khan /* Parse the simple command-line */
139*3ca9760fSShuah Khan if (argc == 2)
140*3ca9760fSShuah Khan disk = argv[1];
141*3ca9760fSShuah Khan else if (argc == 4) {
142*3ca9760fSShuah Khan settle_time = atoi(argv[2]);
143*3ca9760fSShuah Khan disk = argv[3];
144*3ca9760fSShuah Khan } else
145*3ca9760fSShuah Khan usage();
146*3ca9760fSShuah Khan
147*3ca9760fSShuah Khan if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
148*3ca9760fSShuah Khan printf("Can't open %s, because: %s\n", disk, strerror(errno));
149*3ca9760fSShuah Khan exit(-1);
150*3ca9760fSShuah Khan }
151*3ca9760fSShuah Khan
152*3ca9760fSShuah Khan if (settle_time) {
153*3ca9760fSShuah Khan printf("Waiting %d seconds for the system to settle down to "
154*3ca9760fSShuah Khan "'normal'\n", settle_time);
155*3ca9760fSShuah Khan sleep(settle_time);
156*3ca9760fSShuah Khan } else
157*3ca9760fSShuah Khan puts("Not waiting for system to settle down");
158*3ca9760fSShuah Khan
159*3ca9760fSShuah Khan signal(SIGINT, ender);
160*3ca9760fSShuah Khan
161*3ca9760fSShuah Khan measure(fd);
162*3ca9760fSShuah Khan
163*3ca9760fSShuah Khan close(fd);
164*3ca9760fSShuah Khan
165*3ca9760fSShuah Khan return 0;
166*3ca9760fSShuah Khan }
167