src/pkg/os/user/lookup_unix.go - The Go Programming Language

Golang

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