diff options
-rw-r--r-- | getgr/getgr.go | 103 |
1 files changed, 103 insertions, 0 deletions
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 <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 +} |