github.com/haraldrudell/parl@v0.4.176/pos/homedir.go (about)

     1  /*
     2  © 2021–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  // Package parlos provides simplified functions for home-directory and hostname.
     7  package pos
     8  
     9  import (
    10  	"errors"
    11  	"os"
    12  	"os/user"
    13  	"path"
    14  	"strconv"
    15  
    16  	"github.com/haraldrudell/parl/perrors"
    17  )
    18  
    19  // UserHomeDir obtains the absolute path to the process owning user’s
    20  // home directory
    21  //   - does not rely on environment
    22  //   - should never fail. if it does, panic is thrown
    23  func UserHomeDir() (homeDir string) {
    24  
    25  	// try getting home directory from account configuration
    26  	homeDir = getProcessOwnerHomeDir()
    27  
    28  	// if that fails, try shell environment
    29  	if homeDir == "" {
    30  		var err error
    31  		homeDir, err = os.UserHomeDir() // use $HOME environment variable
    32  		if err != nil {
    33  			panic(perrors.Errorf("os.UserHomeDir: '%w'", err))
    34  		}
    35  		if homeDir == "" {
    36  			panic(perrors.New("failed to obtain home directory"))
    37  		}
    38  	}
    39  	return
    40  }
    41  
    42  // UserHome obtains the absolute path to the process owning user’s
    43  // home directory
    44  //   - does not rely on environment
    45  func UserHome() (homeDir string, err error) {
    46  	if homeDir = getProcessOwnerHomeDir(); homeDir == "" {
    47  		err = perrors.NewPF("failed to obtain user ID or userData")
    48  	}
    49  	return
    50  }
    51  
    52  // HomeDir creates levels of directories in users’s home.
    53  // if directories do not exist, they are created with permissions u=rwx.
    54  // This should never fail, when it does, panic is thrown
    55  func HomeDir(relPaths string) (dir string) {
    56  	homeDir := UserHomeDir()
    57  	dir = path.Join(homeDir, relPaths)
    58  	if err := os.MkdirAll(dir, 0700); err != nil {
    59  		if !errors.Is(err, os.ErrExist) {
    60  			panic(perrors.Errorf("os.MkdirAll: %w", err))
    61  		}
    62  	}
    63  	return
    64  }
    65  
    66  // getProcessOwnerHomeDir retrives a user’s home directory
    67  // based on account configuration.
    68  // This is required for Linux system services that do not
    69  // have an environment
    70  // Best effort: errors are ignored
    71  func getProcessOwnerHomeDir() (homeDir string) {
    72  
    73  	// get process user ID
    74  	userID := os.Geteuid()
    75  	if userID == -1 { // on Windows, -1 is returned
    76  		return // FAIL: user ID not found
    77  	}
    78  
    79  	// lookup the user ID
    80  	userdata, err := user.LookupId(strconv.Itoa(userID))
    81  	if err != nil {
    82  		return // FAIL: user data not found
    83  	}
    84  
    85  	return userdata.HomeDir // path to the user's home directory
    86  }