agent/util/powerutil/shutdown_linux.go (56 lines of code) (raw):
//go:build linux
// +build linux
package powerutil
import (
"context"
"fmt"
"os/exec"
"strings"
"github.com/aliyun/aliyun_assist_client/agent/log"
"github.com/aliyun/aliyun_assist_client/agent/util/systemdutil"
)
func IsSystemShutdown(ctx context.Context) (bool, error) {
var (
res bool
systemdErr error
runlevelErr error
)
if systemdutil.IsRunningSystemd() {
if res, systemdErr = checkShutdownBySystemstate(ctx); systemdErr == nil {
return res, nil
}
}
if res, runlevelErr = checkShutdownByRunlevel(ctx); runlevelErr == nil {
if res {
return res, nil
}
}
return false, fmt.Errorf("systemdErr: %v, runlevelErr: %v", systemdErr, runlevelErr)
}
// Use runlevel to determine whether the os is shutting down, it is not reliable.
// True indicates that the os is restarting or shutting down, but it does not
// always return true when the os is restarting or shutting down.
func checkShutdownByRunlevel(ctx context.Context) (bool, error) {
output, err := exec.CommandContext(ctx, "runlevel").CombinedOutput()
if err != nil {
return false, fmt.Errorf("runlevel error, %s, %v", string(output), err)
}
log.GetLogger().Info("checkShutdownByRunlevel: ", string(output))
fields := strings.Split(strings.TrimSpace(string(output)), " ")
if len(fields) != 2 {
return false, fmt.Errorf("unknown runlevel")
}
switch fields[1] {
case "0":
return true, nil
case "6":
return true, nil
case "N":
return false, fmt.Errorf("unknown runlevel")
default:
return false, nil
}
}
// Use system state of systemd to determine whether the os is shutting down.
// It is not reliable too.
func checkShutdownBySystemstate(ctx context.Context) (bool, error) {
systemState, err := systemdutil.SystemState(ctx)
if err != nil {
return false, fmt.Errorf("system state error, %v", err)
}
log.GetLogger().Info("checkShutdownBySystemstate: ", systemState)
return systemState == "stopping", nil
}