// 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. // +build darwin freebsd linux // +build cgo package user import ( "fmt" "strconv" "strings" "syscall" "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); } */ //extern getpwnam_r func libc_getpwnam_r(name *byte, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int //extern getpwuid_r func libc_getpwuid_r(uid syscall.Uid_t, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int // bytePtrToString takes a NUL-terminated array of bytes and convert // it to a Go string. func bytePtrToString(p *byte) string { a := (*[10000]byte)(unsafe.Pointer(p)) i := 0 for a[i] != 0 { i++ } return string(a[:i]) } // Current returns the current user. func Current() (*User, error) { return lookup(syscall.Getuid(), "", false) } // 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, 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 string) (*User, error) { i, e := strconv.Atoi(uid) if e != nil { return nil, e } return lookup(i, "", false) } func lookup(uid int, username string, lookupByName bool) (*User, error) { var pwd syscall.Passwd var result *syscall.Passwd // FIXME: Should let buf grow if necessary. const bufSize = 1024 buf := make([]byte, bufSize) if lookupByName { p := syscall.StringBytePtr(username) syscall.Entersyscall() rv := libc_getpwnam_r(p, &pwd, &buf[0], bufSize, &result) syscall.Exitsyscall() if rv != 0 { return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.GetErrno()) } if result == nil { return nil, UnknownUserError(username) } } else { syscall.Entersyscall() rv := libc_getpwuid_r(syscall.Uid_t(uid), &pwd, &buf[0], bufSize, &result) syscall.Exitsyscall() if rv != 0 { return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.GetErrno()) } if result == nil { return nil, UnknownUserIdError(uid) } } u := &User{ Uid: strconv.Itoa(int(pwd.Pw_uid)), Gid: strconv.Itoa(int(pwd.Pw_gid)), Username: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_name))), Name: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_gecos))), HomeDir: bytePtrToString((*byte)(unsafe.Pointer(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 }