119 lines
2.4 KiB
Diff
119 lines
2.4 KiB
Diff
|
--- 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 <sys/ioctl.h>
|
||
|
#include <linux/hdreg.h>
|
||
|
|
||
|
+#define USE_SYSFS
|
||
|
+#ifdef USE_SYSFS
|
||
|
+
|
||
|
+#include <limits.h>
|
||
|
+#include <errno.h>
|
||
|
+#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)
|