packages feed

encapsule-0.6: src/Script.hs

{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

-- SPDX-License-Identifier: Apache-2.0


module Script (
  SwitchUser(..),
  chooseSwitchUser,
  switchUserArgs,
  switchLabel,
  setupScript,
  Setup(..)
  )
where

import Control.Monad (unless, when)
import Control.Monad.Shell
import Data.Maybe (isJust, isNothing)
import qualified Data.Text.Lazy as T
import System.FilePath ((</>))
import System.Posix.IO

default (T.Text)

data SwitchUser = Runuser | Sudo

chooseSwitchUser :: Bool -> Bool -> Maybe SwitchUser
chooseSwitchUser True _     = Just Runuser
chooseSwitchUser False True = Just Sudo
chooseSwitchUser _ _        = Nothing

-- argv prefix; empty for None
switchUserArgs :: String -> SwitchUser -> [String]
switchUserArgs u Runuser = ["runuser", "-u", u, "--"]
switchUserArgs u Sudo = ["sudo", "-n", "--preserve-env", "-u", u, "--"]

switchLabel :: SwitchUser -> String
switchLabel Runuser = "runuser"
switchLabel Sudo    = "sudo"

data Setup = Setup
  { sudoEnable :: Bool
  , noskel :: Bool
  , username :: T.Text
  , program :: String
  , createhome :: Bool
  , homedir :: T.Text
  , mprojectDir :: Maybe FilePath
  }

setupScript :: Bool -> Maybe SwitchUser -> Bool -> Setup -> String
setupScript dbg mswitch haveSudo (Setup {..}) =
  T.unpack . T.replace "\t" " " . linearScript $
  sudoSetup >> homeSetup
  where
    redir s dest =
        if dbg then s else s |> (dest :: String) &stdError>&stdOutput
    runHide c args = run c args `redir` "/dev/null"
    -- haveCmd c = runHide "command" ["-v",c]

    sudoSetup =
      when haveSudo $
      when sudoEnable $
      -- FIXME handle no sudoers.d?
      let sudoersd = "/etc/sudoers.d" in
        whenCmd (test $ TDirExists sudoersd) $ do
        let sudoersfile = sudoersd </> program
        runHide "echo" [username, "ALL=(ALL) NOPASSWD:ALL"] `redir` sudoersfile
        runHide "chmod" ["440", T.pack sudoersfile]

    homeSetup = do
      when createhome $ do
        runHide "mkdir" ["-p", homedir]
        runHide "chown" [username, homedir]
      unless noskel $
        when (isJust mswitch) $
        whenCmd
        (test (TDirExists homedir)
         -&&-
         test (TDirExists (T.pack "/etc/skel"))) $
        let cpArgs = ["-a", "--update=none", "/etc/skel/.", homedir <> "/"]
        in case map T.pack $ maybe [] (switchUserArgs (T.unpack username)) mswitch of
             prog:args -> runHide prog $ args ++ "cp" : cpArgs
             [] -> return ()
      when (isNothing mprojectDir && createhome) $
       runHide "cd" [homedir]