@[has_globals] module pwd import sync $if windows { $compile_error('pwd: MS Windows is not supported') } #include #include __global pwd_mutex &sync.Mutex fn init() { pwd_mutex = sync.new_mutex() } fn cleanup() { pwd_mutex.destroy() unsafe { free(pwd_mutex) } } struct C.passwd { pw_name &char pw_passwd &char pw_uid i32 pw_gid i32 pw_gecos &char pw_dir &char pw_shell &char } fn C.getpwuid(i32) &C.passwd fn C.getpwnam(&char) &C.passwd fn C.setpwent() fn C.endpwent() fn C.getpwent() &C.passwd pub struct Passwd { pub: name string // username passwd string // user password, usually set to 'x' uid int // user ID gid int // group ID gecos string // user information dir string // home directory shell string // shell program } fn make_passwd(pw &C.passwd) Passwd { return unsafe { Passwd{ name: cstring_to_vstring(pw.pw_name) passwd: cstring_to_vstring(pw.pw_passwd) uid: int(pw.pw_uid) gid: int(pw.pw_gid) gecos: cstring_to_vstring(pw.pw_gecos) dir: cstring_to_vstring(pw.pw_dir) shell: cstring_to_vstring(pw.pw_shell) } } } fn make_error(name string, uid int) IError { err := C.errno if err !in [4, 5, 12, 23, 24, 34] { // Error is not EINTR, EIO, ENOMEM, ENFILE, EMFILE or ERANGE return EntryNotFoundError{ name: name uid: uid } } return error_with_code(c_error_number_str(err), err) } // get_by_uid returns the passwd database entry by user ID. // If the entry is not found, the EntryNotFoundError error will be returned. pub fn get_by_uid(uid int) !Passwd { pwd_mutex.lock() defer { pwd_mutex.unlock() } pw := C.getpwuid(uid) if isnil(pw) { return make_error('', uid) } return make_passwd(pw) } // get_by_uid returns the passwd database entry by user name. // If the entry is not found, the EntryNotFoundError error will be returned. pub fn get_by_name(name string) !Passwd { pwd_mutex.lock() defer { pwd_mutex.unlock() } pw := C.getpwnam(&char(name.str)) if isnil(pw) { return make_error(name, -1) } return make_passwd(pw) } // get_all returns all entries from passwd database in arbitrary order. pub fn get_all() []Passwd { mut pwds := []Passwd{} pwd_mutex.lock() C.setpwent() defer { C.endpwent() pwd_mutex.unlock() } for { pw := C.getpwent() if isnil(pw) { break } pwds << make_passwd(pw) } return pwds } // EntryNotFoundError designates that an entry with the specified UID or name was not found. pub struct EntryNotFoundError { Error name string uid int } // msg returns the EntryNotFoundError error message. pub fn (e EntryNotFoundError) msg() string { if e.name != '' { return "no passwd entry found by username '${e.name}'" } return 'no passwd entry found by user ID ${e.uid}' }