github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podman/main_local.go (about) 1 // +build !remoteclient 2 // +build linux 3 4 package main 5 6 import ( 7 "context" 8 "fmt" 9 "io/ioutil" 10 "log/syslog" 11 "os" 12 "runtime/pprof" 13 "strconv" 14 "syscall" 15 16 "github.com/containers/common/pkg/config" 17 "github.com/containers/libpod/cmd/podman/cliconfig" 18 "github.com/containers/libpod/cmd/podman/libpodruntime" 19 "github.com/containers/libpod/pkg/cgroups" 20 "github.com/containers/libpod/pkg/rootless" 21 "github.com/containers/libpod/pkg/tracing" 22 "github.com/containers/libpod/pkg/util" 23 "github.com/containers/libpod/utils" 24 "github.com/opentracing/opentracing-go" 25 "github.com/pkg/errors" 26 "github.com/sirupsen/logrus" 27 lsyslog "github.com/sirupsen/logrus/hooks/syslog" 28 "github.com/spf13/cobra" 29 ) 30 31 const remote = false 32 33 func init() { 34 cgroupManager := defaultContainerConfig.Engine.CgroupManager 35 cgroupHelp := `Cgroup manager to use ("cgroupfs"|"systemd")` 36 cgroupv2, _ := cgroups.IsCgroup2UnifiedMode() 37 38 defaultContainerConfig = cliconfig.GetDefaultConfig() 39 if rootless.IsRootless() && !cgroupv2 { 40 cgroupManager = "" 41 cgroupHelp = "Cgroup manager is not supported in rootless mode" 42 } 43 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.CGroupManager, "cgroup-manager", cgroupManager, cgroupHelp) 44 // -c is deprecated due to conflict with -c on subcommands 45 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.CpuProfile, "cpu-profile", "", "Path for the cpu profiling results") 46 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.ConmonPath, "conmon", "", "Path of the conmon binary") 47 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.NetworkCmdPath, "network-cmd-path", defaultContainerConfig.Engine.NetworkCmdPath, "Path to the command for configuring the network") 48 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.CniConfigDir, "cni-config-dir", getCNIPluginsDir(), "Path of the configuration directory for CNI networks") 49 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.DefaultMountsFile, "default-mounts-file", defaultContainerConfig.Containers.DefaultMountsFile, "Path to default mounts file") 50 if err := rootCmd.PersistentFlags().MarkHidden("cpu-profile"); err != nil { 51 logrus.Error("unable to mark default-mounts-file flag as hidden") 52 } 53 if err := rootCmd.PersistentFlags().MarkHidden("default-mounts-file"); err != nil { 54 logrus.Error("unable to mark default-mounts-file flag as hidden") 55 } 56 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.EventsBackend, "events-backend", defaultContainerConfig.Engine.EventsLogger, `Events backend to use ("file"|"journald"|"none")`) 57 // Override default --help information of `--help` global flag 58 var dummyHelp bool 59 rootCmd.PersistentFlags().BoolVar(&dummyHelp, "help", false, "Help for podman") 60 rootCmd.PersistentFlags().StringSliceVar(&MainGlobalOpts.HooksDir, "hooks-dir", defaultContainerConfig.Engine.HooksDir, "Set the OCI hooks directory path (may be set multiple times)") 61 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.LogLevel, "log-level", "error", `Log messages above specified level ("debug"|"info"|"warn"|"error"|"fatal"|"panic")`) 62 rootCmd.PersistentFlags().IntVar(&MainGlobalOpts.MaxWorks, "max-workers", 0, "The maximum number of workers for parallel operations") 63 if err := rootCmd.PersistentFlags().MarkHidden("max-workers"); err != nil { 64 logrus.Error("unable to mark max-workers flag as hidden") 65 } 66 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Namespace, "namespace", defaultContainerConfig.Engine.Namespace, "Set the libpod namespace, used to create separate views of the containers and pods on the system") 67 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Root, "root", "", "Path to the root directory in which data, including images, is stored") 68 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Runroot, "runroot", "", "Path to the 'run directory' where all state information is stored") 69 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Runtime, "runtime", "", "Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc") 70 // -s is deprecated due to conflict with -s on subcommands 71 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.StorageDriver, "storage-driver", "", "Select which storage driver is used to manage storage of images and containers (default is overlay)") 72 rootCmd.PersistentFlags().StringArrayVar(&MainGlobalOpts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver") 73 rootCmd.PersistentFlags().BoolVar(&MainGlobalOpts.Syslog, "syslog", false, "Output logging information to syslog as well as the console (default false)") 74 75 rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.TmpDir, "tmpdir", "", "Path to the tmp directory for libpod state content.\n\nNote: use the environment variable 'TMPDIR' to change the temporary storage location for container images, '/var/tmp'.\n") 76 rootCmd.PersistentFlags().BoolVar(&MainGlobalOpts.Trace, "trace", false, "Enable opentracing output (default false)") 77 markFlagHidden(rootCmd.PersistentFlags(), "trace") 78 } 79 80 func setSyslog() error { 81 if MainGlobalOpts.Syslog { 82 hook, err := lsyslog.NewSyslogHook("", "", syslog.LOG_INFO, "") 83 if err == nil { 84 logrus.AddHook(hook) 85 return nil 86 } 87 return err 88 } 89 return nil 90 } 91 92 func profileOn(cmd *cobra.Command) error { 93 if cmd.Flag("cpu-profile").Changed { 94 f, err := os.Create(MainGlobalOpts.CpuProfile) 95 if err != nil { 96 return errors.Wrapf(err, "unable to create cpu profiling file %s", 97 MainGlobalOpts.CpuProfile) 98 } 99 if err := pprof.StartCPUProfile(f); err != nil { 100 return err 101 } 102 } 103 104 if cmd.Flag("trace").Changed { 105 var tracer opentracing.Tracer 106 tracer, closer = tracing.Init("podman") 107 opentracing.SetGlobalTracer(tracer) 108 109 span = tracer.StartSpan("before-context") 110 111 Ctx = opentracing.ContextWithSpan(context.Background(), span) 112 } 113 return nil 114 } 115 116 func profileOff(cmd *cobra.Command) error { 117 if cmd.Flag("cpu-profile").Changed { 118 pprof.StopCPUProfile() 119 } 120 if cmd.Flag("trace").Changed { 121 span.Finish() 122 closer.Close() 123 } 124 return nil 125 } 126 127 func movePauseProcessToScope() error { 128 pausePidPath, err := util.GetRootlessPauseProcessPidPath() 129 if err != nil { 130 return errors.Wrapf(err, "could not get pause process pid file path") 131 } 132 133 data, err := ioutil.ReadFile(pausePidPath) 134 if err != nil { 135 return errors.Wrapf(err, "cannot read pause pid file") 136 } 137 pid, err := strconv.ParseUint(string(data), 10, 0) 138 if err != nil { 139 return errors.Wrapf(err, "cannot parse pid file %s", pausePidPath) 140 } 141 142 return utils.RunUnderSystemdScope(int(pid), "user.slice", "podman-pause.scope") 143 } 144 145 func setupRootless(cmd *cobra.Command, args []string) error { 146 if !rootless.IsRootless() { 147 return nil 148 } 149 150 matches, err := rootless.ConfigurationMatches() 151 if err != nil { 152 return err 153 } 154 if !matches { 155 logrus.Warningf("the current user namespace doesn't match the configuration in /etc/subuid or /etc/subgid") 156 logrus.Warningf("you can use `%s system migrate` to recreate the user namespace and restart the containers", os.Args[0]) 157 } 158 159 podmanCmd := cliconfig.PodmanCommand{ 160 Command: cmd, 161 InputArgs: args, 162 GlobalFlags: MainGlobalOpts, 163 Remote: remoteclient, 164 } 165 166 runtime, err := libpodruntime.GetRuntimeNoStore(getContext(), &podmanCmd) 167 if err != nil { 168 return errors.Wrapf(err, "could not get runtime") 169 } 170 defer runtime.DeferredShutdown(false) 171 172 // do it only after podman has already re-execed and running with uid==0. 173 if os.Geteuid() == 0 { 174 ownsCgroup, err := cgroups.UserOwnsCurrentSystemdCgroup() 175 if err != nil { 176 logrus.Warnf("Failed to detect the owner for the current cgroup: %v", err) 177 } 178 if !ownsCgroup { 179 conf, err := runtime.GetConfig() 180 if err != nil { 181 return err 182 } 183 unitName := fmt.Sprintf("podman-%d.scope", os.Getpid()) 184 if err := utils.RunUnderSystemdScope(os.Getpid(), "user.slice", unitName); err != nil { 185 if conf.Engine.CgroupManager == config.SystemdCgroupsManager { 186 logrus.Warnf("Failed to add podman to systemd sandbox cgroup: %v", err) 187 } else { 188 logrus.Debugf("Failed to add podman to systemd sandbox cgroup: %v", err) 189 } 190 } 191 } 192 } 193 194 if !executeCommandInUserNS(cmd) { 195 return nil 196 } 197 198 pausePidPath, err := util.GetRootlessPauseProcessPidPath() 199 if err != nil { 200 return errors.Wrapf(err, "could not get pause process pid file path") 201 } 202 203 became, ret, err := rootless.TryJoinPauseProcess(pausePidPath) 204 if err != nil { 205 return err 206 } 207 if became { 208 os.Exit(ret) 209 } 210 211 // if there is no pid file, try to join existing containers, and create a pause process. 212 ctrs, err := runtime.GetRunningContainers() 213 if err != nil { 214 logrus.Errorf(err.Error()) 215 os.Exit(1) 216 } 217 218 paths := []string{} 219 for _, ctr := range ctrs { 220 paths = append(paths, ctr.Config().ConmonPidFile) 221 } 222 223 became, ret, err = rootless.TryJoinFromFilePaths(pausePidPath, true, paths) 224 if err := movePauseProcessToScope(); err != nil { 225 conf, err := runtime.GetConfig() 226 if err != nil { 227 return err 228 } 229 if conf.Engine.CgroupManager == config.SystemdCgroupsManager { 230 logrus.Warnf("Failed to add pause process to systemd sandbox cgroup: %v", err) 231 } else { 232 logrus.Debugf("Failed to add pause process to systemd sandbox cgroup: %v", err) 233 } 234 } 235 if err != nil { 236 logrus.Errorf(err.Error()) 237 os.Exit(1) 238 } 239 if became { 240 os.Exit(ret) 241 } 242 return nil 243 } 244 245 // Most podman commands when run in rootless mode, need to be executed in the 246 // users usernamespace. This function is updated with a list of commands that 247 // should NOT be run within the user namespace. 248 func executeCommandInUserNS(cmd *cobra.Command) bool { 249 if os.Geteuid() == 0 { 250 return false 251 } 252 switch cmd { 253 case _migrateCommand, 254 _mountCommand, 255 _renumberCommand, 256 _searchCommand, 257 _versionCommand: 258 return false 259 } 260 return true 261 } 262 263 func setRLimits() error { 264 rlimits := new(syscall.Rlimit) 265 rlimits.Cur = 1048576 266 rlimits.Max = 1048576 267 if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil { 268 if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil { 269 return errors.Wrapf(err, "error getting rlimits") 270 } 271 rlimits.Cur = rlimits.Max 272 if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil { 273 return errors.Wrapf(err, "error setting new rlimits") 274 } 275 } 276 return nil 277 } 278 279 func setUMask() { 280 // Be sure we can create directories with 0755 mode. 281 syscall.Umask(0022) 282 } 283 284 // checkInput can be used to verify any of the globalopt values 285 func checkInput() error { 286 return nil 287 } 288 func getCNIPluginsDir() string { 289 if rootless.IsRootless() { 290 return "" 291 } 292 293 return defaultContainerConfig.Network.CNIPluginDirs[0] 294 }