// Copyright 2015-2016 Luke Shumaker . // // This is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This software is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this manual; if not, see // . // Package getgr provides an interface to query the POSIX group // database. // // BUG(lukeshu) This package should be renamed to "nss" and expanded. package getgr import ( "unsafe" "golang.org/x/sys/unix" ) //#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 == unix.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 == unix.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 }