module Propellor.Ssh where
import Propellor.Base
import Utility.UserInfo
import Utility.FileSystemEncoding
import System.PosixCompat
import Data.Time.Clock.POSIX
import Data.Hashable
sshCachingParams :: HostName -> IO [CommandParam]
sshCachingParams hn = do
home <- myHomeDir
let socketfile = socketFile home hn
createDirectoryIfMissing False (takeDirectory socketfile)
let ps =
[ Param "-o"
, Param ("ControlPath=" ++ socketfile)
, Param "-o", Param "ControlMaster=auto"
, Param "-o", Param "ControlPersist=yes"
]
maybe noop (expireold ps socketfile)
=<< catchMaybeIO (getFileStatus socketfile)
return ps
where
expireold ps f s = do
now <- truncate <$> getPOSIXTime :: IO Integer
if modificationTime s > fromIntegral now - tenminutes
then touchFile f
else do
void $ boolSystem "ssh" $
[ Param "-O", Param "stop" ] ++ ps ++
[ Param "localhost" ]
nukeFile f
tenminutes = 600
socketFile :: FilePath -> HostName -> FilePath
socketFile home hn = selectSocketFile
[ sshdir </> hn ++ ".sock"
, sshdir </> hn
, sshdir </> take 10 hn ++ "-" ++ checksum
, sshdir </> checksum
]
(home </> ".propellor-" ++ checksum)
where
sshdir = home </> ".ssh" </> "propellor"
checksum = take 9 $ show $ abs $ hash hn
selectSocketFile :: [FilePath] -> FilePath -> FilePath
selectSocketFile [] d = d
selectSocketFile (f:fs) d
| valid_unix_socket_path f = f
| otherwise = selectSocketFile fs d
valid_unix_socket_path :: FilePath -> Bool
valid_unix_socket_path f = length (decodeW8 f) < 100 - reservedbyssh
where
reservedbyssh = 18