{- 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 . -} {-# LANGUAGE CPP #-} {-| Module : Monky.Disk.Device Description : Allows access to information about generic block device Maintainer : ongy Stability : experimental Portability : Linux This module allows to read generic information about a block device and its file system. It only works if the file system is mounted when the handle is created since it needs to *find* the mount point to get information about the file system -} module Monky.Disk.Device ( BlockHandle(..) , getBlockHandle , getBlockHandleTag , devToMount ) where import System.Posix.StatVFS import Data.Maybe (listToMaybe) import Data.List (isSuffixOf) import Monky.Blkid import Monky.Disk.Common #if MIN_VERSION_base(4,8,0) #else import Control.Applicative ((<$>)) #endif {- |Get "the" mountpoint of a device. Returns a mointpoint of a device. If there are multiple mountpoints, this will return the first one found. First one is mostly determined by order in /proc/mounts and should be the one that was mounted first (time since boot). -} devToMount :: Dev -> IO (Maybe String) devToMount dev = do masters <- devToMapper dev mounts <- map (take 2 . words) . lines <$> readFile "/proc/mounts" return . listToMaybe . map (!! 1) $ filter (isDev masters) mounts where isDev masters [x, _] = any (\(Label master) -> ('/':master) `isSuffixOf` x) masters isDev _ _ = error "devToMount: How does take 2 not match [_, _]?" -- Size data metadata system -- |The FsInfo handle exported by this module data BlockHandle = BlockH FilePath instance FsInfo BlockHandle where getFsSize = getSize getFsFree = getFree getSize :: BlockHandle -> IO Integer getSize (BlockH path) = do fstat <- statVFS path return $ (fromIntegral $ statVFS_blocks fstat) * (fromIntegral $ statVFS_frsize fstat) getFree :: BlockHandle -> IO Integer getFree (BlockH path) = do fstat <- statVFS path return $ (fromIntegral $ statVFS_bavail fstat) * (fromIntegral $ statVFS_frsize fstat) getBlockHandle' :: Dev -> IO (Maybe (BlockHandle, Dev)) getBlockHandle' dev = do path <- devToMount dev case path of Just x -> return $Just (BlockH x, dev) Nothing -> return Nothing {- |Get a fs handle for 'normal' devices This uses fsStat to get file system information. fsStat takes the mount point of the file system, so we need to find the mount point. In case of mapper devices, this is done by going through the chain of slaves. -} getBlockHandle :: String -> IO (Maybe (BlockHandle, Dev)) getBlockHandle = getBlockHandleTag "UUID" -- | Same as 'getBlockHandle' but allow to pass the tag for libblkid getBlockHandleTag :: String -> String -> IO (Maybe (BlockHandle, Dev)) getBlockHandleTag t fs = do dev <- evaluateTag t fs case dev of Just x -> do y <- labelToDev (Label . reverse . takeWhile (/= '/') . reverse $ x) getBlockHandle' y Nothing -> return Nothing