aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd/fpkg/install.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-02-23 23:23:54 +0900
committerOphestra <cat@gensokyo.uk>2025-02-23 23:25:12 +0900
commite6cd2bb2a8098d555f11034fa912158c469e6138 (patch)
treefdb34784fdbebf870bc06f0d6456c08fa299c00f /cmd/fpkg/install.go
parent0fb72e5d99226a1c67536f926ee2aeba25ca0fdd (diff)
cmd/fpkg: integrate command handler
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'cmd/fpkg/install.go')
-rw-r--r--cmd/fpkg/install.go191
1 files changed, 0 insertions, 191 deletions
diff --git a/cmd/fpkg/install.go b/cmd/fpkg/install.go
deleted file mode 100644
index d1643b40..00000000
--- a/cmd/fpkg/install.go
+++ /dev/null
@@ -1,191 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "flag"
- "log"
- "os"
- "path"
-
- "git.gensokyo.uk/security/fortify/fst"
- "git.gensokyo.uk/security/fortify/internal"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
-)
-
-func actionInstall(args []string) {
- set := flag.NewFlagSet("install", flag.ExitOnError)
- var (
- dropShellInstall bool
- dropShellActivate bool
- )
- set.BoolVar(&dropShellInstall, "si", false, "Drop to a shell on installation")
- set.BoolVar(&dropShellActivate, "sa", false, "Drop to a shell on activation")
-
- // Ignore errors; set is set for ExitOnError.
- _ = set.Parse(args)
-
- args = set.Args()
-
- if len(args) != 1 {
- log.Fatal("invalid argument")
- }
- pkgPath := args[0]
- if !path.IsAbs(pkgPath) {
- if dir, err := os.Getwd(); err != nil {
- log.Fatalf("cannot get current directory: %v", err)
- } else {
- pkgPath = path.Join(dir, pkgPath)
- }
- }
-
- /*
- Look up paths to programs started by fpkg.
- This is done here to ease error handling as cleanup is not yet required.
- */
-
- var (
- _ = lookPath("zstd")
- tar = lookPath("tar")
- chmod = lookPath("chmod")
- rm = lookPath("rm")
- )
-
- /*
- Extract package and set up for cleanup.
- */
-
- var workDir string
- if p, err := os.MkdirTemp("", "fpkg.*"); err != nil {
- log.Fatalf("cannot create temporary directory: %v", err)
- } else {
- workDir = p
- }
- cleanup := func() {
- // should be faster than a native implementation
- mustRun(chmod, "-R", "+w", workDir)
- mustRun(rm, "-rf", workDir)
- }
- beforeRunFail.Store(&cleanup)
-
- mustRun(tar, "-C", workDir, "-xf", pkgPath)
-
- /*
- Parse bundle and app metadata, do pre-install checks.
- */
-
- bundle := loadBundleInfo(path.Join(workDir, "bundle.json"), cleanup)
- pathSet := pathSetByApp(bundle.ID)
-
- app := bundle
- if s, err := os.Stat(pathSet.metaPath); err != nil {
- if !os.IsNotExist(err) {
- cleanup()
- log.Fatalf("cannot access %q: %v", pathSet.metaPath, err)
- }
- // did not modify app, clean installation condition met later
- } else if s.IsDir() {
- cleanup()
- log.Fatalf("metadata path %q is not a file", pathSet.metaPath)
- } else {
- app = loadBundleInfo(pathSet.metaPath, cleanup)
- if app.ID != bundle.ID {
- cleanup()
- log.Fatalf("app %q claims to have identifier %q", bundle.ID, app.ID)
- }
- // sec: should verify credentials
- }
-
- if app != bundle {
- // do not try to re-install
- if app.NixGL == bundle.NixGL &&
- app.CurrentSystem == bundle.CurrentSystem &&
- app.Launcher == bundle.Launcher &&
- app.ActivationPackage == bundle.ActivationPackage {
- cleanup()
- log.Printf("package %q is identical to local application %q", pkgPath, app.ID)
- internal.Exit(0)
- }
-
- // AppID determines uid
- if app.AppID != bundle.AppID {
- cleanup()
- log.Fatalf("package %q app id %d differs from installed %d", pkgPath, bundle.AppID, app.AppID)
- }
-
- // sec: should compare version string
- fmsg.Verbosef("installing application %q version %q over local %q", bundle.ID, bundle.Version, app.Version)
- } else {
- fmsg.Verbosef("application %q clean installation", bundle.ID)
- // sec: should install credentials
- }
-
- /*
- Setup steps for files owned by the target user.
- */
-
- withCacheDir("install", []string{
- // export inner bundle path in the environment
- "export BUNDLE=" + fst.Tmp + "/bundle",
- // replace inner /etc
- "mkdir -p etc",
- "chmod -R +w etc",
- "rm -rf etc",
- "cp -dRf $BUNDLE/etc etc",
- // replace inner /nix
- "mkdir -p nix",
- "chmod -R +w nix",
- "rm -rf nix",
- "cp -dRf /nix nix",
- // copy from binary cache
- "nix copy --offline --no-check-sigs --all --from file://$BUNDLE/res --to $PWD",
- // deduplicate nix store
- "nix store --offline --store $PWD optimise",
- // make cache directory world-readable for autoetc
- "chmod 0755 .",
- }, workDir, bundle, pathSet, dropShellInstall, cleanup)
-
- if bundle.GPU {
- withCacheDir("mesa-wrappers", []string{
- // link nixGL mesa wrappers
- "mkdir -p nix/.nixGL",
- "ln -s " + bundle.Mesa + "/bin/nixGLIntel nix/.nixGL/nixGL",
- "ln -s " + bundle.Mesa + "/bin/nixVulkanIntel nix/.nixGL/nixVulkan",
- }, workDir, bundle, pathSet, false, cleanup)
- }
-
- /*
- Activate home-manager generation.
- */
-
- withNixDaemon("activate", []string{
- // clean up broken links
- "mkdir -p .local/state/{nix,home-manager}",
- "chmod -R +w .local/state/{nix,home-manager}",
- "rm -rf .local/state/{nix,home-manager}",
- // run activation script
- bundle.ActivationPackage + "/activate",
- }, false, func(config *fst.Config) *fst.Config { return config }, bundle, pathSet, dropShellActivate, cleanup)
-
- /*
- Installation complete. Write metadata to block re-installs or downgrades.
- */
-
- // serialise metadata to ensure consistency
- if f, err := os.OpenFile(pathSet.metaPath+"~", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644); err != nil {
- cleanup()
- log.Fatalf("cannot create metadata file: %v", err)
- } else if err = json.NewEncoder(f).Encode(bundle); err != nil {
- cleanup()
- log.Fatalf("cannot write metadata: %v", err)
- } else if err = f.Close(); err != nil {
- log.Printf("cannot close metadata file: %v", err)
- // not fatal
- }
-
- if err := os.Rename(pathSet.metaPath+"~", pathSet.metaPath); err != nil {
- cleanup()
- log.Fatalf("cannot rename metadata file: %v", err)
- }
-
- cleanup()
-}