// GroupName is an adaption from https://codereview.appspot.com/4589049. func GroupName(gid int) (string, error) { var grp C.struct_group var result *C.struct_group bufSize := C.size_t(C.sysconf(C._SC_GETGR_R_SIZE_MAX)) buf := C.malloc(bufSize) if buf == nil { return "", fmt.Errorf(gettext.Gettext("allocation failed")) } defer C.free(buf) // 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. rv := C.mygetgrgid_r(C.int(gid), &grp, (*C.char)(buf), bufSize, &result) if rv != 0 { return "", fmt.Errorf(gettext.Gettext("failed group lookup: %s"), syscall.Errno(rv)) } if result == nil { return "", fmt.Errorf(gettext.Gettext("unknown group %s"), gid) } return C.GoString(result.gr_name), nil }
// Because Go is like... naaaaa, no groups aren't a thing! // Based on Go's src/os/user/lookup_unix.go func currentUserAndGroup() (*userAndGroup, error) { u, err := user.Current() if err != nil { return nil, err } gid, err := strconv.Atoi(u.Gid) if err != nil { return nil, err } var grp C.struct_group var result *C.struct_group buflen := C.sysconf(C._SC_GETPW_R_SIZE_MAX) if buflen <= 0 || buflen > 1<<20 { return nil, fmt.Errorf("unreasonable _SC_GETGR_R_SIZE_MAX of %d", buflen) } buf := C.malloc(C.size_t(buflen)) defer C.free(buf) r := C.mygetgrgid_r(C.gid_t(gid), &grp, (*C.char)(buf), C.size_t(buflen), &result) if r != 0 { return nil, fmt.Errorf("lookup gid %d: %s", gid, syscall.Errno(r)) } if result == nil { return nil, fmt.Errorf("lookup gid %d failed", gid) } return &userAndGroup{ User: u, Groupname: C.GoString(grp.gr_name), }, nil }
func lookupUnixGid(gid int) (*Group, error) { var grp C.struct_group var result *C.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(C.mygetgrgid_r(C.int(gid), &grp, (*C.char)(buf.ptr), C.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 getGroupName(fi os.FileInfo) (string, error) { var rv C.int var grp C.struct_group var grpres *C.struct_group var bufSize C.long var result string bufSize = 1024 buf := C.malloc(C.size_t(bufSize)) defer C.free(buf) gid := fi.Sys().(*syscall.Stat_t).Gid rv = C.mygetgrgid_r(C.int(gid), &grp, (*C.char)(buf), C.size_t(bufSize), &grpres) if rv != 0 { return "", errors.New("Could not read groupname") } if grpres != nil { result = C.GoString(grp.gr_name) } else { return "", errors.New("Could not convert groupname") } return result, nil }
// LookupID looks up a group name based on its group ID. func lookupUnixGroup(gid int, f func(*C.struct_group) *Group) (*Group, error) { var grp C.struct_group var result *C.struct_group buf, bufSize, err := allocBuffer(groupBuffer) if err != nil { return nil, err } defer C.free(buf) // 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. rv := C.mygetgrgid_r(C.int(gid), &grp, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf( "group: lookup groupid %d: %s", gid, syscall.Errno(rv)) } if result == nil { return nil, UnknownGroupIDError(gid) } g := f(&grp) return g, nil }
func lookup(gid int, groupname string, lookupByName bool) (*Group, error) { var ( grp C.struct_group result *C.struct_group ) var bufSize C.long if runtime.GOOS == "freebsd" { // FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX // and just returns -1. So just use the same // size that Linux returns bufSize = 1024 } else { bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX) if bufSize <= 0 || bufSize > 1<<20 { return nil, fmt.Errorf( "user: unreasonable _SC_GETPW_R_SIZE_MAX of %d", bufSize) } } buf := C.malloc(C.size_t(bufSize)) defer C.free(buf) var rv C.int if lookupByName { nameC := C.CString(groupname) defer C.free(unsafe.Pointer(nameC)) rv = C.getgrnam_r(nameC, &grp, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf( "group: lookup groupname %s: %s", groupname, syscall.Errno(rv)) } if result == nil { return nil, UnknownGroupError(groupname) } } else { rv = C.mygetgrgid_r(C.int(gid), &grp, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("group: lookup groupid %d: %s", gid, syscall.Errno(rv)) } if result == nil { return nil, UnknownGroupIdError(gid) } } g := &Group{ Gid: strconv.Itoa(int(grp.gr_gid)), Name: C.GoString(grp.gr_name), Members: getMembers(grp), } return g, nil }
func lookupUnix(gid int, groupname string, lookupByName bool) (*Group, error) { var grp C.struct_group var result *C.struct_group var bufSize C.long if runtime.GOOS == "freebsd" { panic("Don't know how to deal with freebsd.") } else { bufSize = C.sysconf(C._SC_GETGR_R_SIZE_MAX) * 20 if bufSize <= 0 || bufSize > 1<<20 { return nil, fmt.Errorf("group: unreasonable _SC_GETGR_R_SIZE_MAX of %d", bufSize) } } buf := C.malloc(C.size_t(bufSize)) defer C.free(buf) var rv C.int if lookupByName { nameC := C.CString(groupname) defer C.free(unsafe.Pointer(nameC)) rv = C.mygetgrnam_r(nameC, &grp, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("group: lookup groupname %s: %s", groupname, syscall.Errno(rv)) } if result == nil { return nil, UnknownGroupError(groupname) } } else { rv = C.mygetgrgid_r(C.int(gid), &grp, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("group: lookup groupid %d: %s", gid, syscall.Errno(rv)) } if result == nil { return nil, UnknownGroupIdError(gid) } } u := &Group{ Gid: strconv.Itoa(int(grp.gr_gid)), Groupname: C.GoString(grp.gr_name), } return u, nil }
func lookupUnix(gid int, groupname string, lookupByName bool) (*Group, error) { var grp C.struct_group var result *C.struct_group var bufSize C.long if runtime.GOOS == "freebsd" { // FreeBSD doesn't have _SC_GETGR_R_SIZE_MAX // and just returns -1. So just use the same // size that Linux returns // TODO: Confirm this! bufSize = 1024 } else { bufSize = C.sysconf(C._SC_GETGR_R_SIZE_MAX) if bufSize <= 0 || bufSize > 1<<20 { return nil, fmt.Errorf("group: unreasonable _SC_GETGR_R_SIZE_MAX of %d", bufSize) } } buf := C.malloc(C.size_t(bufSize)) defer C.free(buf) var rv C.int if lookupByName { nameC := C.CString(groupname) defer C.free(unsafe.Pointer(nameC)) rv = C.getgrnam_r(nameC, &grp, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("group: lookup groupname %s: %s", groupname, syscall.Errno(rv)) } if result == nil { return nil, UnknownGroupError(groupname) } } else { // mygetgrgid_r is a wrapper around getgrgid_r to // avoid using gid_t because C.gid_t(gid) for // unknown reasons doesn't work on linux. rv = C.mygetgrgid_r(C.int(gid), &grp, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("group: lookup groupid %d: %s", gid, syscall.Errno(rv)) } if result == nil { return nil, UnknownGroupIdError(gid) } } var members []string if grp.gr_mem != nil { members = make([]string, C.member_count(grp.gr_mem)) i := 0 for mem := grp.gr_mem; *mem != nil; mem = C.next_mem(mem) { members[i] = C.GoString(*mem) i += 1 } } else { members = make([]string, 0) } g := &Group{ Gid: strconv.Itoa(int(grp.gr_gid)), Name: C.GoString(grp.gr_name), Members: members, } return g, nil }
func lookupUnix(gid int, groupname string, lookupByName bool) (*Group, error) { var grp C.struct_group var result *C.struct_group var bufSize C.long if runtime.GOOS == "dragonfly" || runtime.GOOS == "freebsd" { // DragonFly and FreeBSD do not have _SC_GETGR_R_SIZE_MAX // and just return -1. So just use the same // size that Linux returns. bufSize = 1024 } else { bufSize = C.sysconf(C._SC_GETGR_R_SIZE_MAX) if bufSize <= 0 || bufSize > 1<<20 { return nil, fmt.Errorf("user: unreasonable _SC_GETGR_R_SIZE_MAX of %d", bufSize) } } buf := C.malloc(C.size_t(bufSize)) defer C.free(buf) var rv C.int if lookupByName { nameC := C.CString(groupname) defer C.free(unsafe.Pointer(nameC)) rv = C.getgrnam_r(nameC, &grp, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("group: lookup group %s: %s", groupname, syscall.Errno(rv)) } if result == nil { return nil, UnknownGroupError(groupname) } } else { // mygetgrgid_r is a wrapper around getgrgid_r to // to avoid using uid_t because C.uid_t(uid) for // unknown reasons doesn't work on linux. rv = C.mygetgrgid_r(C.int(gid), &grp, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("grp: lookup groupid %d: %s", gid, syscall.Errno(rv)) } if result == nil { return nil, UnknownGroupIdError(gid) } } members := make([]string, 0) for memptr := grp.gr_mem; *memptr != nil; memptr = (**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(memptr)) + unsafe.Sizeof(*grp.gr_mem))) { members = append(members, C.GoString(*memptr)) } g := &Group{ Gid: strconv.Itoa(int(grp.gr_gid)), Name: C.GoString(grp.gr_name), Password: C.GoString(grp.gr_passwd), Members: members, } return g, nil }