// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package user import ( "fmt" "os" "runtime" "strings" "unsafe" ) /* #include #include #include #include static int mygetpwuid_r(int uid, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result) { return getpwuid_r(uid, pwd, buf, buflen, result); } */ import "C" // Lookup looks up a user by username. If the user cannot be found, // the returned error is of type UnknownUserError. func Lookup(username string) (*User, os.Error) { return lookup(-1, username, true) } // LookupId looks up a user by userid. If the user cannot be found, // the returned error is of type UnknownUserIdError. func LookupId(uid int) (*User, os.Error) { return lookup(uid, "", false) } func lookup(uid int, username string, lookupByName bool) (*User, os.Error) { var pwd C.struct_passwd var result *C.struct_passwd var bufSize C.long if runtime.GOOS == "freebsd" { // FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX // and just returns -1. So just use the same // size that Linux returns bufSize = 1024 } else { bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX) if bufSize <= 0 || bufSize > 1<<20 { return nil, fmt.Errorf("user: unreasonable _SC_GETPW_R_SIZE_MAX of %d", bufSize) } } buf := C.malloc(C.size_t(bufSize)) defer C.free(buf) var rv C.int if lookupByName { nameC := C.CString(username) defer C.free(unsafe.Pointer(nameC)) rv = C.getpwnam_r(nameC, &pwd, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("user: lookup username %s: %s", username, os.Errno(rv)) } if result == nil { return nil, UnknownUserError(username) } } else { // mygetpwuid_r is a wrapper around getpwuid_r to // to avoid using uid_t because C.uid_t(uid) for // unknown reasons doesn't work on linux. rv = C.mygetpwuid_r(C.int(uid), &pwd, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("user: lookup userid %d: %s", uid, os.Errno(rv)) } if result == nil { return nil, UnknownUserIdError(uid) } } u := &User{ Uid: int(pwd.pw_uid), Gid: int(pwd.pw_gid), Username: C.GoString(pwd.pw_name), Name: C.GoString(pwd.pw_gecos), HomeDir: C.GoString(pwd.pw_dir), } // The pw_gecos field isn't quite standardized. Some docs // say: "It is expected to be a comma separated list of // personal data where the first item is the full name of the // user." if i := strings.Index(u.Name, ","); i >= 0 { u.Name = u.Name[:i] } return u, nil }