github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/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 "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 }