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