]> Cypherpunks repositories - gostls13.git/commitdiff
os/user: use libc (not cgo) on macOS
authorRuss Cox <rsc@golang.org>
Thu, 10 Nov 2022 03:42:25 +0000 (22:42 -0500)
committerGopher Robot <gobot@golang.org>
Fri, 11 Nov 2022 04:31:34 +0000 (04:31 +0000)
With net converted to libc, os/user is the last remaining
cgo code in the standard libary on macOS.
Convert it to libc too.

Now only plugin remains as a cgo-using package on macOS.

Change-Id: Ibb518b5c62ef9ec1e6ab6191f4b576f7c5a4501c
Reviewed-on: https://go-review.googlesource.com/c/go/+/449316
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>

17 files changed:
src/internal/syscall/unix/asm_darwin.s
src/internal/syscall/unix/net_darwin.go
src/internal/syscall/unix/user_darwin.go [new file with mode: 0644]
src/os/user/cgo_listgroups_unix.go
src/os/user/cgo_lookup_cgo.go [new file with mode: 0644]
src/os/user/cgo_lookup_syscall.go [new file with mode: 0644]
src/os/user/cgo_lookup_unix.go
src/os/user/getgrouplist_darwin.go [deleted file]
src/os/user/getgrouplist_syscall.go [new file with mode: 0644]
src/os/user/getgrouplist_unix.go
src/os/user/listgroups_unix.go
src/os/user/listgroups_unix_test.go
src/os/user/lookup.go
src/os/user/lookup_plan9.go
src/os/user/lookup_stubs.go
src/os/user/lookup_unix.go
src/os/user/lookup_unix_test.go

index 771f77186e3a94b4926e2a027b0d76a6c4e4fa0c..8662c2846f2a334d5a967ba3ce8eac3f2b2204c6 100644 (file)
@@ -4,38 +4,21 @@
 
 #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)
index 780aaaa05d1a240f242f6e3e5877c075b59b488f..98403596938641ec65794d547dd8f24d916d58dc 100644 (file)
@@ -111,9 +111,15 @@ func GoString(p *byte) string {
 //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)
 
diff --git a/src/internal/syscall/unix/user_darwin.go b/src/internal/syscall/unix/user_darwin.go
new file mode 100644 (file)
index 0000000..cfbc029
--- /dev/null
@@ -0,0 +1,117 @@
+// 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)
+}
index 0d937da3345dcc4dd2260ebfbc9b5b22a28805b5..59636954b2ab87aff8115683cbb7b2a5f7989935 100644 (file)
@@ -2,7 +2,7 @@
 // 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
 
@@ -12,12 +12,6 @@ import (
        "unsafe"
 )
 
-/*
-#include <unistd.h>
-#include <sys/types.h>
-*/
-import "C"
-
 const maxGroups = 2048
 
 func listGroups(u *User) ([]string, error) {
@@ -25,13 +19,13 @@ 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.
@@ -46,3 +40,18 @@ func listGroups(u *User) ([]string, error) {
        }
        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
+}
diff --git a/src/os/user/cgo_lookup_cgo.go b/src/os/user/cgo_lookup_cgo.go
new file mode 100644 (file)
index 0000000..1799573
--- /dev/null
@@ -0,0 +1,106 @@
+// 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) }
diff --git a/src/os/user/cgo_lookup_syscall.go b/src/os/user/cgo_lookup_syscall.go
new file mode 100644 (file)
index 0000000..321df65
--- /dev/null
@@ -0,0 +1,65 @@
+// 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) }
index 8d328a17a8c213ac32dc06ba3d27b96d677dccac..81787fee2bebbb2f54e7af5fdf0807afc1ea164d 100644 (file)
@@ -2,7 +2,7 @@
 // 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
 
@@ -14,65 +14,21 @@ import (
        "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)
@@ -92,16 +48,14 @@ func lookupUserId(uid string) (*User, error) {
 }
 
 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)
@@ -112,13 +66,13 @@ func lookupUnixUid(uid int) (*User, error) {
        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
@@ -129,19 +83,17 @@ func buildUser(pwd *C.struct_passwd) *User {
 }
 
 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)
@@ -161,16 +113,14 @@ func lookupGroupId(gid string) (*Group, error) {
 }
 
 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)
@@ -181,23 +131,23 @@ func lookupUnixGid(gid int) (*Group, error) {
        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
@@ -208,7 +158,7 @@ func (k bufferKind) initialSize() C.size_t {
                // 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
@@ -238,9 +188,9 @@ func isSizeReasonable(sz int64) bool {
 }
 
 // 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
 }
diff --git a/src/os/user/getgrouplist_darwin.go b/src/os/user/getgrouplist_darwin.go
deleted file mode 100644 (file)
index db6fb87..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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
-}
diff --git a/src/os/user/getgrouplist_syscall.go b/src/os/user/getgrouplist_syscall.go
new file mode 100644 (file)
index 0000000..41b64fc
--- /dev/null
@@ -0,0 +1,19 @@
+// 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
+}
index 104c2243df618cd7cedf33a663e9b3da37ec25b5..fb482d35baee0cbe2c6e8506651dc7bd02f925b1 100644 (file)
@@ -2,7 +2,7 @@
 // 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
 
@@ -16,26 +16,7 @@ static int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngr
 }
 */
 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
-}
index fa2df4931c152e76144fcb30041947c8e3bc770e..ef366fa280082dc5dbac72bf02c42ee18e00dd13 100644 (file)
@@ -2,7 +2,7 @@
 // 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
 
@@ -16,10 +16,6 @@ import (
        "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")
index a9f79ec6bb06eaab342926fad67c038e8a8691e6..4fa8b1f29b226922040018e010f229c012d178cc 100644 (file)
@@ -2,7 +2,7 @@
 // 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
 
@@ -25,7 +25,7 @@ invalidgid:*:notanumber:root
 -minussign:*:21:root
 # Next line is invalid (empty group name)
 :*:22:root
-      
+
 daemon:*:1:root
     indented:*:7:root
 # comment:*:4:found
index b36b7c01c0b1c02437e4466e2aab689f4662ca8c..ed33d0c7cd17b0dd808a6a9189044cc44835b8f4 100644 (file)
@@ -6,6 +6,13 @@ package user
 
 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.
index 07939363e739c69440db6a81da8cf2625b7b3c3a..dcc9319268807f9c61ee8b46b2f95ce191ece904 100644 (file)
@@ -13,9 +13,6 @@ import (
 // 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
@@ -24,7 +21,7 @@ func init() {
 }
 
 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)
        }
index ce1617d2507bdf24be8ccc3e82a521dd1297d58a..b02c1ffa284f93f47ed02b34a74e561dace66bff 100644 (file)
@@ -2,7 +2,7 @@
 // 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
 
index ed06e73fbc3367f7cbd4ab39b61698d0239a1d21..608d9b2140fc4cb5aa92a47bb0b3392ec20a2acf 100644 (file)
@@ -2,7 +2,7 @@
 // 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
 
@@ -16,8 +16,6 @@ import (
        "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)
 
index 399a03fc3c1b2cf1dd6c2b3e152634c4b2ffbab3..78b33922baa5ed0a2ce1e7a3042ce1c535a74528 100644 (file)
@@ -2,7 +2,7 @@
 // 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