diff options
author | joe <joe@jerkface.net> | 2013-06-15 15:07:19 -0400 |
---|---|---|
committer | joe <joe@jerkface.net> | 2013-06-15 15:07:19 -0400 |
commit | 9fd2107e6a7469fe7ba51448e4fe195bf54d7d29 (patch) | |
tree | bb37572b478170e461990695e7d9e6ab823f7606 /Presence/UTmp.hs |
started project
Diffstat (limited to 'Presence/UTmp.hs')
-rw-r--r-- | Presence/UTmp.hs | 93 |
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 #-} | ||
3 | module UTmp (users, utmp_file) where | ||
4 | |||
5 | import qualified Data.ByteString as S | ||
6 | import qualified Data.ByteString.Char8 as C | ||
7 | import Data.BitSyntax | ||
8 | import Data.Functor.Identity | ||
9 | import Foreign.C.String | ||
10 | import Data.Maybe | ||
11 | import System.Posix.Signals | ||
12 | import System.Posix.Types | ||
13 | import Control.Monad | ||
14 | import Unsafe.Coerce | ||
15 | import Data.Word | ||
16 | import Data.Int | ||
17 | import Control.Monad.Error.Class | ||
18 | import System.IO.Error | ||
19 | |||
20 | import Todo | ||
21 | |||
22 | utmp_file = "/var/run/utmp" | ||
23 | |||
24 | utmp_bs = S.readFile utmp_file | ||
25 | |||
26 | decode_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 | |||
42 | utmp_size = 384 -- 768 | ||
43 | |||
44 | |||
45 | utmp_records bs | S.length bs >= utmp_size | ||
46 | = u:utmp_records us | ||
47 | where | ||
48 | (u,us) = S.splitAt utmp_size bs | ||
49 | |||
50 | utmp_records bs = [bs] | ||
51 | |||
52 | utmp = fmap (map decode_utmp_bytestring . utmp_records) utmp_bs | ||
53 | |||
54 | |||
55 | interp_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 | |||
64 | data 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 | |||
81 | processAlive pid = do | ||
82 | catchError (do { signalProcess nullSignal pid ; return True }) | ||
83 | $ \e -> do { return (not ( isDoesNotExistError e)); } | ||
84 | |||
85 | users = 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 | ||