github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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  	"strconv"
    13  	"strings"
    14  	"syscall"
    15  	"unsafe"
    16  )
    17  
    18  /*
    19  #cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS
    20  #include <unistd.h>
    21  #include <sys/types.h>
    22  #include <pwd.h>
    23  #include <stdlib.h>
    24  
    25  static int mygetpwuid_r(int uid, struct passwd *pwd,
    26  	char *buf, size_t buflen, struct passwd **result) {
    27  	return getpwuid_r(uid, pwd, buf, buflen, result);
    28  }
    29  
    30  static int mygetpwnam_r(const char *name, struct passwd *pwd,
    31  	char *buf, size_t buflen, struct passwd **result) {
    32  	return getpwnam_r(name, pwd, buf, buflen, result);
    33  }
    34  */
    35  import "C"
    36  
    37  func current() (*User, error) {
    38  	return lookupUnix(syscall.Getuid(), "", false)
    39  }
    40  
    41  func lookup(username string) (*User, error) {
    42  	return lookupUnix(-1, username, true)
    43  }
    44  
    45  func lookupId(uid string) (*User, error) {
    46  	i, e := strconv.Atoi(uid)
    47  	if e != nil {
    48  		return nil, e
    49  	}
    50  	return lookupUnix(i, "", false)
    51  }
    52  
    53  func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {
    54  	var pwd C.struct_passwd
    55  	var result *C.struct_passwd
    56  
    57  	bufSize := C.sysconf(C._SC_GETPW_R_SIZE_MAX)
    58  	if bufSize == -1 {
    59  		// DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX.
    60  		// Additionally, not all Linux systems have it, either. For
    61  		// example, the musl libc returns -1.
    62  		bufSize = 1024
    63  	}
    64  	if bufSize <= 0 || bufSize > 1<<20 {
    65  		return nil, fmt.Errorf("user: unreasonable _SC_GETPW_R_SIZE_MAX of %d", bufSize)
    66  	}
    67  	buf := C.malloc(C.size_t(bufSize))
    68  	defer C.free(buf)
    69  	var rv C.int
    70  	if lookupByName {
    71  		nameC := C.CString(username)
    72  		defer C.free(unsafe.Pointer(nameC))
    73  		// mygetpwnam_r is a wrapper around getpwnam_r to avoid
    74  		// passing a size_t to getpwnam_r, because for unknown
    75  		// reasons passing a size_t to getpwnam_r doesn't work on
    76  		// Solaris.
    77  		rv = C.mygetpwnam_r(nameC,
    78  			&pwd,
    79  			(*C.char)(buf),
    80  			C.size_t(bufSize),
    81  			&result)
    82  		if rv != 0 {
    83  			return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.Errno(rv))
    84  		}
    85  		if result == nil {
    86  			return nil, UnknownUserError(username)
    87  		}
    88  	} else {
    89  		// mygetpwuid_r is a wrapper around getpwuid_r to
    90  		// to avoid using uid_t because C.uid_t(uid) for
    91  		// unknown reasons doesn't work on linux.
    92  		rv = C.mygetpwuid_r(C.int(uid),
    93  			&pwd,
    94  			(*C.char)(buf),
    95  			C.size_t(bufSize),
    96  			&result)
    97  		if rv != 0 {
    98  			return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.Errno(rv))
    99  		}
   100  		if result == nil {
   101  			return nil, UnknownUserIdError(uid)
   102  		}
   103  	}
   104  	u := &User{
   105  		Uid:      strconv.Itoa(int(pwd.pw_uid)),
   106  		Gid:      strconv.Itoa(int(pwd.pw_gid)),
   107  		Username: C.GoString(pwd.pw_name),
   108  		Name:     C.GoString(pwd.pw_gecos),
   109  		HomeDir:  C.GoString(pwd.pw_dir),
   110  	}
   111  	// The pw_gecos field isn't quite standardized.  Some docs
   112  	// say: "It is expected to be a comma separated list of
   113  	// personal data where the first item is the full name of the
   114  	// user."
   115  	if i := strings.Index(u.Name, ","); i >= 0 {
   116  		u.Name = u.Name[:i]
   117  	}
   118  	return u, nil
   119  }