OLD | NEW |
(Empty) | |
| 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 package user |
| 6 |
| 7 import ( |
| 8 "fmt" |
| 9 "os" |
| 10 "runtime" |
| 11 "strings" |
| 12 "unsafe" |
| 13 ) |
| 14 |
| 15 /* |
| 16 #include <unistd.h> |
| 17 #include <sys/types.h> |
| 18 #include <pwd.h> |
| 19 #include <stdlib.h> |
| 20 |
| 21 static int mygetpwuid_r(int uid, struct passwd *pwd, |
| 22 char *buf, size_t buflen, struct passwd **result) { |
| 23 return getpwuid_r(uid, pwd, buf, buflen, result); |
| 24 } |
| 25 */ |
| 26 import "C" |
| 27 |
| 28 // Lookup looks up a user by username. If the user cannot be found, |
| 29 // the returned error is of type UnknownUserError. |
| 30 func Lookup(username string) (*User, os.Error) { |
| 31 return lookup(-1, username, true) |
| 32 } |
| 33 |
| 34 // LookupId looks up a user by userid. If the user cannot be found, |
| 35 // the returned error is of type UnknownUserIdError. |
| 36 func LookupId(uid int) (*User, os.Error) { |
| 37 return lookup(uid, "", false) |
| 38 } |
| 39 |
| 40 func lookup(uid int, username string, lookupByName bool) (*User, os.Error) { |
| 41 var pwd C.struct_passwd |
| 42 var result *C.struct_passwd |
| 43 |
| 44 var bufSize C.long |
| 45 if runtime.GOOS == "freebsd" { |
| 46 // FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX |
| 47 // and just returns -1. So just use the same |
| 48 // size that Linux returns |
| 49 bufSize = 1024 |
| 50 } else { |
| 51 bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX) |
| 52 if bufSize <= 0 || bufSize > 1<<20 { |
| 53 return nil, fmt.Errorf("user: unreasonable _SC_GETPW_R_S
IZE_MAX of %d", bufSize) |
| 54 } |
| 55 } |
| 56 buf := C.malloc(C.size_t(bufSize)) |
| 57 defer C.free(buf) |
| 58 var rv C.int |
| 59 if lookupByName { |
| 60 nameC := C.CString(username) |
| 61 defer C.free(unsafe.Pointer(nameC)) |
| 62 rv = C.getpwnam_r(nameC, |
| 63 &pwd, |
| 64 (*C.char)(buf), |
| 65 C.size_t(bufSize), |
| 66 &result) |
| 67 if rv != 0 { |
| 68 return nil, fmt.Errorf("user: lookup username %s: %s", u
sername, os.Errno(rv)) |
| 69 } |
| 70 if result == nil { |
| 71 return nil, UnknownUserError(username) |
| 72 } |
| 73 } else { |
| 74 // mygetpwuid_r is a wrapper around getpwuid_r to |
| 75 // to avoid using uid_t because C.uid_t(uid) for |
| 76 // unknown reasons doesn't work on linux. |
| 77 rv = C.mygetpwuid_r(C.int(uid), |
| 78 &pwd, |
| 79 (*C.char)(buf), |
| 80 C.size_t(bufSize), |
| 81 &result) |
| 82 if rv != 0 { |
| 83 return nil, fmt.Errorf("user: lookup userid %d: %s", uid
, os.Errno(rv)) |
| 84 } |
| 85 if result == nil { |
| 86 return nil, UnknownUserIdError(uid) |
| 87 } |
| 88 } |
| 89 u := &User{ |
| 90 Uid: int(pwd.pw_uid), |
| 91 Gid: int(pwd.pw_gid), |
| 92 Username: C.GoString(pwd.pw_name), |
| 93 Name: C.GoString(pwd.pw_gecos), |
| 94 HomeDir: C.GoString(pwd.pw_dir), |
| 95 } |
| 96 // The pw_gecos field isn't quite standardized. Some docs |
| 97 // say: "It is expected to be a comma separated list of |
| 98 // personal data where the first item is the full name of the |
| 99 // user." |
| 100 if i := strings.Index(u.Name, ","); i >= 0 { |
| 101 u.Name = u.Name[:i] |
| 102 } |
| 103 return u, nil |
| 104 } |
OLD | NEW |