{-# LINE 1 "src/Systemd/Journal.hsc" #-}


module Systemd.Journal
    ( -- * Writing to the journal
      sendMessage
    , sendMessageWith
    , sendJournalFields

    , JournalFields

      -- ** Standard systemd journal fields
    , message
    , messageId
    , priority
    , Syslog.Priority(..)
    , codeFile
    , codeLine
    , codeFunc
    , errno
    , syslogFacility
    , syslogIdentifier
    , syslogPid

      -- ** Custom journal fields
    , JournalField
    , mkJournalField
    , journalField

      -- * Reading the journal
    , openJournal
    , Start(..)
    , Direction(..)
    , JournalEntry, JournalEntryCursor
    , journalEntryFields, journalEntryCursor, journalEntryRealtime
    , JournalFlag (..)
    , Filter (..)
    ) where

import Control.Applicative
import Control.Monad (when, void)
import Control.Monad.IO.Class (liftIO)
import Data.Bits ((.|.))
import Data.Char (ord, toUpper)
import Data.Data (Data)
import Data.Foldable (for_)
import Data.Hashable (Hashable)
import Data.Int
import Data.List (foldl')
import Data.Monoid (Monoid, mappend, mempty)
import Data.Semigroup (Semigroup)
import Data.String (IsString (..))
import Data.Typeable (Typeable)
import Data.Word
import Foreign (Ptr, alloca, free, peek, throwIfNeg)
import Foreign.C (CString, peekCString)
import System.Posix.Types (CPid(..))

import Data.Generics.Uniplate.Data ()

import qualified Data.ByteString as BS
import qualified Data.Generics.Uniplate.Operations as Uniplate
import qualified Data.HashMap.Strict as HashMap
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import qualified Data.UUID as UUID
import qualified Data.Vector.Storable as V
import qualified Pipes as Pipes
import qualified Pipes.Safe as Pipes
import qualified System.Posix.Syslog as Syslog
import qualified System.Posix.Types.Iovec as Iovec

--------------------------------------------------------------------------------
foreign import ccall "sd_journal_sendv"
  sdJournalSendV :: Ptr Iovec.CIovec -> Int -> IO Int

--------------------------------------------------------------------------------
newtype JournalField = JournalField Text.Text
  deriving (JournalField -> JournalField -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: JournalField -> JournalField -> Bool
$c/= :: JournalField -> JournalField -> Bool
== :: JournalField -> JournalField -> Bool
$c== :: JournalField -> JournalField -> Bool
Eq, Typeable JournalField
JournalField -> DataType
JournalField -> Constr
(forall b. Data b => b -> b) -> JournalField -> JournalField
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> JournalField -> u
forall u. (forall d. Data d => d -> u) -> JournalField -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> JournalField -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> JournalField -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> JournalField -> m JournalField
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> JournalField -> m JournalField
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c JournalField
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> JournalField -> c JournalField
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c JournalField)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c JournalField)
gmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> JournalField -> m JournalField
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> JournalField -> m JournalField
gmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> JournalField -> m JournalField
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> JournalField -> m JournalField
gmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> JournalField -> m JournalField
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> JournalField -> m JournalField
gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> JournalField -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> JournalField -> u
gmapQ :: forall u. (forall d. Data d => d -> u) -> JournalField -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> JournalField -> [u]
gmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> JournalField -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> JournalField -> r
gmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> JournalField -> r
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> JournalField -> r
gmapT :: (forall b. Data b => b -> b) -> JournalField -> JournalField
$cgmapT :: (forall b. Data b => b -> b) -> JournalField -> JournalField
dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c JournalField)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c JournalField)
dataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c JournalField)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c JournalField)
dataTypeOf :: JournalField -> DataType
$cdataTypeOf :: JournalField -> DataType
toConstr :: JournalField -> Constr
$ctoConstr :: JournalField -> Constr
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c JournalField
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c JournalField
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> JournalField -> c JournalField
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> JournalField -> c JournalField
Data, Eq JournalField
Int -> JournalField -> Int
JournalField -> Int
forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
hash :: JournalField -> Int
$chash :: JournalField -> Int
hashWithSalt :: Int -> JournalField -> Int
$chashWithSalt :: Int -> JournalField -> Int
Hashable, Eq JournalField
JournalField -> JournalField -> Bool
JournalField -> JournalField -> Ordering
JournalField -> JournalField -> JournalField
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: JournalField -> JournalField -> JournalField
$cmin :: JournalField -> JournalField -> JournalField
max :: JournalField -> JournalField -> JournalField
$cmax :: JournalField -> JournalField -> JournalField
>= :: JournalField -> JournalField -> Bool
$c>= :: JournalField -> JournalField -> Bool
> :: JournalField -> JournalField -> Bool
$c> :: JournalField -> JournalField -> Bool
<= :: JournalField -> JournalField -> Bool
$c<= :: JournalField -> JournalField -> Bool
< :: JournalField -> JournalField -> Bool
$c< :: JournalField -> JournalField -> Bool
compare :: JournalField -> JournalField -> Ordering
$ccompare :: JournalField -> JournalField -> Ordering
Ord, ReadPrec [JournalField]
ReadPrec JournalField
Int -> ReadS JournalField
ReadS [JournalField]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [JournalField]
$creadListPrec :: ReadPrec [JournalField]
readPrec :: ReadPrec JournalField
$creadPrec :: ReadPrec JournalField
readList :: ReadS [JournalField]
$creadList :: ReadS [JournalField]
readsPrec :: Int -> ReadS JournalField
$creadsPrec :: Int -> ReadS JournalField
Read, Int -> JournalField -> ShowS
[JournalField] -> ShowS
JournalField -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [JournalField] -> ShowS
$cshowList :: [JournalField] -> ShowS
show :: JournalField -> [Char]
$cshow :: JournalField -> [Char]
showsPrec :: Int -> JournalField -> ShowS
$cshowsPrec :: Int -> JournalField -> ShowS
Show, Typeable, Semigroup JournalField
JournalField
[JournalField] -> JournalField
JournalField -> JournalField -> JournalField
forall a.
Semigroup a -> a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
mconcat :: [JournalField] -> JournalField
$cmconcat :: [JournalField] -> JournalField
mappend :: JournalField -> JournalField -> JournalField
$cmappend :: JournalField -> JournalField -> JournalField
mempty :: JournalField
$cmempty :: JournalField
Monoid, NonEmpty JournalField -> JournalField
JournalField -> JournalField -> JournalField
forall b. Integral b => b -> JournalField -> JournalField
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
stimes :: forall b. Integral b => b -> JournalField -> JournalField
$cstimes :: forall b. Integral b => b -> JournalField -> JournalField
sconcat :: NonEmpty JournalField -> JournalField
$csconcat :: NonEmpty JournalField -> JournalField
<> :: JournalField -> JournalField -> JournalField
$c<> :: JournalField -> JournalField -> JournalField
Semigroup)

instance IsString JournalField where
  fromString :: [Char] -> JournalField
fromString = Text -> JournalField
JournalField forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Text
Text.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper

--------------------------------------------------------------------------------
-- | Construct a 'JournalField' by converting to uppercase, as required by the
-- journal.
mkJournalField :: Text.Text -> JournalField
mkJournalField :: Text -> JournalField
mkJournalField = Text -> JournalField
JournalField forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
Text.toUpper

--------------------------------------------------------------------------------
-- | Extract the name of a 'JournalField'.
journalField :: JournalField -> Text.Text
journalField :: JournalField -> Text
journalField (JournalField Text
f) = Text
f

--------------------------------------------------------------------------------
-- | A structured object of all the fields in an entry in the journal. You
-- generally don't construct this yourself, but you use the monoid instance and
-- smart constructors below.
--
-- For example,
--
-- > sendJournalFields (message "Oh god, it burns!" <> priority Emergency)
type JournalFields = HashMap.HashMap JournalField BS.ByteString

--------------------------------------------------------------------------------
-- | The human readable message string for this entry. This is supposed to be
-- the primary text shown to the user. It is usually not translated (but might be
-- in some cases), and is not supposed to be parsed for meta data.
message :: Text.Text -> JournalFields
message :: Text -> JournalFields
message = forall k v. Hashable k => k -> v -> HashMap k v
HashMap.singleton (Text -> JournalField
JournalField Text
"MESSAGE") forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
Text.encodeUtf8

--------------------------------------------------------------------------------
-- | A 128bit message identifier ID for recognizing certain message types, if
-- this is desirable. Developers can generate a new ID for this purpose with
-- @journalctl --new-id@.
messageId :: UUID.UUID -> JournalFields
messageId :: UUID -> JournalFields
messageId =
  forall k v. Hashable k => k -> v -> HashMap k v
HashMap.singleton (Text -> JournalField
JournalField Text
"MESSAGE_ID") forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
Text.encodeUtf8 forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Text
Text.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. UUID -> [Char]
UUID.toString

--------------------------------------------------------------------------------
-- | A priority value compatible with syslog's priority concept.
priority :: Syslog.Priority -> JournalFields
priority :: Priority -> JournalFields
priority =
  forall k v. Hashable k => k -> v -> HashMap k v
HashMap.singleton (Text -> JournalField
JournalField Text
"PRIORITY") forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
Text.encodeUtf8 forall b c a. (b -> c) -> (a -> b) -> a -> c
.  [Char] -> Text
Text.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => a -> Int
fromEnum

--------------------------------------------------------------------------------
-- | The source code file generating this message.
codeFile :: FilePath -> JournalFields
codeFile :: [Char] -> JournalFields
codeFile =
  forall k v. Hashable k => k -> v -> HashMap k v
HashMap.singleton (Text -> JournalField
JournalField Text
"CODE_FILE") forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
Text.encodeUtf8 forall b c a. (b -> c) -> (a -> b) -> a -> c
.  [Char] -> Text
Text.pack

--------------------------------------------------------------------------------
-- | The source code line number generating this message.
codeLine :: Int -> JournalFields
codeLine :: Int -> JournalFields
codeLine = forall k v. Hashable k => k -> v -> HashMap k v
HashMap.singleton (Text -> JournalField
JournalField Text
"CODE_LINE") forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
Text.encodeUtf8 forall b c a. (b -> c) -> (a -> b) -> a -> c
.  [Char] -> Text
Text.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show

--------------------------------------------------------------------------------
-- | The source code function name generating this message.
codeFunc :: Text.Text -> JournalFields
codeFunc :: Text -> JournalFields
codeFunc = forall k v. Hashable k => k -> v -> HashMap k v
HashMap.singleton (Text -> JournalField
JournalField Text
"CODE_FUNC") forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
Text.encodeUtf8

--------------------------------------------------------------------------------
-- | The low-level Unix error number causing this entry, if any. Contains the
-- numeric value of @errno(3)@.
errno :: Int -> JournalFields
errno :: Int -> JournalFields
errno = forall k v. Hashable k => k -> v -> HashMap k v
HashMap.singleton (Text -> JournalField
JournalField Text
"ERRNO") forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
Text.encodeUtf8 forall b c a. (b -> c) -> (a -> b) -> a -> c
.  [Char] -> Text
Text.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show

--------------------------------------------------------------------------------
-- | Syslog compatibility field.
syslogFacility :: Syslog.Facility -> JournalFields
syslogFacility :: Facility -> JournalFields
syslogFacility =
  forall k v. Hashable k => k -> v -> HashMap k v
HashMap.singleton (Text -> JournalField
JournalField Text
"SYSLOG_FACILITY") forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
Text.encodeUtf8 forall b c a. (b -> c) -> (a -> b) -> a -> c
.  [Char] -> Text
Text.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => a -> Int
fromEnum

--------------------------------------------------------------------------------
-- | Syslog compatibility field.
syslogIdentifier :: Text.Text -> JournalFields
syslogIdentifier :: Text -> JournalFields
syslogIdentifier =
  forall k v. Hashable k => k -> v -> HashMap k v
HashMap.singleton (Text -> JournalField
JournalField Text
"SYSLOG_IDENTIFIER") forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
Text.encodeUtf8

--------------------------------------------------------------------------------
-- | Syslog compatibility field.
syslogPid :: CPid -> JournalFields
syslogPid :: CPid -> JournalFields
syslogPid (CPid Int32
pid) =
  forall k v. Hashable k => k -> v -> HashMap k v
HashMap.singleton (Text -> JournalField
JournalField Text
"SYSLOG_PID") (Text -> ByteString
Text.encodeUtf8 forall a b. (a -> b) -> a -> b
$ [Char] -> Text
Text.pack forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> [Char]
show Int32
pid)

--------------------------------------------------------------------------------
-- | Send a message to the systemd journal.
--
-- > sendMessage t == sendJournalFields (message t)
sendMessage :: Text.Text -> IO ()
sendMessage :: Text -> IO ()
sendMessage = JournalFields -> IO ()
sendJournalFields forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> JournalFields
message

--------------------------------------------------------------------------------
-- | Send a message and supply extra fields.
--
-- Note: The @MESSAGE@ field  will be replaced with the first parameter to this
-- function. If you don't want this, use 'sendJournalFields'
sendMessageWith :: Text.Text -> JournalFields -> IO ()
sendMessageWith :: Text -> JournalFields -> IO ()
sendMessageWith Text
text JournalFields
meta = JournalFields -> IO ()
sendJournalFields forall a b. (a -> b) -> a -> b
$ forall a. Monoid a => a -> a -> a
mappend JournalFields
meta forall a b. (a -> b) -> a -> b
$ Text -> JournalFields
message Text
text

--------------------------------------------------------------------------------
-- | Send an exact set of fields to the systemd journal.
sendJournalFields :: JournalFields -> IO ()
sendJournalFields :: JournalFields -> IO ()
sendJournalFields JournalFields
meta = forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$
  forall a. (Ord a, Num a) => (a -> [Char]) -> IO a -> IO a
throwIfNeg (([Char]
"sd_journal_send returned :" ++) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show) forall a b. (a -> b) -> a -> b
$
  ([CIovec] -> [CIovec])
-> Int -> [(JournalField, ByteString)] -> IO Int
go forall a. a -> a
id Int
0 (forall k v. HashMap k v -> [(k, v)]
HashMap.toList JournalFields
meta)

  where
  go :: ([CIovec] -> [CIovec])
-> Int -> [(JournalField, ByteString)] -> IO Int
go [CIovec] -> [CIovec]
f Int
n [] = forall a b. Storable a => Vector a -> (Ptr a -> IO b) -> IO b
V.unsafeWith (forall a. Storable a => [a] -> Vector a
V.fromList ([CIovec] -> [CIovec]
f [])) forall a b. (a -> b) -> a -> b
$ \Ptr CIovec
iovecs ->
    Ptr CIovec -> Int -> IO Int
sdJournalSendV Ptr CIovec
iovecs Int
n

  go [CIovec] -> [CIovec]
f Int
n ((JournalField
k, ByteString
v) : [(JournalField, ByteString)]
xs) =
    forall a. ByteString -> (CIovec -> IO a) -> IO a
Iovec.unsafeUseAsCIovec (JournalField -> ByteString -> ByteString
encodeKv JournalField
k ByteString
v) forall a b. (a -> b) -> a -> b
$
      \CIovec
messageIovec -> ([CIovec] -> [CIovec])
-> Int -> [(JournalField, ByteString)] -> IO Int
go ([CIovec] -> [CIovec]
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. [a] -> [a] -> [a]
++ [CIovec
messageIovec])) (Int
n forall a. Num a => a -> a -> a
+ Int
1) [(JournalField, ByteString)]
xs

--------------------------------------------------------------------------------
encodeKv :: JournalField -> BS.ByteString -> BS.ByteString
encodeKv :: JournalField -> ByteString -> ByteString
encodeKv (JournalField Text
k) ByteString
v =
  Text -> ByteString
Text.encodeUtf8 Text
k forall a. Monoid a => a -> a -> a
`mappend` Word8 -> ByteString
BS.singleton (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ Char -> Int
ord Char
'=') forall a. Monoid a => a -> a -> a
`mappend` ByteString
v

--------------------------------------------------------------------------------
foreign import ccall "sd_journal_open"
 sdJournalOpen :: Ptr (Ptr JournalEntry) -> Int32 -> IO Int
{-# LINE 203 "src/Systemd/Journal.hsc" #-}

foreign import ccall "sd_journal_enumerate_data"
 sdJournalEnumerateData :: Ptr JournalEntry -> Ptr CString -> Ptr Word64 -> IO Int32
{-# LINE 206 "src/Systemd/Journal.hsc" #-}

foreign import ccall "sd_journal_next"
 sdJournalNext :: Ptr JournalEntry -> IO Int

foreign import ccall "sd_journal_previous"
 sdJournalPrevious :: Ptr JournalEntry -> IO Int

foreign import ccall "sd_journal_add_match"
 sdJournalAddMatch :: Ptr JournalEntry -> Ptr a -> Word64 -> IO Int
{-# LINE 215 "src/Systemd/Journal.hsc" #-}

foreign import ccall "sd_journal_add_conjunction"
 sdJournalAddConjunction :: Ptr JournalEntry -> IO Int

foreign import ccall "sd_journal_add_disjunction"
 sdJournalAddDisjunction :: Ptr JournalEntry -> IO Int

foreign import ccall "sd_journal_close"
  sdJournalClose :: Ptr JournalEntry -> IO ()

foreign import ccall "sd_journal_get_cursor"
  sdJournalGetCursor :: Ptr JournalEntry -> Ptr CString -> IO ()

foreign import ccall "sd_journal_seek_cursor"
  sdJournalSeekCursor :: Ptr JournalEntry -> CString -> IO Int32
{-# LINE 230 "src/Systemd/Journal.hsc" #-}

foreign import ccall "sd_journal_seek_tail"
  sdJournalSeekTail :: Ptr JournalEntry -> IO Int32
{-# LINE 233 "src/Systemd/Journal.hsc" #-}

foreign import ccall "sd_journal_previous_skip"
  sdJournalPreviousSkip :: Ptr JournalEntry -> Word64 -> IO Int32
{-# LINE 236 "src/Systemd/Journal.hsc" #-}

foreign import ccall "sd_journal_wait"
  sdJournalWait :: Ptr JournalEntry -> Word64 -> IO Int32
{-# LINE 239 "src/Systemd/Journal.hsc" #-}

foreign import ccall "sd_journal_set_data_threshold"
  sdJournalSetDataThreshold :: Ptr JournalEntry -> Word64 -> IO Int32
{-# LINE 242 "src/Systemd/Journal.hsc" #-}

foreign import ccall "strerror" c'strerror
  :: Int32 -> IO CString
{-# LINE 245 "src/Systemd/Journal.hsc" #-}

foreign import ccall "sd_journal_get_realtime_usec"
 sdJournalGetRealtimeUsec :: Ptr JournalEntry -> Ptr Word64 -> IO Int32
{-# LINE 248 "src/Systemd/Journal.hsc" #-}

--------------------------------------------------------------------------------
-- | Flags to specify which journal entries to read.
data JournalFlag
  = LocalOnly
  -- ^ Only journal files generated on the local machine will be opened.
  | RuntimeOnly
  -- ^ Only volatile journal files will be opened, excluding those which are
  -- stored on persistent storage.
  | SystemOnly
  -- ^ Only journal files of system services and the kernel (in opposition to
  -- user session processes) will be opened.
  deriving (JournalFlag
forall a. a -> a -> Bounded a
maxBound :: JournalFlag
$cmaxBound :: JournalFlag
minBound :: JournalFlag
$cminBound :: JournalFlag
Bounded, Int -> JournalFlag
JournalFlag -> Int
JournalFlag -> [JournalFlag]
JournalFlag -> JournalFlag
JournalFlag -> JournalFlag -> [JournalFlag]
JournalFlag -> JournalFlag -> JournalFlag -> [JournalFlag]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: JournalFlag -> JournalFlag -> JournalFlag -> [JournalFlag]
$cenumFromThenTo :: JournalFlag -> JournalFlag -> JournalFlag -> [JournalFlag]
enumFromTo :: JournalFlag -> JournalFlag -> [JournalFlag]
$cenumFromTo :: JournalFlag -> JournalFlag -> [JournalFlag]
enumFromThen :: JournalFlag -> JournalFlag -> [JournalFlag]
$cenumFromThen :: JournalFlag -> JournalFlag -> [JournalFlag]
enumFrom :: JournalFlag -> [JournalFlag]
$cenumFrom :: JournalFlag -> [JournalFlag]
fromEnum :: JournalFlag -> Int
$cfromEnum :: JournalFlag -> Int
toEnum :: Int -> JournalFlag
$ctoEnum :: Int -> JournalFlag
pred :: JournalFlag -> JournalFlag
$cpred :: JournalFlag -> JournalFlag
succ :: JournalFlag -> JournalFlag
$csucc :: JournalFlag -> JournalFlag
Enum, JournalFlag -> JournalFlag -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: JournalFlag -> JournalFlag -> Bool
$c/= :: JournalFlag -> JournalFlag -> Bool
== :: JournalFlag -> JournalFlag -> Bool
$c== :: JournalFlag -> JournalFlag -> Bool
Eq, Eq JournalFlag
JournalFlag -> JournalFlag -> Bool
JournalFlag -> JournalFlag -> Ordering
JournalFlag -> JournalFlag -> JournalFlag
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: JournalFlag -> JournalFlag -> JournalFlag
$cmin :: JournalFlag -> JournalFlag -> JournalFlag
max :: JournalFlag -> JournalFlag -> JournalFlag
$cmax :: JournalFlag -> JournalFlag -> JournalFlag
>= :: JournalFlag -> JournalFlag -> Bool
$c>= :: JournalFlag -> JournalFlag -> Bool
> :: JournalFlag -> JournalFlag -> Bool
$c> :: JournalFlag -> JournalFlag -> Bool
<= :: JournalFlag -> JournalFlag -> Bool
$c<= :: JournalFlag -> JournalFlag -> Bool
< :: JournalFlag -> JournalFlag -> Bool
$c< :: JournalFlag -> JournalFlag -> Bool
compare :: JournalFlag -> JournalFlag -> Ordering
$ccompare :: JournalFlag -> JournalFlag -> Ordering
Ord)

--------------------------------------------------------------------------------
type JournalEntryCursor = BS.ByteString

--------------------------------------------------------------------------------
-- | An entry that has been read from the systemd journal.
data JournalEntry = JournalEntry
  { JournalEntry -> JournalFields
journalEntryFields :: JournalFields
    -- ^ A map of each 'JournalField' to its value.

  , JournalEntry -> ByteString
journalEntryCursor :: JournalEntryCursor
  -- ^ A 'JournalCursor' can be used as marker into the journal stream. This can
  -- be used to re-open the journal at a specific point in the future, and
  -- 'JournalCursor's can be serialized to disk.

  , JournalEntry -> Word64
journalEntryRealtime :: Word64
  -- ^ The time (in microseconds since the epoch) when this journal entry was
  -- received by the systemd journal.
  }
  deriving (JournalEntry -> JournalEntry -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: JournalEntry -> JournalEntry -> Bool
$c/= :: JournalEntry -> JournalEntry -> Bool
== :: JournalEntry -> JournalEntry -> Bool
$c== :: JournalEntry -> JournalEntry -> Bool
Eq, Int -> JournalEntry -> ShowS
[JournalEntry] -> ShowS
JournalEntry -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [JournalEntry] -> ShowS
$cshowList :: [JournalEntry] -> ShowS
show :: JournalEntry -> [Char]
$cshow :: JournalEntry -> [Char]
showsPrec :: Int -> JournalEntry -> ShowS
$cshowsPrec :: Int -> JournalEntry -> ShowS
Show)

--------------------------------------------------------------------------------
-- | A logical expression to filter journal entries when reading the journal.
data Filter
  = Match JournalField BS.ByteString
  -- ^ A binary exact match on a given 'JournalField'.
  | And Filter Filter
  -- ^ Logical conjunction of two filters. Will only show journal entries that
  -- satisfy both conditions.
  | Or Filter Filter
  -- ^ Logical disjunction of two filters. Will show journal entries that
  -- satisfy either condition.
  deriving (Typeable Filter
Filter -> DataType
Filter -> Constr
(forall b. Data b => b -> b) -> Filter -> Filter
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> Filter -> u
forall u. (forall d. Data d => d -> u) -> Filter -> [u]
forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Filter -> r
forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Filter -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Filter -> m Filter
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Filter -> m Filter
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Filter
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Filter -> c Filter
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Filter)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Filter)
gmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Filter -> m Filter
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Filter -> m Filter
gmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Filter -> m Filter
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Filter -> m Filter
gmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Filter -> m Filter
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Filter -> m Filter
gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Filter -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Filter -> u
gmapQ :: forall u. (forall d. Data d => d -> u) -> Filter -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> Filter -> [u]
gmapQr :: forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Filter -> r
$cgmapQr :: forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Filter -> r
gmapQl :: forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Filter -> r
$cgmapQl :: forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Filter -> r
gmapT :: (forall b. Data b => b -> b) -> Filter -> Filter
$cgmapT :: (forall b. Data b => b -> b) -> Filter -> Filter
dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Filter)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Filter)
dataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Filter)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Filter)
dataTypeOf :: Filter -> DataType
$cdataTypeOf :: Filter -> DataType
toConstr :: Filter -> Constr
$ctoConstr :: Filter -> Constr
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Filter
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Filter
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Filter -> c Filter
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Filter -> c Filter
Data, Filter -> Filter -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Filter -> Filter -> Bool
$c/= :: Filter -> Filter -> Bool
== :: Filter -> Filter -> Bool
$c== :: Filter -> Filter -> Bool
Eq, Int -> Filter -> ShowS
[Filter] -> ShowS
Filter -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [Filter] -> ShowS
$cshowList :: [Filter] -> ShowS
show :: Filter -> [Char]
$cshow :: Filter -> [Char]
showsPrec :: Int -> Filter -> ShowS
$cshowsPrec :: Int -> Filter -> ShowS
Show, Typeable)


--------------------------------------------------------------------------------
-- | In which direction to read the journal.
data Direction
  = Forwards
  -- ^ Read towards the end.
  | Backwards
  -- ^ Read towards the beginning.
  deriving (Direction -> Direction -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Direction -> Direction -> Bool
$c/= :: Direction -> Direction -> Bool
== :: Direction -> Direction -> Bool
$c== :: Direction -> Direction -> Bool
Eq)

--------------------------------------------------------------------------------
-- | Where to begin reading the journal from.
data Start
  = FromStart
  -- ^ Begin reading from the start of the journal.
  | FromEnd Direction
  -- ^ Begin reading from the end of the journal.
  | FromCursor JournalEntryCursor Direction
  -- ^ From a 'JournalEntryCursor'.

--------------------------------------------------------------------------------
-- | Opens the journal for reading, optionally filtering the journal entries.
-- Filters are defined as arbitrary binary expression trees, which are then
-- rewritten to be in conjunctive normal form before filtering with systemd
-- to comply with systemd's rule system.
openJournal
  :: Pipes.MonadSafe m
  => [JournalFlag]
  -- ^ A list of flags taken under logical disjunction (or) to specify which
  -- journal files to open.
  -> Start
  -- ^ Where to begin reading journal entries from.
  -> Maybe Filter
  -- ^ An optional filter to apply the journal. Only entries satisfying the
  -- filter will be emitted.
  -> Maybe Integer
  -- ^ The data field size threshold, or Nothing for no field size limit
  -> Pipes.Producer' JournalEntry m ()
openJournal :: forall (m :: * -> *).
MonadSafe m =>
[JournalFlag]
-> Start
-> Maybe Filter
-> Maybe Integer
-> Producer' JournalEntry m ()
openJournal [JournalFlag]
flags Start
start Maybe Filter
journalFilter Maybe Integer
threshold =
  forall (m :: * -> *) a b c.
MonadSafe m =>
Base m a -> (a -> Base m b) -> (a -> m c) -> m c
Pipes.bracket (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO (Ptr JournalEntry)
openJournalPtr) (forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr JournalEntry -> IO ()
sdJournalClose) forall {m :: * -> *} {x'} {x}.
MonadIO m =>
Ptr JournalEntry -> Proxy x' x () JournalEntry m ()
go

  where
  openJournalPtr :: IO (Ptr JournalEntry)
openJournalPtr = do
    Ptr JournalEntry
journalPtr <- forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (Ptr JournalEntry)
journalPtrPtr -> do
      Int
_ <- forall a. (Ord a, Num a) => (a -> [Char]) -> IO a -> IO a
throwIfNeg (([Char]
"sdl_journal_open returned: " ++) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show) forall a b. (a -> b) -> a -> b
$
             Ptr (Ptr JournalEntry) -> Int32 -> IO Int
sdJournalOpen Ptr (Ptr JournalEntry)
journalPtrPtr Int32
encodedJournalFlags
      forall a. Storable a => Ptr a -> IO a
peek Ptr (Ptr JournalEntry)
journalPtrPtr

    forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ Maybe Filter
journalFilter forall a b. (a -> b) -> a -> b
$ Ptr JournalEntry -> Filter -> IO Int
applyFilter Ptr JournalEntry
journalPtr

    case Start
start of
      Start
FromStart ->
        forall (m :: * -> *) a. Monad m => a -> m a
return ()

      FromEnd Direction
d -> forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ do
        forall a. (Ord a, Num a) => (a -> [Char]) -> IO a -> IO a
throwIfNeg (([Char]
"sd_journal_seek_tail: " ++) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show) forall a b. (a -> b) -> a -> b
$
          Ptr JournalEntry -> IO Int32
sdJournalSeekTail Ptr JournalEntry
journalPtr
        forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Direction
d forall a. Eq a => a -> a -> Bool
== Direction
Forwards) forall a b. (a -> b) -> a -> b
$ do
          forall a. (Ord a, Num a) => (a -> [Char]) -> IO a -> IO a
throwIfNeg (([Char]
"sd_journal_previous_skip" ++) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show) forall a b. (a -> b) -> a -> b
$
            Ptr JournalEntry -> Word64 -> IO Int32
sdJournalPreviousSkip Ptr JournalEntry
journalPtr Word64
1
          forall (m :: * -> *) a. Monad m => a -> m a
return ()

      FromCursor ByteString
cursor Direction
_ -> forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$
        forall a. ByteString -> (CString -> IO a) -> IO a
BS.useAsCString ByteString
cursor (Ptr JournalEntry -> CString -> IO Int32
sdJournalSeekCursor Ptr JournalEntry
journalPtr)

    Int32
_ <- forall a. (Ord a, Num a) => (a -> [Char]) -> IO a -> IO a
throwIfNeg (([Char]
"sd_journal_set_data_threshold returned: " ++) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show) forall b c a. (b -> c) -> (a -> b) -> a -> c
.
        Ptr JournalEntry -> Word64 -> IO Int32
sdJournalSetDataThreshold Ptr JournalEntry
journalPtr forall a b. (a -> b) -> a -> b
$ case Maybe Integer
threshold of
                                                Maybe Integer
Nothing -> forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer
0 :: Integer)
                                                Just Integer
n  -> forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
n

    forall (m :: * -> *) a. Monad m => a -> m a
return Ptr JournalEntry
journalPtr

  encodedJournalFlags :: Int32
encodedJournalFlags = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' forall a. Bits a => a -> a -> a
(.|.) Int32
0 (forall a b. (a -> b) -> [a] -> [b]
map JournalFlag -> Int32
encodeJournalFlag [JournalFlag]
flags)

  applyFilter :: Ptr JournalEntry -> Filter -> IO Int
applyFilter Ptr JournalEntry
journalPtr =
    let cnf :: Filter -> Filter
cnf (Or Filter
a (And Filter
b Filter
c)) = Filter -> Filter -> Filter
And (Filter -> Filter -> Filter
Or Filter
a Filter
b) (Filter -> Filter -> Filter
Or Filter
a Filter
c)
        cnf (Or (And Filter
a Filter
b) Filter
c) = Filter -> Filter -> Filter
And (Filter -> Filter -> Filter
Or Filter
a Filter
c) (Filter -> Filter -> Filter
Or Filter
b Filter
c)
        cnf Filter
x = Filter
x

        addRule :: Filter -> IO Int
addRule (And Filter
l Filter
r) = Filter -> IO Int
addRule Filter
l forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Ptr JournalEntry -> IO Int
sdJournalAddConjunction Ptr JournalEntry
journalPtr forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Filter -> IO Int
addRule Filter
r
        addRule (Or Filter
l Filter
r) = Filter -> IO Int
addRule Filter
l forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Ptr JournalEntry -> IO Int
sdJournalAddDisjunction Ptr JournalEntry
journalPtr forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Filter -> IO Int
addRule Filter
r
        addRule (Match JournalField
k ByteString
v) = forall a. ByteString -> (CStringLen -> IO a) -> IO a
BS.useAsCStringLen (JournalField -> ByteString -> ByteString
encodeKv JournalField
k ByteString
v) forall a b. (a -> b) -> a -> b
$ \(CString
ptr, Int
len) ->
          forall a. Ptr JournalEntry -> Ptr a -> Word64 -> IO Int
sdJournalAddMatch Ptr JournalEntry
journalPtr CString
ptr (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)

    in Filter -> IO Int
addRule forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall on. Uniplate on => (on -> on) -> on -> on
Uniplate.transform Filter -> Filter
cnf


  sdJournalDirection :: Direction
  sdJournalDirection :: Direction
sdJournalDirection = case Start
start of
    Start
FromStart -> Direction
Forwards
    FromEnd Direction
d -> Direction
d
    FromCursor ByteString
_ Direction
d -> Direction
d

  sdJournalMove :: Ptr JournalEntry -> IO Int
  sdJournalMove :: Ptr JournalEntry -> IO Int
sdJournalMove = if Direction
sdJournalDirection forall a. Eq a => a -> a -> Bool
== Direction
Forwards then Ptr JournalEntry -> IO Int
sdJournalNext else Ptr JournalEntry -> IO Int
sdJournalPrevious

  go :: Ptr JournalEntry -> Proxy x' x () JournalEntry m ()
go Ptr JournalEntry
journalPtr = do
    let readField :: IO (Maybe ByteString)
readField =
          forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr CString
dataPtrPtr ->
          forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr Word64
lengthPtr -> do
            Int32
ret <- Ptr JournalEntry -> Ptr CString -> Ptr Word64 -> IO Int32
sdJournalEnumerateData Ptr JournalEntry
journalPtr Ptr CString
dataPtrPtr Ptr Word64
lengthPtr
            if Int32
ret forall a. Eq a => a -> a -> Bool
== Int32
0
              then forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
              else if Int32
ret forall a. Ord a => a -> a -> Bool
< Int32
0
                      then Int32 -> IO CString
c'strerror (forall a. Num a => a -> a
negate Int32
ret) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CString -> IO [Char]
peekCString
                             forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a. HasCallStack => [Char] -> a
error forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char]
"sd_journal_enumerate_data: " ++)
                      else do CString
dataPtr <- forall a. Storable a => Ptr a -> IO a
peek Ptr CString
dataPtrPtr
                              Word64
dataLength <- forall a. Storable a => Ptr a -> IO a
peek Ptr Word64
lengthPtr
                              forall a. a -> Maybe a
Just forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CStringLen -> IO ByteString
BS.packCStringLen (CString
dataPtr, forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ Word64
dataLength)

        readFields :: JournalFields -> IO JournalFields
readFields JournalFields
acc = do
          Maybe ByteString
field <- IO (Maybe ByteString)
readField
          case Maybe ByteString
field of
            Just ByteString
f ->
              let (ByteString
fieldName, ByteString
fieldValue) =
                    (Word8 -> Bool) -> ByteString -> (ByteString, ByteString)
BS.break (forall a. Eq a => a -> a -> Bool
== (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ Char -> Int
ord Char
'=')) ByteString
f
              in JournalFields -> IO JournalFields
readFields
                   (forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HashMap.insert
                      (Text -> JournalField
JournalField forall a b. (a -> b) -> a -> b
$ ByteString -> Text
Text.decodeUtf8 ByteString
fieldName)
                      (HasCallStack => ByteString -> ByteString
BS.tail ByteString
fieldValue)
                      JournalFields
acc)

            Maybe ByteString
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return JournalFields
acc

    Int
progressedBy <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (Ptr JournalEntry -> IO Int
sdJournalMove Ptr JournalEntry
journalPtr)

    case forall a. Ord a => a -> a -> Ordering
compare Int
progressedBy Int
0 of
      Ordering
GT -> do
        JournalEntry
entry <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ JournalFields -> ByteString -> Word64 -> JournalEntry
JournalEntry
          forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> JournalFields -> IO JournalFields
readFields forall a. Monoid a => a
mempty
          forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr CString
cursorStrPtr -> do
                Ptr JournalEntry -> Ptr CString -> IO ()
sdJournalGetCursor Ptr JournalEntry
journalPtr Ptr CString
cursorStrPtr
                CString
cursorCString <- forall a. Storable a => Ptr a -> IO a
peek Ptr CString
cursorStrPtr
                CString -> IO ByteString
BS.packCString CString
cursorCString forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* forall a. Ptr a -> IO ()
free CString
cursorCString)
          forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr Word64
realtimePtr -> do
                Ptr JournalEntry -> Ptr Word64 -> IO Int32
sdJournalGetRealtimeUsec Ptr JournalEntry
journalPtr Ptr Word64
realtimePtr
                forall a. Storable a => Ptr a -> IO a
peek Ptr Word64
realtimePtr)

        forall (m :: * -> *) a x' x. Functor m => a -> Proxy x' x () a m ()
Pipes.yield JournalEntry
entry

        Ptr JournalEntry -> Proxy x' x () JournalEntry m ()
go Ptr JournalEntry
journalPtr

      Ordering
EQ -> forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Direction
sdJournalDirection forall a. Eq a => a -> a -> Bool
== Direction
Forwards) forall a b. (a -> b) -> a -> b
$ do
        forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Ptr JournalEntry -> Word64 -> IO Int32
sdJournalWait Ptr JournalEntry
journalPtr forall a. Bounded a => a
maxBound
        Ptr JournalEntry -> Proxy x' x () JournalEntry m ()
go Ptr JournalEntry
journalPtr

      Ordering
LT -> forall a. HasCallStack => [Char] -> a
error forall a b. (a -> b) -> a -> b
$ [Char]
"sd_journal_next: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show Int
progressedBy

--------------------------------------------------------------------------------
encodeJournalFlag :: JournalFlag -> Int32
{-# LINE 445 "src/Systemd/Journal.hsc" #-}
encodeJournalFlag LocalOnly = 1
{-# LINE 446 "src/Systemd/Journal.hsc" #-}
encodeJournalFlag RuntimeOnly = 2
{-# LINE 447 "src/Systemd/Journal.hsc" #-}
encodeJournalFlag SystemOnly = 4
{-# LINE 448 "src/Systemd/Journal.hsc" #-}