github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/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 "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 }