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