blob: 5107e3b8598ba4065161285a19d881f5ccd8e1c3 [file] [log] [blame]
David K. Bainbridge528b3182017-01-23 08:51:59 -08001// Copyright 2015 Canonical Ltd.
2// Licensed under the LGPLv3, see LICENCE file for details.
3
4package utils
5
6import (
7 "os"
8 "os/user"
9
10 "github.com/juju/errors"
11)
12
13// ResolveSudo returns the original username if sudo was used. The
14// original username is extracted from the OS environment.
15func ResolveSudo(username string) string {
16 return resolveSudo(username, os.Getenv)
17}
18
19func resolveSudo(username string, getenvFunc func(string) string) string {
20 if username != "root" {
21 return username
22 }
23 // sudo was probably called, get the original user.
24 if username := getenvFunc("SUDO_USER"); username != "" {
25 return username
26 }
27 return username
28}
29
30// EnvUsername returns the username from the OS environment.
31func EnvUsername() (string, error) {
32 return os.Getenv("USER"), nil
33}
34
35// OSUsername returns the username of the current OS user (based on UID).
36func OSUsername() (string, error) {
37 u, err := user.Current()
38 if err != nil {
39 return "", errors.Trace(err)
40 }
41 return u.Username, nil
42}
43
44// ResolveUsername returns the username determined by the provided
45// functions. The functions are tried in the same order in which they
46// were passed in. An error returned from any of them is immediately
47// returned. If an empty string is returned then that signals that the
48// function did not find the username and the next function is tried.
49// Once a username is found, the provided resolveSudo func (if any) is
50// called with that username and the result is returned. If no username
51// is found then errors.NotFound is returned.
52func ResolveUsername(resolveSudo func(string) string, usernameFuncs ...func() (string, error)) (string, error) {
53 for _, usernameFunc := range usernameFuncs {
54 username, err := usernameFunc()
55 if err != nil {
56 return "", errors.Trace(err)
57 }
58 if username != "" {
59 if resolveSudo != nil {
60 if original := resolveSudo(username); original != "" {
61 username = original
62 }
63 }
64 return username, nil
65 }
66 }
67 return "", errors.NotFoundf("username")
68}
69
70// LocalUsername determines the current username on the local host.
71func LocalUsername() (string, error) {
72 username, err := ResolveUsername(ResolveSudo, EnvUsername, OSUsername)
73 if err != nil {
74 return "", errors.Annotatef(err, "cannot get current user from the environment: %v", os.Environ())
75 }
76 return username, nil
77}