// Code generated by cmd/cgo; DO NOT EDIT. //line /workdir/go/src/os/user/cgo_lookup_unix.go:1:1 // 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 dragonfly freebsd !android,linux netbsd openbsd solaris // +build cgo,!osusergo package user; import _cgo_unsafe "unsafe" import ( "fmt" "strconv" "strings" "syscall" "unsafe" ) /* #cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS #include #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); } static int mygetpwnam_r(const char *name, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result) { return getpwnam_r(name, pwd, buf, buflen, result); } static int mygetgrgid_r(int gid, struct group *grp, char *buf, size_t buflen, struct group **result) { return getgrgid_r(gid, grp, buf, buflen, result); } static int mygetgrnam_r(const char *name, struct group *grp, char *buf, size_t buflen, struct group **result) { return getgrnam_r(name, grp, buf, buflen, result); } */ import _ "unsafe" func current() (*User, error) { return lookupUnixUid(syscall.Getuid()) } func lookupUser(username string) (*User, error) { var pwd _Ctype_struct_passwd var result *_Ctype_struct_passwd nameC := make([]byte, len(username)+1) copy(nameC, username) buf := alloc(userBuffer) defer buf.free() err := retryWithBuffer(buf, func() syscall.Errno { // mygetpwnam_r is a wrapper around getpwnam_r to avoid // passing a size_t to getpwnam_r, because for unknown // reasons passing a size_t to getpwnam_r doesn't work on // Solaris. return syscall.Errno(func(_cgo0 *_Ctype_char, _cgo1 *_Ctype_struct_passwd, _cgo2 *_Ctype_char, _cgo3 _Ctype_size_t, _cgo4 **_Ctype_struct_passwd) _Ctype_int {; _cgoCheckPointer(_cgo1, true); _cgoCheckPointer(_cgo4, true); return (_Cfunc_mygetpwnam_r)(_cgo0, _cgo1, _cgo2, _cgo3, _cgo4);}((*_Ctype_char)(unsafe.Pointer(&nameC[0])), &pwd, (*_Ctype_char)(buf.ptr), _Ctype_size_t(buf.size), &result)) }) if err != nil { return nil, fmt.Errorf("user: lookup username %s: %v", username, err) } if result == nil { return nil, UnknownUserError(username) } return buildUser(&pwd), err } func lookupUserId(uid string) (*User, error) { i, e := strconv.Atoi(uid) if e != nil { return nil, e } return lookupUnixUid(i) } func lookupUnixUid(uid int) (*User, error) { var pwd _Ctype_struct_passwd var result *_Ctype_struct_passwd buf := alloc(userBuffer) defer buf.free() err := retryWithBuffer(buf, func() syscall.Errno { // 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. return syscall.Errno(func(_cgo0 _Ctype_int, _cgo1 *_Ctype_struct_passwd, _cgo2 *_Ctype_char, _cgo3 _Ctype_size_t, _cgo4 **_Ctype_struct_passwd) _Ctype_int {; _cgoCheckPointer(_cgo1, true); _cgoCheckPointer(_cgo4, true); return (_Cfunc_mygetpwuid_r)(_cgo0, _cgo1, _cgo2, _cgo3, _cgo4);}(_Ctype_int(uid), &pwd, (*_Ctype_char)(buf.ptr), _Ctype_size_t(buf.size), &result)) }) if err != nil { return nil, fmt.Errorf("user: lookup userid %d: %v", uid, err) } if result == nil { return nil, UnknownUserIdError(uid) } return buildUser(&pwd), nil } func buildUser(pwd *_Ctype_struct_passwd) *User { u := &User{ Uid: strconv.FormatUint(uint64(pwd.pw_uid), 10), Gid: strconv.FormatUint(uint64(pwd.pw_gid), 10), Username: (_Cfunc_GoString)(pwd.pw_name), Name: (_Cfunc_GoString)(pwd.pw_gecos), HomeDir: (_Cfunc_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 } func currentGroup() (*Group, error) { return lookupUnixGid(syscall.Getgid()) } func lookupGroup(groupname string) (*Group, error) { var grp _Ctype_struct_group var result *_Ctype_struct_group buf := alloc(groupBuffer) defer buf.free() cname := make([]byte, len(groupname)+1) copy(cname, groupname) err := retryWithBuffer(buf, func() syscall.Errno { return syscall.Errno(func(_cgo0 *_Ctype_char, _cgo1 *_Ctype_struct_group, _cgo2 *_Ctype_char, _cgo3 _Ctype_size_t, _cgo4 **_Ctype_struct_group) _Ctype_int {; _cgoCheckPointer(_cgo1, true); _cgoCheckPointer(_cgo4, true); return (_Cfunc_mygetgrnam_r)(_cgo0, _cgo1, _cgo2, _cgo3, _cgo4);}((*_Ctype_char)(unsafe.Pointer(&cname[0])), &grp, (*_Ctype_char)(buf.ptr), _Ctype_size_t(buf.size), &result)) }) if err != nil { return nil, fmt.Errorf("user: lookup groupname %s: %v", groupname, err) } if result == nil { return nil, UnknownGroupError(groupname) } return buildGroup(&grp), nil } func lookupGroupId(gid string) (*Group, error) { i, e := strconv.Atoi(gid) if e != nil { return nil, e } return lookupUnixGid(i) } func lookupUnixGid(gid int) (*Group, error) { var grp _Ctype_struct_group var result *_Ctype_struct_group buf := alloc(groupBuffer) defer buf.free() err := retryWithBuffer(buf, func() syscall.Errno { // mygetgrgid_r is a wrapper around getgrgid_r to // to avoid using gid_t because C.gid_t(gid) for // unknown reasons doesn't work on linux. return syscall.Errno(func(_cgo0 _Ctype_int, _cgo1 *_Ctype_struct_group, _cgo2 *_Ctype_char, _cgo3 _Ctype_size_t, _cgo4 **_Ctype_struct_group) _Ctype_int {; _cgoCheckPointer(_cgo1, true); _cgoCheckPointer(_cgo4, true); return (_Cfunc_mygetgrgid_r)(_cgo0, _cgo1, _cgo2, _cgo3, _cgo4);}(_Ctype_int(gid), &grp, (*_Ctype_char)(buf.ptr), _Ctype_size_t(buf.size), &result)) }) if err != nil { return nil, fmt.Errorf("user: lookup groupid %d: %v", gid, err) } if result == nil { return nil, UnknownGroupIdError(strconv.Itoa(gid)) } return buildGroup(&grp), nil } func buildGroup(grp *_Ctype_struct_group) *Group { g := &Group{ Gid: strconv.Itoa(int(grp.gr_gid)), Name: (_Cfunc_GoString)(grp.gr_name), } return g } type bufferKind _Ctype_int const ( userBuffer = bufferKind((_Ciconst__SC_GETPW_R_SIZE_MAX)) groupBuffer = bufferKind((_Ciconst__SC_GETGR_R_SIZE_MAX)) ) func (k bufferKind) initialSize() _Ctype_size_t { sz := (_Cfunc_sysconf)(_Ctype_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 // example, the musl libc returns -1. return 1024 } if !isSizeReasonable(int64(sz)) { // Truncate. If this truly isn't enough, retryWithBuffer will error on the first run. return maxBufferSize } return _Ctype_size_t(sz) } type memBuffer struct { ptr unsafe.Pointer size _Ctype_size_t } func alloc(kind bufferKind) *memBuffer { sz := kind.initialSize() return &memBuffer{ ptr: (_Cfunc__CMalloc)(sz), size: sz, } } func (mb *memBuffer) resize(newSize _Ctype_size_t) { mb.ptr = func(_cgo0 _cgo_unsafe.Pointer, _cgo1 _Ctype_size_t) _cgo_unsafe.Pointer {; _cgoCheckPointer(_cgo0); return (_Cfunc_realloc)(_cgo0, _cgo1);}(mb.ptr, newSize) mb.size = newSize } func (mb *memBuffer) free() { func(_cgo0 _cgo_unsafe.Pointer) {; _cgoCheckPointer(_cgo0); (_Cfunc_free)(_cgo0);}(mb.ptr) } // retryWithBuffer repeatedly calls f(), increasing the size of the // buffer each time, until f succeeds, fails with a non-ERANGE error, // or the buffer exceeds a reasonable limit. func retryWithBuffer(buf *memBuffer, f func() syscall.Errno) error { for { errno := f() if errno == 0 { return nil } else if errno != syscall.ERANGE { return errno } newSize := buf.size * 2 if !isSizeReasonable(int64(newSize)) { return fmt.Errorf("internal buffer exceeds %d bytes", maxBufferSize) } buf.resize(newSize) } } const maxBufferSize = 1 << 20 func isSizeReasonable(sz int64) bool { return sz > 0 && sz <= maxBufferSize } // Because we can't use cgo in tests: func structPasswdForNegativeTest() _Ctype_struct_passwd { sp := _Ctype_struct_passwd{} sp.pw_uid = 1<<32 - 2 sp.pw_gid = 1<<32 - 3 return sp }