Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ There are various ways of installing `hd-idle`
### Precompiled binaries

Precompiled binaries for released versions are available in the
[*releases* section](https://github.com/adelolmo/hd-idle/releases).
[*releases*](https://github.com/adelolmo/hd-idle/releases) section.

### Building from source

Expand All @@ -69,14 +69,11 @@ On Debian you can also clone the repository yourself and build using `dpkg-build
$ cd $GOPATH/src/github.com/adelolmo
$ git clone https://github.com/adelolmo/hd-idle.git
$ cd hd-idle
$ dpkg-buildpackage -a armhf -us -uc -b

In the example above, the package is built for `armhf`, but you can build it also for the platforms `i386`, `amd64`, and `arm64`
by substituting the parameter `-a`.
$ dpkg-buildpackage -us -uc -b

Then install the package:

# dpkg -i ../hd-idle_1.5_armhf.deb
# dpkg -i ../hd-idle*.deb

## Running hd-idle

Expand Down Expand Up @@ -118,7 +115,15 @@ Command line options:
+ -c *command_type*
Api call to stop the device. Possible values are `scsi`
(default value) and `ata`.


+ -s *symlink_policy*
Set the policy to resolve symlinks for devices. If set
to `0`, symlinks are resolve only on start. If set to `1`,
symlinks are also resolved on runtime until success.
By default symlinks are only resolve on start. If the
symlink doesn't resolve to a device, the default
configuration will be applied.

+ -l *logfile*
Name of logfile (written only after a disk has spun
up). Please note that this option might cause the
Expand All @@ -142,8 +147,8 @@ Miscellaneous options:

Regarding the parameter *-a*:

The parameter *-a* can be used to set a filter on
the disk's device name (omit /dev/) for subsequent idle-time settings.
The parameter *-a* can be used to set a filter on the disk's device name (omit /dev/)
for subsequent idle-time settings.

1)
A *-i* option before the first *-a* option will set the default idle time.
Expand Down
10 changes: 10 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
hd-idle (1.6) unstable; urgency=low

* The parameter "-s" allows to resolve symlinks for disk names also in runtime.
It is disable by default, because resolving symlinks causes an overhead.
That means that disk symlinks only get resolved on start up by default.
If the parameter "-s" is set to 1, disk symlinks will be also resolve during
execution until the symlink is resolved.

-- Andoni del Olmo <[email protected]> Wed, 28 Aug 2019 19:33:00 +0100

hd-idle (1.5) unstable; urgency=low

* Monitor the skew between monitoring cycles, on discovery of clock skew
Expand Down
19 changes: 0 additions & 19 deletions device/disk.go

This file was deleted.

64 changes: 0 additions & 64 deletions device/disk_test.go

This file was deleted.

7 changes: 7 additions & 0 deletions hd-idle.1
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ all disks.
Api call to stop the device. Possible values are "scsi" (default value)
and "ata".
.TP
.B \-s symlink_policy
Set the policy to resolve symlinks for devices. If set to "0", symlinks
are resolve only on start. If set to "1", symlinks are also resolved on
runtime until success. By default symlinks are only resolve on start.
If the symlink doesn't resolve to a device, the default configuration
will be applied.
.TP
.B \-l logfile
Name of logfile (written only after a disk has spun up). Please note that
this option might cause the disk which holds the logfile to spin up just
Expand Down
6 changes: 6 additions & 0 deletions hd-idle.conf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ START_HD_IDLE=false
# -i <idle_time> Idle time in seconds.
# -c <command_type> Api call to stop the device. Possible values are "scsi"
# (default value) and "ata".
# -s symlink_policy Set the policy to resolve symlinks for devices.
# If set to "0", symlinks are resolve only on start.
# If set to "1", symlinks are also resolved on runtime
# until success. By default symlinks are only resolve on start.
# If the symlink doesn't resolve to a device, the default
# configuration will be applied.
# -l <logfile> Name of logfile (written only after a disk has spun
# up). Please note that this option might cause the
# disk which holds the logfile to spin up just because
Expand Down
66 changes: 45 additions & 21 deletions hdidle.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"fmt"
"github.com/adelolmo/hd-idle/diskstats"
"github.com/adelolmo/hd-idle/io"
"github.com/adelolmo/hd-idle/sgio"
"log"
"os"
Expand All @@ -16,14 +17,16 @@ const (
)

type DefaultConf struct {
Idle int
CommandType string
Debug bool
LogFile string
Idle int
CommandType string
Debug bool
LogFile string
SymlinkPolicy int
}

type DeviceConf struct {
Name string
GivenName string
Idle int
CommandType string
}
Expand All @@ -42,12 +45,33 @@ func ObserveDiskActivity(config *Config) {
actualSnapshot := diskstats.Snapshot()

now = time.Now()
resolveSymlinks(config)
for _, stats := range actualSnapshot {
updateState(stats, config)
}
lastNow = now
}

func resolveSymlinks(config *Config) {
if config.Defaults.SymlinkPolicy == 0 {
return
}
for i := range config.Devices {
device := config.Devices[i]
if len(device.Name) == 0 {
realPath, err := io.RealPath(device.GivenName)
if err == nil {
config.Devices[i].Name = realPath
logToFile(config.Defaults.LogFile,
fmt.Sprintf("symlink %s resolved to %s", device.GivenName, realPath))
}
if err != nil && config.Defaults.Debug {
fmt.Printf("Cannot resolve sysmlink %s\n", device.GivenName)
}
}
}
}

func updateState(tmp diskstats.DiskStats, config *Config) {
dsi := previousDiskStatsIndex(tmp.Name)
if dsi < 0 {
Expand Down Expand Up @@ -81,9 +105,7 @@ func updateState(tmp diskstats.DiskStats, config *Config) {
if ds.SpunDown {
/* disk was spun down, thus it has just spun up */
fmt.Printf("%s spinup\n", ds.Name)
if len(config.Defaults.LogFile) > 0 {
logSpinup(ds, config.Defaults.LogFile)
}
logSpinup(ds, config.Defaults.LogFile)
previousSnapshots[dsi].SpinUpAt = now
}
previousSnapshots[dsi].Reads = tmp.Reads
Expand Down Expand Up @@ -162,33 +184,35 @@ func spindownDisk(deviceName, command string) {

func logSpinup(ds diskstats.DiskStats, file string) {
now := time.Now()
text := fmt.Sprintf("date: %s, time: %s, disk: %s, running: %d, stopped: %d\n",
text := fmt.Sprintf("date: %s, time: %s, disk: %s, running: %d, stopped: %d",
now.Format("2006-01-02"), now.Format("15:04:05"), ds.Name,
int(ds.SpinDownAt.Sub(ds.SpinUpAt).Seconds()), int(now.Sub(ds.SpinDownAt).Seconds()))
logToFile(file, text)
}

func logSpinupAfterSleep(name string, file string) {
text := fmt.Sprintf("date: %s, time: %s, disk: %s, assuming disk spun up after long sleep\n",
text := fmt.Sprintf("date: %s, time: %s, disk: %s, assuming disk spun up after long sleep",
now.Format("2006-01-02"), now.Format("15:04:05"), name)
logToFile(file, text)
}

func logToFile(file string, text string) {
cacheFile, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
log.Fatalf("Cannot open file %s. Error: %s", file, err)
}
if _, err = cacheFile.WriteString(text); err != nil {
log.Fatalf("Cannot write into file %s. Error: %s", file, err)
}
err = cacheFile.Close()
if err != nil {
log.Fatalf("Cannot close file %s. Error: %s", file, err)
if len(file) > 0 {
cacheFile, err := os.OpenFile(file, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
log.Fatalf("Cannot open file %s. Error: %s", file, err)
}
if _, err = cacheFile.WriteString(text + "\n"); err != nil {
log.Fatalf("Cannot write into file %s. Error: %s", file, err)
}
err = cacheFile.Close()
if err != nil {
log.Fatalf("Cannot close file %s. Error: %s", file, err)
}
}
}

func (c *Config) String() string {
return fmt.Sprintf("defaultIdle=%d, defaultCommand=%s, debug=%t, devices=%v, logFile=%s",
c.Defaults.Idle, c.Defaults.CommandType, c.Defaults.Debug, c.Devices, c.Defaults.LogFile)
return fmt.Sprintf("symlinkPolicy=%d, defaultIdle=%d, defaultCommand=%s, debug=%t, devices=%v, logFile=%s",
c.Defaults.SymlinkPolicy, c.Defaults.Idle, c.Defaults.CommandType, c.Defaults.Debug, c.Devices, c.Defaults.LogFile)
}
23 changes: 23 additions & 0 deletions io/disk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io

import (
"fmt"
"os"
"path/filepath"
"strings"
)

func RealPath(path string) (string, error) {
if path[0] != '/' {
return path, nil
}
if !strings.Contains(path, "by-") {
return filepath.Base(path), nil
}
s, err := os.Readlink(path)
if err == nil {
return filepath.Base(s), nil
}

return "", fmt.Errorf("cannot find device for %s", path)
}
Loading