Hello community, here is the log from the commit of package ghc-pid1 for openSUSE:Factory checked in at 2017-07-23 12:14:44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ghc-pid1 (Old) and /work/SRC/openSUSE:Factory/.ghc-pid1.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-pid1" Sun Jul 23 12:14:44 2017 rev:2 rq:511917 version:0.1.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/ghc-pid1/ghc-pid1.changes 2017-04-14 13:35:37.617148726 +0200 +++ /work/SRC/openSUSE:Factory/.ghc-pid1.new/ghc-pid1.changes 2017-07-23 12:14:45.268739244 +0200 @@ -1,0 +2,10 @@ +Mon Jul 17 03:01:30 UTC 2017 - psim...@suse.com + +- Update to version 0.1.2.0 revision 1. + +------------------------------------------------------------------- +Tue Jul 11 03:02:31 UTC 2017 - psim...@suse.com + +- Update to version 0.1.1.0 revision 1. + +------------------------------------------------------------------- Old: ---- pid1-0.1.0.1.tar.gz New: ---- pid1-0.1.2.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ghc-pid1.spec ++++++ --- /var/tmp/diff_new_pack.IB1Wa5/_old 2017-07-23 12:14:45.892651112 +0200 +++ /var/tmp/diff_new_pack.IB1Wa5/_new 2017-07-23 12:14:45.892651112 +0200 @@ -18,7 +18,7 @@ %global pkg_name pid1 Name: ghc-%{pkg_name} -Version: 0.1.0.1 +Version: 0.1.2.0 Release: 0 Summary: Do signal handling and orphan reaping for Unix PID1 init processes License: MIT @@ -28,6 +28,7 @@ Source1: https://hackage.haskell.org/package/%{pkg_name}-%{version}/revision/1.cabal#/%{pkg_name}.cabal BuildRequires: chrpath BuildRequires: ghc-Cabal-devel +BuildRequires: ghc-directory-devel BuildRequires: ghc-process-devel BuildRequires: ghc-rpm-macros BuildRequires: ghc-unix-devel ++++++ pid1-0.1.0.1.tar.gz -> pid1-0.1.2.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pid1-0.1.0.1/ChangeLog.md new/pid1-0.1.2.0/ChangeLog.md --- old/pid1-0.1.0.1/ChangeLog.md 2016-11-23 07:17:09.000000000 +0100 +++ new/pid1-0.1.2.0/ChangeLog.md 2017-07-13 17:47:22.000000000 +0200 @@ -1,3 +1,14 @@ +## 0.1.2.0 + +* Removes support for ',' separated list of environment variables + for `-e` command line option +* Adds support for setting child processes wait timeout on SIGTERM or SIGINT + +## 0.1.1.0 + +* Adds support for setuid and setguid when running command +* Adds support for setting current directory when running command + ## 0.1.0.1 * Turn off all RTS options diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pid1-0.1.0.1/README.md new/pid1-0.1.2.0/README.md --- old/pid1-0.1.0.1/README.md 2016-11-23 07:17:09.000000000 +0100 +++ new/pid1-0.1.2.0/README.md 2017-07-13 17:47:22.000000000 +0200 @@ -22,6 +22,18 @@ ### Usage +> pid1 [-e|--env ENV] [-u|--user USER] [-g|--group GROUP] [-w|--workdir DIR] [-t|--timeout TIMEOUT] COMMAND [ARG1 ARG2 ... ARGN] + +Where: +* `-e`, `--env` `ENV` - Override environment variable from given name=value + pair. Can be specified multiple times to set multiple environment variables. +* `-u`, `--user` `USER` - The username the process will setuid before executing + COMMAND +* `-g`, `--group` `GROUP` - The group name the process will setgid before + executing COMMAND +* `-w`, `--workdir` `DIR` - chdir to `DIR` before executing COMMAND +* `-t`, `--timeout` `TIMEOUT` - timeout (in seconds) to wait for all child processes to exit + The recommended use case for this executable is to embed it in a Docker image. Assuming you've placed it at `/sbin/pid1`, the two commonly recommended usages are: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pid1-0.1.0.1/app/Main.hs new/pid1-0.1.2.0/app/Main.hs --- old/pid1-0.1.0.1/app/Main.hs 2016-11-23 07:17:09.000000000 +0100 +++ new/pid1-0.1.2.0/app/Main.hs 2017-07-13 17:47:22.000000000 +0200 @@ -1,19 +1,39 @@ -module Main where - +module Main (main) where -- | This is a valid PID 1 process in Haskell, intended as a Docker -- entrypoint. It will handle reaping orphans and handling TERM and -- INT signals. + +import Data.Maybe (fromMaybe) import System.Process.PID1 import System.Environment +import System.Console.GetOpt +import System.IO (stderr, hPutStr) +import System.Exit (exitFailure) + +-- | `GetOpt` command line options +options :: [(String, String)] -> [OptDescr (RunOptions -> RunOptions)] +options defaultEnv = + [ Option ['e'] ["env"] (ReqArg (\opt opts -> setRunEnv (optEnvList (getRunEnv opts) opt) opts) "ENV") "override environment variable from given name=value pair. Can be specified multiple times to set multiple environment variables" + , Option ['u'] ["user"] (ReqArg setRunUser "USER") "run command as user" + , Option ['g'] ["group"] (ReqArg setRunGroup "GROUP") "run command as group" + , Option ['w'] ["workdir"] (ReqArg setRunWorkDir "DIR") "command working directory" + , Option ['t'] ["timeout"] (ReqArg (setRunExitTimeoutSec . read) "TIMEOUT") "timeout (in seconds) to wait for all child processes to exit" ] + where optEnv env' kv = + let kvp = fmap (drop 1) $ span (/= '=') kv in + kvp:filter ((fst kvp /=) . fst) env' + optEnvList = optEnv . fromMaybe defaultEnv main :: IO () main = do -- Figure out the actual thing to run and spawn it off. args0 <- getArgs - - (cmd, args) <- - case args0 of - [] -> error "No arguments provided" - cmd:args -> return (cmd, args) - - run cmd args Nothing + defaultEnv <- getEnvironment + progName <- getProgName + let opts = options defaultEnv + case getOpt RequireOrder opts args0 of + (o, (cmd:args), []) -> let runOpts = foldl (flip id) defaultRunOptions o in + runWithOptions runOpts cmd args + _ -> do + let usage = "Usage: " ++ progName ++ " [OPTION...] command [args...]" + hPutStr stderr (usageInfo usage opts) + exitFailure diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pid1-0.1.0.1/pid1.cabal new/pid1-0.1.2.0/pid1.cabal --- old/pid1-0.1.0.1/pid1.cabal 2016-11-23 07:17:09.000000000 +0100 +++ new/pid1-0.1.2.0/pid1.cabal 2017-07-13 17:47:22.000000000 +0200 @@ -1,5 +1,5 @@ name: pid1 -version: 0.1.0.1 +version: 0.1.2.0 synopsis: Do signal handling and orphan reaping for Unix PID1 init processes description: Please see README.md or view Haddocks at <https://www.stackage.org/package/pid1> homepage: https://github.com/fpco/pid1#readme @@ -19,6 +19,7 @@ build-depends: base >= 4 && < 5 , process >= 1.2 , unix + , directory default-language: Haskell2010 ghc-options: -Wall diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pid1-0.1.0.1/src/System/Process/PID1.hs new/pid1-0.1.2.0/src/System/Process/PID1.hs --- old/pid1-0.1.0.1/src/System/Process/PID1.hs 2016-11-23 07:17:09.000000000 +0100 +++ new/pid1-0.1.2.0/src/System/Process/PID1.hs 2017-07-13 17:47:22.000000000 +0200 @@ -1,12 +1,27 @@ {-# LANGUAGE CPP #-} module System.Process.PID1 - ( run + ( RunOptions + , defaultRunOptions + , getRunEnv + , getRunExitTimeoutSec + , getRunGroup + , getRunUser + , getRunWorkDir + , run + , runWithOptions + , setRunEnv + , setRunExitTimeoutSec + , setRunGroup + , setRunUser + , setRunWorkDir ) where import Control.Concurrent (forkIO, newEmptyMVar, takeMVar, threadDelay, tryPutMVar) import Control.Exception (assert, catch, throwIO) import Control.Monad (forever, void) +import Data.Foldable (for_) +import System.Directory (setCurrentDirectory) import System.Exit (ExitCode (ExitFailure), exitWith) import System.IO.Error (isDoesNotExistError) import System.Posix.Process (ProcessStatus (..), executeFile, @@ -16,12 +31,104 @@ installHandler, sigINT, sigKILL, sigTERM, signalProcess) import System.Posix.Types (CPid) +import System.Posix.User (getGroupEntryForName, + getUserEntryForName, + groupID, setGroupID, + setUserID, userID) import System.Process (createProcess, proc, env) import System.Process.Internals (ProcessHandle__ (..), modifyProcessHandle) +-- | Holder for pid1 run options +data RunOptions = RunOptions + { -- optional environment variable override, default is current env + runEnv :: Maybe [(String, String)] + -- optional posix user name + , runUser :: Maybe String + -- optional posix group name + , runGroup :: Maybe String + -- optional working directory + , runWorkDir :: Maybe FilePath + -- timeout (in seconds) to wait for all child processes to exit after + -- receiving SIGTERM or SIGINT signal + , runExitTimeoutSec :: Int + } deriving Show + +-- | return default `RunOptions` +-- +-- @since 0.1.1.0 +defaultRunOptions :: RunOptions +defaultRunOptions = RunOptions + { runEnv = Nothing + , runUser = Nothing + , runGroup = Nothing + , runWorkDir = Nothing + , runExitTimeoutSec = 5 } + +-- | Get environment variable overrides for the given `RunOptions` +-- +-- @since 0.1.1.0 +getRunEnv :: RunOptions -> Maybe [(String, String)] +getRunEnv = runEnv + +-- | Set environment variable overrides for the given `RunOptions` +-- +-- @since 0.1.1.0 +setRunEnv :: [(String, String)] -> RunOptions -> RunOptions +setRunEnv env' opts = opts { runEnv = Just env' } + +-- | Get the process 'setUserID' user for the given `RunOptions` +-- +-- @since 0.1.1.0 +getRunUser :: RunOptions -> Maybe String +getRunUser = runUser + +-- | Set the process 'setUserID' user for the given `RunOptions` +-- +-- @since 0.1.1.0 +setRunUser :: String -> RunOptions -> RunOptions +setRunUser user opts = opts { runUser = Just user } + +-- | Get the process 'setGroupID' group for the given `RunOptions` +-- +-- @since 0.1.1.0 +getRunGroup :: RunOptions -> Maybe String +getRunGroup = runGroup + +-- | Set the process 'setGroupID' group for the given `RunOptions` +-- +-- @since 0.1.1.0 +setRunGroup :: String -> RunOptions -> RunOptions +setRunGroup group opts = opts { runGroup = Just group } + +-- | Get the process current directory for the given `RunOptions` +-- +-- @since 0.1.1.0 +getRunWorkDir :: RunOptions -> Maybe FilePath +getRunWorkDir = runWorkDir + +-- | Set the process current directory for the given `RunOptions` +-- +-- @since 0.1.1.0 +setRunWorkDir :: FilePath -> RunOptions -> RunOptions +setRunWorkDir dir opts = opts { runWorkDir = Just dir } + +-- | Return the timeout (in seconds) timeout (in seconds) to wait for all child +-- processes to exit after receiving SIGTERM or SIGINT signal +-- +-- @since 0.1.2.0 +getRunExitTimeoutSec :: RunOptions -> Int +getRunExitTimeoutSec = runExitTimeoutSec + +-- | Set the timeout in seconds for the process reaper to wait for all child +-- processes to exit after receiving SIGTERM or SIGINT signal +-- +-- @since 0.1.2.0 +setRunExitTimeoutSec :: Int -> RunOptions -> RunOptions +setRunExitTimeoutSec sec opts = opts { runExitTimeoutSec = sec } + -- | Run the given command with specified arguments, with optional environment --- variable override (default is to use the current process's environment).. +-- variable override (default is to use the current process's environment). -- -- This function will check if the current process has a process ID of 1. If it -- does, it will install signal handlers for SIGTERM and SIGINT, set up a loop @@ -40,23 +147,43 @@ -> Maybe [(String, String)] -- ^ optional environment variable override, default is current env -> IO a -run cmd args env' = do - -- check if we should act as pid1 or just exec the process - myID <- getProcessID - if myID == 1 - then runAsPID1 cmd args env' - else executeFile cmd True args env' +run cmd args env' = runWithOptions (defaultRunOptions {runEnv = env'}) cmd args + +-- | Variant of 'run' that runs a command, with optional environment posix +-- user/group and working directory (default is to use the current process's +-- user, group, environment, and current directory). +-- +-- @since 0.1.1.0 +runWithOptions :: RunOptions -- ^ run options + -> FilePath -- ^ command to run + -> [String] -- ^ command line arguments + -> IO a +runWithOptions opts cmd args = do + for_ (runGroup opts) $ \name -> do + entry <- getGroupEntryForName name + setGroupID $ groupID entry + for_ (runUser opts) $ \name -> do + entry <- getUserEntryForName name + setUserID $ userID entry + for_ (runWorkDir opts) setCurrentDirectory + let env' = runEnv opts + timeout = runExitTimeoutSec opts + -- check if we should act as pid1 or just exec the process + myID <- getProcessID + if myID == 1 + then runAsPID1 cmd args env' timeout + else executeFile cmd True args env' -- | Run as a child with signal handling and orphan reaping. -runAsPID1 :: FilePath -> [String] -> Maybe [(String, String)] -> IO a -runAsPID1 cmd args env' = do +runAsPID1 :: FilePath -> [String] -> Maybe [(String, String)] -> Int -> IO a +runAsPID1 cmd args env' timeout = do -- Set up an MVar to indicate we're ready to start killing all -- children processes. Then start a thread waiting for that -- variable to be filled and do the actual killing. killChildrenVar <- newEmptyMVar _ <- forkIO $ do takeMVar killChildrenVar - killAllChildren + killAllChildren timeout -- Helper function to start killing, used below let startKilling = void $ tryPutMVar killChildrenVar () @@ -120,19 +247,19 @@ startKilling | otherwise -> return () -killAllChildren :: IO () -killAllChildren = do +killAllChildren :: Int -> IO () +killAllChildren timeout = do -- Send all children processes the TERM signal signalProcess sigTERM (-1) `catch` \e -> if isDoesNotExistError e then return () else throwIO e - -- Wait for five seconds. We don't need to put in any logic about + -- Wait for `timeout` seconds. We don't need to put in any logic about -- whether there are still child processes; if all children have -- exited, then the reap loop will exit and our process will shut -- down. - threadDelay $ 5 * 1000 * 1000 + threadDelay $ timeout * 1000 * 1000 -- OK, some children didn't exit. Now time to get serious! signalProcess sigKILL (-1) `catch` \e -> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pid1-0.1.0.1/stack.yaml new/pid1-0.1.2.0/stack.yaml --- old/pid1-0.1.0.1/stack.yaml 2016-11-23 07:17:09.000000000 +0100 +++ new/pid1-0.1.2.0/stack.yaml 2017-07-09 19:37:33.000000000 +0200 @@ -15,7 +15,7 @@ # resolver: # name: custom-snapshot # location: "./custom-snapshot.yaml" -resolver: lts-7.1 +resolver: lts-8.21 # User packages to be built. # Various formats can be used as shown in the example below. @@ -63,4 +63,4 @@ # extra-lib-dirs: [/path/to/dir] # # Allow a newer minor version of GHC than the snapshot specifies -# compiler-check: newer-minor \ No newline at end of file +# compiler-check: newer-minor ++++++ pid1.cabal ++++++ --- /var/tmp/diff_new_pack.IB1Wa5/_old 2017-07-23 12:14:45.976639249 +0200 +++ /var/tmp/diff_new_pack.IB1Wa5/_new 2017-07-23 12:14:45.980638684 +0200 @@ -1,5 +1,5 @@ name: pid1 -version: 0.1.0.1 +version: 0.1.2.0 x-revision: 1 synopsis: Do signal handling and orphan reaping for Unix PID1 init processes description: Please see README.md or view Haddocks at <https://www.stackage.org/package/pid1> @@ -20,6 +20,7 @@ build-depends: base >= 4.6 && < 5 , process >= 1.2 , unix + , directory default-language: Haskell2010 ghc-options: -Wall