(key string, s state)
| 321 | } |
| 322 | |
| 323 | func saveState(key string, s state) { |
| 324 | path := statePath(key) |
| 325 | data, err := json.MarshalIndent(s, "", " ") |
| 326 | if err != nil { |
| 327 | err = taskError(key, fmt.Errorf("save state file: %v", err)) |
| 328 | slog.Error("not saving setup task state", "err", err, "task", key) |
| 329 | return |
| 330 | } |
| 331 | |
| 332 | err = os.MkdirAll(filepath.Dir(path), 0o755) |
| 333 | if err == nil { |
| 334 | err = os.WriteFile(path, data, 0o644) |
| 335 | } |
| 336 | if err != nil { |
| 337 | err = taskError(key, fmt.Errorf("save state file: %v", err)) |
| 338 | slog.Error("not saving setup task state", "err", err, "task", key) |
| 339 | return |
| 340 | } |
| 341 | |
| 342 | sudoUID, sudoGID := os.Getenv("SUDO_UID"), os.Getenv("SUDO_GID") |
| 343 | if sudoUID != "" || sudoGID != "" { |
| 344 | uid, err := strconv.Atoi(sudoUID) |
| 345 | if err != nil { |
| 346 | uid = -1 |
| 347 | } |
| 348 | gid, err := strconv.Atoi(sudoGID) |
| 349 | if err != nil { |
| 350 | gid = -1 |
| 351 | } |
| 352 | err = os.Chown(path, uid, gid) |
| 353 | if err != nil { |
| 354 | err = taskError(key, fmt.Errorf("chown state file to non-sudo user: %v", err)) |
| 355 | slog.Error("cannot ensure task state is owned by sudoing user", "err", err, "task", key, "uid", sudoUID, "gid", sudoGID) |
| 356 | } |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | func statePath(key string) string { |
| 361 | dir := xdg.StateSubpath("devbox") |
no test coverage detected