summaryrefslogtreecommitdiff
path: root/src/getgr
diff options
context:
space:
mode:
Diffstat (limited to 'src/getgr')
-rw-r--r--src/getgr/getgr.go103
1 files changed, 103 insertions, 0 deletions
diff --git a/src/getgr/getgr.go b/src/getgr/getgr.go
new file mode 100644
index 0000000..5470b2c
--- /dev/null
+++ b/src/getgr/getgr.go
@@ -0,0 +1,103 @@
+package getgr
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+//#define _POSIX_SOURCE // for getgrnam_r(3) in grp.h
+//#include <stdlib.h> // for free(3)
+//#include <unistd.h> // for sysconf(3)
+//#include <grp.h> // 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
+}