github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/go/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  
    36  // bytePtrToString takes a NUL-terminated array of bytes and convert
    37  // it to a Go string.
    38  func bytePtrToString(p *byte) string {
    39  	a := (*[10000]byte)(unsafe.Pointer(p))
    40  	i := 0
    41  	for a[i] != 0 {
    42  		i++
    43  	}
    44  	return string(a[:i])
    45  }
    46  
    47  func current() (*User, error) {
    48  	return lookupUnix(syscall.Getuid(), "", false)
    49  }
    50  
    51  func lookup(username string) (*User, error) {
    52  	return lookupUnix(-1, username, true)
    53  }
    54  
    55  func lookupId(uid string) (*User, error) {
    56  	i, e := strconv.Atoi(uid)
    57  	if e != nil {
    58  		return nil, e
    59  	}
    60  	return lookupUnix(i, "", false)
    61  }
    62  
    63  func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {
    64  	var pwd syscall.Passwd
    65  	var result *syscall.Passwd
    66  
    67  	// FIXME: Should let buf grow if necessary.
    68  	const bufSize = 1024
    69  	buf := make([]byte, bufSize)
    70  	if lookupByName {
    71  		nameC := syscall.StringBytePtr(username)
    72  		syscall.Entersyscall()
    73  		rv := libc_getpwnam_r(nameC,
    74  			&pwd,
    75  			&buf[0],
    76  			bufSize,
    77  			&result)
    78  		syscall.Exitsyscall()
    79  		if rv != 0 {
    80  			return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.GetErrno())
    81  		}
    82  		if result == nil {
    83  			return nil, UnknownUserError(username)
    84  		}
    85  	} else {
    86  		syscall.Entersyscall()
    87  		rv := libc_getpwuid_r(syscall.Uid_t(uid),
    88  			&pwd,
    89  			&buf[0],
    90  			bufSize,
    91  			&result)
    92  		syscall.Exitsyscall()
    93  		if rv != 0 {
    94  			return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.GetErrno())
    95  		}
    96  		if result == nil {
    97  			return nil, UnknownUserIdError(uid)
    98  		}
    99  	}
   100  	u := &User{
   101  		Uid:      strconv.Itoa(int(pwd.Pw_uid)),
   102  		Gid:      strconv.Itoa(int(pwd.Pw_gid)),
   103  		Username: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_name))),
   104  		Name:     bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_gecos))),
   105  		HomeDir:  bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_dir))),
   106  	}
   107  	// The pw_gecos field isn't quite standardized.  Some docs
   108  	// say: "It is expected to be a comma separated list of
   109  	// personal data where the first item is the full name of the
   110  	// user."
   111  	if i := strings.Index(u.Name, ","); i >= 0 {
   112  		u.Name = u.Name[:i]
   113  	}
   114  	return u, nil
   115  }