Skip to content

Commit

Permalink
feat: add error when users attempt to call install command on homebre…
Browse files Browse the repository at this point in the history
…w-installed batt

#25

Signed-off-by: Charlie Chiang <[email protected]>
  • Loading branch information
charlie0129 committed Feb 20, 2025
1 parent a6952e4 commit f2b6e64
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 140 deletions.
32 changes: 31 additions & 1 deletion brew.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,34 @@

package main

var hideInstallCommands = true
import (
"errors"

"github.com/spf13/cobra"
)

// NewInstallCommand .
func NewInstallCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "install",
Hidden: true,
RunE: func(cmd *cobra.Command, _ []string) error {
return errors.New("install command is not available on Homebrew-installed batt. Use `sudo brew services start batt` instead.")
},
}

cmd.Flags().Bool("allow-non-root-access", false, "Allow non-root users to access batt daemon.")

return cmd
}

// NewUninstallCommand .
func NewUninstallCommand() *cobra.Command {
return &cobra.Command{
Use: "uninstall",
Hidden: true,
RunE: func(cmd *cobra.Command, _ []string) error {
return errors.New("uninstall command is not available on Homebrew-installed batt. Use `sudo brew services stop batt` instead.")
},
}
}
146 changes: 8 additions & 138 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ package main
import (
"encoding/json"
"fmt"
"os"
"strconv"

"github.com/distatus/battery"
"github.com/fatih/color"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"

"github.com/charlie0129/batt/pkg/smc"
"github.com/charlie0129/batt/pkg/version"
)

Expand All @@ -20,9 +18,9 @@ var (
)

var (
gBasic = "Basic"
gAdvanced = "Advanced"
gInstallation = "Installation"
gBasic = "Basic:"
gAdvanced = "Advanced:"
gInstallation = "Installation:"
commandGroups = []string{
gBasic,
gAdvanced,
Expand All @@ -32,8 +30,9 @@ var (
// NewCommand .
func NewCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "batt",
Short: "batt is a tool to control battery charging on Apple Silicon MacBooks",
Use: "batt",
Short: "batt is a tool to control battery charging on Apple Silicon MacBooks",
SilenceUsage: true,
PersistentPreRunE: func(_ *cobra.Command, _ []string) error {
return setupLogger()
},
Expand Down Expand Up @@ -62,21 +61,10 @@ func NewCommand() *cobra.Command {
NewAdapterCommand(),
NewLowerLimitDeltaCommand(),
NewSetControlMagSafeLEDCommand(),
NewInstallCommand(),
NewUninstallCommand(),
)

// If building for non-brew, show install commands.
// If building for brew, hide install commands because brew will handle installation.
if !hideInstallCommands {
cmd.AddGroup(&cobra.Group{
ID: gInstallation,
Title: gInstallation,
})
cmd.AddCommand(
NewInstallCommand(),
NewUninstallCommand(),
)
}

return cmd
}

Expand Down Expand Up @@ -112,124 +100,6 @@ func NewDaemonCommand() *cobra.Command {
return cmd
}

// NewInstallCommand .
func NewInstallCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "install",
Short: "Install batt (system-wide)",
GroupID: gInstallation,
Long: `Install batt daemon to launchd (system-wide).
This makes batt run in the background and automatically start on boot. You must run this command as root.
By default, only root user is allowed to access the batt daemon for security reasons. As a result, you will need to run batt as root to control battery charging, e.g. setting charge limit. If you want to allow non-root users, i.e., you, to access the daemon, you can use the --allow-non-root-access flag, so you don't have to use sudo every time. However, bear in mind that it introduces security risks.`,
PreRunE: func(cmd *cobra.Command, _ []string) error {

err := loadConfig()
if err != nil {
return err
}

flags := cmd.Flags()
b, err := flags.GetBool("allow-non-root-access")
if err != nil {
return err
}

if config.AllowNonRootAccess && !b {
logrus.Warnf("Previously, non-root users were allowed to access the batt daemon. However, this will be disabled at every installation unless you provide the --allow-non-root-access flag.")
}

// Before installation, always reset config.AllowNonRootAccess to flag value
// instead of the one in config file.
config.AllowNonRootAccess = b

return nil
},
RunE: func(cmd *cobra.Command, _ []string) error {
if config.AllowNonRootAccess {
logrus.Warnf("non-root users are allowed to access the batt daemon. It can be a security risk.")
}

err := installDaemon()
if err != nil {
// check if current user is root
if os.Geteuid() != 0 {
logrus.Errorf("you must run this command as root")
}
return fmt.Errorf("failed to install daemon: %v. Are you root?", err)
}

err = saveConfig()
if err != nil {
return err
}

logrus.Infof("installation succeeded")

exePath, _ := os.Executable()

cmd.Printf("`launchd' will use current binary (%s) at startup so please make sure you do not move this binary. Once this binary is moved or deleted, you will need to run ``batt install'' again.\n", exePath)

return nil
},
}

cmd.Flags().Bool("allow-non-root-access", false, "Allow non-root users to access batt daemon.")

return cmd
}

// NewUninstallCommand .
func NewUninstallCommand() *cobra.Command {
return &cobra.Command{
Use: "uninstall",
Short: "Uninstall batt (system-wide)",
GroupID: gInstallation,
Long: `Uninstall batt daemon from launchd (system-wide).
This stops batt and removes it from launchd.
You must run this command as root.`,
RunE: func(cmd *cobra.Command, _ []string) error {
err := uninstallDaemon()
if err != nil {
// check if current user is root
if os.Geteuid() != 0 {
logrus.Errorf("you must run this command as root")
}
return fmt.Errorf("failed to uninstall daemon: %v", err)
}

logrus.Infof("resetting charge limits")

// Open Apple SMC for read/writing
smcC := smc.New()
if err := smcC.Open(); err != nil {
return fmt.Errorf("failed to open SMC: %v", err)
}

err = smcC.EnableCharging()
if err != nil {
return fmt.Errorf("failed to enable charging: %v", err)
}

err = smcC.EnableAdapter()
if err != nil {
return fmt.Errorf("failed to enable adapter: %v", err)
}

if err := smcC.Close(); err != nil {
return fmt.Errorf("failed to close SMC: %v", err)
}

fmt.Println("successfully uninstalled")

cmd.Printf("Your config is kept in %s, in case you want to use `batt' again. If you want a complete uninstall, you can remove both config file and batt itself manually.\n", configPath)

return nil
},
}
}

// NewLimitCommand .
func NewLimitCommand() *cobra.Command {
return &cobra.Command{
Expand Down
131 changes: 130 additions & 1 deletion nonbrew.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,133 @@

package main

var hideInstallCommands = false
import (
"fmt"
"os"

"github.com/charlie0129/batt/pkg/smc"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

func init() {
commandGroups = append(commandGroups, gInstallation)
}

// NewInstallCommand .
func NewInstallCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "install",
Short: "Install batt (system-wide)",
GroupID: gInstallation,
Long: `Install batt daemon to launchd (system-wide).
This makes batt run in the background and automatically start on boot. You must run this command as root.
By default, only root user is allowed to access the batt daemon for security reasons. As a result, you will need to run batt as root to control battery charging, e.g. setting charge limit. If you want to allow non-root users, i.e., you, to access the daemon, you can use the --allow-non-root-access flag, so you don't have to use sudo every time. However, bear in mind that it introduces security risks.`,
PreRunE: func(cmd *cobra.Command, _ []string) error {

err := loadConfig()
if err != nil {
return err
}

flags := cmd.Flags()
b, err := flags.GetBool("allow-non-root-access")
if err != nil {
return err
}

if config.AllowNonRootAccess && !b {
logrus.Warnf("Previously, non-root users were allowed to access the batt daemon. However, this will be disabled at every installation unless you provide the --allow-non-root-access flag.")
}

// Before installation, always reset config.AllowNonRootAccess to flag value
// instead of the one in config file.
config.AllowNonRootAccess = b

return nil
},
RunE: func(cmd *cobra.Command, _ []string) error {
if config.AllowNonRootAccess {
logrus.Warnf("non-root users are allowed to access the batt daemon. It can be a security risk.")
}

err := installDaemon()
if err != nil {
// check if current user is root
if os.Geteuid() != 0 {
logrus.Errorf("you must run this command as root")
}
return fmt.Errorf("failed to install daemon: %v. Are you root?", err)
}

err = saveConfig()
if err != nil {
return err
}

logrus.Infof("installation succeeded")

exePath, _ := os.Executable()

cmd.Printf("`launchd' will use current binary (%s) at startup so please make sure you do not move this binary. Once this binary is moved or deleted, you will need to run ``batt install'' again.\n", exePath)

return nil
},
}

cmd.Flags().Bool("allow-non-root-access", false, "Allow non-root users to access batt daemon.")

return cmd
}

// NewUninstallCommand .
func NewUninstallCommand() *cobra.Command {
return &cobra.Command{
Use: "uninstall",
Short: "Uninstall batt (system-wide)",
GroupID: gInstallation,
Long: `Uninstall batt daemon from launchd (system-wide).
This stops batt and removes it from launchd.
You must run this command as root.`,
RunE: func(cmd *cobra.Command, _ []string) error {
err := uninstallDaemon()
if err != nil {
// check if current user is root
if os.Geteuid() != 0 {
logrus.Errorf("you must run this command as root")
}
return fmt.Errorf("failed to uninstall daemon: %v", err)
}

logrus.Infof("resetting charge limits")

// Open Apple SMC for read/writing
smcC := smc.New()
if err := smcC.Open(); err != nil {
return fmt.Errorf("failed to open SMC: %v", err)
}

err = smcC.EnableCharging()
if err != nil {
return fmt.Errorf("failed to enable charging: %v", err)
}

err = smcC.EnableAdapter()
if err != nil {
return fmt.Errorf("failed to enable adapter: %v", err)
}

if err := smcC.Close(); err != nil {
return fmt.Errorf("failed to close SMC: %v", err)
}

fmt.Println("successfully uninstalled")

cmd.Printf("Your config is kept in %s, in case you want to use `batt' again. If you want a complete uninstall, you can remove both config file and batt itself manually.\n", configPath)

return nil
},
}
}

0 comments on commit f2b6e64

Please sign in to comment.