From 9359c8a5e83ba1666728f02c6ec1d900473d25eb Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Mon, 7 Sep 2015 23:15:28 -0600 Subject: Pull the mucking with getgrnam into a getgr package. --- getgr/getgr.go | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 getgr/getgr.go diff --git a/getgr/getgr.go b/getgr/getgr.go new file mode 100644 index 0000000..5470b2c --- /dev/null +++ b/getgr/getgr.go @@ -0,0 +1,103 @@ +package getgr + +import ( + "syscall" + "unsafe" +) + +//#define _POSIX_SOURCE // for getgrnam_r(3) in grp.h +//#include // for free(3) +//#include // for sysconf(3) +//#include // for getgrnam_r(3) +//static char *strary(char **ary, unsigned int n) { return ary[n]; } +import "C" + +type Gid uint + +type Group struct { + Name string + Passwd string + Gid Gid + Mem []string +} + +func strary(c **C.char) (g []string) { + g = make([]string, 0) + for i := C.uint(0); true; i++ { + cstr := C.strary(c, i) + if cstr == nil { + return + } + g = append(g, C.GoString(cstr)) + } + panic("not reached") +} + +// A wrapper around C getgrnam_r +func ByName(name string) (*Group, error) { + nameC := C.CString(name) + defer C.free(unsafe.Pointer(nameC)) + + buflen := C.sysconf(C._SC_GETGR_R_SIZE_MAX) + if buflen < 1 { + buflen = 1024 + } + buf := make([]byte, buflen) + var grp C.struct_group + var ret *C.struct_group + for { + success, errno := C.getgrnam_r(nameC, &grp, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(buflen), &ret) + if success >= 0 { + break + } + if errno == syscall.ERANGE { + buflen += 256 + buf = make([]byte, buflen) + } else { + return nil, errno + } + } + if ret == nil { + return nil, nil + } + return &Group{ + Name: C.GoString(ret.gr_name), + Passwd: C.GoString(ret.gr_passwd), + Gid: Gid(ret.gr_gid), + Mem: strary(ret.gr_mem), + }, nil +} + +// A wrapper around C getgrgid_r +func ByGid(gid int32) (*Group, error) { + gidC := C.__gid_t(gid) + + buflen := C.sysconf(C._SC_GETGR_R_SIZE_MAX) + if buflen < 1 { + buflen = 1024 + } + buf := make([]byte, buflen) + var grp C.struct_group + var ret *C.struct_group + for { + success, errno := C.getgrgid_r(gidC, &grp, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(buflen), &ret) + if success >= 0 { + break + } + if errno == syscall.ERANGE { + buflen += 256 + buf = make([]byte, buflen) + } else { + return nil, errno + } + } + if ret == nil { + return nil, nil + } + return &Group{ + Name: C.GoString(ret.gr_name), + Passwd: C.GoString(ret.gr_passwd), + Gid: Gid(ret.gr_gid), + Mem: strary(ret.gr_mem), + }, nil +} -- cgit v1.1-4-g5e80