SudoDevbox relaunches Devbox as root using sudo, taking care to preserve Devbox environment variables that can affect the new process. If the current user is already root, then it returns (false, nil) to indicate that no sudo process ran. The caller can use this as a hint to know if it's running as
(ctx context.Context, arg ...string)
| 142 | // the sudo process without re-prompting the user or a second call to its |
| 143 | // NeedsRun method. |
| 144 | func SudoDevbox(ctx context.Context, arg ...string) (ran bool, err error) { |
| 145 | if os.Getuid() == 0 { |
| 146 | return false, nil |
| 147 | } |
| 148 | |
| 149 | taskKey := "" |
| 150 | if v := ctx.Value(ctxKeyTask); v != nil { |
| 151 | taskKey = v.(string) |
| 152 | } |
| 153 | |
| 154 | // Ensure the state file and its directory exist before sudoing, |
| 155 | // otherwise they will be owned by root. This is easier than recursively |
| 156 | // chowning new directories/files after root creates them. |
| 157 | if taskKey != "" { |
| 158 | saveState(taskKey, state{}) |
| 159 | } |
| 160 | |
| 161 | // Use the absolute path to Devbox instead of relying on PATH for two |
| 162 | // reasons: |
| 163 | // |
| 164 | // 1. sudo isn't guaranteed to preserve the current PATH and the root |
| 165 | // user might not have devbox in its PATH. |
| 166 | // 2. If we're running an alternative version of Devbox |
| 167 | // (such as a dev build) we want to use the same binary. |
| 168 | exe, err := devboxExecutable() |
| 169 | if err != nil { |
| 170 | return false, err |
| 171 | } |
| 172 | |
| 173 | sudoArgs := make([]string, 0, len(arg)+4) |
| 174 | sudoArgs = append(sudoArgs, "--preserve-env="+strings.Join([]string{ |
| 175 | // Keep writing debug logs from the sudo process. |
| 176 | "DEVBOX_DEBUG", |
| 177 | |
| 178 | // Use the same Devbox API and auth token. |
| 179 | "DEVBOX_API_TOKEN", |
| 180 | "DEVBOX_PROD", |
| 181 | |
| 182 | // In case the Devbox version is overridden. |
| 183 | "DEVBOX_USE_VERSION", |
| 184 | |
| 185 | // Use the same XDG directories for state, caching, etc. |
| 186 | "XDG_CACHE_HOME", |
| 187 | "XDG_CONFIG_DIRS", |
| 188 | "XDG_CONFIG_HOME", |
| 189 | "XDG_DATA_DIRS", |
| 190 | "XDG_DATA_HOME", |
| 191 | "XDG_RUNTIME_DIR", |
| 192 | "XDG_STATE_HOME", |
| 193 | }, ",")) |
| 194 | if taskKey != "" { |
| 195 | sudoArgs = append(sudoArgs, "DEVBOX_SUDO_TASK="+taskKey) |
| 196 | } |
| 197 | sudoArgs = append(sudoArgs, "--", exe) |
| 198 | sudoArgs = append(sudoArgs, arg...) |
| 199 | |
| 200 | cmd := exec.CommandContext(ctx, "sudo", sudoArgs...) |
| 201 | cmd.Stdin = os.Stdin |