content: {-
      Copyright 2015,2017 Markus Ongyerth, Stephan Guenther
  
      This file is part of Monky.
  
      Monky is free software: you can redistribute it and/or modify
      it under the terms of the GNU Lesser General Public License as published by
      the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.
  
      Monky is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU Lesser General Public License for more details.
  
      You should have received a copy of the GNU Lesser General Public License
      along with Monky.  If not, see <http://www.gnu.org/licenses/>.
  -}
  {-|
  Module      : Monky.Disk
  Description : Allows access to information about a btrfs pool
  Maintainer  : moepi
  Stability   : experimental
  Portability : Linux
  
  This module allows for some support for btrfs devices.
  This may be renamed in the future when a general block-device module appears.
  -}
  module Monky.Disk
    ( DiskHandle
    , getDiskReadWrite
    , getDiskFree
    , getDiskHandle
    , getDiskHandleTag
    )
  where
  
  import Monky.Utility
  import Data.Time.Clock.POSIX
  import Data.IORef
  
  import Monky.Disk.Common
  import Monky.Disk.Btrfs
  import Monky.Disk.Device
  
  -- |The handle xported by this module
  -- A disk may have multiple physical devices so we use lists for them
  data DiskHandle = DiskH FSI [File] [IORef Int] [IORef Int] (IORef POSIXTime)
  
  
  sectorSize :: Int
  sectorSize = 512
  
  
  -- |Get the read write rates from the disk (in bytes/s)
  getDiskReadWrite :: DiskHandle -> IO (Int, Int)
  getDiskReadWrite (DiskH _ fs readrefs writerefs timeref) = do
    contents <- mapM readValues fs
    time <- getPOSIXTime
    let nreads = map (\c -> (c !! 2) * sectorSize) contents
    let writes = map (\c -> (c !! 6) * sectorSize) contents
    oreads <- mapM readIORef readrefs
    owrites <- mapM readIORef writerefs
    otime <- readIORef timeref
    let creads = zipWith (-) nreads oreads
    let cwrites = zipWith (-) writes owrites
    let ctime = time - otime
    _ <- sequence $zipWith writeIORef readrefs nreads
    _ <- sequence $zipWith writeIORef writerefs writes
    writeIORef timeref time
    return (sum $map (`sdivBound` round ctime) creads, sum $map (`sdivBound` round ctime) cwrites)
  
  
  -- |Get the space left on the disk
  getDiskFree :: DiskHandle -> IO Integer
  getDiskFree (DiskH (FSI h) _ _ _ _) = getFsFree h
  
  
  getBtrfsDH :: (BtrfsHandle, [Dev]) -> IO DiskHandle
  getBtrfsDH (h, devs) = do
    -- Open the stat file for each physical device
    fs <- mapM (\(Dev dev) -> fopen (blBasePath ++ dev ++ "/stat")) devs
    -- this gets the right number of IORefs without number hacking
    wfs <- mapM (\_ -> newIORef 0) devs
    rfs <- mapM (\_ -> newIORef 0) devs
    t <- newIORef 0
    return (DiskH (FSI h) fs wfs rfs t)
  
  
  getBlockDH :: (BlockHandle, Dev) -> IO DiskHandle
  getBlockDH (h, Dev dev) = do
    f <- fopen (blBasePath ++ dev ++ "/stat")
    wf <- newIORef 0
    rf <- newIORef 0
    t <- newIORef 0
    return (DiskH (FSI h) [f] [wf] [rf] t)
  
  
  -- | Get a disk handle from uuid. This special-cases btrfs.
  getDiskHandle :: String -> IO DiskHandle
  getDiskHandle uuid = do
  -- First try btrfs file systems
    btrfs <- getBtrfsHandle uuid
    case btrfs of
      (Just x) -> getBtrfsDH x
      Nothing -> getDiskHandleTag "UUID" uuid
  
  -- | Get the disk handle from a user chosen blkid tag.
  getDiskHandleTag :: String -> String -> IO DiskHandle
  getDiskHandleTag t v = do
      block <- getBlockHandleTag t v
      case block of
          Just x -> getBlockDH x
          Nothing -> error "Disk currently does not support your setup"
  