1
0
out-of-tree/main.go

202 lines
4.7 KiB
Go
Raw Normal View History

2023-01-31 07:13:33 +00:00
// Copyright 2023 Mikhail Klementev. All rights reserved.
2018-10-08 20:51:32 +00:00
// Use of this source code is governed by a AGPLv3 license
// (or later) that can be found in the LICENSE file.
package main
import (
2018-12-10 02:51:15 +00:00
"fmt"
2023-04-06 17:32:42 +00:00
"io"
"math/rand"
"net/url"
2023-03-18 21:30:07 +00:00
"os"
"os/exec"
2023-04-06 17:32:42 +00:00
"os/user"
2023-05-11 02:42:34 +00:00
"path/filepath"
2023-04-06 12:50:44 +00:00
"runtime/debug"
2023-03-19 13:14:14 +00:00
"strconv"
"time"
2023-04-06 17:32:42 +00:00
"github.com/natefinch/lumberjack"
2023-03-18 21:30:07 +00:00
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
2023-01-31 07:13:33 +00:00
"github.com/alecthomas/kong"
2018-11-17 20:18:50 +00:00
2023-05-13 10:46:43 +00:00
"code.dumpstack.io/tools/out-of-tree/cache"
2019-02-02 21:24:29 +00:00
"code.dumpstack.io/tools/out-of-tree/config"
"code.dumpstack.io/tools/out-of-tree/container"
"code.dumpstack.io/tools/out-of-tree/fs"
)
2023-01-31 07:13:33 +00:00
type Globals struct {
Config config.OutOfTree `help:"path to out-of-tree configuration" default:"~/.out-of-tree/out-of-tree.toml"`
2023-01-31 07:13:33 +00:00
WorkDir string `help:"path to work directory" default:"./" type:"path"`
2023-05-13 10:46:43 +00:00
CacheURL url.URL
2023-01-31 07:13:33 +00:00
}
2023-01-31 07:13:33 +00:00
type CLI struct {
Globals
2023-04-06 19:05:21 +00:00
Pew PewCmd `cmd:"" help:"build, run, and test module/exploit"`
Kernel KernelCmd `cmd:"" help:"manipulate kernels"`
Debug DebugCmd `cmd:"" help:"debug environment"`
Log LogCmd `cmd:"" help:"query logs"`
Pack PackCmd `cmd:"" help:"exploit pack test"`
Gen GenCmd `cmd:"" help:"generate .out-of-tree.toml skeleton"`
Image ImageCmd `cmd:"" help:"manage images"`
Container ContainerCmd `cmd:"" help:"manage containers"`
Distro DistroCmd `cmd:"" help:"distro-related helpers" hidden:""`
2023-01-31 07:13:33 +00:00
Version VersionFlag `name:"version" help:"print version information and quit"`
2023-03-18 21:53:53 +00:00
2023-04-06 18:00:46 +00:00
LogLevel LogLevelFlag `enum:"trace,debug,info,warn,error" default:"info"`
ContainerRuntime string `enum:"podman,docker" default:"podman"`
2023-03-18 21:53:53 +00:00
}
type LogLevelFlag string
func (loglevel LogLevelFlag) AfterApply() error {
switch loglevel {
2023-04-06 18:00:46 +00:00
case "debug", "trace":
zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
short := file
for i := len(file) - 1; i > 0; i-- {
if file[i] == '/' {
short = file[i+1:]
break
}
}
file = short
return file + ":" + strconv.Itoa(line)
}
log.Logger = log.With().Caller().Logger()
2023-03-18 21:53:53 +00:00
}
return nil
}
2023-01-31 07:13:33 +00:00
type VersionFlag string
2018-12-10 02:51:15 +00:00
2023-01-31 07:13:33 +00:00
func (v VersionFlag) Decode(ctx *kong.DecodeContext) error { return nil }
func (v VersionFlag) IsBool() bool { return true }
func (v VersionFlag) BeforeApply(app *kong.Kong, vars kong.Vars) error {
fmt.Println(vars["version"])
app.Exit(0)
return nil
}
2023-04-06 17:32:42 +00:00
type LevelWriter struct {
io.Writer
Level zerolog.Level
}
2019-08-16 00:04:57 +00:00
2023-04-06 17:32:42 +00:00
func (lw *LevelWriter) WriteLevel(l zerolog.Level, p []byte) (n int, err error) {
if l >= lw.Level {
return lw.Writer.Write(p)
}
return len(p), nil
}
var consoleWriter, fileWriter LevelWriter
var loglevel zerolog.Level
2023-04-06 17:32:42 +00:00
func main() {
rand.Seed(time.Now().UnixNano())
2023-01-31 07:13:33 +00:00
cli := CLI{}
ctx := kong.Parse(&cli,
kong.Name("out-of-tree"),
kong.Description("kernel {module, exploit} development tool"),
kong.UsageOnError(),
kong.ConfigureHelp(kong.HelpOptions{
Compact: true,
}),
kong.Vars{
2023-04-26 14:36:25 +00:00
"version": "2.1.2",
2023-01-31 07:13:33 +00:00
},
2018-10-27 08:14:10 +00:00
)
2023-04-06 17:32:42 +00:00
switch cli.LogLevel {
2023-04-06 18:00:46 +00:00
case "trace":
loglevel = zerolog.TraceLevel
2023-04-06 17:32:42 +00:00
case "debug":
loglevel = zerolog.DebugLevel
case "info":
loglevel = zerolog.InfoLevel
case "warn":
loglevel = zerolog.WarnLevel
case "error":
loglevel = zerolog.ErrorLevel
}
usr, err := user.Current()
if err != nil {
return
}
consoleWriter = LevelWriter{Writer: zerolog.NewConsoleWriter(
func(w *zerolog.ConsoleWriter) {
w.Out = os.Stderr
2023-04-06 17:32:42 +00:00
},
),
Level: loglevel,
}
fileWriter = LevelWriter{Writer: &lumberjack.Logger{
Filename: usr.HomeDir + "/.out-of-tree/logs/out-of-tree.log",
},
Level: zerolog.TraceLevel,
}
log.Logger = log.Output(zerolog.MultiLevelWriter(
&consoleWriter,
&fileWriter,
2023-04-06 17:32:42 +00:00
))
2023-04-06 18:13:56 +00:00
log.Trace().Msg("start out-of-tree")
2023-04-06 17:32:42 +00:00
log.Debug().Msgf("%v", os.Args)
log.Debug().Msgf("%v", cli)
2023-04-06 12:50:44 +00:00
if buildInfo, ok := debug.ReadBuildInfo(); ok {
log.Debug().Msgf("%v", buildInfo.GoVersion)
log.Debug().Msgf("%v", buildInfo.Settings)
}
2023-05-11 02:42:34 +00:00
path := filepath.Join(usr.HomeDir, ".out-of-tree")
yes, err := fs.CaseInsensitive(path)
2023-05-11 02:42:34 +00:00
if err != nil {
log.Fatal().Err(err).Msg(path)
}
if yes {
log.Warn().Msg("case-insensitive file system not supported")
}
_, err = exec.LookPath(cli.ContainerRuntime)
if err != nil {
if cli.ContainerRuntime == "podman" { // default value
log.Debug().Msgf("podman is not found in $PATH, " +
"fall back to docker")
cli.ContainerRuntime = "docker"
}
_, err = exec.LookPath(cli.ContainerRuntime)
if err != nil {
log.Fatal().Msgf("%v is not found in $PATH",
cli.ContainerRuntime)
}
}
container.Runtime = cli.ContainerRuntime
if cli.Globals.CacheURL.String() != "" {
cache.URL = cli.Globals.CacheURL.String()
}
log.Debug().Msgf("set cache url to %s", cache.URL)
2023-05-13 10:46:43 +00:00
2023-04-06 17:32:42 +00:00
err = ctx.Run(&cli.Globals)
2023-01-31 07:13:33 +00:00
ctx.FatalIfErrorf(err)
}