{
cmd := cmdr.NewCommand(
"pkg add|remove|list|apply",
abroot.Trans("pkg.long"),
abroot.Trans("pkg.short"),
pkg,
)
cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"dry-run",
"d",
abroot.Trans("pkg.dryRunFlag"),
false))
cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"force-enable-user-agreement",
"f",
abroot.Trans("pkg.forceEnableUserAgreementFlag"),
false))
cmd.Args = cobra.MinimumNArgs(1)
cmd.ValidArgs = validPkgArgs
cmd.Example = "abroot pkg add <pkg>"
return cmd
}
{
if !core.RootCheck(false) {
cmdr.Error.Println(abroot.Trans("pkg.rootRequired"))
return nil
}
dryRun, err := cmd.Flags().GetBool("dry-run")
if err != nil {
cmdr.Error.Println(err)
return err
}
forceEnableUserAgreement, err := cmd.Flags().GetBool("force-enable-user-agreement")
if err != nil {
cmdr.Error.Println(err)
return err
}
pkgM, err := core.NewPackageManager(false)
if err != nil {
cmdr.Error.Println(abroot.Trans("pkg.failedGettingPkgManagerInstance", err))
return err
}
// Check for user agreement, here we could simply call the CheckStatus
// function which also checks if the package manager is enabled or not
// since this pkg command is not even added to the root command if the
// package manager is disabled, but we want to be explicit here to avoid
// potential hard to debug errors in the future in weird development
// scenarios. Yeah, trust me, I've been there.
if pkgM.Status == core.PKG_MNG_REQ_AGREEMENT {
err = pkgM.CheckStatus()
if err != nil {
if !forceEnableUserAgreement {
cmdr.Info.Println(abroot.Trans("pkg.agreementMsg"))
reader := bufio.NewReader(os.Stdin)
answer, _ := reader.ReadString('\n')
answer = strings.TrimSpace(answer)
if answer == "y" || answer == "Y" {
err := pkgM.AcceptUserAgreement()
if err != nil {
cmdr.Error.Println(abroot.Trans("pkg.agreementSignFailed"), err)
return err
}
} else {
cmdr.Info.Println(abroot.Trans("pkg.agreementDeclined"))
return nil
}
} else {
err := pkgM.AcceptUserAgreement()
if err != nil {
cmdr.Error.Println(abroot.Trans("pkg.agreementSignFailed"), err)
return err
}
}
}
}
switch args[0] {
case "add":
if len(args) < 2 {
return errors.New(abroot.Trans("pkg.noPackageNameProvided"))
}
for _, pkg := range args[1:] {
err := pkgM.Add(pkg)
if err != nil {
cmdr.Error.Println(err)
return err
}
}
cmdr.Info.Printf(abroot.Trans("pkg.addedMsg"), strings.Join(args[1:], ", "))
case "remove":
if len(args) < 2 {
return errors.New(abroot.Trans("pkg.noPackageNameProvided"))
}
for _, pkg := range args[1:] {
err := pkgM.Remove(pkg)
if err != nil {
cmdr.Error.Println(err)
return err
}
}
cmdr.Info.Printf(abroot.Trans("pkg.removedMsg"), strings.Join(args[1:], ", "))
case "list":
added, err := pkgM.GetAddPackagesString("\n")
if err != nil {
cmdr.Error.Println(err)
return err
}
removed, err := pkgM.GetRemovePackagesString("\n")
if err != nil {
cmdr.Error.Println(err)
return err
}
cmdr.Info.Printf(abroot.Trans("pkg.listMsg"), added, removed)
return nil
case "apply":
unstaged, err := pkgM.GetUnstagedPackages()
if err != nil {
cmdr.Error.Println(err)
return err
}
if len(unstaged) == 0 {
cmdr.Info.Println(abroot.Trans("pkg.noChanges"))
return nil
}
aBsys, err := core.NewABSystem()
if err != nil {
cmdr.Error.Println(err)
return err
}
if dryRun {
err = aBsys.RunOperation(core.DRY_RUN_APPLY)
} else {
err = aBsys.RunOperation(core.APPLY)
}
if err != nil {
cmdr.Error.Printf(abroot.Trans("pkg.applyFailed"), err)
return err
}
default:
cmdr.Error.Println(abroot.Trans("pkg.unknownCommand", args[0]))
return nil
}
return nil
}
{
cmd := cmdr.NewCommand(
"rollback",
abroot.Trans("rollback.long"),
abroot.Trans("rollback.short"),
rollback,
)
cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"check-only",
"c",
abroot.Trans("rollback.checkOnlyFlag"),
false))
cmd.Example = "abroot rollback"
return cmd
}
{
if !core.RootCheck(false) {
cmdr.Error.Println(abroot.Trans("rollback.rootRequired"))
return nil
}
checkOnly, err := cmd.Flags().GetBool("check-only")
if err != nil {
cmdr.Error.Println(err)
return err
}
aBsys, err := core.NewABSystem()
if err != nil {
cmdr.Error.Println(err)
return err
}
response, err := aBsys.Rollback(checkOnly)
switch response {
case core.ROLLBACK_RES_YES:
// NOTE: the following strings could lead to misinterpretation, with
// "can" and "cannot", we don't mean "is it possible to rollback?",
// but "is it necessary to rollback?"
cmdr.Info.Println(abroot.Trans("rollback.canRollback"))
os.Exit(0)
case core.ROLLBACK_RES_NO:
cmdr.Info.Println(abroot.Trans("rollback.cannotRollback"))
os.Exit(1)
case core.ROLLBACK_UNNECESSARY:
cmdr.Info.Println(abroot.Trans("rollback.rollbackUnnecessary"))
os.Exit(0)
case core.ROLLBACK_SUCCESS:
cmdr.Info.Println(abroot.Trans("rollback.rollbackSuccess"))
os.Exit(0)
case core.ROLLBACK_FAILED:
cmdr.Info.Println(abroot.Trans("rollback.rollbackFailed", err))
os.Exit(1)
return err
}
return nil
}
{
abroot = cmdr.NewApp("abroot", version, fs)
return abroot
}
{
root := cmdr.NewCommand(
abroot.Trans("abroot.use"),
abroot.Trans("abroot.long"),
abroot.Trans("abroot.short"),
nil).
WithPersistentBoolFlag(
cmdr.NewBoolFlag(
verboseFlag,
"V",
abroot.Trans("abroot.verboseFlag"),
false))
root.Version = version
return root
}
{
cmd := cmdr.NewCommand(
"upgrade",
abroot.Trans("upgrade.long"),
abroot.Trans("upgrade.short"),
upgrade,
)
cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"check-only",
"c",
abroot.Trans("upgrade.checkOnlyFlag"),
false))
cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"dry-run",
"d",
abroot.Trans("upgrade.dryRunFlag"),
false))
cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"force",
"f",
abroot.Trans("upgrade.forceFlag"),
false))
cmd.Example = "abroot upgrade"
return cmd
}
{
checkOnly, err := cmd.Flags().GetBool("check-only")
if err != nil {
cmdr.Error.Println(err)
return err
}
dryRun, err := cmd.Flags().GetBool("dry-run")
if err != nil {
cmdr.Error.Println(err)
return err
}
aBsys, err := core.NewABSystem()
if err != nil {
cmdr.Error.Println(err)
return err
}
if checkOnly {
_, raw := os.LookupEnv("ABROOT_JSON_OUTPUT")
if !raw {
cmdr.Info.Println(abroot.Trans("upgrade.checkingSystemUpdate"))
}
// Check for image updates
newDigest, res := aBsys.CheckUpdate()
sysAdded, sysUpgraded, sysDowngraded, sysRemoved := []diff.PackageDiff{}, []diff.PackageDiff{}, []diff.PackageDiff{}, []diff.PackageDiff{}
if res {
if !raw {
cmdr.Info.Println(abroot.Trans("upgrade.systemUpdateAvailable"))
}
sysAdded, sysUpgraded, sysDowngraded, sysRemoved, err = core.BaseImagePackageDiff(aBsys.CurImage.Digest, newDigest)
if err != nil {
return err
}
if !raw {
err = renderPackageDiff(sysAdded, sysUpgraded, sysDowngraded, sysRemoved)
if err != nil {
return err
}
}
} else if !raw {
cmdr.Info.Println(abroot.Trans("upgrade.noUpdateAvailable"))
}
// Check for package updates
if !raw {
cmdr.Info.Println(abroot.Trans("upgrade.checkingPackageUpdate"))
}
ovlAdded, ovlUpgraded, ovlDowngraded, ovlRemoved, err := core.OverlayPackageDiff()
if err != nil {
return err
}
sumChanges := len(ovlAdded) + len(ovlUpgraded) + len(ovlDowngraded) + len(ovlRemoved)
if sumChanges == 0 && !raw {
cmdr.Info.Println(abroot.Trans("upgrade.noUpdateAvailable"))
} else if !raw {
cmdr.Info.Sprintf(abroot.Trans("upgrade.packageUpdateAvailable"), sumChanges)
err = renderPackageDiff(ovlAdded, ovlUpgraded, ovlDowngraded, ovlRemoved)
if err != nil {
return err
}
}
if raw {
newDigestIfHasUpdate := ""
if res {
newDigestIfHasUpdate = newDigest
}
out, err := json.Marshal(map[string]any{
"hasUpdate": res,
"newDigest": newDigestIfHasUpdate,
"systemPackageDiff": map[string][]diff.PackageDiff{
"added": sysAdded,
"upgraded": sysUpgraded,
"downgraded": sysDowngraded,
"removed": sysRemoved,
},
"overlayPackageDiff": map[string][]diff.PackageDiff{
"added": ovlAdded,
"upgraded": ovlUpgraded,
"downgraded": ovlDowngraded,
"removed": ovlRemoved,
},
})
if err != nil {
cmdr.Error.Println(err)
}
fmt.Println(string(out))
}
if !res && sumChanges == 0 {
os.Exit(1) // No update available
} else {
os.Exit(0) // Update available
}
}
if !core.RootCheck(false) {
cmdr.Error.Println(abroot.Trans("upgrade.rootRequired"))
return nil
}
force, err := cmd.Flags().GetBool("force")
if err != nil {
cmdr.Error.Println(err)
return err
}
var operation core.ABSystemOperation
if force {
operation = core.FORCE_UPGRADE
} else if dryRun {
operation = core.DRY_RUN_UPGRADE
} else {
operation = core.UPGRADE
}
cmdr.Info.Println(abroot.Trans("upgrade.checkingSystemUpdate"))
err = aBsys.RunOperation(operation)
if err != nil {
if err == core.ErrNoUpdate {
cmdr.Info.Println(abroot.Trans("upgrade.noUpdateAvailable"))
return err
}
cmdr.Error.Println(err)
return err
}
if dryRun {
cmdr.Info.Println(abroot.Trans("upgrade.dryRunSuccess"))
}
cmdr.Info.Println(abroot.Trans("upgrade.success"))
os.Exit(0)
return nil
}
{
pkgFmt := "%s '%s' -> '%s'"
// Calculate largest string for proper alignment
largestPkgName := 0
for _, pkgSet := range [][]diff.PackageDiff{added, upgraded, downgraded, removed} {
for _, pkg := range pkgSet {
if len(pkg.Name) > largestPkgName {
largestPkgName = len(pkg.Name)
}
}
}
for _, pkgSet := range []struct {
Set []diff.PackageDiff
Header string
Color cmdr.Color
}{
{added, abroot.Trans("upgrade.added"), cmdr.FgGreen},
{upgraded, abroot.Trans("upgrade.upgraded"), cmdr.FgBlue},
{downgraded, abroot.Trans("upgrade.downgraded"), cmdr.FgYellow},
{removed, abroot.Trans("upgrade.removed"), cmdr.FgRed},
} {
cmdr.NewStyle(cmdr.Bold, pkgSet.Color).Println(pkgSet.Header + ":")
bulletItems := []cmdr.BulletListItem{}
for _, pkg := range pkgSet.Set {
bulletItems = append(bulletItems, cmdr.BulletListItem{
Level: 1,
Text: fmt.Sprintf(pkgFmt, pkg.Name+strings.Repeat(" ", largestPkgName-len(pkg.Name)), pkg.PreviousVersion, pkg.NewVersion),
})
}
err := cmdr.BulletList.WithItems(bulletItems).Render()
if err != nil {
return err
}
}
return nil
}
{
cmd := cmdr.NewCommand(
"config-editor",
abroot.Trans("cnf.long"),
abroot.Trans("cnf.short"),
cnf,
)
return cmd
}
{
if !core.RootCheck(false) {
cmdr.Error.Println(abroot.Trans("cnf.rootRequired"))
return nil
}
result, err := core.ConfEdit()
switch result {
case core.CONF_CHANGED:
cmdr.Info.Println(abroot.Trans("cnf.changed"))
case core.CONF_UNCHANGED:
cmdr.Info.Println(abroot.Trans("cnf.unchanged"))
case core.CONF_FAILED:
cmdr.Error.Println(abroot.Trans("cnf.failed", err))
}
return nil
}
{
cmd := cmdr.NewCommand(
"kargs edit|show",
abroot.Trans("kargs.long"),
abroot.Trans("kargs.short"),
kargs,
)
cmd.Args = cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs)
cmd.ValidArgs = validKargsArgs
cmd.Example = "abroot kargs edit"
return cmd
}
{
if !core.RootCheck(false) {
cmdr.Error.Println(abroot.Trans("kargs.rootRequired"))
return nil
}
switch args[0] {
case "edit":
changed, err := core.KargsEdit()
if err != nil {
cmdr.Error.Println(err)
return err
}
if !changed {
cmdr.Info.Println(abroot.Trans("kargs.notChanged"))
return nil
}
aBsys, err := core.NewABSystem()
if err != nil {
cmdr.Error.Println(err)
return err
}
err = aBsys.RunOperation(core.APPLY)
if err != nil {
cmdr.Error.Println(abroot.Trans("pkg.applyFailed"))
return err
}
case "show":
kargsStr, err := core.KargsRead()
if err != nil {
cmdr.Error.Println(err)
return err
}
cmdr.Info.Println(kargsStr)
default:
return errors.New(abroot.Trans("kargs.unknownCommand", args[0]))
}
return nil
}
{
return fmt.Sprintf("device %s has an unsupported layout", e.Device)
}
{
return fmt.Sprintf("partition %s could not be found", e.Partition)
}
{
cmd := cmdr.NewCommand(
"mount-sys",
"",
"",
mountSysCmd,
)
cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"dry-run",
"d",
"perform a dry run of the operation",
false,
),
)
cmd.Example = "abroot mount-sys"
cmd.Hidden = true
return cmd
}
helper function which only returns syntax errors and prints other ones
{
err := mountSys(cmd, args)
if err != nil {
cmdr.Error.Println(err)
os.Exit(1)
}
return nil
}
{
if !core.RootCheck(false) {
cmdr.Error.Println("This operation requires root.")
return nil
}
dryRun, err := cmd.Flags().GetBool("dry-run")
if err != nil {
return err
}
manager := core.NewABRootManager()
present, err := manager.GetPresent()
if err != nil {
return err
}
err = mountVar(manager.VarPartition, dryRun)
if err != nil {
cmdr.Error.Println(err)
os.Exit(5)
}
err = compatBindMounts(dryRun)
if err != nil {
cmdr.Error.Println(err)
return err
}
err = mountBindMounts(dryRun)
if err != nil {
cmdr.Error.Println(err)
os.Exit(6)
}
if present.Label == "" {
return &PartNotFoundError{"current root"}
}
err = mountOverlayMounts(present.Label, dryRun)
if err != nil {
cmdr.Error.Println(err)
os.Exit(7)
}
if present.Uuid == "" {
return &PartNotFoundError{"current root"}
}
err = adjustFstab(present.Uuid, dryRun)
if err != nil {
cmdr.Error.Println(err)
os.Exit(8)
}
if dryRun {
cmdr.Info.Println("Dry run complete.")
} else {
cmdr.Info.Println("The system mounts have been performed successfully.")
}
return nil
}
{
cmdr.FgDefault.Println("mounting " + varPart.Device + " in /var")
if varPart.Device == "" {
return &PartNotFoundError{settings.Cnf.PartLabelVar}
}
if !dryRun {
err := varPart.Mount("/var")
if err != nil {
return err
}
}
return nil
}
{
type bindMount struct {
from, to string
options uintptr
}
binds := []bindMount{
{"/.system/usr", "/.system/usr", syscall.MS_RDONLY},
}
for _, bind := range binds {
cmdr.FgDefault.Println("bind-mounting " + bind.from + " to " + bind.to)
if !dryRun {
err := syscall.Mount(bind.from, bind.to, "", syscall.MS_BIND|bind.options, "")
if err != nil {
return err
}
}
}
return nil
}
{
type overlayMount struct {
destination string
lowerdirs []string
upperdir, workdir string
}
overlays := []overlayMount{
{"/.system/etc", []string{"/.system/etc"}, "/var/lib/abroot/etc/" + rootLabel, "/var/lib/abroot/etc/" + rootLabel + "-work"},
{"/opt", []string{"/.system/opt"}, "/var/opt", "/var/opt-work"},
}
for _, overlay := range overlays {
if _, err := os.Lstat(overlay.workdir); os.IsNotExist(err) {
err := os.MkdirAll(overlay.workdir, 0o755)
cmdr.Warning.Println(err)
// failing the boot here won't help so ingore any error
}
lowerCombined := strings.Join(overlay.lowerdirs, ":")
options := "lowerdir=" + lowerCombined + ",upperdir=" + overlay.upperdir + ",workdir=" + overlay.workdir
cmdr.FgDefault.Println("mounting overlay mount " + overlay.destination + " with options " + options)
if !dryRun {
err := syscall.Mount("overlay", overlay.destination, "overlay", 0, options)
if err != nil {
return err
}
}
}
return nil
}
{
cmdr.FgDefault.Println("switching the root in fstab")
const fstabFile = "/etc/fstab"
systemMounts := []string{"/", "/var", "/.system/usr", "/.system/etc"}
fstabContentsRaw, err := os.ReadFile(fstabFile)
if err != nil {
return err
}
fstabContents := string(fstabContentsRaw)
lines := strings.Split(fstabContents, "\n")
linesNew := make([]string, 0, len(lines))
// remove system Mounts if they exist in fstab
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "#") {
linesNew = append(linesNew, line)
continue
}
words := strings.Fields(line)
if len(words) < 2 {
linesNew = append(linesNew, line)
continue
}
if !slices.Contains[[]string](systemMounts, words[1]) {
linesNew = append(linesNew, line)
continue
}
cmdr.FgDefault.Println("Deleting line: ", line)
}
currentRootLine := "UUID=" + uuid + " / btrfs defaults 0 0"
cmdr.FgDefault.Println("Adding line: ", currentRootLine)
linesNew = append([]string{currentRootLine}, linesNew...)
newFstabContents := strings.Join(linesNew, "\n")
newFstabFile := fstabFile + ".new"
if !dryRun {
cmdr.FgDefault.Println("writing new fstab file")
err := os.WriteFile(newFstabFile, []byte(newFstabContents), 0o644)
if err != nil {
return err
}
err = core.AtomicSwap(fstabFile, newFstabFile)
if err != nil {
return err
}
err = os.Rename(newFstabFile, fstabFile+".old")
if err != nil {
cmdr.Warning.Println("Old Fstab file will keep .new suffix")
// ignore, backup is not neccessary to boot
}
}
return nil
}
this is here to keep compatibility with older systems
/home was a bind mount instead of a symlink to /var/home
{
type bindMount struct {
from, to string
options uintptr
}
binds := []bindMount{
{"/var/home", "/home", 0},
}
for _, bind := range binds {
if info, err := os.Lstat(bind.to); err == nil && !info.IsDir() {
// path has been migrated already
continue
}
cmdr.FgDefault.Println("bind-mounting " + bind.from + " to " + bind.to)
if !dryRun {
err := syscall.Mount(bind.from, bind.to, "", syscall.MS_BIND|bind.options, "")
if err != nil {
return err
}
}
}
return nil
}
{
cmd := cmdr.NewCommand(
"status",
abroot.Trans("status.long"),
abroot.Trans("status.short"),
status,
)
cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"json",
"j",
abroot.Trans("status.jsonFlag"),
false))
cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"dump",
"d",
abroot.Trans("status.dumpFlag"),
false))
cmd.Example = "abroot status"
return cmd
}
{
if !core.RootCheck(false) {
cmdr.Error.Println(abroot.Trans("status.rootRequired"))
return nil
}
jsonFlag, err := cmd.Flags().GetBool("json")
if err != nil {
return err
}
dumpFlag, err := cmd.Flags().GetBool("dump")
if err != nil {
return err
}
a := core.NewABRootManager()
present, err := a.GetPresent()
if err != nil {
return err
}
future, err := a.GetFuture()
if err != nil {
return err
}
specs := core.GetPCSpecs()
abImage, err := core.NewABImageFromRoot()
if err != nil {
return err
}
kargs, err := core.KargsRead()
if err != nil {
return err
}
pkgMngAgreementStatus := false
pkgMng, err := core.NewPackageManager(false)
if err != nil {
return err
}
if pkgMng.Status == core.PKG_MNG_REQ_AGREEMENT {
err = pkgMng.CheckStatus()
pkgMngAgreementStatus = err == nil
}
pkgsAdd, err := pkgMng.GetAddPackages()
if err != nil {
return err
}
pkgsRm, err := pkgMng.GetRemovePackages()
if err != nil {
return err
}
pkgsUnstg, err := pkgMng.GetUnstagedPackagesPlain()
if err != nil {
return err
}
if jsonFlag || dumpFlag {
type status struct {
Present string `json:"present"`
Future string `json:"future"`
CnfFile string `json:"cnfFile"`
CPU string `json:"cpu"`
GPU []string `json:"gpu"`
Memory string `json:"memory"`
ABImage core.ABImage `json:"abimage"`
Kargs string `json:"kargs"`
PkgsAdd []string `json:"pkgsAdd"`
PkgsRm []string `json:"pkgsRm"`
PkgsUnstg []string `json:"pkgsUnstg"`
PkgMngStatus int `json:"pkgMngStatus"`
PkgMngAgreement bool `json:"pkgMngAg"`
}
s := status{
Present: present.Label,
Future: future.Label,
CnfFile: settings.CnfFileUsed,
CPU: specs.CPU,
GPU: specs.GPU,
Memory: specs.Memory,
ABImage: *abImage,
Kargs: kargs,
PkgsAdd: pkgsAdd,
PkgsRm: pkgsRm,
PkgsUnstg: pkgsUnstg,
PkgMngStatus: settings.Cnf.IPkgMngStatus,
PkgMngAgreement: pkgMngAgreementStatus,
}
b, err := json.Marshal(s)
if err != nil {
return err
}
if jsonFlag {
fmt.Println(string(b))
return nil
}
tarballPath := fmt.Sprintf("/tmp/abroot-status-%s.tar.gz", uuid.New().String())
tarballFile, err := os.Create(tarballPath)
if err != nil {
return err
}
defer tarballFile.Close()
gzipWriter := gzip.NewWriter(tarballFile)
defer gzipWriter.Close()
tarWriter := tar.NewWriter(gzipWriter)
defer tarWriter.Close()
tarHeader := &tar.Header{
Name: "status.json",
Mode: 0o644,
Size: int64(len(b)),
}
err = tarWriter.WriteHeader(tarHeader)
if err != nil {
return err
}
_, err = tarWriter.Write(b)
if err != nil {
return err
}
err = filepath.Walk("/var/log/", func(path string, info os.FileInfo, err error) error {
if strings.Contains(path, "abroot.log") {
relPath, err := filepath.Rel("/var/log/", path)
if err != nil {
return err
}
tarHeader := &tar.Header{
Name: filepath.Join("logs", relPath),
Mode: 0o644,
Size: info.Size(),
}
err = tarWriter.WriteHeader(tarHeader)
if err != nil {
return err
}
logFile, err := os.Open(path)
if err != nil {
return err
}
defer logFile.Close()
_, err = io.Copy(tarWriter, logFile)
if err != nil {
return err
}
}
return nil
})
if err != nil {
return err
}
cmdr.Info.Printf(abroot.Trans("status.dumpMsg"), tarballPath)
return nil
}
formattedGPU := ""
for _, gpu := range specs.GPU {
formattedGPU += fmt.Sprintf("\n\t\t- %s", gpu)
}
unstagedAlert := ""
if len(pkgsUnstg) > 0 {
unstagedAlert = abroot.Trans("status.unstagedFoundMsg", len(pkgsUnstg))
}
presentMark, futureMark, err := getCurrentlyBootedPartition(a)
if err != nil {
return err
}
// ABRoot partitions:
cmdr.Bold.Println(abroot.Trans("status.partitions.title"))
cmdr.BulletList.WithItems([]cmdr.BulletListItem{
{Level: 1, Text: abroot.Trans("status.partitions.present", present.Label, presentMark)},
{Level: 1, Text: abroot.Trans("status.partitions.future", future.Label, futureMark)},
}).Render()
// Loaded Configuration: ...
cmdr.Bold.Print(abroot.Trans("status.loadedConfig") + " ")
cmdr.FgDefault.Println(settings.CnfFileUsed)
fmt.Println()
// Device Specification:
cmdr.Bold.Println(abroot.Trans("status.specs.title"))
cmdr.BulletList.WithItems([]cmdr.BulletListItem{
{Level: 1, Text: abroot.Trans("status.specs.cpu", specs.CPU)},
{Level: 1, Text: abroot.Trans("status.specs.gpu", specs.GPU)},
{Level: 1, Text: abroot.Trans("status.specs.memory", specs.Memory)},
}).Render()
// ABImage:
cmdr.Bold.Println(abroot.Trans("status.abimage.title"))
cmdr.BulletList.WithItems([]cmdr.BulletListItem{
{Level: 1, Text: abroot.Trans("status.abimage.digest", abImage.Digest)},
{Level: 1, Text: abroot.Trans("status.abimage.timestamp", abImage.Timestamp.Format("2006-01-02 15:04:05"))},
{Level: 1, Text: abroot.Trans("status.abimage.image", abImage.Image)},
}).Render()
// Kernel Arguments: ...
cmdr.Bold.Printf(abroot.Trans("status.kargs") + " ")
cmdr.FgDefault.Println(kargs)
cmdr.FgDefault.Println()
// Packages:
cmdr.Bold.Println(abroot.Trans("status.packages.title"))
cmdr.BulletList.WithItems([]cmdr.BulletListItem{
{Level: 1, Text: abroot.Trans("status.packages.added", strings.Join(pkgsAdd, ", "))},
{Level: 1, Text: abroot.Trans("status.packages.removed", strings.Join(pkgsRm, ", "))},
{Level: 1, Text: abroot.Trans("status.packages.unstaged", strings.Join(pkgsUnstg, ", "), unstagedAlert)},
}).Render()
// Package Agreement: ...
cmdr.Bold.Print(abroot.Trans("status.agreementStatus") + " ")
cmdr.FgDefault.Println(pkgMngAgreementStatus)
return nil
}
{
bootPart, err := a.GetBoot()
if err != nil {
return "", "", err
}
uuid := uuid.New().String()
tmpBootMount := filepath.Join("/tmp", uuid)
err = os.Mkdir(tmpBootMount, 0o755)
if err != nil {
return "", "", err
}
err = bootPart.Mount(tmpBootMount)
if err != nil {
return "", "", err
}
defer bootPart.Unmount()
g, err := core.NewGrub(bootPart)
if err != nil {
return "", "", err
}
isPresent, err := g.IsBootedIntoPresentRoot()
if err != nil {
return "", "", err
}
presentMark := ""
futureMark := ""
if isPresent {
presentMark = " ✓"
} else {
futureMark = " ✓"
}
return presentMark, futureMark, nil
}
{
return "the /var disk " + e.passedDisk + " does not exist"
}
{
return "the var partition is not encrypted"
}
{
cmd := cmdr.NewCommand(
"unlock-var",
"",
"",
unlockVarCmd,
)
cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"dry-run",
"d",
"perform a dry run of the operation",
false,
),
)
// this is just meant for compatability with old Installations
cmd.WithStringFlag(
cmdr.NewStringFlag(
"var-disk",
"m",
"pass /var disk directly instead of reading from configuration",
"",
),
)
cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"check-encrypted",
"c",
"check if drive is encrypted and return",
false,
),
)
cmd.Example = "abroot unlock-var"
cmd.Hidden = true
return cmd
}
helper function which only returns syntax errors and prints other ones
{
err := unlockVar(cmd, args)
if err != nil {
cmdr.Error.Println(err)
os.Exit(1)
return nil
}
return nil
}
{
if !core.RootCheck(false) {
cmdr.Error.Println("You must be root to run this command.")
os.Exit(2)
return nil
}
varDisk, err := cmd.Flags().GetString("var-disk")
if err != nil {
return err
}
check_only, err := cmd.Flags().GetBool("check-encrypted")
if err != nil {
return err
}
_, err = os.Stat(filepath.Join("/dev/disk/by-label/", settings.Cnf.PartLabelVar))
if err == nil || !errors.Is(err, os.ErrNotExist) {
return &NotEncryptedError{}
}
if check_only {
cmdr.Info.Println("The var partition is encrypted.")
return nil
}
if varDisk == "" {
if settings.Cnf.PartCryptVar == "" {
cmdr.Error.Println("Encrypted var partition not found in configuration.")
os.Exit(3)
return nil
}
varDisk = settings.Cnf.PartCryptVar
}
dryRun, err := cmd.Flags().GetBool("dry-run")
if err != nil {
return err
}
partitions, err := core.NewDiskManager().GetPartitions("")
if err != nil {
return err
}
var varLuksPart core.Partition
foundPart := false
for _, partition := range partitions {
devName := "/dev/"
if partition.IsDevMapper() {
devName += "mapper/"
}
devName += partition.Device
if devName == varDisk {
varLuksPart = partition
foundPart = true
break
}
}
if !foundPart {
return &VarInvalidError{varDisk}
}
uuid := varLuksPart.Uuid
cmdr.FgDefault.Println("unlocking", varDisk)
if dryRun {
cmdr.Info.Println("Dry run complete.")
} else {
cryptsetupCmd := exec.Command("/usr/sbin/cryptsetup", "luksOpen", varDisk, "luks-"+uuid)
cryptsetupCmd.Stdin = os.Stdin
cryptsetupCmd.Stderr = os.Stderr
cryptsetupCmd.Stdout = os.Stdout
err := cryptsetupCmd.Run()
if err != nil {
return err
}
cmdr.Info.Println("The system mounts have been performed successfully.")
}
return nil
}
{
cmd := cmdr.NewCommand(
"update-initramfs",
abroot.Trans("updateInitramfs.long"),
abroot.Trans("updateInitramfs.short"),
updateInitramfs,
)
cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"dry-run",
"d",
abroot.Trans("updateInitramfs.dryRunFlag"),
false))
cmd.Example = "abroot update-initramfs"
return cmd
}
{
if !core.RootCheck(false) {
cmdr.Error.Println(abroot.Trans("updateInitramfs.rootRequired"))
return nil
}
dryRun, err := cmd.Flags().GetBool("dry-run")
if err != nil {
cmdr.Error.Println(err)
return err
}
aBsys, err := core.NewABSystem()
if err != nil {
cmdr.Error.Println(err)
return err
}
if dryRun {
err = aBsys.RunOperation(core.DRY_RUN_INITRAMFS)
} else {
err = aBsys.RunOperation(core.INITRAMFS)
}
if err != nil {
cmdr.Error.Printf(abroot.Trans("updateInitramfs.updateFailed"), err)
return err
}
cmdr.Info.Println(abroot.Trans("updateInitramfs.updateSuccess"))
return nil
}
import "bufio"
import "errors"
import "os"
import "strings"
import "github.com/spf13/cobra"
import "github.com/vanilla-os/abroot/core"
import "github.com/vanilla-os/orchid/cmdr"
import "os"
import "github.com/spf13/cobra"
import "github.com/vanilla-os/abroot/core"
import "github.com/vanilla-os/orchid/cmdr"
import "embed"
import "github.com/vanilla-os/orchid/cmdr"
import "encoding/json"
import "fmt"
import "os"
import "strings"
import "github.com/spf13/cobra"
import "github.com/vanilla-os/abroot/core"
import "github.com/vanilla-os/differ/diff"
import "github.com/vanilla-os/orchid/cmdr"
import "github.com/spf13/cobra"
import "github.com/vanilla-os/abroot/core"
import "github.com/vanilla-os/orchid/cmdr"
import "errors"
import "github.com/spf13/cobra"
import "github.com/vanilla-os/abroot/core"
import "github.com/vanilla-os/orchid/cmdr"
import "fmt"
import "os"
import "slices"
import "strings"
import "syscall"
import "github.com/spf13/cobra"
import "github.com/vanilla-os/abroot/core"
import "github.com/vanilla-os/abroot/settings"
import "github.com/vanilla-os/orchid/cmdr"
import "archive/tar"
import "compress/gzip"
import "encoding/json"
import "fmt"
import "io"
import "os"
import "path/filepath"
import "strings"
import "github.com/spf13/cobra"
import "github.com/google/uuid"
import "github.com/vanilla-os/abroot/core"
import "github.com/vanilla-os/abroot/settings"
import "github.com/vanilla-os/orchid/cmdr"
import "errors"
import "os"
import "os/exec"
import "path/filepath"
import "github.com/spf13/cobra"
import "github.com/vanilla-os/abroot/core"
import "github.com/vanilla-os/abroot/settings"
import "github.com/vanilla-os/orchid/cmdr"
import "github.com/spf13/cobra"
import "github.com/vanilla-os/abroot/core"
import "github.com/vanilla-os/orchid/cmdr"