#include "textflag.h"
-TEXT ·libc_getentropy_trampoline(SB),NOSPLIT,$0-0
- JMP libc_getentropy(SB)
-
-TEXT ·libc_getaddrinfo_trampoline(SB),NOSPLIT,$0-0
- JMP libc_getaddrinfo(SB)
-
-TEXT ·libc_freeaddrinfo_trampoline(SB),NOSPLIT,$0-0
- JMP libc_freeaddrinfo(SB)
-
-TEXT ·libc_getnameinfo_trampoline(SB),NOSPLIT,$0-0
- JMP libc_getnameinfo(SB)
-
-TEXT ·libc_gai_strerror_trampoline(SB),NOSPLIT,$0-0
- JMP libc_gai_strerror(SB)
-
-TEXT ·libresolv_res_9_ninit_trampoline(SB),NOSPLIT,$0-0
- JMP libresolv_res_9_ninit(SB)
-
-TEXT ·libresolv_res_9_nclose_trampoline(SB),NOSPLIT,$0-0
- JMP libresolv_res_9_nclose(SB)
-
-TEXT ·libresolv_res_9_nsearch_trampoline(SB),NOSPLIT,$0-0
- JMP libresolv_res_9_nsearch(SB)
-
-TEXT ·libc_grantpt_trampoline(SB),NOSPLIT,$0-0
- JMP libc_grantpt(SB)
-
-TEXT ·libc_unlockpt_trampoline(SB),NOSPLIT,$0-0
- JMP libc_unlockpt(SB)
-
-TEXT ·libc_ptsname_r_trampoline(SB),NOSPLIT,$0-0
- JMP libc_ptsname_r(SB)
-
-TEXT ·libc_posix_openpt_trampoline(SB),NOSPLIT,$0-0
- JMP libc_posix_openpt(SB)
+TEXT ·libc_getentropy_trampoline(SB),NOSPLIT,$0-0; JMP libc_getentropy(SB)
+TEXT ·libc_getaddrinfo_trampoline(SB),NOSPLIT,$0-0; JMP libc_getaddrinfo(SB)
+TEXT ·libc_freeaddrinfo_trampoline(SB),NOSPLIT,$0-0; JMP libc_freeaddrinfo(SB)
+TEXT ·libc_getnameinfo_trampoline(SB),NOSPLIT,$0-0; JMP libc_getnameinfo(SB)
+TEXT ·libc_gai_strerror_trampoline(SB),NOSPLIT,$0-0; JMP libc_gai_strerror(SB)
+TEXT ·libresolv_res_9_ninit_trampoline(SB),NOSPLIT,$0-0; JMP libresolv_res_9_ninit(SB)
+TEXT ·libresolv_res_9_nclose_trampoline(SB),NOSPLIT,$0-0; JMP libresolv_res_9_nclose(SB)
+TEXT ·libresolv_res_9_nsearch_trampoline(SB),NOSPLIT,$0-0; JMP libresolv_res_9_nsearch(SB)
+TEXT ·libc_grantpt_trampoline(SB),NOSPLIT,$0-0; JMP libc_grantpt(SB)
+TEXT ·libc_unlockpt_trampoline(SB),NOSPLIT,$0-0; JMP libc_unlockpt(SB)
+TEXT ·libc_ptsname_r_trampoline(SB),NOSPLIT,$0-0; JMP libc_ptsname_r(SB)
+TEXT ·libc_posix_openpt_trampoline(SB),NOSPLIT,$0-0; JMP libc_posix_openpt(SB)
+TEXT ·libc_getgrouplist_trampoline(SB),NOSPLIT,$0-0; JMP libc_getgrouplist(SB)
+TEXT ·libc_getpwnam_r_trampoline(SB),NOSPLIT,$0-0; JMP libc_getpwnam_r(SB)
+TEXT ·libc_getpwuid_r_trampoline(SB),NOSPLIT,$0-0; JMP libc_getpwuid_r(SB)
+TEXT ·libc_getgrnam_r_trampoline(SB),NOSPLIT,$0-0; JMP libc_getgrnam_r(SB)
+TEXT ·libc_getgrgid_r_trampoline(SB),NOSPLIT,$0-0; JMP libc_getgrgid_r(SB)
+TEXT ·libc_sysconf_trampoline(SB),NOSPLIT,$0-0; JMP libc_sysconf(SB)
//go:linkname syscall_syscall syscall.syscall
func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
+//go:linkname syscall_syscallPtr syscall.syscallPtr
+func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
+
//go:linkname syscall_syscall6 syscall.syscall6
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
+//go:linkname syscall_syscall6X syscall.syscall6X
+func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
+
//go:linkname syscall_syscall9 syscall.syscall9
func syscall_syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
--- /dev/null
+// Copyright 2022 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 unix
+
+import (
+ "internal/abi"
+ "syscall"
+ "unsafe"
+)
+
+//go:cgo_import_dynamic libc_getgrouplist getgrouplist "/usr/lib/libSystem.B.dylib"
+func libc_getgrouplist_trampoline()
+
+func Getgrouplist(name *byte, gid uint32, gids *uint32, n *int32) error {
+ _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_getgrouplist_trampoline),
+ uintptr(unsafe.Pointer(name)), uintptr(gid), uintptr(unsafe.Pointer(gids)),
+ uintptr(unsafe.Pointer(n)), 0, 0)
+ if errno != 0 {
+ return errno
+ }
+ return nil
+}
+
+const (
+ SC_GETGR_R_SIZE_MAX = 0x46
+ SC_GETPW_R_SIZE_MAX = 0x47
+)
+
+type Passwd struct {
+ Name *byte
+ Passwd *byte
+ Uid uint32 // uid_t
+ Gid uint32 // gid_t
+ Change int64 // time_t
+ Class *byte
+ Gecos *byte
+ Dir *byte
+ Shell *byte
+ Expire int64 // time_t
+}
+
+type Group struct {
+ Name *byte
+ Passwd *byte
+ Gid uint32 // gid_t
+ Mem **byte
+}
+
+//go:cgo_import_dynamic libc_getpwnam_r getpwnam_r "/usr/lib/libSystem.B.dylib"
+func libc_getpwnam_r_trampoline()
+
+func Getpwnam(name *byte, pwd *Passwd, buf *byte, size uintptr, result **Passwd) syscall.Errno {
+ _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_getpwnam_r_trampoline),
+ uintptr(unsafe.Pointer(name)),
+ uintptr(unsafe.Pointer(pwd)),
+ uintptr(unsafe.Pointer(buf)),
+ size,
+ uintptr(unsafe.Pointer(result)),
+ 0)
+ return errno
+}
+
+//go:cgo_import_dynamic libc_getpwuid_r getpwuid_r "/usr/lib/libSystem.B.dylib"
+func libc_getpwuid_r_trampoline()
+
+func Getpwuid(uid uint32, pwd *Passwd, buf *byte, size uintptr, result **Passwd) syscall.Errno {
+ _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_getpwuid_r_trampoline),
+ uintptr(uid),
+ uintptr(unsafe.Pointer(pwd)),
+ uintptr(unsafe.Pointer(buf)),
+ size,
+ uintptr(unsafe.Pointer(result)),
+ 0)
+ return errno
+}
+
+//go:cgo_import_dynamic libc_getgrnam_r getgrnam_r "/usr/lib/libSystem.B.dylib"
+func libc_getgrnam_r_trampoline()
+
+func Getgrnam(name *byte, grp *Group, buf *byte, size uintptr, result **Group) syscall.Errno {
+ _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_getgrnam_r_trampoline),
+ uintptr(unsafe.Pointer(name)),
+ uintptr(unsafe.Pointer(grp)),
+ uintptr(unsafe.Pointer(buf)),
+ size,
+ uintptr(unsafe.Pointer(result)),
+ 0)
+ return errno
+}
+
+//go:cgo_import_dynamic libc_getgrgid_r getgrgid_r "/usr/lib/libSystem.B.dylib"
+func libc_getgrgid_r_trampoline()
+
+func Getgrgid(gid uint32, grp *Group, buf *byte, size uintptr, result **Group) syscall.Errno {
+ _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_getgrgid_r_trampoline),
+ uintptr(gid),
+ uintptr(unsafe.Pointer(grp)),
+ uintptr(unsafe.Pointer(buf)),
+ size,
+ uintptr(unsafe.Pointer(result)),
+ 0)
+ return errno
+}
+
+//go:cgo_import_dynamic libc_sysconf sysconf "/usr/lib/libSystem.B.dylib"
+func libc_sysconf_trampoline()
+
+func Sysconf(key int32) int64 {
+ val, _, errno := syscall_syscall6X(abi.FuncPCABI0(libc_sysconf_trampoline),
+ uintptr(key), 0, 0, 0, 0, 0)
+ if errno != 0 {
+ return -1
+ }
+ return int64(val)
+}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build (dragonfly || darwin || freebsd || (!android && linux) || netbsd || openbsd || (solaris && !illumos)) && cgo && !osusergo
+//go:build (cgo || darwin) && !osusergo && (darwin || dragonfly || freebsd || (linux && !android) || netbsd || openbsd || (solaris && !illumos))
package user
"unsafe"
)
-/*
-#include <unistd.h>
-#include <sys/types.h>
-*/
-import "C"
-
const maxGroups = 2048
func listGroups(u *User) ([]string, error) {
if err != nil {
return nil, fmt.Errorf("user: list groups for %s: invalid gid %q", u.Username, u.Gid)
}
- userGID := C.gid_t(ug)
+ userGID := _C_gid_t(ug)
nameC := make([]byte, len(u.Username)+1)
copy(nameC, u.Username)
- n := C.int(256)
- gidsC := make([]C.gid_t, n)
- rv := getGroupList((*C.char)(unsafe.Pointer(&nameC[0])), userGID, &gidsC[0], &n)
+ n := _C_int(256)
+ gidsC := make([]_C_gid_t, n)
+ rv := getGroupList((*_C_char)(unsafe.Pointer(&nameC[0])), userGID, &gidsC[0], &n)
if rv == -1 {
// Mac is the only Unix that does not set n properly when rv == -1, so
// we need to use different logic for Mac vs. the other OS's.
}
return gids, nil
}
+
+// groupRetry retries getGroupList with much larger size for n. The result is
+// stored in gids.
+func groupRetry(username string, name []byte, userGID _C_gid_t, gids *[]_C_gid_t, n *_C_int) error {
+ // More than initial buffer, but now n contains the correct size.
+ if *n > maxGroups {
+ return fmt.Errorf("user: %q is a member of more than %d groups", username, maxGroups)
+ }
+ *gids = make([]_C_gid_t, *n)
+ rv := getGroupList((*_C_char)(unsafe.Pointer(&name[0])), userGID, &(*gids)[0], n)
+ if rv == -1 {
+ return fmt.Errorf("user: list groups for %s failed", username)
+ }
+ return nil
+}
--- /dev/null
+// 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.
+
+//go:build cgo && !osusergo && unix && !android && !darwin
+
+package user
+
+import (
+ "syscall"
+)
+
+/*
+#cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdlib.h>
+
+static struct passwd mygetpwuid_r(int uid, char *buf, size_t buflen, int *found, int *perr) {
+ struct passwd pwd;
+ struct passwd *result;
+ *perr = getpwuid_r(uid, &pwd, buf, buflen, &result);
+ *found = result != NULL;
+ return pwd;
+}
+
+static struct passwd mygetpwnam_r(const char *name, char *buf, size_t buflen, int *found, int *perr) {
+ struct passwd pwd;
+ struct passwd *result;
+ *perr = getpwnam_r(name, &pwd, buf, buflen, &result);
+ *found = result != NULL;
+ return pwd;
+}
+
+static struct group mygetgrgid_r(int gid, char *buf, size_t buflen, int *found, int *perr) {
+ struct group grp;
+ struct group *result;
+ *perr = getgrgid_r(gid, &grp, buf, buflen, &result);
+ *found = result != NULL;
+ return grp;
+}
+
+static struct group mygetgrnam_r(const char *name, char *buf, size_t buflen, int *found, int *perr) {
+ struct group grp;
+ struct group *result;
+ *perr = getgrnam_r(name, &grp, buf, buflen, &result);
+ *found = result != NULL;
+ return grp;
+}
+*/
+import "C"
+
+type _C_char = C.char
+type _C_int = C.int
+type _C_gid_t = C.gid_t
+type _C_uid_t = C.uid_t
+type _C_size_t = C.size_t
+type _C_struct_group = C.struct_group
+type _C_struct_passwd = C.struct_passwd
+type _C_long = C.long
+
+func _C_pw_uid(p *_C_struct_passwd) _C_uid_t { return p.pw_uid }
+func _C_pw_uidp(p *_C_struct_passwd) *_C_uid_t { return &p.pw_uid }
+func _C_pw_gid(p *_C_struct_passwd) _C_gid_t { return p.pw_gid }
+func _C_pw_gidp(p *_C_struct_passwd) *_C_gid_t { return &p.pw_gid }
+func _C_pw_name(p *_C_struct_passwd) *_C_char { return p.pw_name }
+func _C_pw_gecos(p *_C_struct_passwd) *_C_char { return p.pw_gecos }
+func _C_pw_dir(p *_C_struct_passwd) *_C_char { return p.pw_dir }
+
+func _C_gr_gid(g *_C_struct_group) _C_gid_t { return g.gr_gid }
+func _C_gr_name(g *_C_struct_group) *_C_char { return g.gr_name }
+
+func _C_GoString(p *_C_char) string { return C.GoString(p) }
+
+func _C_getpwnam_r(name *_C_char, buf *_C_char, size _C_size_t) (pwd _C_struct_passwd, found bool, errno syscall.Errno) {
+ var f, e _C_int
+ pwd = C.mygetpwnam_r(name, buf, size, &f, &e)
+ return pwd, f != 0, syscall.Errno(e)
+}
+
+func _C_getpwuid_r(uid _C_uid_t, buf *_C_char, size _C_size_t) (pwd _C_struct_passwd, found bool, errno syscall.Errno) {
+ var f, e _C_int
+ pwd = C.mygetpwuid_r(_C_int(uid), buf, size, &f, &e)
+ return pwd, f != 0, syscall.Errno(e)
+}
+
+func _C_getgrnam_r(name *_C_char, buf *_C_char, size _C_size_t) (grp _C_struct_group, found bool, errno syscall.Errno) {
+ var f, e _C_int
+ grp = C.mygetgrnam_r(name, buf, size, &f, &e)
+ return grp, f != 0, syscall.Errno(e)
+}
+
+func _C_getgrgid_r(gid _C_gid_t, buf *_C_char, size _C_size_t) (grp _C_struct_group, found bool, errno syscall.Errno) {
+ var f, e _C_int
+ grp = C.mygetgrgid_r(_C_int(gid), buf, size, &f, &e)
+ return grp, f != 0, syscall.Errno(e)
+}
+
+const (
+ _C__SC_GETPW_R_SIZE_MAX = C._SC_GETPW_R_SIZE_MAX
+ _C__SC_GETGR_R_SIZE_MAX = C._SC_GETGR_R_SIZE_MAX
+)
+
+func _C_sysconf(key _C_int) _C_long { return C.sysconf(key) }
--- /dev/null
+// 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.
+
+//go:build !osusergo && darwin
+
+package user
+
+import (
+ "internal/syscall/unix"
+ "syscall"
+)
+
+type _C_char = byte
+type _C_int = int32
+type _C_gid_t = uint32
+type _C_uid_t = uint32
+type _C_size_t = uintptr
+type _C_struct_group = unix.Group
+type _C_struct_passwd = unix.Passwd
+type _C_long = int64
+
+func _C_pw_uid(p *_C_struct_passwd) _C_uid_t { return p.Uid }
+func _C_pw_uidp(p *_C_struct_passwd) *_C_uid_t { return &p.Uid }
+func _C_pw_gid(p *_C_struct_passwd) _C_gid_t { return p.Gid }
+func _C_pw_gidp(p *_C_struct_passwd) *_C_gid_t { return &p.Gid }
+func _C_pw_name(p *_C_struct_passwd) *_C_char { return p.Name }
+func _C_pw_gecos(p *_C_struct_passwd) *_C_char { return p.Gecos }
+func _C_pw_dir(p *_C_struct_passwd) *_C_char { return p.Dir }
+
+func _C_gr_gid(g *_C_struct_group) _C_gid_t { return g.Gid }
+func _C_gr_name(g *_C_struct_group) *_C_char { return g.Name }
+
+func _C_GoString(p *_C_char) string { return unix.GoString(p) }
+
+func _C_getpwnam_r(name *_C_char, buf *_C_char, size _C_size_t) (pwd _C_struct_passwd, found bool, errno syscall.Errno) {
+ var result *_C_struct_passwd
+ errno = unix.Getpwnam(name, &pwd, buf, size, &result)
+ return pwd, result != nil, errno
+}
+
+func _C_getpwuid_r(uid _C_uid_t, buf *_C_char, size _C_size_t) (pwd _C_struct_passwd, found bool, errno syscall.Errno) {
+ var result *_C_struct_passwd
+ errno = unix.Getpwuid(uid, &pwd, buf, size, &result)
+ return pwd, result != nil, errno
+}
+
+func _C_getgrnam_r(name *_C_char, buf *_C_char, size _C_size_t) (grp _C_struct_group, found bool, errno syscall.Errno) {
+ var result *_C_struct_group
+ errno = unix.Getgrnam(name, &grp, buf, size, &result)
+ return grp, result != nil, errno
+}
+
+func _C_getgrgid_r(gid _C_gid_t, buf *_C_char, size _C_size_t) (grp _C_struct_group, found bool, errno syscall.Errno) {
+ var result *_C_struct_group
+ errno = unix.Getgrgid(gid, &grp, buf, size, &result)
+ return grp, result != nil, errno
+}
+
+const (
+ _C__SC_GETPW_R_SIZE_MAX = unix.SC_GETPW_R_SIZE_MAX
+ _C__SC_GETGR_R_SIZE_MAX = unix.SC_GETGR_R_SIZE_MAX
+)
+
+func _C_sysconf(key _C_int) _C_long { return unix.Sysconf(key) }
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build unix && !android && cgo && !osusergo
+//go:build (cgo || darwin) && !osusergo && unix && !android
package user
"unsafe"
)
-/*
-#cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS
-#include <unistd.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <grp.h>
-#include <stdlib.h>
-
-static struct passwd mygetpwuid_r(int uid, char *buf, size_t buflen, int *found, int *perr) {
- struct passwd pwd;
- struct passwd *result;
- *perr = getpwuid_r(uid, &pwd, buf, buflen, &result);
- *found = result != NULL;
- return pwd;
-}
-
-static struct passwd mygetpwnam_r(const char *name, char *buf, size_t buflen, int *found, int *perr) {
- struct passwd pwd;
- struct passwd *result;
- *perr = getpwnam_r(name, &pwd, buf, buflen, &result);
- *found = result != NULL;
- return pwd;
-}
-
-static struct group mygetgrgid_r(int gid, char *buf, size_t buflen, int *found, int *perr) {
- struct group grp;
- struct group *result;
- *perr = getgrgid_r(gid, &grp, buf, buflen, &result);
- *found = result != NULL;
- return grp;
-}
-
-static struct group mygetgrnam_r(const char *name, char *buf, size_t buflen, int *found, int *perr) {
- struct group grp;
- struct group *result;
- *perr = getgrnam_r(name, &grp, buf, buflen, &result);
- *found = result != NULL;
- return grp;
-}
-*/
-import "C"
-
func current() (*User, error) {
return lookupUnixUid(syscall.Getuid())
}
func lookupUser(username string) (*User, error) {
- var pwd C.struct_passwd
+ var pwd _C_struct_passwd
var found bool
nameC := make([]byte, len(username)+1)
copy(nameC, username)
err := retryWithBuffer(userBuffer, func(buf []byte) syscall.Errno {
- var cfound, cerr C.int
- pwd = C.mygetpwnam_r((*C.char)(unsafe.Pointer(&nameC[0])),
- (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)),
- &cfound, &cerr)
- found = cfound != 0
- return syscall.Errno(cerr)
+ var errno syscall.Errno
+ pwd, found, errno = _C_getpwnam_r((*_C_char)(unsafe.Pointer(&nameC[0])),
+ (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf)))
+ return errno
})
if err != nil {
return nil, fmt.Errorf("user: lookup username %s: %v", username, err)
}
func lookupUnixUid(uid int) (*User, error) {
- var pwd C.struct_passwd
+ var pwd _C_struct_passwd
var found bool
err := retryWithBuffer(userBuffer, func(buf []byte) syscall.Errno {
- var cfound, cerr C.int
- pwd = C.mygetpwuid_r(C.int(uid),
- (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)),
- &cfound, &cerr)
- found = cfound != 0
- return syscall.Errno(cerr)
+ var errno syscall.Errno
+ pwd, found, errno = _C_getpwuid_r(_C_uid_t(uid),
+ (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf)))
+ return errno
})
if err != nil {
return nil, fmt.Errorf("user: lookup userid %d: %v", uid, err)
return buildUser(&pwd), nil
}
-func buildUser(pwd *C.struct_passwd) *User {
+func buildUser(pwd *_C_struct_passwd) *User {
u := &User{
- Uid: strconv.FormatUint(uint64(pwd.pw_uid), 10),
- Gid: strconv.FormatUint(uint64(pwd.pw_gid), 10),
- Username: C.GoString(pwd.pw_name),
- Name: C.GoString(pwd.pw_gecos),
- HomeDir: C.GoString(pwd.pw_dir),
+ Uid: strconv.FormatUint(uint64(_C_pw_uid(pwd)), 10),
+ Gid: strconv.FormatUint(uint64(_C_pw_gid(pwd)), 10),
+ Username: _C_GoString(_C_pw_name(pwd)),
+ Name: _C_GoString(_C_pw_gecos(pwd)),
+ HomeDir: _C_GoString(_C_pw_dir(pwd)),
}
// The pw_gecos field isn't quite standardized. Some docs
// say: "It is expected to be a comma separated list of
}
func lookupGroup(groupname string) (*Group, error) {
- var grp C.struct_group
+ var grp _C_struct_group
var found bool
cname := make([]byte, len(groupname)+1)
copy(cname, groupname)
err := retryWithBuffer(groupBuffer, func(buf []byte) syscall.Errno {
- var cfound, cerr C.int
- grp = C.mygetgrnam_r((*C.char)(unsafe.Pointer(&cname[0])),
- (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)),
- &cfound, &cerr)
- found = cfound != 0
- return syscall.Errno(cerr)
+ var errno syscall.Errno
+ grp, found, errno = _C_getgrnam_r((*_C_char)(unsafe.Pointer(&cname[0])),
+ (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf)))
+ return errno
})
if err != nil {
return nil, fmt.Errorf("user: lookup groupname %s: %v", groupname, err)
}
func lookupUnixGid(gid int) (*Group, error) {
- var grp C.struct_group
+ var grp _C_struct_group
var found bool
err := retryWithBuffer(groupBuffer, func(buf []byte) syscall.Errno {
- var cfound, cerr C.int
- grp = C.mygetgrgid_r(C.int(gid),
- (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)),
- &cfound, &cerr)
- found = cfound != 0
- return syscall.Errno(cerr)
+ var errno syscall.Errno
+ grp, found, errno = _C_getgrgid_r(_C_gid_t(gid),
+ (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf)))
+ return syscall.Errno(errno)
})
if err != nil {
return nil, fmt.Errorf("user: lookup groupid %d: %v", gid, err)
return buildGroup(&grp), nil
}
-func buildGroup(grp *C.struct_group) *Group {
+func buildGroup(grp *_C_struct_group) *Group {
g := &Group{
- Gid: strconv.Itoa(int(grp.gr_gid)),
- Name: C.GoString(grp.gr_name),
+ Gid: strconv.Itoa(int(_C_gr_gid(grp))),
+ Name: _C_GoString(_C_gr_name(grp)),
}
return g
}
-type bufferKind C.int
+type bufferKind _C_int
const (
- userBuffer = bufferKind(C._SC_GETPW_R_SIZE_MAX)
- groupBuffer = bufferKind(C._SC_GETGR_R_SIZE_MAX)
+ userBuffer = bufferKind(_C__SC_GETPW_R_SIZE_MAX)
+ groupBuffer = bufferKind(_C__SC_GETGR_R_SIZE_MAX)
)
-func (k bufferKind) initialSize() C.size_t {
- sz := C.sysconf(C.int(k))
+func (k bufferKind) initialSize() _C_size_t {
+ sz := _C_sysconf(_C_int(k))
if sz == -1 {
// DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX.
// Additionally, not all Linux systems have it, either. For
// Truncate. If this truly isn't enough, retryWithBuffer will error on the first run.
return maxBufferSize
}
- return C.size_t(sz)
+ return _C_size_t(sz)
}
// retryWithBuffer repeatedly calls f(), increasing the size of the
}
// Because we can't use cgo in tests:
-func structPasswdForNegativeTest() C.struct_passwd {
- sp := C.struct_passwd{}
- sp.pw_uid = 1<<32 - 2
- sp.pw_gid = 1<<32 - 3
+func structPasswdForNegativeTest() _C_struct_passwd {
+ sp := _C_struct_passwd{}
+ *_C_pw_uidp(&sp) = 1<<32 - 2
+ *_C_pw_gidp(&sp) = 1<<32 - 3
return sp
}
+++ /dev/null
-// Copyright 2016 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.
-
-//go:build cgo && !osusergo
-
-package user
-
-/*
-#include <unistd.h>
-#include <sys/types.h>
-#include <stdlib.h>
-
-static int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) {
- int* buf = malloc(*ngroups * sizeof(int));
- int rv = getgrouplist(user, (int) group, buf, ngroups);
- int i;
- if (rv == 0) {
- for (i = 0; i < *ngroups; i++) {
- groups[i] = (gid_t) buf[i];
- }
- }
- free(buf);
- return rv;
-}
-*/
-import "C"
-import (
- "fmt"
- "unsafe"
-)
-
-func getGroupList(name *C.char, userGID C.gid_t, gids *C.gid_t, n *C.int) C.int {
- return C.mygetgrouplist(name, userGID, gids, n)
-}
-
-// groupRetry retries getGroupList with an increasingly large size for n. The
-// result is stored in gids.
-func groupRetry(username string, name []byte, userGID C.gid_t, gids *[]C.gid_t, n *C.int) error {
- *n = C.int(256 * 2)
- for {
- *gids = make([]C.gid_t, *n)
- rv := getGroupList((*C.char)(unsafe.Pointer(&name[0])), userGID, &(*gids)[0], n)
- if rv >= 0 {
- // n is set correctly
- break
- }
- if *n > maxGroups {
- return fmt.Errorf("user: %q is a member of more than %d groups", username, maxGroups)
- }
- *n = *n * C.int(2)
- }
- return nil
-}
--- /dev/null
+// Copyright 2016 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.
+
+//go:build !osusergo && darwin
+
+package user
+
+import (
+ "internal/syscall/unix"
+)
+
+func getGroupList(name *_C_char, userGID _C_gid_t, gids *_C_gid_t, n *_C_int) _C_int {
+ err := unix.Getgrouplist(name, userGID, gids, n)
+ if err != nil {
+ return -1
+ }
+ return 0
+}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build (dragonfly || freebsd || (!android && linux) || netbsd || openbsd || (solaris && !illumos)) && cgo && !osusergo
+//go:build cgo && !osusergo && (dragonfly || freebsd || (!android && linux) || netbsd || openbsd || (solaris && !illumos))
package user
}
*/
import "C"
-import (
- "fmt"
- "unsafe"
-)
-func getGroupList(name *C.char, userGID C.gid_t, gids *C.gid_t, n *C.int) C.int {
+func getGroupList(name *_C_char, userGID _C_gid_t, gids *_C_gid_t, n *_C_int) _C_int {
return C.mygetgrouplist(name, userGID, gids, n)
}
-
-// groupRetry retries getGroupList with much larger size for n. The result is
-// stored in gids.
-func groupRetry(username string, name []byte, userGID C.gid_t, gids *[]C.gid_t, n *C.int) error {
- // More than initial buffer, but now n contains the correct size.
- if *n > maxGroups {
- return fmt.Errorf("user: %q is a member of more than %d groups", username, maxGroups)
- }
- *gids = make([]C.gid_t, *n)
- rv := getGroupList((*C.char)(unsafe.Pointer(&name[0])), userGID, &(*gids)[0], n)
- if rv == -1 {
- return fmt.Errorf("user: list groups for %s failed", username)
- }
- return nil
-}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build ((darwin || dragonfly || freebsd || (js && wasm) || (!android && linux) || netbsd || openbsd || solaris) && (!cgo || osusergo)) || aix || illumos
+//go:build ((darwin || dragonfly || freebsd || (js && wasm) || (!android && linux) || netbsd || openbsd || solaris) && ((!cgo && !darwin) || osusergo)) || aix || illumos
package user
"strconv"
)
-const groupFile = "/etc/group"
-
-var colon = []byte{':'}
-
func listGroupsFromReader(u *User, r io.Reader) ([]string, error) {
if u.Username == "" {
return nil, errors.New("user: list groups: empty username")
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build ((darwin || dragonfly || freebsd || (js && wasm) || (!android && linux) || netbsd || openbsd || solaris) && (!cgo || osusergo)) || aix || illumos
+//go:build ((darwin || dragonfly || freebsd || (js && wasm) || (!android && linux) || netbsd || openbsd || solaris) && ((!cgo && !darwin) || osusergo)) || aix || illumos
package user
-minussign:*:21:root
# Next line is invalid (empty group name)
:*:22:root
-
+
daemon:*:1:root
indented:*:7:root
# comment:*:4:found
import "sync"
+const (
+ userFile = "/etc/passwd"
+ groupFile = "/etc/group"
+)
+
+var colon = []byte{':'}
+
// Current returns the current user.
//
// The first call will cache the current user information.
// Partial os/user support on Plan 9.
// Supports Current(), but not Lookup()/LookupId().
// The latter two would require parsing /adm/users.
-const (
- userFile = "/dev/user"
-)
func init() {
userImplemented = false
}
func current() (*User, error) {
- ubytes, err := os.ReadFile(userFile)
+ ubytes, err := os.ReadFile("/dev/user")
if err != nil {
return nil, fmt.Errorf("user: %s", err)
}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build (!cgo && !windows && !plan9) || android || (osusergo && !windows && !plan9)
+//go:build (!cgo && !darwin && !windows && !plan9) || android || (osusergo && !windows && !plan9)
package user
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build ((unix && !android) || (js && wasm)) && (!cgo || osusergo)
+//go:build ((unix && !android) || (js && wasm)) && ((!cgo && !darwin) || osusergo)
package user
"strings"
)
-const userFile = "/etc/passwd"
-
// lineFunc returns a value, an error, or (nil, nil) to skip the row.
type lineFunc func(line []byte) (v any, err error)
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build unix && !android && !cgo
+//go:build unix && !android && !cgo && !darwin
package user