func lookupUser(username string) (*User, error) { var pwd C.struct_passwd var result *C.struct_passwd nameC := C.CString(username) defer C.free(unsafe.Pointer(nameC)) buf := alloc(userBuffer) defer buf.free() err := retryWithBuffer(buf, func() syscall.Errno { // mygetpwnam_r is a wrapper around getpwnam_r to avoid // passing a size_t to getpwnam_r, because for unknown // reasons passing a size_t to getpwnam_r doesn't work on // Solaris. return syscall.Errno(C.mygetpwnam_r(nameC, &pwd, (*C.char)(buf.ptr), C.size_t(buf.size), &result)) }) if err != nil { return nil, fmt.Errorf("user: lookup username %s: %v", username, err) } if result == nil { return nil, UnknownUserError(username) } return buildUser(&pwd), err }
func lookupUnix(uid int, username string, lookupByName bool) (*User, error) { var pwd C.struct_passwd var result *C.struct_passwd bufSize := C.sysconf(C._SC_GETPW_R_SIZE_MAX) if bufSize == -1 { // DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX. // Additionally, not all Linux systems have it, either. For // example, the musl libc returns -1. bufSize = 1024 } 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(username) defer C.free(unsafe.Pointer(nameC)) // mygetpwnam_r is a wrapper around getpwnam_r to avoid // passing a size_t to getpwnam_r, because for unknown // reasons passing a size_t to getpwnam_r doesn't work on // Solaris. rv = C.mygetpwnam_r(nameC, &pwd, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.Errno(rv)) } if result == nil { return nil, UnknownUserError(username) } } else { // mygetpwuid_r is a wrapper around getpwuid_r to // to avoid using uid_t because C.uid_t(uid) for // unknown reasons doesn't work on linux. rv = C.mygetpwuid_r(C.int(uid), &pwd, (*C.char)(buf), C.size_t(bufSize), &result) if rv != 0 { return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.Errno(rv)) } if result == nil { return nil, UnknownUserIdError(uid) } } u := &User{ Uid: strconv.Itoa(int(pwd.pw_uid)), Gid: strconv.Itoa(int(pwd.pw_gid)), Username: C.GoString(pwd.pw_name), Name: C.GoString(pwd.pw_gecos), HomeDir: C.GoString(pwd.pw_dir), } // The pw_gecos field isn't quite standardized. Some docs // say: "It is expected to be a comma separated list of // personal data where the first item is the full name of the // user." if i := strings.Index(u.Name, ","); i >= 0 { u.Name = u.Name[:i] } return u, nil }