summaryrefslogtreecommitdiff
path: root/Presence/UTmp.hs
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2013-06-15 15:07:19 -0400
committerjoe <joe@jerkface.net>2013-06-15 15:07:19 -0400
commit9fd2107e6a7469fe7ba51448e4fe195bf54d7d29 (patch)
treebb37572b478170e461990695e7d9e6ab823f7606 /Presence/UTmp.hs
started project
Diffstat (limited to 'Presence/UTmp.hs')
-rw-r--r--Presence/UTmp.hs93
1 files changed, 93 insertions, 0 deletions
diff --git a/Presence/UTmp.hs b/Presence/UTmp.hs
new file mode 100644
index 00000000..c94dcef2
--- /dev/null
+++ b/Presence/UTmp.hs
@@ -0,0 +1,93 @@
1
2{-# LANGUAGE TemplateHaskell #-}
3module UTmp (users, utmp_file) where
4
5import qualified Data.ByteString as S
6import qualified Data.ByteString.Char8 as C
7import Data.BitSyntax
8import Data.Functor.Identity
9import Foreign.C.String
10import Data.Maybe
11import System.Posix.Signals
12import System.Posix.Types
13import Control.Monad
14import Unsafe.Coerce
15import Data.Word
16import Data.Int
17import Control.Monad.Error.Class
18import System.IO.Error
19
20import Todo
21
22utmp_file = "/var/run/utmp"
23
24utmp_bs = S.readFile utmp_file
25
26decode_utmp_bytestring =
27 runIdentity
28 . $(bitSyn [ UnsignedLE 4 -- type
29 , UnsignedLE 4 -- pid
30 , Fixed 32 -- tty
31 , Fixed 4 -- inittab id
32 , Fixed 32 -- username
33 , Fixed 256 -- remote host
34 , UnsignedLE 4 -- termination status
35 , UnsignedLE 4 -- exit status
36 , Fixed 4 -- session id
37 , Fixed 8 -- time entry was made
38 , Fixed 16 -- remote addr v6
39 , Skip 20 -- reserved
40 ])
41
42utmp_size = 384 -- 768
43
44
45utmp_records bs | S.length bs >= utmp_size
46 = u:utmp_records us
47 where
48 (u,us) = S.splitAt utmp_size bs
49
50utmp_records bs = [bs]
51
52utmp = fmap (map decode_utmp_bytestring . utmp_records) utmp_bs
53
54
55interp_utmp_record (typ,pid,tty,inittab,user,hostv4,term,exit,session,time,hostv6) =
56 (toStr user, toStr tty, processId pid, (toEnum . fromIntegral) typ :: UT_Type)
57 where
58 toStr = takeWhile (/='\0') . C.unpack
59 processId = CPid . coerce
60 coerce :: Word32 -> Int32
61 coerce = unsafeCoerce
62
63
64data UT_Type
65 = EMPTY -- No valid user accounting information. */
66
67 | RUN_LVL -- The system's runlevel. */
68 | BOOT_TIME -- Time of system boot. */
69 | NEW_TIME -- Time after system clock changed. */
70 | OLD_TIME -- Time when system clock changed. */
71
72 | INIT_PROCESS -- Process spawned by the init process. */
73 | LOGIN_PROCESS -- Session leader of a logged in user. */
74 | USER_PROCESS -- Normal process. */
75 | DEAD_PROCESS -- Terminated process. */
76
77 | ACCOUNTING
78
79 deriving (Enum,Show,Eq,Read)
80
81processAlive pid = do
82 catchError (do { signalProcess nullSignal pid ; return True })
83 $ \e -> do { return (not ( isDoesNotExistError e)); }
84
85users = do
86 us <- utmp
87 let us' = map interp_utmp_record us
88 us'' = mapMaybe user_proc us'
89 user_proc (u,tty,pid,USER_PROCESS) = Just (u,tty,pid)
90 user_proc _ = Nothing
91 onThrd f (_,_,pid) = f pid
92 us3 <- filterM (onThrd processAlive) us''
93 return us3