summaryrefslogtreecommitdiff
path: root/fsmgr.hs
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2018-07-16 07:41:33 -0400
committerAndrew Cady <d@jerkface.net>2018-07-16 07:41:33 -0400
commitd66f1b658186356df2d3c40994853da596c2b1e5 (patch)
tree34f45c96815cf298c0cbebf2ed740ee6788f80ce /fsmgr.hs
parente4520bb718e8eca78b8ce2eee972830afb893b70 (diff)
basic chroot support
Diffstat (limited to 'fsmgr.hs')
-rw-r--r--fsmgr.hs69
1 files changed, 53 insertions, 16 deletions
diff --git a/fsmgr.hs b/fsmgr.hs
index a72e510..e715b3b 100644
--- a/fsmgr.hs
+++ b/fsmgr.hs
@@ -1,11 +1,13 @@
1{-# LANGUAGE ViewPatterns #-}
1{-# OPTIONS_GHC -fno-warn-type-defaults #-} 2{-# OPTIONS_GHC -fno-warn-type-defaults #-}
2{-# LANGUAGE ExtendedDefaultRules #-} 3{-# LANGUAGE DuplicateRecordFields #-}
3{-# LANGUAGE LambdaCase #-} 4{-# LANGUAGE ExtendedDefaultRules #-}
4{-# LANGUAGE NamedFieldPuns #-} 5{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE NoImplicitPrelude #-} 6{-# LANGUAGE NamedFieldPuns #-}
6{-# LANGUAGE OverloadedStrings #-} 7{-# LANGUAGE NoImplicitPrelude #-}
7{-# LANGUAGE RecordWildCards #-} 8{-# LANGUAGE OverloadedStrings #-}
8{-# LANGUAGE ScopedTypeVariables #-} 9{-# LANGUAGE RecordWildCards #-}
10{-# LANGUAGE ScopedTypeVariables #-}
9 11
10module Main where 12module Main where
11import Rebase.Prelude hiding (bool, hash, o, (<.>)) 13import Rebase.Prelude hiding (bool, hash, o, (<.>))
@@ -17,9 +19,11 @@ import Development.Shake hiding (getEnv)
17import Development.Shake.Command () 19import Development.Shake.Command ()
18import Development.Shake.FilePath 20import Development.Shake.FilePath
19 21
20import Options.Applicative as Opt 22import qualified Options.Applicative as Opt
23 ;import Options.Applicative hiding (action)
21 24
22import ConfigFile 25import ConfigFile
26import System.Posix.Process (getProcessID)
23 27
24noParent :: BaseImageSpecification -> Bool 28noParent :: BaseImageSpecification -> Bool
25noParent (EmptyImageOfBytes _) = True 29noParent (EmptyImageOfBytes _) = True
@@ -64,6 +68,8 @@ buildRoot DiskImageConfig{..} finalOut = do
64 -- assume that this has already happened. 68 -- assume that this has already happened.
65 cmd_ "selfstrap --skip-update" (("--unpack" `consWhen` unpackOnly) ["-t", mountpoint]) packageNames 69 cmd_ "selfstrap --skip-update" (("--unpack" `consWhen` unpackOnly) ["-t", mountpoint]) packageNames
66 forM_ debs $ \pkg -> do cmd_ "dpkg -i --root" [mountpoint, pkg] 70 forM_ debs $ \pkg -> do cmd_ "dpkg -i --root" [mountpoint, pkg]
71 {- 2.5. install apt package cache -}
72 -- TODO
67 {- 3. binaries -} 73 {- 3. binaries -}
68 forM_ (unpack <$> binaries) $ \b -> do 74 forM_ (unpack <$> binaries) $ \b -> do
69 p <- fromMaybe (fail $ "not found in ${PATH}: " ++ b) <$> liftIO (pathLocate b) 75 p <- fromMaybe (fail $ "not found in ${PATH}: " ++ b) <$> liftIO (pathLocate b)
@@ -95,19 +101,20 @@ createDefaultSubvolume mountpoint = do
95 when (null subvolId) $ fail "could not obtain btrfs Subvolume ID" 101 when (null subvolId) $ fail "could not obtain btrfs Subvolume ID"
96 cmd_ "btrfs subvolume set-default" [strip subvolId, mountpoint] 102 cmd_ "btrfs subvolume set-default" [strip subvolId, mountpoint]
97 103
98defaultImageName :: String
99defaultImageName = "minbase"
100
101stripSuffix :: Text -> String -> String 104stripSuffix :: Text -> String -> String
102stripSuffix s t = fromMaybe t $ fmap unpack $ Text.stripSuffix s $ pack t 105stripSuffix s t = fromMaybe t $ fmap unpack $ Text.stripSuffix s $ pack t
103 106
104data Options = Options { optCommand :: Command } 107data Options = Options { optCommand :: Command }
105data Command = Build BuildOpts 108data Command = Build BuildOpts | Chroot ChrootOpts
106data BuildOpts = BuildOpts { optTarget :: String } 109data BuildOpts = BuildOpts { optTarget :: String }
110data ChrootOpts = ChrootOpts { optTarget :: String, optChrootCommand :: [String] }
107 111
108buildOpts :: Parser Command 112buildOpts :: Parser Command
109buildOpts = Build . BuildOpts <$> argument str idm 113buildOpts = Build . BuildOpts <$> argument str idm
110 114
115chrootOpts :: Parser Command
116chrootOpts = fmap Chroot $ ChrootOpts <$> argument str idm <*> many (argument str idm)
117
111-- TODO: Fail early on: 118-- TODO: Fail early on:
112-- 1. not running as root 119-- 1. not running as root
113-- 2. no "selfstrap" in PATH 120-- 2. no "selfstrap" in PATH
@@ -121,16 +128,40 @@ main = customExecParser (prefs showHelpOnEmpty) (info opts desc) >>= run
121 "which, much like 'debootstrap', creates new installations of Debian."] 128 "which, much like 'debootstrap', creates new installations of Debian."]
122 parseCommand :: Parser Command 129 parseCommand :: Parser Command
123 parseCommand = subparser $ Opt.command "build" (info' buildOpts buildDesc) 130 parseCommand = subparser $ Opt.command "build" (info' buildOpts buildDesc)
124 buildDesc = ["build the image specified by the YAML config file"] 131 <> Opt.command "chroot" (info' chrootOpts chrootDesc)
132 buildDesc = ["build the image specified by the YAML config file"]
133 chrootDesc = ["chroot into the mounted image. ",
134 "Iff the chroot exits with a success value, filesystem changes will persist"]
135
125 info' o d = info (helper <*> o) (progDesc $ unwords d) 136 info' o d = info (helper <*> o) (progDesc $ unwords d)
126 137
127run :: Options -> IO () 138run :: Options -> IO ()
128run (Options (Build (BuildOpts target)))= shakeBuildOneImage (stripSuffix ".yaml" target) 139run (Options (Build (BuildOpts target))) = shakeBuildOneImage target
140run (Options (Chroot (ChrootOpts target args))) = chrootImage target args
141
142chrootImage :: FilePath -> [String] -> IO ()
143chrootImage target args =
144 shake shakeOptions {shakeFiles = "_build"} $ do
145 shakeRules
146 action $ do
147 pid <- show <$> liftIO getProcessID
148 let inp = target -<.> "btrfs"
149 let tmp = inp <.> "tmp" <.> pid
150 let mnt = tmp <.> "mnt"
151 orderOnly [inp]
152 cmd_ "cp --reflink=always" [inp, tmp]
153 cmd_ "btrfstune -S0 -f" tmp
154 cmd_ "mkdir" [mnt]
155 cmd_ "mount -t btrfs" [tmp, mnt]
156 cmd_ (WithStderr False) (WithStdout False) "chroot" (mnt:args) -- TODO: cgroup
157 cmd_ "umount" [mnt] -- TODO: recursive umount
158 cmd_ "btrfstune -S1" tmp
159 cmd_ "mv" [tmp, inp]
129 160
130shakeBuildOneImage :: FilePath -> IO () 161shakeBuildOneImage :: FilePath -> IO ()
131shakeBuildOneImage target = 162shakeBuildOneImage target =
132 shake shakeOptions {shakeFiles = "_build"} $ do 163 shake shakeOptions {shakeFiles = "_build"} $ do
133 want [target <.> "btrfs"] 164 want [target -<.> "btrfs"]
134 shakeRules 165 shakeRules
135 166
136head1 :: String -> String 167head1 :: String -> String
@@ -148,6 +179,13 @@ pathLocate c = (getEnv "SUDO_USER" >>=) $ fmap (validatePath . head1 . fromStdou
148 validatePath "" = Nothing 179 validatePath "" = Nothing
149 validatePath x = Just x 180 validatePath x = Just x
150 181
182infix 1 ~%>
183(~%>) :: FilePattern -> (FilePath -> Action ()) -> Rules ()
184filepat ~%> act = phonys f
185 where
186 f file | (filepat ?== file) = Just (act file)
187 f _ = Nothing
188
151shakeRules :: Rules () 189shakeRules :: Rules ()
152shakeRules = do 190shakeRules = do
153 "_build/*.yaml.canon" %> \out -> do 191 "_build/*.yaml.canon" %> \out -> do
@@ -160,7 +198,6 @@ shakeRules = do
160 need [cfgFile] 198 need [cfgFile]
161 cfg <- read <$> readFile' cfgFile 199 cfg <- read <$> readFile' cfgFile
162 buildRoot cfg out 200 buildRoot cfg out
163
164 "*.btrfs" %> \out -> do 201 "*.btrfs" %> \out -> do
165 need ["_build" </> out] 202 need ["_build" </> out]
166 -- WithStderr False needed for `cp` to interact with the tty 203 -- WithStderr False needed for `cp` to interact with the tty