diff options
-rw-r--r-- | Presence/UTmp.hs | 52 | ||||
-rw-r--r-- | consolation.hs | 18 |
2 files changed, 41 insertions, 29 deletions
diff --git a/Presence/UTmp.hs b/Presence/UTmp.hs index 86a19751..f22d1426 100644 --- a/Presence/UTmp.hs +++ b/Presence/UTmp.hs | |||
@@ -7,6 +7,7 @@ module UTmp | |||
7 | , Tty | 7 | , Tty |
8 | , ProcessID | 8 | , ProcessID |
9 | , UtmpRecord(..) | 9 | , UtmpRecord(..) |
10 | , UT_Type(..) | ||
10 | ) where | 11 | ) where |
11 | 12 | ||
12 | import qualified Data.ByteString as S | 13 | import qualified Data.ByteString as S |
@@ -18,14 +19,18 @@ import Data.Maybe | |||
18 | import System.Posix.Signals | 19 | import System.Posix.Signals |
19 | import System.Posix.Types | 20 | import System.Posix.Types |
20 | import Control.Monad | 21 | import Control.Monad |
21 | import Unsafe.Coerce | 22 | import Data.Char |
22 | import Data.Word | 23 | import Data.Word |
23 | import Data.Int | 24 | import Data.Int |
24 | import Control.Monad.Error.Class | 25 | import Control.Monad.Error.Class |
25 | import System.IO.Error | 26 | import System.IO.Error |
27 | import Debug.Trace | ||
26 | import qualified Paths | 28 | import qualified Paths |
27 | import Data.Text ( Text ) | 29 | import Data.Text ( Text ) |
30 | import Unsafe.Coerce ( unsafeCoerce ) | ||
31 | import qualified Data.Text as Text | ||
28 | import qualified Data.Text.Encoding as Text | 32 | import qualified Data.Text.Encoding as Text |
33 | import qualified Codec.Binary.Base16 as Hex | ||
29 | 34 | ||
30 | 35 | ||
31 | utmp_file = Paths.utmp -- "/var/run/utmp" | 36 | utmp_file = Paths.utmp -- "/var/run/utmp" |
@@ -40,9 +45,9 @@ decode_utmp_bytestring = | |||
40 | , Fixed 4 -- inittab id | 45 | , Fixed 4 -- inittab id |
41 | , Fixed 32 -- username | 46 | , Fixed 32 -- username |
42 | , Fixed 256 -- remote host | 47 | , Fixed 256 -- remote host |
43 | , UnsignedLE 4 -- termination status | 48 | , UnsignedLE 2 -- termination status |
44 | , UnsignedLE 4 -- exit status | 49 | , UnsignedLE 2 -- exit status (int) |
45 | , Fixed 4 -- session id | 50 | , UnsignedLE 4 -- session id (int) |
46 | , Fixed 8 -- time entry was made | 51 | , Fixed 8 -- time entry was made |
47 | , Fixed 16 -- remote addr v6 | 52 | , Fixed 16 -- remote addr v6 |
48 | , Skip 20 -- reserved | 53 | , Skip 20 -- reserved |
@@ -66,9 +71,10 @@ interp_utmp_record (typ,pid,tty,inittab,user,hostv4,term,exit,session,time,hostv | |||
66 | ( (toEnum . fromIntegral) typ :: UT_Type | 71 | ( (toEnum . fromIntegral) typ :: UT_Type |
67 | , toStr user, toStr tty, processId pid, toStr hostv4 ) | 72 | , toStr user, toStr tty, processId pid, toStr hostv4 ) |
68 | where | 73 | where |
69 | processId = CPid . coerce | 74 | processId = CPid . coerceToSigned |
70 | coerce :: Word32 -> Int32 | 75 | |
71 | coerce = unsafeCoerce | 76 | coerceToSigned :: Word32 -> Int32 |
77 | coerceToSigned = unsafeCoerce | ||
72 | 78 | ||
73 | 79 | ||
74 | data UT_Type | 80 | data UT_Type |
@@ -86,7 +92,7 @@ data UT_Type | |||
86 | 92 | ||
87 | | ACCOUNTING | 93 | | ACCOUNTING |
88 | 94 | ||
89 | deriving (Enum,Show,Eq,Read) | 95 | deriving (Enum,Show,Eq,Ord,Read) |
90 | 96 | ||
91 | processAlive pid = do | 97 | processAlive pid = do |
92 | catchError (do { signalProcess nullSignal pid ; return True }) | 98 | catchError (do { signalProcess nullSignal pid ; return True }) |
@@ -110,37 +116,35 @@ users = fmap (map only3) $ do | |||
110 | only3 (a,b,c,_) = (a,b,c) | 116 | only3 (a,b,c,_) = (a,b,c) |
111 | 117 | ||
112 | data UtmpRecord = UtmpRecord | 118 | data UtmpRecord = UtmpRecord |
113 | { utmpUser :: Text | 119 | { utmpType :: UT_Type |
120 | , utmpUser :: Text | ||
114 | , utmpTty :: Text | 121 | , utmpTty :: Text |
115 | , utmpPid :: CPid | 122 | , utmpPid :: CPid |
116 | , utmpHost :: Text | 123 | , utmpHost :: Text |
124 | , utmpSession :: Int32 | ||
125 | , utmpRemoteAddr :: Text | ||
117 | } | 126 | } |
118 | deriving ( Show, Read, Eq, Ord ) | 127 | deriving ( Show, Read, Eq, Ord ) |
119 | 128 | ||
120 | toText bs = Text.decodeUtf8 $ C.takeWhile (/='\0') bs | 129 | toText bs = Text.decodeUtf8 $ C.takeWhile (/='\0') bs |
121 | 130 | ||
122 | interp_utmp_record2 (typ,pid,tty,inittab,user,hostv4,term,exit,session,time,hostv6) = | 131 | interp_utmp_record2 (typ,pid,tty,inittab,user,hostv4,term,exit,session,time,addr) = |
123 | ( (toEnum . fromIntegral) typ :: UT_Type | 132 | UtmpRecord |
124 | , UtmpRecord | 133 | { utmpType = toEnum (fromIntegral typ) :: UT_Type |
125 | { utmpUser = toText user | 134 | , utmpUser = toText user |
126 | , utmpTty = toText tty | 135 | , utmpTty = toText tty |
127 | , utmpPid = processId pid | 136 | , utmpPid = processId pid |
128 | , utmpHost = toText hostv4 } | 137 | , utmpHost = toText hostv4 |
129 | ) | 138 | , utmpSession = coerceToSigned session |
139 | , utmpRemoteAddr = Text.pack (Hex.encode $ map (fromIntegral . ord) $ C.unpack addr) } | ||
130 | where | 140 | where |
131 | processId = CPid . coerce | 141 | processId = CPid . coerceToSigned |
132 | coerce :: Word32 -> Int32 | ||
133 | coerce = unsafeCoerce | ||
134 | 142 | ||
135 | -- users2 :: IO [(UserName, Tty, ProcessID)] | 143 | -- users2 :: IO [(UserName, Tty, ProcessID)] |
136 | users2 = do | 144 | users2 = do |
137 | us <- utmp | 145 | us <- utmp |
138 | let us' = map interp_utmp_record2 us | 146 | let us' = map interp_utmp_record2 us |
139 | us'' = mapMaybe user_proc us' | 147 | us3 <- filterM (processAlive . utmpPid) us' |
140 | user_proc (USER_PROCESS, rec) | ||
141 | = Just rec | ||
142 | user_proc _ = Nothing | ||
143 | us3 <- filterM (processAlive . utmpPid) us'' | ||
144 | return us3 | 148 | return us3 |
145 | 149 | ||
146 | {- | 150 | {- |
diff --git a/consolation.hs b/consolation.hs index 640b51c2..0c6e907a 100644 --- a/consolation.hs +++ b/consolation.hs | |||
@@ -19,7 +19,7 @@ import qualified Data.Text.IO as Text | |||
19 | import qualified Network.BSD as BSD | 19 | import qualified Network.BSD as BSD |
20 | 20 | ||
21 | import WaitForSignal ( waitForTermSignal ) | 21 | import WaitForSignal ( waitForTermSignal ) |
22 | import UTmp ( users2, utmp_file, UtmpRecord(..) ) | 22 | import UTmp ( users2, utmp_file, UtmpRecord(..), UT_Type(USER_PROCESS) ) |
23 | import FGConsole ( monitorTTY ) | 23 | import FGConsole ( monitorTTY ) |
24 | 24 | ||
25 | data ConsoleState = ConsoleState | 25 | data ConsoleState = ConsoleState |
@@ -33,7 +33,13 @@ newConsoleState = atomically $ | |||
33 | 33 | ||
34 | onLogin cs start = \e -> do | 34 | onLogin cs start = \e -> do |
35 | us <- UTmp.users2 | 35 | us <- UTmp.users2 |
36 | let m = foldl' (\m x -> Map.insert (utmpTty x) x m) Map.empty us | 36 | let (m,cruft) = |
37 | foldl' (\(m,cruft) x -> | ||
38 | if utmpType x==USER_PROCESS | ||
39 | then (Map.insert (utmpTty x) x m,cruft) | ||
40 | else (m,Map.insert (utmpTty x) x cruft)) | ||
41 | (Map.empty,Map.empty) | ||
42 | us | ||
37 | newborn <- atomically $ do | 43 | newborn <- atomically $ do |
38 | old <- readTVar (csUtmp cs) -- swapTVar (csUtmp cs) m | 44 | old <- readTVar (csUtmp cs) -- swapTVar (csUtmp cs) m |
39 | newborn <- flip Traversable.mapM (m Map.\\ old) | 45 | newborn <- flip Traversable.mapM (m Map.\\ old) |
@@ -89,9 +95,11 @@ newCon log activeTTY utmp = do | |||
89 | flip (maybe $ return ()) u $ \u -> do | 95 | flip (maybe $ return ()) u $ \u -> do |
90 | jid <- ujid u | 96 | jid <- ujid u |
91 | log $ status (resource u) tty tu <> " " <> jid <> " pid=" <> tshow (utmpPid u) | 97 | log $ status (resource u) tty tu <> " " <> jid <> " pid=" <> tshow (utmpPid u) |
92 | <> if istty (resource u) | 98 | <> (if istty (resource u) |
93 | then " host=" <> tshow (utmpHost u) | 99 | then " host=" <> tshow (utmpHost u) |
94 | else "" | 100 | else "") |
101 | <> " session=" <> tshow (utmpSession u) | ||
102 | <> " addr=" <> utmpRemoteAddr u | ||
95 | loop tty tu (Just u) | 103 | loop tty tu (Just u) |
96 | where | 104 | where |
97 | bstatus r ttynum mtu | 105 | bstatus r ttynum mtu |