...
Run Format

Source file src/os/user/lookup_unix.go

     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	}
   120	

View as plain text