--- src/hddown.c +++ src/hddown.c 2007-06-05 14:37:50.248140535 +0200 @@ -18,6 +18,106 @@ char *v_hddown = "@(#)hddown.c 1.02 22 #include #include +#define USE_SYSFS +#ifdef USE_SYSFS + +#include +#include +#define SYS_BLK "/sys/block" +#define DEV_BASE "/dev" + +/* + * Find all disks through /sys/block. + */ +static char *list_disks(DIR* blk) +{ + struct dirent *d; + + while ((d = readdir(blk))) { + if (d->d_name[1] == 'd' && (d->d_name[0] == 'h' || d->d_name[0] == 's')) { + char buf[NAME_MAX+1]; + int fd, ret; + FILE *fp; + + ret = snprintf(buf, sizeof(buf), SYS_BLK "/%s/removable", d->d_name); + if ((ret >= sizeof(buf)) || (ret < 0)) + goto empty; + + fd = open(buf, O_RDONLY|O_NOCTTY); + if ((fd < 0) && (errno != ENOENT)) + goto empty; + + fp = fdopen(fd, "r"); + if (fp == (FILE*)0) { + close(fd); + goto empty; + } + + ret = getc(fp); + fclose(fp); + + if (ret == '0') break; /* found disk, out here */ + } + } + if (d == (struct dirent*)0) + goto empty; + return d->d_name; +empty: + return (char*)0; +} + +/* + * Put an disk in standby mode. + * Code stolen from hdparm.c + */ +static int do_standby_idedisk(char *device) +{ +#ifndef WIN_STANDBYNOW1 +#define WIN_STANDBYNOW1 0xE0 +#endif +#ifndef WIN_STANDBYNOW2 +#define WIN_STANDBYNOW2 0x94 +#endif + unsigned char args1[4] = {WIN_STANDBYNOW1,0,0,0}; + unsigned char args2[4] = {WIN_STANDBYNOW2,0,0,0}; + char buf[NAME_MAX+1]; + int fd, ret; + + ret = snprintf(buf, sizeof(buf), DEV_BASE "/%s", device); + if ((ret >= sizeof(buf)) || (ret < 0)) + return -1; + + if ((fd = open(buf, O_RDWR)) < 0) + return -1; + + ret = ioctl(fd, HDIO_DRIVE_CMD, &args1) && + ioctl(fd, HDIO_DRIVE_CMD, &args2); + close(fd); + + if (ret) + return -1; + return 0; +} + +/* + * List all disks and put them in standby mode. + * This has the side-effect of flushing the writecache, + * which is exactly what we want on poweroff. + */ +int hddown(void) +{ + DIR *blk; + char *disk; + + if ((blk = opendir(SYS_BLK)) == (DIR*)0) + return -1; + + while ((disk = list_disks(blk))) + do_standby_idedisk(disk); + + return closedir(blk); +} +#else /* ! USE_SYSFS */ #define MAX_DISKS 64 #define PROC_IDE "/proc/ide" #define DEV_BASE "/dev" @@ -104,7 +204,7 @@ int hddown(void) return 0; } - +#endif /* ! USE_SYSFS */ #else /* __linux__ */ int hddown(void)