Compare commits
6 Commits
c032cdba58
...
3adba7a09d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3adba7a09d | ||
|
|
36efbeec1d | ||
|
|
d963dcf9a2 | ||
|
|
70320156e4 | ||
|
|
fcdbc4ed41 | ||
|
|
84a4bf8093 |
|
|
@ -21,9 +21,9 @@ func NewSafeCmd() *cobra.Command {
|
||||||
Short: "交互式安全确认,将可疑对象加入白名单",
|
Short: "交互式安全确认,将可疑对象加入白名单",
|
||||||
Long: "查看当前的可疑文件和进程列表,并选择将其移入白名单。",
|
Long: "查看当前的可疑文件和进程列表,并选择将其移入白名单。",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cfg, err := config.LoadConfig("./config.yaml")
|
cfg, ok := cmd.Context().Value("config").(*config.Config)
|
||||||
if err != nil {
|
if !ok {
|
||||||
fmt.Printf("加载配置失败: %v\n", err)
|
fmt.Println("无法获取配置")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,15 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"sysmonitord/internal/config"
|
"sysmonitord/internal/config"
|
||||||
|
"sysmonitord/pkg/logger"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewStatusCmd() *cobra.Command {
|
func NewStatusCmd() *cobra.Command {
|
||||||
|
|
@ -16,10 +21,9 @@ func NewStatusCmd() *cobra.Command {
|
||||||
Short: "显示系统状态",
|
Short: "显示系统状态",
|
||||||
Long: "显示Sysmonitod的当前状态",
|
Long: "显示Sysmonitod的当前状态",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cfg, err := config.LoadConfig("./config.yaml")
|
cfg, ok := cmd.Context().Value("config").(*config.Config)
|
||||||
|
if !ok {
|
||||||
if err != nil {
|
fmt.Println("无法获取配置")
|
||||||
fmt.Printf("加载配置失败: %v\n", err)
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,7 +40,7 @@ func printStatus(cfg *config.Config) {
|
||||||
fmt.Println("================")
|
fmt.Println("================")
|
||||||
|
|
||||||
// Todo: 显示运行时长
|
// Todo: 显示运行时长
|
||||||
runtimeInfo := "N/A"
|
runtimeInfo := getRuntime()
|
||||||
|
|
||||||
fmt.Printf("Runtime: %s\n", runtimeInfo)
|
fmt.Printf("Runtime: %s\n", runtimeInfo)
|
||||||
fmt.Printf("Data Directory: %s\n", dataDir)
|
fmt.Printf("Data Directory: %s\n", dataDir)
|
||||||
|
|
@ -88,3 +92,69 @@ func countLines(filePath string) (int, error) {
|
||||||
|
|
||||||
return lineCount, scanner.Err()
|
return lineCount, scanner.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRuntime() string {
|
||||||
|
cmd := exec.Command("systemctl", "is-active", "sysmonitord")
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil || strings.TrimSpace(string(output)) != "active" {
|
||||||
|
return "N/A"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = exec.Command("systemctl", "show", "sysmonitord", "--property=ActiveEnterTimestamp")
|
||||||
|
output, err = cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return "N/A"
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.SplitN(string(output), "=", 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return "N/A"
|
||||||
|
}
|
||||||
|
|
||||||
|
timestampStr := strings.TrimSpace(parts[1])
|
||||||
|
if timestampStr == "" {
|
||||||
|
return "N/A"
|
||||||
|
}
|
||||||
|
|
||||||
|
layouts := []string{
|
||||||
|
"Mon 2006-01-02 15:04:05 MST",
|
||||||
|
"Mon 2006-01-02 15:04:05",
|
||||||
|
"2006-01-02 15:04:05 MST",
|
||||||
|
"2006-01-02 15:04:05",
|
||||||
|
"Mon 2006-01-02 15:04:05 MST 2006",
|
||||||
|
}
|
||||||
|
|
||||||
|
var startTime time.Time
|
||||||
|
var parseErr error
|
||||||
|
for _, layout := range layouts {
|
||||||
|
startTime, parseErr = time.Parse(layout, timestampStr)
|
||||||
|
if parseErr == nil {
|
||||||
|
logger.Log.Debug("时间解析成功", zap.String("layout", layout))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if parseErr != nil {
|
||||||
|
return "N/A"
|
||||||
|
}
|
||||||
|
|
||||||
|
if time.Since(startTime) < 0 {
|
||||||
|
return "N/A"
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime := time.Since(startTime)
|
||||||
|
|
||||||
|
days := int(runtime.Hours()) / 24
|
||||||
|
hours := int(runtime.Hours()) % 24
|
||||||
|
minutes := int(runtime.Minutes()) % 60
|
||||||
|
seconds := int(runtime.Seconds()) % 60
|
||||||
|
|
||||||
|
if days > 0 {
|
||||||
|
return fmt.Sprintf("%d天 %d小时 %d分钟 %d秒", days, hours, minutes, seconds)
|
||||||
|
} else if hours > 0 {
|
||||||
|
return fmt.Sprintf("%d小时 %d分钟 %d秒", hours, minutes, seconds)
|
||||||
|
} else if minutes > 0 {
|
||||||
|
return fmt.Sprintf("%d分钟 %d秒", minutes, seconds)
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("%d秒", seconds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,65 @@ scanner:
|
||||||
include_paths:
|
include_paths:
|
||||||
- /
|
- /
|
||||||
exclude_paths:
|
exclude_paths:
|
||||||
|
# ========== 虚拟/临时文件系统==========
|
||||||
- /proc
|
- /proc
|
||||||
- /sys
|
- /sys
|
||||||
|
- /dev
|
||||||
|
- /tmp
|
||||||
|
- /var/tmp
|
||||||
|
- /run
|
||||||
|
- /mnt
|
||||||
|
- /media
|
||||||
|
|
||||||
|
# ========== 系统高频写入目录==========
|
||||||
|
- /var/log
|
||||||
|
- /var/cache
|
||||||
|
- /var/mail
|
||||||
|
- /var/spool
|
||||||
|
- /var/lib/docker
|
||||||
|
- /var/lib/containerd
|
||||||
|
- /var/lib/systemd
|
||||||
|
|
||||||
|
# ========== 内核模块==========
|
||||||
|
- /usr/lib/modules
|
||||||
|
- /lib/modules
|
||||||
|
- /usr/src
|
||||||
|
|
||||||
|
# ========== 应用缓存和构建目录==========
|
||||||
|
# 通用
|
||||||
|
- "**/node_modules"
|
||||||
|
- "**/.git"
|
||||||
|
- "**/.cache"
|
||||||
|
- "**/build"
|
||||||
|
- "**/dist"
|
||||||
|
- "**/unpackage"
|
||||||
|
- "**/vendor"
|
||||||
|
- "**/__pycache__"
|
||||||
|
- "**/.idea"
|
||||||
|
- "**/.vscode"
|
||||||
|
|
||||||
|
# ========== Web 应用特定==========
|
||||||
|
- "**/cache"
|
||||||
|
- "**/logs"
|
||||||
|
- "**/tmp"
|
||||||
|
- "**/temp"
|
||||||
|
- "**/uploads/tmp"
|
||||||
|
|
||||||
|
# ========== 用户缓存目录 ==========
|
||||||
|
- /root/.cache
|
||||||
|
- /root/.npm
|
||||||
|
- /root/.local
|
||||||
|
- /home/*/.cache
|
||||||
|
- /home/*/.npm
|
||||||
|
- /home/*/.local
|
||||||
|
- /home/*/.gradle
|
||||||
|
- /home/*/.m2
|
||||||
|
|
||||||
|
# ========== 其他高频变化目录 ==========
|
||||||
|
- /var/run
|
||||||
|
- /var/lock
|
||||||
|
- /opt/*/cache
|
||||||
|
- /opt/*/logs
|
||||||
fast_hash: true
|
fast_hash: true
|
||||||
fast_hash_size: 100MB
|
fast_hash_size: 100MB
|
||||||
fast_hash_chunk: 2MB
|
fast_hash_chunk: 2MB
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,9 @@ func (s *Scanner) Scan() ([]FileInfo, error) {
|
||||||
var allFiles []FileInfo
|
var allFiles []FileInfo
|
||||||
hashCfg, _ := s.cfg.GetHashConfig()
|
hashCfg, _ := s.cfg.GetHashConfig()
|
||||||
|
|
||||||
bar := progressbar.NewOptions(len(allPaths),
|
var bar *progressbar.ProgressBar
|
||||||
|
if isInteractiveTerminal() {
|
||||||
|
bar = progressbar.NewOptions(len(allPaths),
|
||||||
progressbar.OptionSetDescription("[scan]计算文件哈希"),
|
progressbar.OptionSetDescription("[scan]计算文件哈希"),
|
||||||
progressbar.OptionSetWriter(os.Stderr),
|
progressbar.OptionSetWriter(os.Stderr),
|
||||||
progressbar.OptionShowCount(),
|
progressbar.OptionShowCount(),
|
||||||
|
|
@ -66,9 +68,14 @@ func (s *Scanner) Scan() ([]FileInfo, error) {
|
||||||
logger.Log.Info("[scan]文件哈希计算完成")
|
logger.Log.Info("[scan]文件哈希计算完成")
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
logger.Log.Info("[scan]开始计算文件哈希", zap.Int("total_files", len(allPaths)))
|
||||||
|
}
|
||||||
|
|
||||||
for _, path := range allPaths {
|
for _, path := range allPaths {
|
||||||
|
if bar != nil {
|
||||||
bar.Add(1)
|
bar.Add(1)
|
||||||
|
}
|
||||||
|
|
||||||
info, err := os.Stat(path)
|
info, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -155,6 +162,17 @@ func (s *Scanner) collectPathsFunc(result *[]string) fs.WalkDirFunc {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info, err := d.Info()
|
||||||
|
if err == nil {
|
||||||
|
if info.Mode()&os.ModeSymlink != 0 {
|
||||||
|
realInfo, err := os.Stat(path)
|
||||||
|
if err == nil && realInfo.IsDir() {
|
||||||
|
logger.Log.Debug("[scan]跳过指向目录的符号链接", zap.String("path", path))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, exclude := range s.cfg.Scanner.File.ExcludePaths {
|
for _, exclude := range s.cfg.Scanner.File.ExcludePaths {
|
||||||
if strings.HasPrefix(path, exclude) {
|
if strings.HasPrefix(path, exclude) {
|
||||||
logger.Log.Debug("[scan]跳过路径", zap.String("path", path), zap.String("reason", "匹配排除路径"))
|
logger.Log.Debug("[scan]跳过路径", zap.String("path", path), zap.String("reason", "匹配排除路径"))
|
||||||
|
|
@ -167,6 +185,15 @@ func (s *Scanner) collectPathsFunc(result *[]string) fs.WalkDirFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isInteractiveTerminal() bool {
|
||||||
|
fileInfo, err := os.Stderr.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return (fileInfo.Mode() & os.ModeCharDevice) != 0
|
||||||
|
}
|
||||||
|
|
||||||
func (f FileInfo) String() string {
|
func (f FileInfo) String() string {
|
||||||
return fmt.Sprintf("%s:%s", f.Path, f.Hash)
|
return fmt.Sprintf("%s:%s", f.Path, f.Hash)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# sysmonitord 卸载脚本
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "正在卸载 sysmonitord..."
|
||||||
|
|
||||||
|
# 检测是否为 root 用户
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo "请使用 root 用户运行此卸载脚本。"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 路径设置
|
||||||
|
BIN_NAME="sysmonitord"
|
||||||
|
INSTALL_DIR="/usr/local/bin"
|
||||||
|
CONFIG_DIR="/etc/sysmonitord"
|
||||||
|
DATA_DIR="/var/lib/sysmonitord"
|
||||||
|
LOG_DIR="/var/log/sysmonitord"
|
||||||
|
SERVICE_FILE="/etc/systemd/system/sysmonitord.service"
|
||||||
|
|
||||||
|
# 停止并禁用服务
|
||||||
|
if systemctl is-active --quiet sysmonitord; then
|
||||||
|
echo "正在停止 sysmonitord 服务..."
|
||||||
|
systemctl stop sysmonitord
|
||||||
|
fi
|
||||||
|
|
||||||
|
if systemctl is-enabled --quiet sysmonitord 2>/dev/null; then
|
||||||
|
echo "正在禁用 sysmonitord 服务..."
|
||||||
|
systemctl disable sysmonitord
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 删除 systemd 服务文件
|
||||||
|
if [ -f "$SERVICE_FILE" ]; then
|
||||||
|
echo "正在删除 systemd 服务文件..."
|
||||||
|
rm -f "$SERVICE_FILE"
|
||||||
|
systemctl daemon-reload
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 删除可执行文件
|
||||||
|
if [ -f "$INSTALL_DIR/$BIN_NAME" ]; then
|
||||||
|
echo "正在删除可执行文件..."
|
||||||
|
rm -f "$INSTALL_DIR/$BIN_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 询问是否删除数据文件
|
||||||
|
echo ""
|
||||||
|
read -p "是否删除所有数据文件(包括配置、数据和日志)?[y/N] " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo "正在删除数据文件..."
|
||||||
|
rm -rf "$CONFIG_DIR"
|
||||||
|
rm -rf "$DATA_DIR"
|
||||||
|
rm -rf "$LOG_DIR"
|
||||||
|
echo "数据文件已删除。"
|
||||||
|
else
|
||||||
|
echo "保留数据文件。"
|
||||||
|
echo "配置文件目录: $CONFIG_DIR"
|
||||||
|
echo "数据目录: $DATA_DIR"
|
||||||
|
echo "日志目录: $LOG_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "sysmonitord 卸载完成!"
|
||||||
Loading…
Reference in New Issue
Block a user