{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE CPP #-} {-# LANGUAGE CApiFFI #-} ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Net.FreeBSD -- Copyright : (c) 2011, 2012, 2013, 2014, 2017, 2020 Jose Antonio Ortega Ruiz -- (c) 2007-2010 Andrea Rossato -- License : BSD-style (see LICENSE) -- -- Maintainer : Jose A. Ortega Ruiz -- Stability : unstable -- Portability : unportable -- -- A net device monitor for Xmobar -- ----------------------------------------------------------------------------- module Xmobar.Plugins.Monitors.Net.FreeBSD ( existingDevs , findNetDev ) where import Xmobar.Plugins.Monitors.Net.Common (NetDevRawTotal, NetDev(..), NetDevInfo(..)) import Control.Exception (catch, SomeException(..)) import Foreign (Int32, plusPtr) import Foreign.C.Types (CUIntMax, CUChar) import Foreign.C.String (peekCString) import Foreign.Storable (Storable, alignment, sizeOf, peek, poke) import System.BSD.Sysctl (OID, sysctlPrepareOid, sysctlReadInt, sysctlPeek) #include #include #include data IfData = AvailableIfData { name :: String , txBytes :: CUIntMax , rxBytes :: CUIntMax , isUp :: Bool } | NotAvailableIfData deriving (Show, Read, Eq) instance Storable IfData where alignment _ = #{alignment struct ifmibdata} sizeOf _ = #{size struct ifmibdata} peek ptr = do cname <- peekCString (ptr `plusPtr` (#offset struct ifmibdata, ifmd_name)) tx <- peek ((ifmd_data_ptr ptr) `plusPtr` (#offset struct if_data, ifi_obytes)) :: IO CUIntMax rx <- peek ((ifmd_data_ptr ptr) `plusPtr` (#offset struct if_data, ifi_ibytes)) :: IO CUIntMax state <- peek ((ifmd_data_ptr ptr) `plusPtr` (#offset struct if_data, ifi_link_state)) :: IO CUChar return $ AvailableIfData {name = cname, txBytes = tx, rxBytes = rx, isUp = up state} where up state = state == (#const LINK_STATE_UP) ifmd_data_ptr p = p `plusPtr` (#offset struct ifmibdata, ifmd_data) poke _ _ = pure () getNetIfCountOID :: IO OID getNetIfCountOID = sysctlPrepareOid [ #const CTL_NET , #const PF_LINK , #const NETLINK_GENERIC , #const IFMIB_SYSTEM , #const IFMIB_IFCOUNT] getNetIfDataOID :: Int32 -> IO OID getNetIfDataOID i = sysctlPrepareOid [ #const CTL_NET , #const PF_LINK , #const NETLINK_GENERIC , #const IFMIB_IFDATA , i , #const IFDATA_GENERAL] getNetIfCount :: IO Int32 getNetIfCount = do oid <- getNetIfCountOID sysctlReadInt oid getNetIfData :: Int32 -> IO IfData getNetIfData i = do oid <- getNetIfDataOID i res <- catch (sysctlPeek oid) (\(SomeException _) -> return NotAvailableIfData) return res getAllNetworkData :: IO [IfData] getAllNetworkData = do count <- getNetIfCount result <- mapM getNetIfData [1..count] return result existingDevs :: IO [String] existingDevs = getAllNetworkData >>= (\xs -> return $ filter (/= "lo0") $ fmap name xs) convertIfDataToNetDev :: IfData -> IO NetDevRawTotal convertIfDataToNetDev ifData = do let up = isUp ifData rx = fromInteger . toInteger $ rxBytes ifData tx = fromInteger . toInteger $ txBytes ifData d = name ifData return $ N d (if up then ND rx tx else NI) netConvertIfDataToNetDev :: [IfData] -> IO [NetDevRawTotal] netConvertIfDataToNetDev = mapM convertIfDataToNetDev findNetDev :: String -> IO NetDevRawTotal findNetDev dev = do nds <- getAllNetworkData >>= netConvertIfDataToNetDev case filter isDev nds of x:_ -> return x _ -> return NA where isDev (N d _) = d == dev isDev NA = False