...
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		"runtime"
    13		"strconv"
    14		"strings"
    15		"syscall"
    16		"unsafe"
    17	)
    18	
    19	/*
    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	import "C"
    31	
    32	func current() (*User, error) {
    33		return lookupUnix(syscall.Getuid(), "", false)
    34	}
    35	
    36	func lookup(username string) (*User, error) {
    37		return lookupUnix(-1, username, true)
    38	}
    39	
    40	func lookupId(uid string) (*User, error) {
    41		i, e := strconv.Atoi(uid)
    42		if e != nil {
    43			return nil, e
    44		}
    45		return lookupUnix(i, "", false)
    46	}
    47	
    48	func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {
    49		var pwd C.struct_passwd
    50		var result *C.struct_passwd
    51	
    52		var bufSize C.long
    53		if runtime.GOOS == "dragonfly" || runtime.GOOS == "freebsd" {
    54			// DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX
    55			// and just return -1.  So just use the same
    56			// size that Linux returns.
    57			bufSize = 1024
    58		} else {
    59			bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX)
    60			if bufSize <= 0 || bufSize > 1<<20 {
    61				return nil, fmt.Errorf("user: unreasonable _SC_GETPW_R_SIZE_MAX of %d", bufSize)
    62			}
    63		}
    64		buf := C.malloc(C.size_t(bufSize))
    65		defer C.free(buf)
    66		var rv C.int
    67		if lookupByName {
    68			nameC := C.CString(username)
    69			defer C.free(unsafe.Pointer(nameC))
    70			rv = C.getpwnam_r(nameC,
    71				&pwd,
    72				(*C.char)(buf),
    73				C.size_t(bufSize),
    74				&result)
    75			if rv != 0 {
    76				return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.Errno(rv))
    77			}
    78			if result == nil {
    79				return nil, UnknownUserError(username)
    80			}
    81		} else {
    82			// mygetpwuid_r is a wrapper around getpwuid_r to
    83			// to avoid using uid_t because C.uid_t(uid) for
    84			// unknown reasons doesn't work on linux.
    85			rv = C.mygetpwuid_r(C.int(uid),
    86				&pwd,
    87				(*C.char)(buf),
    88				C.size_t(bufSize),
    89				&result)
    90			if rv != 0 {
    91				return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.Errno(rv))
    92			}
    93			if result == nil {
    94				return nil, UnknownUserIdError(uid)
    95			}
    96		}
    97		u := &User{
    98			Uid:      strconv.Itoa(int(pwd.pw_uid)),
    99			Gid:      strconv.Itoa(int(pwd.pw_gid)),
   100			Username: C.GoString(pwd.pw_name),
   101			Name:     C.GoString(pwd.pw_gecos),
   102			HomeDir:  C.GoString(pwd.pw_dir),
   103		}
   104		// The pw_gecos field isn't quite standardized.  Some docs
   105		// say: "It is expected to be a comma separated list of
   106		// personal data where the first item is the full name of the
   107		// user."
   108		if i := strings.Index(u.Name, ","); i >= 0 {
   109			u.Name = u.Name[:i]
   110		}
   111		return u, nil
   112	}
   113	

View as plain text