github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/utils/host/host.go (about) 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. 23 package host 24 25 import ( 26 "fmt" 27 "os" 28 "path/filepath" 29 "strings" 30 31 "github.com/spf13/cobra" 32 ) 33 34 var ( 35 HostRoot string 36 HostProcFs string 37 ) 38 39 func init() { 40 // Initialize HostRoot and HostProcFs 41 HostRoot = os.Getenv("HOST_ROOT") 42 if HostRoot == "" { 43 HostRoot = "/" 44 } 45 HostProcFs = filepath.Join(HostRoot, "/proc") 46 } 47 48 type 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 57 AutoMountFilesystems bool 58 } 59 60 var ( 61 autoSdUnitRestartFlag bool 62 autoMountFilesystemsFlag bool 63 autoWSLWorkaroundFlag bool 64 65 initDone bool 66 ) 67 68 func Init(config Config) error { 69 var 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. 74 if initDone { 75 return nil 76 } 77 78 // Apply systemd workaround first because it might start a new process and 79 // exit before the other workarounds. 80 if autoSdUnitRestartFlag { 81 exit, err := autoSdUnitRestart() 82 if exit { 83 if err != nil { 84 fmt.Fprintf(os.Stderr, "error: %v\n", err) 85 os.Exit(1) 86 } 87 os.Exit(0) 88 } 89 if err != nil { 90 return err 91 } 92 } else { 93 if err := suggestSdUnitRestart(); err != nil { 94 fmt.Fprintf(os.Stderr, "error: %v\n", err) 95 os.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). 101 if config.AutoMountFilesystems || autoMountFilesystemsFlag { 102 _, err = autoMountFilesystems(false) 103 if err != nil { 104 return err 105 } 106 } else { 107 mountsSuggested, err := autoMountFilesystems(true) 108 if err != nil { 109 fmt.Fprintf(os.Stderr, "error: %v\n", err) 110 os.Exit(1) 111 } 112 if len(mountsSuggested) != 0 { 113 fmt.Fprintf(os.Stderr, "error: filesystems %s not mounted (did you try --auto-mount-filesystems?)\n", strings.Join(mountsSuggested, ", ")) 114 os.Exit(1) 115 } 116 } 117 118 // The WSL workaround is applied with the flag (in ig). 119 if autoWSLWorkaroundFlag { 120 err = autoWSLWorkaround() 121 if err != nil { 122 return err 123 } 124 } else { 125 err = suggestWSLWorkaround() 126 if err != nil { 127 fmt.Fprintf(os.Stderr, "error: %v\n", err) 128 os.Exit(1) 129 } 130 } 131 132 initDone = true 133 return nil 134 } 135 136 // AddFlags adds CLI flags for various workarounds 137 func AddFlags(command *cobra.Command) { 138 command.PersistentFlags().BoolVarP( 139 &autoSdUnitRestartFlag, 140 "auto-sd-unit-restart", 141 "", 142 false, 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. 147 automountFilesystemsDefault := false 148 if HostRoot != "" && HostRoot != "/" { 149 automountFilesystemsDefault = true 150 } 151 command.PersistentFlags().BoolVarP( 152 &autoMountFilesystemsFlag, 153 "auto-mount-filesystems", 154 "", 155 automountFilesystemsDefault, 156 "Automatically mount bpffs, debugfs and tracefs if they are not already mounted", 157 ) 158 command.PersistentFlags().BoolVarP( 159 &autoWSLWorkaroundFlag, 160 "auto-wsl-workaround", 161 "", 162 false, 163 "Automatically find the host procfs when running in WSL2", 164 ) 165 } 166 167 func GetProcComm(pid int) string { 168 pidStr := fmt.Sprint(pid) 169 commBytes, _ := os.ReadFile(filepath.Join(HostProcFs, pidStr, "comm")) 170 return strings.TrimRight(string(commBytes), "\n") 171 } 172 173 func GetProcCmdline(pid int) []string { 174 pidStr := fmt.Sprint(pid) 175 cmdlineBytes, _ := os.ReadFile(filepath.Join(HostProcFs, pidStr, "cmdline")) 176 return strings.Split(string(cmdlineBytes), "\x00") 177 }