github.com/c0deoo1/golang1.5@v0.0.0-20220525150107-c87c805d4593/src/os/user/lookup_unix.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
     6  // +build cgo
     7  
     8  package user
     9  
    10  import (
    11  	"fmt"
    12  	"runtime"
    13  	"strconv"
    14  	"strings"
    15  	"syscall"
    16  	"unsafe"
    17  )
    18  
    19  /*
    20  #cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS
    21  #include <unistd.h>
    22  #include <sys/types.h>
    23  #include <pwd.h>
    24  #include <stdlib.h>
    25  
    26  static int mygetpwuid_r(int uid, struct passwd *pwd,
    27  	char *buf, size_t buflen, struct passwd **result) {
    28  	return getpwuid_r(uid, pwd, buf, buflen, result);
    29  }
    30  
    31  static int mygetpwnam_r(const char *name, struct passwd *pwd,
    32  	char *buf, size_t buflen, struct passwd **result) {
    33  	return getpwnam_r(name, pwd, buf, buflen, result);
    34  }
    35  */
    36  import "C"
    37  
    38  func current() (*User, error) {
    39  	return lookupUnix(syscall.Getuid(), "", false)
    40  }
    41  
    42  func lookup(username string) (*User, error) {
    43  	return lookupUnix(-1, username, true)
    44  }
    45  
    46  func lookupId(uid string) (*User, error) {
    47  	i, e := strconv.Atoi(uid)
    48  	if e != nil {
    49  		return nil, e
    50  	}
    51  	return lookupUnix(i, "", false)
    52  }
    53  
    54  func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {
    55  	var pwd C.struct_passwd
    56  	var result *C.struct_passwd
    57  
    58  	var bufSize C.long
    59  	if runtime.GOOS == "dragonfly" || runtime.GOOS == "freebsd" {
    60  		// DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX
    61  		// and just return -1.  So just use the same
    62  		// size that Linux returns.
    63  		bufSize = 1024
    64  	} else {
    65  		bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX)
    66  		if bufSize <= 0 || bufSize > 1<<20 {
    67  			return nil, fmt.Errorf("user: unreasonable _SC_GETPW_R_SIZE_MAX of %d", bufSize)
    68  		}
    69  	}
    70  	buf := C.malloc(C.size_t(bufSize))
    71  	defer C.free(buf)
    72  	var rv C.int
    73  	if lookupByName {
    74  		nameC := C.CString(username)
    75  		defer C.free(unsafe.Pointer(nameC))
    76  		// mygetpwnam_r is a wrapper around getpwnam_r to avoid
    77  		// passing a size_t to getpwnam_r, because for unknown
    78  		// reasons passing a size_t to getpwnam_r doesn't work on
    79  		// Solaris.
    80  		rv = C.mygetpwnam_r(nameC,
    81  			&pwd,
    82  			(*C.char)(buf),
    83  			C.size_t(bufSize),
    84  			&result)
    85  		if rv != 0 {
    86  			return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.Errno(rv))
    87  		}
    88  		if result == nil {
    89  			return nil, UnknownUserError(username)
    90  		}
    91  	} else {
    92  		// mygetpwuid_r is a wrapper around getpwuid_r to
    93  		// to avoid using uid_t because C.uid_t(uid) for
    94  		// unknown reasons doesn't work on linux.
    95  		rv = C.mygetpwuid_r(C.int(uid),
    96  			&pwd,
    97  			(*C.char)(buf),
    98  			C.size_t(bufSize),
    99  			&result)
   100  		if rv != 0 {
   101  			return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.Errno(rv))
   102  		}
   103  		if result == nil {
   104  			return nil, UnknownUserIdError(uid)
   105  		}
   106  	}
   107  	u := &User{
   108  		Uid:      strconv.Itoa(int(pwd.pw_uid)),
   109  		Gid:      strconv.Itoa(int(pwd.pw_gid)),
   110  		Username: C.GoString(pwd.pw_name),
   111  		Name:     C.GoString(pwd.pw_gecos),
   112  		HomeDir:  C.GoString(pwd.pw_dir),
   113  	}
   114  	// The pw_gecos field isn't quite standardized.  Some docs
   115  	// say: "It is expected to be a comma separated list of
   116  	// personal data where the first item is the full name of the
   117  	// user."
   118  	if i := strings.Index(u.Name, ","); i >= 0 {
   119  		u.Name = u.Name[:i]
   120  	}
   121  	return u, nil
   122  }