This commit is contained in:
ge
2026-01-25 13:31:10 +03:00
commit 3b381ba118
10 changed files with 303 additions and 0 deletions

137
pwd.c.v Normal file
View File

@@ -0,0 +1,137 @@
@[has_globals]
module pwd
import sync
$if windows {
$compile_error('pwd: MS Windows is not supported')
}
#include <errno.h>
#include <pwd.h>
__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 // used 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 string representation of EntryNotFoundError error.
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}'
}