packages feed

statgrab-0.1.3: src/System/Statgrab/Base.hsc

{-# LANGUAGE CPP                      #-}
{-# LANGUAGE FlexibleContexts         #-}
{-# LANGUAGE FlexibleInstances        #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE RecordWildCards          #-}
{-# LANGUAGE TypeFamilies             #-}

-- Module      : System.Statgrab.Base
-- Copyright   : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
-- License     : This Source Code Form is subject to the terms of
--               the Mozilla Public License, v. 2.0.
--               A copy of the MPL can be found in the LICENSE file or
--               you can obtain it at http://mozilla.org/MPL/2.0/.
-- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>
-- Stability   : experimental
-- Portability : non-portable (GHC extensions)

-- | Bindings to the libstatgrab library.
module System.Statgrab.Base where

import Control.Applicative
import Data.ByteString          (packCString)
import Foreign
import Foreign.C.String
import Foreign.C.Types
import System.Statgrab.Internal

data family Struct a

-- | A wrapper around @Ptr a@ which keeps track of the result @Entries@,
-- needed for 'copyBatch'.
data PtrN a = PtrN
    { ptrUnwrap  :: Ptr a
    , ptrEntries :: !Int
    }

-- | Copy routines to marshall and unmarshall Storable @Stat a@ structures.
class Copy a where
    copyAt    :: Ptr  (Struct a) -> Int -> IO a
    copyBatch :: PtrN (Struct a) -> IO [a]
    copy      :: PtrN (Struct a) -> IO a

    copy      PtrN{..} = copyAt ptrUnwrap 0
    copyBatch PtrN{..} = mapM (copyAt ptrUnwrap) entries
      where
        entries
            | ptrEntries > 1 = [0..ptrEntries - 1]
            | otherwise      = [0]

    {-# MINIMAL copyAt    #-}
    {-# INLINE  copy      #-}
    {-# INLINE  copyBatch #-}

-- | Bracket routines for acquiring and releasing @Ptr a@s.
class Stat a where
    acquire :: Entries -> IO (Ptr a)
    release :: Ptr a   -> IO Error

-- | A wrapper for 'acquire'. This allows tracking the number of @Entries@
-- contained in a @Ptr a@.
acquireN :: Stat a => IO (PtrN a)
acquireN = alloca $ \x -> PtrN <$> acquire x <*> (fromIntegral <$> peek x)
{-# INLINE acquireN #-}

releaseN :: Stat a => PtrN a -> IO Error
releaseN = release . ptrUnwrap
{-# INLINE releaseN #-}

type ErrorDetailsPtr     = Ptr ErrorDetails
type HostPtr             = Ptr (Struct Host)
type CPUPtr              = Ptr (Struct CPU)
type CPUPercentPtr       = Ptr (Struct CPUPercent)
type MemoryPtr           = Ptr (Struct Memory)
type LoadPtr             = Ptr (Struct Load)
type UserPtr             = Ptr (Struct User)
type SwapPtr             = Ptr (Struct Swap)
type FileSystemPtr       = Ptr (Struct FileSystem)
type DiskIOPtr           = Ptr (Struct DiskIO)
type NetworkIOPtr        = Ptr (Struct NetworkIO)
type NetworkInterfacePtr = Ptr (Struct NetworkInterface)
type PagePtr             = Ptr (Struct Page)
type ProcessPtr          = Ptr (Struct Process)
type ProcessCountPtr     = Ptr (Struct ProcessCount)

#include <statgrab.h>

#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)

#{enum Error, Error
    , errNone               = SG_ERROR_NONE
    , errAsPrintf           = SG_ERROR_ASPRINTF
    , errDevices            = SG_ERROR_DEVICES
    , errDevStatGetDevs     = SG_ERROR_DEVSTAT_GETDEVS
    , errDevstat_selectdevs = SG_ERROR_DEVSTAT_SELECTDEVS
    , errDiskinfo           = SG_ERROR_DISKINFO
    , errEnoent             = SG_ERROR_ENOENT
    , errGetifaddrs         = SG_ERROR_GETIFADDRS
    , errGetmountInfo       = SG_ERROR_GETMNTINFO
    , errGetPageSize        = SG_ERROR_GETPAGESIZE
    , errHost               = SG_ERROR_HOST
    , errKstatDataLookup    = SG_ERROR_KSTAT_DATA_LOOKUP
    , errKstatLookup        = SG_ERROR_KSTAT_LOOKUP
    , errKstatOpen          = SG_ERROR_KSTAT_OPEN
    , errKstatRead          = SG_ERROR_KSTAT_READ
    , errKvmGetSwapInfo     = SG_ERROR_KVM_GETSWAPINFO
    , errKvmOpenFiles       = SG_ERROR_KVM_OPENFILES
    , errMalloc             = SG_ERROR_MALLOC
    , errMemStatus          = SG_ERROR_MEMSTATUS
    , errOpen               = SG_ERROR_OPEN
    , errOpenDir            = SG_ERROR_OPENDIR
    , errParse              = SG_ERROR_PARSE
    , errPdhAdd             = SG_ERROR_PDHADD
    , errPdhCollect         = SG_ERROR_PDHCOLLECT
    , errPdhOpen            = SG_ERROR_PDHOPEN
    , errPdhRead            = SG_ERROR_PDHREAD
    , errPermission         = SG_ERROR_PERMISSION
    , errPStat              = SG_ERROR_PSTAT
    , errSetEGid            = SG_ERROR_SETEGID
    , errSetEUid            = SG_ERROR_SETEUID
    , errSetMntent          = SG_ERROR_SETMNTENT
    , errSocket             = SG_ERROR_SOCKET
    , errSwapCtl            = SG_ERROR_SWAPCTL
    , errSysConf            = SG_ERROR_SYSCONF
    , errSysCtl             = SG_ERROR_SYSCTL
    , errSysCtlByName       = SG_ERROR_SYSCTLBYNAME
    , errSysctlNameToMib    = SG_ERROR_SYSCTLNAMETOMIB
    , errUname              = SG_ERROR_UNAME
    , errUnsupported        = SG_ERROR_UNSUPPORTED
    , errXswVerMismatch     = SG_ERROR_XSW_VER_MISMATCH
    , errGetMsg             = SG_ERROR_GETMSG
    , errPutMsg             = SG_ERROR_PUTMSG
    , errInitialisation     = SG_ERROR_INITIALISATION
    , errMutexLock          = SG_ERROR_MUTEX_LOCK
    , errMutexUnlock        = SG_ERROR_MUTEX_UNLOCK
    }

data ErrorDetails = ErrorDetails
    { erError :: !Error
    , erValue :: !CInt
    , erArg   :: !CString
    }

foreign import ccall safe "statgrab.h sg_get_error"
     sg_get_error :: IO Error

foreign import ccall safe "statgrab.h sg_get_error_arg"
     sg_get_error_arg :: IO CString

foreign import ccall safe "statgrab.h sg_get_error_errno"
     sg_get_error_errno :: IO CInt

foreign import ccall safe "statgrab.h sg_get_error_details"
     sg_get_error_details :: ErrorDetailsPtr -> IO Error

foreign import ccall safe "statgrab.h sg_str_error"
     sg_str_error :: Error -> IO CString

foreign import ccall safe "statgrab.h sg_strperror"
     sg_strperror :: Ptr CString -> ErrorDetailsPtr -> IO CString

foreign import ccall safe "statgrab.h sg_init"
     sg_init :: CInt -> IO Error

foreign import ccall safe "statgrab.h sg_snapshot"
     sg_snapshot :: IO Error

foreign import ccall safe "statgrab.h sg_shutdown"
     sg_shutdown :: IO Error

foreign import ccall safe "statgrab.h sg_drop_privileges"
     sg_drop_privileges :: IO Error

foreign import ccall safe "statgrab.h sg_get_nelements"
     sg_get_nelements :: Ptr () -> IO CSize

foreign import ccall safe "statgrab.h sg_free_stats_buf"
     sg_free_stats_buf :: Ptr () -> IO Error

foreign import ccall safe "statgrab.h sg_lock_mutex"
     sg_lock_mutex :: CString -> IO Error

foreign import ccall safe "statgrab.h sg_unlock_mutex"
     sg_unlock_mutex :: CString -> IO Error

#{enum HostState, HostState
    , stateUnknownConfig   = sg_unknown_configuration
    , statePhysicalHost    = sg_physical_host
    , stateVirtual         = sg_virtual_machine
    , stateParaVirtual     = sg_paravirtual_machine
    , stateHardwareVirtual = sg_hardware_virtualized
    }

data instance Struct Host = CHost
    { hostOsName    :: !CString
    , hostOsRelease :: !CString
    , hostOsVersion :: !CString
    , hostPlatform  :: !CString
    , hostName      :: !CString
    , hostBitWidth  :: !CUInt
    , hostState     :: !HostState
    , hostNCPU      :: !CUInt
    , hostMaxCPU    :: !CUInt
    , hostUptime    :: !CTime
    , hostSystime   :: !CTime
    }

instance Copy Host where
    copyAt ptr i = do
        CHost{..} <- peekElemOff ptr i
        Host <$> packCString hostOsName
             <*> packCString hostOsRelease
             <*> packCString hostOsVersion
             <*> packCString hostPlatform
             <*> packCString hostName
             <#> hostBitWidth
             <!> hostState
             <#> hostNCPU
             <#> hostMaxCPU
             <@> hostUptime
             <@> hostSystime

instance Storable (Struct Host) where
    alignment _ = #{alignment sg_host_info}
    sizeOf    _ = #{size      sg_host_info}

    peek p = CHost
        <$> #{peek sg_host_info, os_name} p
        <*> #{peek sg_host_info, os_release} p
        <*> #{peek sg_host_info, os_version} p
        <*> #{peek sg_host_info, platform} p
        <*> #{peek sg_host_info, hostname} p
        <*> #{peek sg_host_info, bitwidth} p
        <*> #{peek sg_host_info, host_state} p
        <*> #{peek sg_host_info, ncpus} p
        <*> #{peek sg_host_info, maxcpus} p
        <*> #{peek sg_host_info, uptime} p
        <*> #{peek sg_host_info, systime} p

    poke p CHost{..} = do
        #{poke sg_host_info, os_name} p hostOsName
        #{poke sg_host_info, os_release} p hostOsRelease
        #{poke sg_host_info, os_version} p hostOsVersion
        #{poke sg_host_info, platform} p hostPlatform
        #{poke sg_host_info, hostname} p hostName
        #{poke sg_host_info, bitwidth} p hostBitWidth
        #{poke sg_host_info, host_state} p hostState
        #{poke sg_host_info, ncpus} p hostNCPU
        #{poke sg_host_info, maxcpus} p hostMaxCPU
        #{poke sg_host_info, uptime} p hostUptime
        #{poke sg_host_info, systime} p hostSystime

instance Stat (Struct Host) where
    acquire = sg_get_host_info_r
    release = sg_free_host_info

foreign import ccall safe "statgrab.h sg_get_host_info"
    sg_get_host_info :: Entries -> IO HostPtr

foreign import ccall safe "statgrab.h sg_get_host_info_r"
    sg_get_host_info_r :: Entries -> IO HostPtr

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_host_info :: HostPtr -> IO Error

data instance Struct CPU = CCPU
    { cpuUser                   :: !CLLong
    , cpuKernel                 :: !CLLong
    , cpuIdle                   :: !CLLong
    , cpuIOWait                 :: !CLLong
    , cpuSwap                   :: !CLLong
    , cpuNice                   :: !CLLong
    , cpuTotal                  :: !CLLong
    , cpuCtxSwitches            :: !CLLong
    , cpuVoluntaryCtxSwitches   :: !CLLong
    , cpuInvoluntaryCtxSwitches :: !CLLong
    , cpuSyscalls               :: !CLLong
    , cpuInterrupts             :: !CLLong
    , cpuSoftInterrupts         :: !CLLong
    , cpuSystime                :: !CTime
    }

instance Copy CPU where
    copyAt ptr i = do
        CCPU{..} <- peekElemOff ptr i
        CPU <%> cpuUser
            <#> cpuKernel
            <#> cpuIdle
            <#> cpuIOWait
            <#> cpuSwap
            <#> cpuNice
            <#> cpuTotal
            <#> cpuCtxSwitches
            <#> cpuVoluntaryCtxSwitches
            <#> cpuInvoluntaryCtxSwitches
            <#> cpuSyscalls
            <#> cpuInterrupts
            <#> cpuSoftInterrupts
            <@> cpuSystime

instance Storable (Struct CPU) where
    alignment _ = #{alignment sg_cpu_stats}
    sizeOf    _ = #{size      sg_cpu_stats}

    peek p = CCPU
        <$> #{peek sg_cpu_stats, user} p
        <*> #{peek sg_cpu_stats, kernel} p
        <*> #{peek sg_cpu_stats, idle} p
        <*> #{peek sg_cpu_stats, iowait} p
        <*> #{peek sg_cpu_stats, swap} p
        <*> #{peek sg_cpu_stats, nice} p
        <*> #{peek sg_cpu_stats, total} p
        <*> #{peek sg_cpu_stats, context_switches} p
        <*> #{peek sg_cpu_stats, voluntary_context_switches} p
        <*> #{peek sg_cpu_stats, involuntary_context_switches} p
        <*> #{peek sg_cpu_stats, syscalls} p
        <*> #{peek sg_cpu_stats, interrupts} p
        <*> #{peek sg_cpu_stats, soft_interrupts} p
        <*> #{peek sg_cpu_stats, systime} p

    poke p CCPU{..} = do
        #{poke sg_cpu_stats, user} p cpuUser
        #{poke sg_cpu_stats, kernel} p cpuKernel
        #{poke sg_cpu_stats, idle} p cpuIdle
        #{poke sg_cpu_stats, iowait} p cpuIOWait
        #{poke sg_cpu_stats, swap} p cpuSwap
        #{poke sg_cpu_stats, nice} p cpuNice
        #{poke sg_cpu_stats, total} p cpuTotal
        #{poke sg_cpu_stats, context_switches} p cpuCtxSwitches
        #{poke sg_cpu_stats, voluntary_context_switches} p cpuVoluntaryCtxSwitches
        #{poke sg_cpu_stats, involuntary_context_switches} p cpuInvoluntaryCtxSwitches
        #{poke sg_cpu_stats, syscalls} p cpuSyscalls
        #{poke sg_cpu_stats, interrupts} p cpuInterrupts
        #{poke sg_cpu_stats, soft_interrupts} p cpuSoftInterrupts
        #{poke sg_cpu_stats, systime} p cpuSystime

instance Stat (Struct CPU) where
    acquire = sg_get_cpu_stats_r
    release = sg_free_cpu_stats

foreign import ccall safe "statgrab.h sg_get_cpu_stats"
    sg_get_cpu_stats :: Entries -> IO CPUPtr

foreign import ccall safe "statgrab.h sg_get_cpu_stats_diff"
    sg_get_cpu_stats_diff :: Entries -> IO CPUPtr

foreign import ccall safe "statgrab.h sg_get_cpu_stats_r"
    sg_get_cpu_stats_r :: Entries -> IO CPUPtr

foreign import ccall safe "statgrab.h sg_get_cpu_stats_diff_between"
    sg_get_cpu_stats_diff_between :: CPUPtr -> CPUPtr -> Entries -> IO CPUPtr

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_cpu_stats :: CPUPtr -> IO Error

data instance Struct CPUPercent = CCPUPercent
    { cpuPctUser      :: !CDouble
    , cpuPctKernel    :: !CDouble
    , cpuPctIdle      :: !CDouble
    , cpuPctIOWait    :: !CDouble
    , cpuPctSwap      :: !CDouble
    , cpuPctNice      :: !CDouble
    , cpuPctTimeTaken :: !CTime
    }

instance Copy CPUPercent where
    copyAt ptr i = do
        CCPUPercent{..} <- peekElemOff ptr i
        CPUPercent <$> pure (realToFrac cpuPctUser)
                   <@> cpuPctKernel
                   <@> cpuPctIdle
                   <@> cpuPctIOWait
                   <@> cpuPctSwap
                   <@> cpuPctNice
                   <@> cpuPctTimeTaken

instance Storable (Struct CPUPercent) where
    alignment _ = #{alignment sg_cpu_percents}
    sizeOf    _ = #{size      sg_cpu_percents}

    peek p = CCPUPercent
        <$> #{peek sg_cpu_percents, user} p
        <*> #{peek sg_cpu_percents, kernel} p
        <*> #{peek sg_cpu_percents, idle} p
        <*> #{peek sg_cpu_percents, iowait} p
        <*> #{peek sg_cpu_percents, swap} p
        <*> #{peek sg_cpu_percents, nice} p
        <*> #{peek sg_cpu_percents, time_taken} p

    poke p CCPUPercent{..} = do
        #{poke sg_cpu_percents, user} p cpuPctUser
        #{poke sg_cpu_percents, kernel} p cpuPctKernel
        #{poke sg_cpu_percents, idle} p cpuPctIdle
        #{poke sg_cpu_percents, iowait} p cpuPctIOWait
        #{poke sg_cpu_percents, swap} p cpuPctSwap
        #{poke sg_cpu_percents, nice} p cpuPctNice
        #{poke sg_cpu_percents, time_taken} p cpuPctTimeTaken

#{enum CPUPercentSource, CPUPercentSource
    , sourceEntireCCPU = sg_entire_cpu_percent
    , sourceDiffCCPU   = sg_last_diff_cpu_percent
    , sourceNewDiffCCPU= sg_new_diff_cpu_percent
}

foreign import ccall safe "statgrab.h sg_get_cpu_percents_of"
    sg_get_cpu_percents_of :: CPUPercentSource -> Entries -> IO CPUPercentPtr

foreign import ccall safe "statgrab.h sg_get_cpu_percents_r"
    sg_get_cpu_percents_r :: CPUPtr -> Entries -> IO CPUPercentPtr

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_cpu_percents :: CPUPercentPtr -> IO Error

data instance Struct Memory = CMemory
    { memTotal   :: !CULLong
    , memFree    :: !CULLong
    , memUsed    :: !CULLong
    , memCache   :: !CULLong
    , memSystime :: !CTime
    }

instance Copy Memory where
    copyAt ptr i = do
        CMemory{..} <- peekElemOff ptr i
        Memory <%> memTotal
               <#> memFree
               <#> memUsed
               <#> memCache
               <@> memSystime

instance Storable (Struct Memory) where
    alignment _ = #{alignment sg_mem_stats}
    sizeOf    _ = #{size      sg_mem_stats}

    peek p = CMemory
        <$> #{peek sg_mem_stats, total} p
        <*> #{peek sg_mem_stats, free} p
        <*> #{peek sg_mem_stats, used} p
        <*> #{peek sg_mem_stats, cache} p
        <*> #{peek sg_mem_stats, systime} p

    poke p CMemory{..} = do
        #{poke sg_mem_stats, total} p memTotal
        #{poke sg_mem_stats, free} p memFree
        #{poke sg_mem_stats, used} p memUsed
        #{poke sg_mem_stats, systime} p memSystime

instance Stat (Struct Memory) where
    acquire = sg_get_mem_stats_r
    release = sg_free_mem_stats

foreign import ccall safe "statgrab.h sg_get_mem_stats"
    sg_get_mem_stats :: Entries -> IO MemoryPtr

foreign import ccall safe "statgrab.h sg_get_mem_stats_r"
    sg_get_mem_stats_r :: Entries -> IO MemoryPtr

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_mem_stats :: MemoryPtr -> IO Error

data instance Struct Load = CLoad
    { load1       :: !CDouble
    , load5       :: !CDouble
    , load15      :: !CDouble
    , loadSystime :: !CTime
    }

instance Copy Load where
    copyAt ptr i = do
        CLoad{..} <- peekElemOff ptr i
        Load <$> pure (realToFrac load1)
             <@> load5
             <@> load15
             <@> loadSystime

instance Storable (Struct Load) where
    alignment _ = #{alignment sg_load_stats}
    sizeOf    _ = #{size      sg_load_stats}

    peek p = CLoad
        <$> #{peek sg_load_stats, min1} p
        <*> #{peek sg_load_stats, min5} p
        <*> #{peek sg_load_stats, min15} p
        <*> #{peek sg_load_stats, systime} p

    poke p CLoad{..} = do
        #{poke sg_load_stats, min1} p load1
        #{poke sg_load_stats, min5} p load5
        #{poke sg_load_stats, min15} p load15
        #{poke sg_load_stats, systime} p loadSystime

instance Stat (Struct Load) where
    acquire = sg_get_load_stats_r
    release = sg_free_load_stats

foreign import ccall safe "statgrab.h sg_get_load_stats"
    sg_get_load_stats :: Entries -> IO LoadPtr

foreign import ccall safe "statgrab.h sg_get_load_stats_r"
    sg_get_load_stats_r :: Entries -> IO LoadPtr

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_load_stats :: LoadPtr -> IO Error

data instance Struct User = CUser
    { userLoginName    :: !CString
    , userRecordId     :: !CString
    , userRecordIdSize :: !CSize
    , userDevice       :: !CString
    , userHostName     :: !CString
    , userPid          :: !CInt
    , userLoginTime    :: !CTime
    , userSystime      :: !CTime
    }

instance Copy User where
    copyAt ptr i = do
        CUser{..} <- peekElemOff ptr i
        User <$> packCString userLoginName
             <*> packCString userRecordId
             <#> userRecordIdSize
             <*> packCString userDevice
             <*> packCString userHostName
             <#> userPid
             <@> userLoginTime
             <@> userSystime

instance Storable (Struct User) where
    alignment _ = #{alignment sg_user_stats}
    sizeOf    _ = #{size      sg_user_stats}

    peek p = CUser
        <$> #{peek sg_user_stats, login_name} p
        <*> #{peek sg_user_stats, record_id} p
        <*> #{peek sg_user_stats, record_id_size} p
        <*> #{peek sg_user_stats, device} p
        <*> #{peek sg_user_stats, hostname} p
        <*> #{peek sg_user_stats, pid} p
        <*> #{peek sg_user_stats, login_time} p
        <*> #{peek sg_user_stats, systime} p

    poke p CUser{..} = do
        #{poke sg_user_stats, login_name} p userLoginTime
        #{poke sg_user_stats, record_id} p userRecordId
        #{poke sg_user_stats, record_id_size} p userRecordIdSize
        #{poke sg_user_stats, device} p userDevice
        #{poke sg_user_stats, hostname} p userHostName
        #{poke sg_user_stats, pid} p userPid
        #{poke sg_user_stats, login_time} p userLoginTime
        #{poke sg_user_stats, systime} p userSystime

instance Stat (Struct User) where
    acquire = sg_get_user_stats_r
    release = sg_free_user_stats

foreign import ccall safe "statgrab.h sg_get_user_stats"
    sg_get_user_stats :: Entries -> IO UserPtr

foreign import ccall safe "statgrab.h sg_get_user_stats_r"
    sg_get_user_stats_r :: Entries -> IO UserPtr

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_user_stats :: UserPtr -> IO Error

data instance Struct Swap = CSwap
    { swapTotal   :: !CULLong
    , swapUsed    :: !CULLong
    , swapFree    :: !CULLong
    , swapSystime :: !CTime
    }

instance Copy Swap where
    copyAt ptr i = do
        CSwap{..} <- peekElemOff ptr i
        Swap <%> swapTotal
             <#> swapUsed
             <#> swapFree
             <@> swapSystime

instance Storable (Struct Swap) where
    alignment _ = #{alignment sg_swap_stats}
    sizeOf    _ = #{size      sg_swap_stats}

    peek p = CSwap
        <$> #{peek sg_swap_stats, total} p
        <*> #{peek sg_swap_stats, used} p
        <*> #{peek sg_swap_stats, free} p
        <*> #{peek sg_swap_stats, systime} p

    poke p CSwap{..} = do
        #{poke sg_swap_stats, total} p swapTotal
        #{poke sg_swap_stats, used} p swapUsed
        #{poke sg_swap_stats, free} p swapFree
        #{poke sg_swap_stats, systime} p swapSystime

instance Stat (Struct Swap) where
    acquire = sg_get_swap_stats_r
    release = sg_free_swap_stats

foreign import ccall safe "statgrab.h sg_get_swap_stats"
    sg_get_swap_stats :: Entries -> IO SwapPtr

foreign import ccall safe "statgrab.h sg_get_swap_stats_r"
    sg_get_swap_stats_r :: Entries -> IO SwapPtr

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_swap_stats :: SwapPtr -> IO Error

#{enum DeviceType, DeviceType
    , deviceUnknown  = sg_fs_unknown
    , deviceRegular  = sg_fs_regular
    , deviceSpecial  = sg_fs_special
    , deviceLoopback = sg_fs_loopback
    , deviceRemote   = sg_fs_remote
    , deviceLocal    = sg_fs_local
    , deviceAllTypes = sg_fs_alltypes
    }

data instance Struct FileSystem = CFileSystem
    { fsDeviceName  :: !CString
    , fsType        :: !CString
    , fsMountPoint  :: !CString
    , fsDeviceType  :: !DeviceType
    , fsSize        :: !CULLong
    , fsUsed        :: !CULLong
    , fsFree        :: !CULLong
    , fsAvail       :: !CULLong
    , fsTotalInodes :: !CULLong
    , fsUsedInodes  :: !CULLong
    , fsFreeInodes  :: !CULLong
    , fsAvailInodes :: !CULLong
    , fsIOSize      :: !CULLong
    , fsBlockSize   :: !CULLong
    , fsTotalBlocks :: !CULLong
    , fsFreeBlocks  :: !CULLong
    , fsUsedBlocks  :: !CULLong
    , fsAvailBlocks :: !CULLong
    , fsSystime     :: !CTime
    }

instance Copy FileSystem where
    copyAt ptr i = do
        CFileSystem{..} <- peekElemOff ptr i
        FileSystem <$> packCString fsDeviceName
                   <*> packCString fsType
                   <*> packCString fsMountPoint
                   <!> fsDeviceType
                   <#> fsSize
                   <#> fsUsed
                   <#> fsFree
                   <#> fsAvail
                   <#> fsTotalInodes
                   <#> fsUsedInodes
                   <#> fsFreeInodes
                   <#> fsAvailInodes
                   <#> fsIOSize
                   <#> fsBlockSize
                   <#> fsTotalBlocks
                   <#> fsFreeBlocks
                   <#> fsUsedBlocks
                   <#> fsAvailBlocks
                   <@> fsSystime

instance Storable (Struct FileSystem) where
    alignment _ = #{alignment sg_fs_stats}
    sizeOf    _ = #{size      sg_fs_stats}

    peek p = CFileSystem
        <$> #{peek sg_fs_stats, device_name} p
        <*> #{peek sg_fs_stats, fs_type} p
        <*> #{peek sg_fs_stats, mnt_point} p
        <*> #{peek sg_fs_stats, device_type} p
        <*> #{peek sg_fs_stats, size} p
        <*> #{peek sg_fs_stats, used} p
        <*> #{peek sg_fs_stats, free} p
        <*> #{peek sg_fs_stats, avail} p
        <*> #{peek sg_fs_stats, total_inodes} p
        <*> #{peek sg_fs_stats, used_inodes} p
        <*> #{peek sg_fs_stats, free_inodes} p
        <*> #{peek sg_fs_stats, avail_inodes} p
        <*> #{peek sg_fs_stats, io_size} p
        <*> #{peek sg_fs_stats, block_size} p
        <*> #{peek sg_fs_stats, total_blocks} p
        <*> #{peek sg_fs_stats, free_blocks} p
        <*> #{peek sg_fs_stats, used_blocks} p
        <*> #{peek sg_fs_stats, avail_blocks} p
        <*> #{peek sg_fs_stats, systime} p

    poke p CFileSystem{..} = do
        #{poke sg_fs_stats, device_name} p fsDeviceName
        #{poke sg_fs_stats, fs_type} p fsType
        #{poke sg_fs_stats, mnt_point} p fsMountPoint
        #{poke sg_fs_stats, device_type} p fsDeviceType
        #{poke sg_fs_stats, size} p fsSize
        #{poke sg_fs_stats, used} p fsUsed
        #{poke sg_fs_stats, free} p fsFree
        #{poke sg_fs_stats, avail} p fsAvail
        #{poke sg_fs_stats, total_inodes} p fsTotalInodes
        #{poke sg_fs_stats, used_inodes} p fsUsedInodes
        #{poke sg_fs_stats, free_inodes} p fsFreeInodes
        #{poke sg_fs_stats, avail_inodes} p fsAvailInodes
        #{poke sg_fs_stats, io_size} p fsIOSize
        #{poke sg_fs_stats, block_size} p fsBlockSize
        #{poke sg_fs_stats, total_blocks} p fsTotalBlocks
        #{poke sg_fs_stats, free_blocks} p fsFreeBlocks
        #{poke sg_fs_stats, used_blocks} p fsUsedBlocks
        #{poke sg_fs_stats, avail_blocks} p fsAvailBlocks
        #{poke sg_fs_stats, systime} p fsSystime

instance Stat (Struct FileSystem) where
    acquire = sg_get_fs_stats_r
    release = sg_free_fs_stats

foreign import ccall safe "statgrab.h sg_get_valid_filesystems"
     sg_get_valid_filesystems :: Entries -> IO (Ptr CString)

-- foreign import ccall safe "statgrab.h sg_get_fs_val"
--      sg_set_valid_filesystems :: Ptr CString -> IO Error
-- __sg_public const char **sg_get_valid_filesystems(size_t *entries);
-- __sg_public sg_error sg_set_valid_filesystems(const char *valid_fs[]);

foreign import ccall safe "statgrab.h sg_get_fs_stats"
     sg_get_fs_stats :: Entries -> IO FileSystemPtr

foreign import ccall safe "statgrab.h sg_get_fs_stats_r"
     sg_get_fs_stats_r :: Entries -> IO FileSystemPtr

foreign import ccall safe "statgrab.h sg_get_fs_stats_diff"
     sg_get_fs_stats_diff :: Entries -> IO FileSystemPtr

foreign import ccall safe "statgrab.h sg_get_fs_stats_diff_between"
     sg_get_fs_stats_diff_between :: FileSystemPtr
                                  -> FileSystemPtr
                                  -> Entries
                                  -> IO FileSystemPtr

foreign import ccall safe "statgrab.h sg_fs_compare_device_name"
     sg_fs_compare_device_name :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_fs_compare_mnt_point"
     sg_fs_compare_mnt_point :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_fs_stats :: FileSystemPtr -> IO Error

data instance Struct DiskIO = CDiskIO
    { diskName    :: !CString
    , diskRead    :: !CULLong
    , diskWrite   :: !CULLong
    , diskSystime :: !CTime
    }

instance Copy DiskIO where
    copyAt ptr i = do
        CDiskIO{..} <- peekElemOff ptr i
        DiskIO <$> packCString diskName
               <#> diskRead
               <#> diskWrite
               <@> diskSystime

instance Storable (Struct DiskIO) where
    alignment _ = #{alignment sg_disk_io_stats}
    sizeOf    _ = #{size      sg_disk_io_stats}

    peek p = CDiskIO
        <$> #{peek sg_disk_io_stats, disk_name} p
        <*> #{peek sg_disk_io_stats, read_bytes} p
        <*> #{peek sg_disk_io_stats, write_bytes} p
        <*> #{peek sg_disk_io_stats, systime} p

    poke p CDiskIO{..} = do
        #{poke sg_disk_io_stats, disk_name} p diskName
        #{poke sg_disk_io_stats, read_bytes} p diskRead
        #{poke sg_disk_io_stats, write_bytes} p diskWrite
        #{poke sg_disk_io_stats, systime} p diskSystime

instance Stat (Struct DiskIO) where
    acquire = sg_get_disk_io_stats_r
    release = sg_free_disk_io_stats

foreign import ccall safe "statgrab.h sg_get_disk_io_stats"
    sg_get_disk_io_stats :: Entries -> IO DiskIOPtr

foreign import ccall safe "statgrab.h sg_get_disk_io_stats_r"
    sg_get_disk_io_stats_r :: Entries -> IO DiskIOPtr

foreign import ccall safe "statgrab.h sg_get_disk_io_stats_diff"
    sg_get_disk_io_stats_diff :: Entries -> IO DiskIOPtr

foreign import ccall safe "statgrab.h sg_get_disk_io_stats_diff_between"
    sg_get_disk_io_stats_diff_between :: DiskIOPtr
                                      -> DiskIOPtr
                                      -> Entries
                                      -> IO DiskIOPtr

foreign import ccall safe "statgrab.h sg_disk_io_compare_name"
    sg_disk_io_compare_name :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_disk_io_compare_traffic"
    sg_disk_io_compare_traffic :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_disk_io_stats :: DiskIOPtr -> IO Error

data instance Struct NetworkIO = CNetworkIO
    { ifaceIOName     :: !CString
    , ifaceTX         :: !CULLong
    , ifaceRX         :: !CULLong
    , ifaceIPackets   :: !CULLong
    , ifaceOPackets   :: !CULLong
    , ifaceIErrors    :: !CULLong
    , ifaceOErrors    :: !CULLong
    , ifaceCollisions :: !CULLong
    , ifaceSystem     :: !CTime
    }

instance Copy NetworkIO where
    copyAt ptr i = do
        CNetworkIO{..} <- peekElemOff ptr i
        NetworkIO <$> packCString ifaceIOName
                  <#> ifaceTX
                  <#> ifaceRX
                  <#> ifaceIPackets
                  <#> ifaceOPackets
                  <#> ifaceIErrors
                  <#> ifaceOErrors
                  <#> ifaceCollisions
                  <@> ifaceSystem

instance Storable (Struct NetworkIO) where
    alignment _ = #{alignment sg_network_io_stats}
    sizeOf    _ = #{size      sg_network_io_stats}

    peek p = CNetworkIO
        <$> #{peek sg_network_io_stats, interface_name} p
        <*> #{peek sg_network_io_stats, tx} p
        <*> #{peek sg_network_io_stats, rx} p
        <*> #{peek sg_network_io_stats, ipackets} p
        <*> #{peek sg_network_io_stats, opackets} p
        <*> #{peek sg_network_io_stats, ierrors} p
        <*> #{peek sg_network_io_stats, oerrors} p
        <*> #{peek sg_network_io_stats, collisions} p
        <*> #{peek sg_network_io_stats, systime} p

    poke p CNetworkIO{..} = do
        #{poke sg_network_io_stats, interface_name} p ifaceIOName
        #{poke sg_network_io_stats, tx} p ifaceTX
        #{poke sg_network_io_stats, rx} p ifaceRX
        #{poke sg_network_io_stats, ipackets} p ifaceIPackets
        #{poke sg_network_io_stats, opackets} p ifaceOPackets
        #{poke sg_network_io_stats, ierrors} p ifaceIErrors
        #{poke sg_network_io_stats, oerrors} p ifaceOErrors
        #{poke sg_network_io_stats, collisions} p ifaceCollisions
        #{poke sg_network_io_stats, systime} p ifaceSystem

instance Stat (Struct NetworkIO) where
    acquire = sg_get_network_io_stats_r
    release = sg_free_network_io_stats

foreign import ccall safe "statgrab.h sg_get_network_io_stats"
     sg_get_network_io_stats :: Entries -> IO NetworkIOPtr

foreign import ccall safe "statgrab.h sg_get_network_io_stats_r"
     sg_get_network_io_stats_r :: Entries -> IO NetworkIOPtr

foreign import ccall safe "statgrab.h sg_get_network_io_stats_diff"
     sg_get_network_io_stats_diff :: Entries -> IO NetworkIOPtr

foreign import ccall safe "statgrab.h sg_get_network_io_stats_diff_between"
     sg_get_network_io_stats_diff_between :: NetworkIOPtr
                                          -> NetworkIOPtr
                                          -> Entries
                                          -> IO NetworkIOPtr

foreign import ccall safe "statgrab.h sg_network_io_compare_name"
     sg_network_io_compare_name :: Ptr () -> Ptr () -> IO (CInt)

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_network_io_stats :: NetworkIOPtr -> IO Error

#{enum InterfaceMode, InterfaceMode
    , duplexFull    = SG_IFACE_DUPLEX_FULL
    , duplexHalf    = SG_IFACE_DUPLEX_HALF
    , duplexUnknown = SG_IFACE_DUPLEX_UNKNOWN
    }

#{enum InterfaceStatus, InterfaceStatus
    , statusDown = SG_IFACE_DOWN
    , statusUp   = SG_IFACE_UP
    }

data instance Struct NetworkInterface = CNetworkInterface
    { ifaceName    :: !CString
    , ifaceSpeed   :: !CULLong
    , ifaceFactor  :: !CULLong
    , ifaceDuplex  :: !InterfaceMode
    , ifaceUp      :: !InterfaceStatus
    , ifaceSystime :: !CTime
    }

instance Copy NetworkInterface where
    copyAt ptr i = do
        CNetworkInterface{..} <- peekElemOff ptr i
        NetworkInterface <$> packCString ifaceName
                         <#> ifaceSpeed
                         <#> ifaceFactor
                         <!> ifaceDuplex
                         <!> ifaceUp
                         <@> ifaceSystime

instance Storable (Struct NetworkInterface) where
    alignment _ = #{alignment sg_network_iface_stats}
    sizeOf    _ = #{size      sg_network_iface_stats}

    peek p = CNetworkInterface
        <$> #{peek sg_network_iface_stats, interface_name} p
        <*> #{peek sg_network_iface_stats, speed} p
        <*> #{peek sg_network_iface_stats, factor} p
        <*> #{peek sg_network_iface_stats, duplex} p
        <*> #{peek sg_network_iface_stats, up} p
        <*> #{peek sg_network_iface_stats, systime} p

    poke p CNetworkInterface{..} = do
        #{poke sg_network_iface_stats, interface_name} p ifaceName
        #{poke sg_network_iface_stats, speed} p ifaceSpeed
        #{poke sg_network_iface_stats, factor} p ifaceFactor
        #{poke sg_network_iface_stats, duplex} p ifaceDuplex
        #{poke sg_network_iface_stats, up} p ifaceUp
        #{poke sg_network_iface_stats, systime} p ifaceSystime

instance Stat (Struct NetworkInterface) where
    acquire = sg_get_network_iface_stats_r
    release = sg_free_network_iface_stats

foreign import ccall safe "statgrab.h sg_get_network_iface_stats"
    sg_get_network_iface_stats :: Entries -> IO NetworkInterfacePtr

foreign import ccall safe "statgrab.h sg_get_network_iface_stats_r"
    sg_get_network_iface_stats_r :: Entries -> IO NetworkInterfacePtr

foreign import ccall safe "statgrab.h sg_network_iface_compare_name"
    sg_network_iface_compare_name :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_network_iface_stats :: NetworkInterfacePtr -> IO Error

data instance Struct Page = CPage
    { pagesIn      :: !CULLong
    , pagesOut     :: !CULLong
    , pagesSysTime :: !CTime
    }

instance Copy Page where
    copyAt ptr i = do
        CPage{..} <- peekElemOff ptr i
        Page <%> pagesIn
             <#> pagesOut
             <@> pagesSysTime

instance Storable (Struct Page) where
    alignment _ = #{alignment sg_page_stats}
    sizeOf    _ = #{size      sg_page_stats}

    peek p = CPage
        <$> #{peek sg_page_stats, pages_pagein} p
        <*> #{peek sg_page_stats, pages_pageout} p
        <*> #{peek sg_page_stats, systime} p

    poke p CPage{..} = do
        #{poke sg_page_stats, pages_pagein} p pagesIn
        #{poke sg_page_stats, pages_pageout} p pagesOut
        #{poke sg_page_stats, systime} p pagesSysTime

instance Stat (Struct Page) where
    acquire = sg_get_page_stats_r
    release = sg_free_page_stats

foreign import ccall safe "statgrab.h sg_get_page_stats"
     sg_get_page_stats :: Entries -> IO PagePtr

foreign import ccall safe "statgrab.h sg_get_page_stats_r"
     sg_get_page_stats_r :: Entries -> IO PagePtr

foreign import ccall safe "statgrab.h sg_get_page_stats_diff"
     sg_get_page_stats_diff :: Entries -> IO PagePtr

foreign import ccall safe "statgrab.h sg_get_page_stats_diff_between"
     sg_get_page_stats_diff_between :: PagePtr
                                    -> PagePtr
                                    -> Entries
                                    -> IO PagePtr

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_page_stats :: PagePtr -> IO Error

#{enum ProcessState, ProcessState
    , stateRunning  = SG_PROCESS_STATE_RUNNING
    , stateSleeping = SG_PROCESS_STATE_SLEEPING
    , stateStopped  = SG_PROCESS_STATE_STOPPED
    , stateZombie   = SG_PROCESS_STATE_ZOMBIE
    , stateUnknown  = SG_PROCESS_STATE_UNKNOWN
    }

data instance Struct Process = CProcess
    { procName        :: !CString
    , procTitle       :: !CString
    , procPid         :: !CInt
    , procParent      :: !CInt
    , procPGid        :: !CInt
    , procSessId      :: !CInt
    , procUid         :: !CUInt
    , procEUid        :: !CUInt
    , procGid         :: !CUInt
    , procEGid        :: !CUInt
    , procSwitches    :: !CULLong
    , procVoluntary   :: !CULLong
    , procInvoluntary :: !CULLong
    , procSize        :: !CULLong
    , procResident    :: !CULLong
    , procStart       :: !CTime
    , procSpent       :: !CTime
    , procCPUPercent  :: !CDouble
    , procNice        :: !CInt
    , procState       :: !ProcessState
    , procSystime     :: !CTime
    }

instance Copy Process where
    copyAt ptr i = do
        CProcess{..} <- peekElemOff ptr i
        Process <$> packCString procName
                <*> packCString procTitle
                <#> procPid
                <#> procParent
                <#> procPGid
                <#> procSessId
                <#> procUid
                <#> procEUid
                <#> procGid
                <#> procEGid
                <#> procSwitches
                <#> procVoluntary
                <#> procInvoluntary
                <#> procSize
                <#> procResident
                <@> procStart
                <@> procSpent
                <@> procCPUPercent
                <#> procNice
                <!> procState
                <@> procSystime

instance Storable (Struct Process) where
    alignment _ = #{alignment sg_process_stats}
    sizeOf    _ = #{size      sg_process_stats}

    peek p = CProcess
        <$> #{peek sg_process_stats, process_name} p
        <*> #{peek sg_process_stats, proctitle} p
        <*> #{peek sg_process_stats, pid} p
        <*> #{peek sg_process_stats, parent} p
        <*> #{peek sg_process_stats, pgid} p
        <*> #{peek sg_process_stats, sessid} p
        <*> #{peek sg_process_stats, uid} p
        <*> #{peek sg_process_stats, euid} p
        <*> #{peek sg_process_stats, gid} p
        <*> #{peek sg_process_stats, egid} p
        <*> #{peek sg_process_stats, context_switches} p
        <*> #{peek sg_process_stats, voluntary_context_switches} p
        <*> #{peek sg_process_stats, involuntary_context_switches} p
        <*> #{peek sg_process_stats, proc_size} p
        <*> #{peek sg_process_stats, proc_resident} p
        <*> #{peek sg_process_stats, start_time} p
        <*> #{peek sg_process_stats, time_spent} p
        <*> #{peek sg_process_stats, cpu_percent} p
        <*> #{peek sg_process_stats, nice} p
        <*> #{peek sg_process_stats, state} p
        <*> #{peek sg_process_stats, systime} p

    poke p CProcess{..} = do
        #{poke sg_process_stats, process_name} p procName
        #{poke sg_process_stats, proctitle} p procTitle
        #{poke sg_process_stats, pid} p procPid
        #{poke sg_process_stats, parent} p procParent
        #{poke sg_process_stats, pgid} p procPGid
        #{poke sg_process_stats, sessid} p procSessId
        #{poke sg_process_stats, uid} p procUid
        #{poke sg_process_stats, euid} p procEUid
        #{poke sg_process_stats, gid} p procGid
        #{poke sg_process_stats, egid} p procEGid
        #{poke sg_process_stats, context_switches} p procSwitches
        #{poke sg_process_stats, voluntary_context_switches} p procVoluntary
        #{poke sg_process_stats, involuntary_context_switches} p procInvoluntary
        #{poke sg_process_stats, proc_size} p procSize
        #{poke sg_process_stats, proc_resident} p procResident
        #{poke sg_process_stats, start_time} p procStart
        #{poke sg_process_stats, time_spent} p procSpent
        #{poke sg_process_stats, cpu_percent} p procCPUPercent
        #{poke sg_process_stats, nice} p procNice
        #{poke sg_process_stats, state} p procState
        #{poke sg_process_stats, systime} p procSystime

instance Stat (Struct Process) where
    acquire = sg_get_process_stats_r
    release = sg_free_process_stats

foreign import ccall safe "statgrab.h sg_get_process_stats"
    sg_get_process_stats :: Entries -> IO ProcessPtr

foreign import ccall safe "statgrab.h sg_get_process_stats_r"
    sg_get_process_stats_r :: Entries -> IO ProcessPtr

foreign import ccall safe "statgrab.h sg_process_compare_name"
    sg_process_compare_name :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_process_compare_pid"
    sg_process_compare_pid :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_process_compare_uid"
    sg_process_compare_uid :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_process_compare_gid"
    sg_process_compare_gid :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_process_compare_size"
    sg_process_compare_size :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_process_compare_res"
    sg_process_compare_res :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_process_compare_cpu"
    sg_process_compare_cpu :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_process_compare_time"
    sg_process_compare_time :: Ptr () -> Ptr () -> IO CInt

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_process_stats :: ProcessPtr -> IO Error

#{enum ProcessSource, ProcessSource
    , sourceEntire = sg_entire_process_count
    , sourceLast   = sg_last_process_count
    }

data instance Struct ProcessCount = CProcessCount
    { countTotal    :: !CULLong
    , countRunning  :: !CULLong
    , countSleeping :: !CULLong
    , countStopped  :: !CULLong
    , countZombie   :: !CULLong
    , countUnknown  :: !CULLong
    , countSystime  :: !CTime
    }

instance Copy ProcessCount where
    copyAt ptr i = do
        CProcessCount{..} <- peekElemOff ptr i
        ProcessCount <%> countTotal
                     <#> countRunning
                     <#> countSleeping
                     <#> countStopped
                     <#> countZombie
                     <#> countUnknown
                     <@> countSystime

instance Storable (Struct ProcessCount) where
    alignment _ = #{alignment sg_process_count}
    sizeOf    _ = #{size      sg_process_count}

    peek p = CProcessCount
        <$> #{peek sg_process_count, total} p
        <*> #{peek sg_process_count, running} p
        <*> #{peek sg_process_count, sleeping} p
        <*> #{peek sg_process_count, stopped} p
        <*> #{peek sg_process_count, zombie} p
        <*> #{peek sg_process_count, unknown} p
        <*> #{peek sg_process_count, systime} p

    poke p CProcessCount{..} = do
        #{poke sg_process_count, total} p countTotal
        #{poke sg_process_count, running} p countRunning
        #{poke sg_process_count, sleeping} p countSleeping
        #{poke sg_process_count, stopped} p countStopped
        #{poke sg_process_count, zombie} p countZombie
        #{poke sg_process_count, unknown} p countUnknown
        #{poke sg_process_count, systime} p countSystime

foreign import ccall safe "statgrab.h sg_get_process_count_of"
    sg_get_process_count_of :: ProcessSource -> IO ProcessCountPtr

foreign import ccall safe "statgrab.h sg_get_process_count_r"
    sg_get_process_count_r :: ProcessPtr -> IO ProcessCountPtr

foreign import ccall safe "statgrab.h sg_free_stats_buf"
    sg_free_process_count :: ProcessCountPtr -> IO Error