diff options
author | Joey Hess <joeyh@joeyh.name> | 2017-02-15 15:08:46 -0400 |
---|---|---|
committer | Joey Hess <joeyh@joeyh.name> | 2017-02-15 15:08:46 -0400 |
commit | 6892102ea2ef394de2a9802aa36dfe19761f37dd (patch) | |
tree | 3e90dcf2faf1db369ffa601bb858cf334364fc28 /Remote | |
parent | ebd15a59b4453e4e99a3a7225f50b897dd83653a (diff) |
Run ssh with -n whenever input is not being piped into it
... to avoid it consuming stdin that it shouldn't.
This fixes git-annex-checkpresentkey --batch remote, which didn't output
results for all keys passed into it.
Other git-annex commands that communicate with a remote over ssh may also
have been consuming stdin that they shouldn't have, which could have
impacted using them in eg, shell scripts. For example, a shell script
reading files from stdin and passing them to git annex drop would be
impacted by this bug, whenever git annex drop ran git-annex-shell
checkpresent, it would consume part/all of the stdin that the shell script
was supposed to consume.
Fixed by adding a ConsumeStdin parameter to Annex.Ssh.sshOptions, which
is used throughout git-annex to run ssh (in order for ssh connection
caching to work). Every call site was checked to see if it used
CreatePipe for stdin, and if not was marked NoConsumeStdin.
Diffstat (limited to 'Remote')
-rw-r--r-- | Remote/Bup.hs | 3 | ||||
-rw-r--r-- | Remote/Ddar.hs | 22 | ||||
-rw-r--r-- | Remote/GCrypt.hs | 7 | ||||
-rw-r--r-- | Remote/Git.hs | 15 | ||||
-rw-r--r-- | Remote/Helper/Ssh.hs | 25 | ||||
-rw-r--r-- | Remote/Rsync.hs | 2 |
6 files changed, 42 insertions, 32 deletions
diff --git a/Remote/Bup.hs b/Remote/Bup.hs index 9bdb22edd..5594bac9f 100644 --- a/Remote/Bup.hs +++ b/Remote/Bup.hs @@ -28,6 +28,7 @@ import Remote.Helper.Messages import Utility.Hash import Utility.UserInfo import Annex.UUID +import Annex.Ssh import Utility.Metered type BupRepo = String @@ -213,7 +214,7 @@ storeBupUUID u buprepo = do onBupRemote :: Git.Repo -> (FilePath -> [CommandParam] -> IO a) -> FilePath -> [CommandParam] -> Annex a onBupRemote r a command params = do c <- Annex.getRemoteGitConfig r - sshparams <- Ssh.toRepo r c [Param $ + sshparams <- Ssh.toRepo NoConsumeStdin r c [Param $ "cd " ++ dir ++ " && " ++ unwords (command : toCommand params)] liftIO $ a "ssh" sshparams where diff --git a/Remote/Ddar.hs b/Remote/Ddar.hs index 603eccd5e..146928499 100644 --- a/Remote/Ddar.hs +++ b/Remote/Ddar.hs @@ -118,11 +118,11 @@ splitRemoteDdarRepo ddarrepo = {- Return the command and parameters to use for a ddar call that may need to be - made on a remote repository. This will call ssh if needed. -} -ddarRemoteCall :: DdarRepo -> Char -> [CommandParam] -> Annex (String, [CommandParam]) -ddarRemoteCall ddarrepo cmd params +ddarRemoteCall :: ConsumeStdin -> DdarRepo -> Char -> [CommandParam] -> Annex (String, [CommandParam]) +ddarRemoteCall cs ddarrepo cmd params | ddarLocal ddarrepo = return ("ddar", localParams) | otherwise = do - os <- sshOptions (host, Nothing) (ddarRepoConfig ddarrepo) [] + os <- sshOptions cs (host, Nothing) (ddarRepoConfig ddarrepo) [] return ("ssh", os ++ remoteParams) where (host, ddarrepo') = splitRemoteDdarRepo ddarrepo @@ -130,13 +130,13 @@ ddarRemoteCall ddarrepo cmd params remoteParams = Param host : Param "ddar" : Param [cmd] : Param ddarrepo' : params {- Specialized ddarRemoteCall that includes extraction command and flags -} -ddarExtractRemoteCall :: DdarRepo -> Key -> Annex (String, [CommandParam]) -ddarExtractRemoteCall ddarrepo k = - ddarRemoteCall ddarrepo 'x' [Param "--force-stdout", Param $ key2file k] +ddarExtractRemoteCall :: ConsumeStdin -> DdarRepo -> Key -> Annex (String, [CommandParam]) +ddarExtractRemoteCall cs ddarrepo k = + ddarRemoteCall cs ddarrepo 'x' [Param "--force-stdout", Param $ key2file k] retrieve :: DdarRepo -> Retriever retrieve ddarrepo = byteRetriever $ \k sink -> do - (cmd, params) <- ddarExtractRemoteCall ddarrepo k + (cmd, params) <- ddarExtractRemoteCall NoConsumeStdin ddarrepo k let p = (proc cmd $ toCommand params) { std_out = CreatePipe } (_, Just h, _, pid) <- liftIO $ createProcess p liftIO (hClose h >> forceSuccessProcess p pid) @@ -147,7 +147,8 @@ retrieveCheap _ _ _ = return False remove :: DdarRepo -> Remover remove ddarrepo key = do - (cmd, params) <- ddarRemoteCall ddarrepo 'd' [Param $ key2file key] + (cmd, params) <- ddarRemoteCall NoConsumeStdin ddarrepo 'd' + [Param $ key2file key] liftIO $ boolSystem cmd params ddarDirectoryExists :: DdarRepo -> Annex (Either String Bool) @@ -158,7 +159,8 @@ ddarDirectoryExists ddarrepo Left _ -> Right False Right status -> Right $ isDirectory status | otherwise = do - ps <- sshOptions (host, Nothing) (ddarRepoConfig ddarrepo) [] + ps <- sshOptions NoConsumeStdin (host, Nothing) + (ddarRepoConfig ddarrepo) [] exitCode <- liftIO $ safeSystem "ssh" (ps ++ params) case exitCode of ExitSuccess -> return $ Right True @@ -178,7 +180,7 @@ ddarDirectoryExists ddarrepo {- Use "ddar t" to determine if a given key is present in a ddar archive -} inDdarManifest :: DdarRepo -> Key -> Annex (Either String Bool) inDdarManifest ddarrepo k = do - (cmd, params) <- ddarRemoteCall ddarrepo 't' [] + (cmd, params) <- ddarRemoteCall NoConsumeStdin ddarrepo 't' [] let p = proc cmd $ toCommand params liftIO $ catchMsgIO $ withHandle StdoutHandle createProcessSuccess p $ \h -> do contents <- hGetContents h diff --git a/Remote/GCrypt.hs b/Remote/GCrypt.hs index 78b1eed3c..79020f40c 100644 --- a/Remote/GCrypt.hs +++ b/Remote/GCrypt.hs @@ -159,7 +159,7 @@ rsyncTransport r gc let rsyncpath = if "/~/" `isPrefixOf` path then drop 3 path else path - opts <- sshOptions (host, Nothing) gc [] + opts <- sshOptions ConsumeStdin (host, Nothing) gc [] return (rsyncShell $ Param "ssh" : opts, host ++ ":" ++ rsyncpath, AccessShell) othertransport = return ([], loc, AccessDirect) @@ -263,7 +263,8 @@ setupRepo gcryptid r {- Ask git-annex-shell to configure the repository as a gcrypt - repository. May fail if it is too old. -} - gitannexshellsetup = Ssh.onRemote r (boolSystem, return False) + gitannexshellsetup = Ssh.onRemote NoConsumeStdin r + (boolSystem, return False) "gcryptsetup" [ Param gcryptid ] [] denyNonFastForwards = "receive.denyNonFastForwards" @@ -398,7 +399,7 @@ getGCryptId fast r gc | Git.repoIsLocal r || Git.repoIsLocalUnknown r = extract <$> liftIO (catchMaybeIO $ Git.Config.read r) | not fast = extract . liftM fst <$> getM (eitherToMaybe <$>) - [ Ssh.onRemote r (Git.Config.fromPipe r, return (Left $ error "configlist failed")) "configlist" [] [] + [ Ssh.onRemote NoConsumeStdin r (Git.Config.fromPipe r, return (Left $ error "configlist failed")) "configlist" [] [] , getConfigViaRsync r gc ] | otherwise = return (Nothing, r) diff --git a/Remote/Git.hs b/Remote/Git.hs index a0b590654..604056fc2 100644 --- a/Remote/Git.hs +++ b/Remote/Git.hs @@ -210,7 +210,9 @@ tryGitConfigRead :: Bool -> Git.Repo -> Annex Git.Repo tryGitConfigRead autoinit r | haveconfig r = return r -- already read | Git.repoIsSsh r = store $ do - v <- Ssh.onRemote r (pipedconfig, return (Left $ giveup "configlist failed")) "configlist" [] configlistfields + v <- Ssh.onRemote NoConsumeStdin r + (pipedconfig, return (Left $ giveup "configlist failed")) + "configlist" [] configlistfields case v of Right r' | haveconfig r' -> return r' @@ -384,7 +386,8 @@ lockKey r key callback ) | Git.repoIsSsh (repo r) = do showLocking r - Just (cmd, params) <- Ssh.git_annex_shell (repo r) "lockcontent" + Just (cmd, params) <- Ssh.git_annex_shell ConsumeStdin + (repo r) "lockcontent" [Param $ key2file key] [] (Just hin, Just hout, Nothing, p) <- liftIO $ withFile devNull WriteMode $ \nullh -> @@ -477,7 +480,8 @@ copyFromRemote' r key file dest meterupdate u <- getUUID let fields = (Fields.remoteUUID, fromUUID u) : maybe [] (\f -> [(Fields.associatedFile, f)]) file - Just (cmd, params) <- Ssh.git_annex_shell (repo r) "transferinfo" + Just (cmd, params) <- Ssh.git_annex_shell ConsumeStdin + (repo r) "transferinfo" [Param $ key2file key] fields v <- liftIO (newEmptySV :: IO (MSampleVar Integer)) pidv <- liftIO $ newEmptyMVar @@ -583,7 +587,7 @@ copyToRemote' r key file meterupdate fsckOnRemote :: Git.Repo -> [CommandParam] -> Annex (IO Bool) fsckOnRemote r params | Git.repoIsUrl r = do - s <- Ssh.git_annex_shell r "fsck" params [] + s <- Ssh.git_annex_shell NoConsumeStdin r "fsck" params [] return $ case s of Nothing -> return False Just (c, ps) -> batchCommand c ps @@ -665,7 +669,8 @@ commitOnCleanup r a = go `after` a Annex.Branch.commit "update" | otherwise = void $ do Just (shellcmd, shellparams) <- - Ssh.git_annex_shell (repo r) "commit" [] [] + Ssh.git_annex_shell NoConsumeStdin + (repo r) "commit" [] [] -- Throw away stderr, since the remote may not -- have a new enough git-annex shell to diff --git a/Remote/Helper/Ssh.hs b/Remote/Helper/Ssh.hs index dff16b656..7f64b4645 100644 --- a/Remote/Helper/Ssh.hs +++ b/Remote/Helper/Ssh.hs @@ -26,17 +26,17 @@ import Config {- Generates parameters to ssh to a repository's host and run a command. - Caller is responsible for doing any neccessary shellEscaping of the - passed command. -} -toRepo :: Git.Repo -> RemoteGitConfig -> [CommandParam] -> Annex [CommandParam] -toRepo r gc sshcmd = do +toRepo :: ConsumeStdin -> Git.Repo -> RemoteGitConfig -> [CommandParam] -> Annex [CommandParam] +toRepo cs r gc sshcmd = do let opts = map Param $ remoteAnnexSshOptions gc let host = fromMaybe (giveup "bad ssh url") $ Git.Url.hostuser r - params <- sshOptions (host, Git.Url.port r) gc opts + params <- sshOptions cs (host, Git.Url.port r) gc opts return $ params ++ Param host : sshcmd {- Generates parameters to run a git-annex-shell command on a remote - repository. -} -git_annex_shell :: Git.Repo -> String -> [CommandParam] -> [(Field, String)] -> Annex (Maybe (FilePath, [CommandParam])) -git_annex_shell r command params fields +git_annex_shell :: ConsumeStdin -> Git.Repo -> String -> [CommandParam] -> [(Field, String)] -> Annex (Maybe (FilePath, [CommandParam])) +git_annex_shell cs r command params fields | not $ Git.repoIsUrl r = do shellopts <- getshellopts return $ Just (shellcmd, shellopts ++ fieldopts) @@ -49,7 +49,7 @@ git_annex_shell r command params fields : map shellEscape (toCommand shellopts) ++ uuidcheck u ++ map shellEscape (toCommand fieldopts) - sshparams <- toRepo r gc [Param sshcmd] + sshparams <- toRepo cs r gc [Param sshcmd] return $ Just ("ssh", sshparams) | otherwise = return Nothing where @@ -76,14 +76,15 @@ git_annex_shell r command params fields - Or, if the remote does not support running remote commands, returns - a specified error value. -} onRemote - :: Git.Repo + :: ConsumeStdin + -> Git.Repo -> (FilePath -> [CommandParam] -> IO a, Annex a) -> String -> [CommandParam] -> [(Field, String)] -> Annex a -onRemote r (with, errorval) command params fields = do - s <- git_annex_shell r command params fields +onRemote cs r (with, errorval) command params fields = do + s <- git_annex_shell cs r command params fields case s of Just (c, ps) -> liftIO $ with c ps Nothing -> errorval @@ -92,7 +93,7 @@ onRemote r (with, errorval) command params fields = do inAnnex :: Git.Repo -> Key -> Annex Bool inAnnex r k = do showChecking r - onRemote r (check, cantCheck r) "inannex" [Param $ key2file k] [] + onRemote NoConsumeStdin r (check, cantCheck r) "inannex" [Param $ key2file k] [] where check c p = dispatch =<< safeSystem c p dispatch ExitSuccess = return True @@ -101,7 +102,7 @@ inAnnex r k = do {- Removes a key from a remote. -} dropKey :: Git.Repo -> Key -> Annex Bool -dropKey r key = onRemote r (boolSystem, return False) "dropkey" +dropKey r key = onRemote NoConsumeStdin r (boolSystem, return False) "dropkey" [ Param "--quiet", Param "--force" , Param $ key2file key ] @@ -133,7 +134,7 @@ rsyncParamsRemote unlocked r direction key file afile = do -- compatability. : (Fields.direct, if unlocked then "1" else "") : maybe [] (\f -> [(Fields.associatedFile, f)]) afile - Just (shellcmd, shellparams) <- git_annex_shell (repo r) + Just (shellcmd, shellparams) <- git_annex_shell ConsumeStdin (repo r) (if direction == Download then "sendkey" else "recvkey") [ Param $ key2file key ] fields diff --git a/Remote/Rsync.hs b/Remote/Rsync.hs index dbaf2acc9..52ec90104 100644 --- a/Remote/Rsync.hs +++ b/Remote/Rsync.hs @@ -122,7 +122,7 @@ rsyncTransport gc url let (port, sshopts') = sshReadPort sshopts userhost = takeWhile (/=':') url -- Connection caching - (Param "ssh":) <$> sshOptions + (Param "ssh":) <$> sshOptions ConsumeStdin (userhost, port) gc (map Param $ loginopt ++ sshopts') "rsh":rshopts -> return $ map Param $ "rsh" : |