module Linux.Systemd
  ( listenFds
  , isSocket
  ) where

import Foreign.C.Error (Errno, getErrno)
import Foreign.C.Types (CInt (..))
import Posix.Socket (Family (..), Type (..))
import System.Posix.Types (Fd (..))

foreign import ccall unsafe "systemd/sd-daemon.h sd_listen_fds"
  c_listenFds :: CInt -> IO CInt

foreign import ccall unsafe "systemd/sd-daemon.h sd_is_socket"
  c_isSocket :: Fd -> Family -> Type -> CInt -> IO CInt

{- | Check for file descriptors passed by the system manager. Returns
the number of received file descriptors. If no file descriptors
have been received, zero is returned.
-}
listenFds ::
  -- | unset environment (non-zero unsets @LISTEN_FDS@, @LISTEN_PID@, and @LISTEN_FDNAMES@)
  CInt ->
  IO (Either Errno CInt)
listenFds :: CInt -> IO (Either Errno CInt)
listenFds CInt
a = CInt -> IO CInt
c_listenFds CInt
a IO CInt
-> (CInt -> IO (Either Errno CInt)) -> IO (Either Errno CInt)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CInt -> IO (Either Errno CInt)
errorsFromInt

isSocket ::
  -- | File descriptor
  Fd ->
  -- | Socket family
  Family ->
  -- | Socket type
  Type ->
  -- | Positive: require listen mode. Zero: require non-listening mode.
  CInt ->
  IO (Either Errno CInt)
isSocket :: Fd -> Family -> Type -> CInt -> IO (Either Errno CInt)
isSocket Fd
a Family
b Type
c CInt
d = Fd -> Family -> Type -> CInt -> IO CInt
c_isSocket Fd
a Family
b Type
c CInt
d IO CInt
-> (CInt -> IO (Either Errno CInt)) -> IO (Either Errno CInt)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CInt -> IO (Either Errno CInt)
errorsFromInt

errorsFromInt :: CInt -> IO (Either Errno CInt)
errorsFromInt :: CInt -> IO (Either Errno CInt)
errorsFromInt CInt
r =
  if CInt
r CInt -> CInt -> Bool
forall a. Ord a => a -> a -> Bool
>= CInt
0
    then Either Errno CInt -> IO (Either Errno CInt)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CInt -> Either Errno CInt
forall a b. b -> Either a b
Right CInt
r)
    else (Errno -> Either Errno CInt) -> IO Errno -> IO (Either Errno CInt)
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Errno -> Either Errno CInt
forall a b. a -> Either a b
Left IO Errno
getErrno