inspektor-gadget
177 строк · 4.5 Кб
1//go:build linux
2// +build linux
3
4// Copyright 2023 The Inspektor Gadget authors
5//
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18// Package host provides ways to access the host filesystem.
19//
20// Inspektor Gadget can run either in the host or in a container. When running
21// in a container, the host filesystem must be available in a specific
22// directory.
23package host
24
25import (
26"fmt"
27"os"
28"path/filepath"
29"strings"
30
31"github.com/spf13/cobra"
32)
33
34var (
35HostRoot string
36HostProcFs string
37)
38
39func init() {
40// Initialize HostRoot and HostProcFs
41HostRoot = os.Getenv("HOST_ROOT")
42if HostRoot == "" {
43HostRoot = "/"
44}
45HostProcFs = filepath.Join(HostRoot, "/proc")
46}
47
48type Config struct {
49// AutoMountFilesystems will automatically mount bpffs, debugfs and
50// tracefs if they are not already mounted.
51//
52// This is useful for some environments where those filesystems are not
53// mounted by default on the host, such as:
54// - minikube with the Docker driver
55// - Docker Desktop with WSL2
56// - Talos Linux
57AutoMountFilesystems bool
58}
59
60var (
61autoSdUnitRestartFlag bool
62autoMountFilesystemsFlag bool
63autoWSLWorkaroundFlag bool
64
65initDone bool
66)
67
68func Init(config Config) error {
69var err error
70
71// Init() is called both from the local runtime and the local manager operator.
72// Different gadgets (trace-exec and top-ebpf) have different code paths, and we need both to make both work.
73// TODO: understand why we need to call Init() twice and fix it.
74if initDone {
75return nil
76}
77
78// Apply systemd workaround first because it might start a new process and
79// exit before the other workarounds.
80if autoSdUnitRestartFlag {
81exit, err := autoSdUnitRestart()
82if exit {
83if err != nil {
84fmt.Fprintf(os.Stderr, "error: %v\n", err)
85os.Exit(1)
86}
87os.Exit(0)
88}
89if err != nil {
90return err
91}
92} else {
93if err := suggestSdUnitRestart(); err != nil {
94fmt.Fprintf(os.Stderr, "error: %v\n", err)
95os.Exit(1)
96}
97}
98
99// The mount workaround could either be applied unconditionally (in the
100// gadget DaemonSet) or with the flag (in ig).
101if config.AutoMountFilesystems || autoMountFilesystemsFlag {
102_, err = autoMountFilesystems(false)
103if err != nil {
104return err
105}
106} else {
107mountsSuggested, err := autoMountFilesystems(true)
108if err != nil {
109fmt.Fprintf(os.Stderr, "error: %v\n", err)
110os.Exit(1)
111}
112if len(mountsSuggested) != 0 {
113fmt.Fprintf(os.Stderr, "error: filesystems %s not mounted (did you try --auto-mount-filesystems?)\n", strings.Join(mountsSuggested, ", "))
114os.Exit(1)
115}
116}
117
118// The WSL workaround is applied with the flag (in ig).
119if autoWSLWorkaroundFlag {
120err = autoWSLWorkaround()
121if err != nil {
122return err
123}
124} else {
125err = suggestWSLWorkaround()
126if err != nil {
127fmt.Fprintf(os.Stderr, "error: %v\n", err)
128os.Exit(1)
129}
130}
131
132initDone = true
133return nil
134}
135
136// AddFlags adds CLI flags for various workarounds
137func AddFlags(command *cobra.Command) {
138command.PersistentFlags().BoolVarP(
139&autoSdUnitRestartFlag,
140"auto-sd-unit-restart",
141"",
142false,
143"Automatically run in a privileged systemd unit if lacking enough capabilities",
144)
145
146// Enable the mount workaround by default when running inside a container.
147automountFilesystemsDefault := false
148if HostRoot != "" && HostRoot != "/" {
149automountFilesystemsDefault = true
150}
151command.PersistentFlags().BoolVarP(
152&autoMountFilesystemsFlag,
153"auto-mount-filesystems",
154"",
155automountFilesystemsDefault,
156"Automatically mount bpffs, debugfs and tracefs if they are not already mounted",
157)
158command.PersistentFlags().BoolVarP(
159&autoWSLWorkaroundFlag,
160"auto-wsl-workaround",
161"",
162false,
163"Automatically find the host procfs when running in WSL2",
164)
165}
166
167func GetProcComm(pid int) string {
168pidStr := fmt.Sprint(pid)
169commBytes, _ := os.ReadFile(filepath.Join(HostProcFs, pidStr, "comm"))
170return strings.TrimRight(string(commBytes), "\n")
171}
172
173func GetProcCmdline(pid int) []string {
174pidStr := fmt.Sprint(pid)
175cmdlineBytes, _ := os.ReadFile(filepath.Join(HostProcFs, pidStr, "cmdline"))
176return strings.Split(string(cmdlineBytes), "\x00")
177}
178