Implement pwd.h
This commit is contained in:
Generated
+11
@@ -249,6 +249,16 @@ dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pwd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cbindgen 0.5.2",
|
||||
"errno 0.1.0",
|
||||
"fcntl 0.1.0",
|
||||
"platform 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.3.15"
|
||||
@@ -324,6 +334,7 @@ dependencies = [
|
||||
"locale 0.1.0",
|
||||
"netinet 0.1.0",
|
||||
"platform 0.1.0",
|
||||
"pwd 0.1.0",
|
||||
"semaphore 0.1.0",
|
||||
"setjmp 0.1.0",
|
||||
"signal 0.1.0",
|
||||
|
||||
@@ -26,6 +26,7 @@ inttypes = { path = "src/inttypes" }
|
||||
locale = { path = "src/locale" }
|
||||
netinet = { path = "src/netinet" }
|
||||
platform = { path = "src/platform" }
|
||||
pwd = { path = "src/pwd" }
|
||||
semaphore = { path = "src/semaphore" }
|
||||
setjmp = { path = "src/setjmp" }
|
||||
signal = { path = "src/signal" }
|
||||
|
||||
+7
-17
@@ -2,41 +2,31 @@
|
||||
#define _SYS_TYPES_H
|
||||
|
||||
typedef long blksize_t;
|
||||
|
||||
typedef long dev_t;
|
||||
|
||||
typedef unsigned long ino_t;
|
||||
|
||||
typedef int gid_t;
|
||||
|
||||
typedef int uid_t;
|
||||
|
||||
typedef int mode_t;
|
||||
|
||||
typedef unsigned long nlink_t;
|
||||
|
||||
typedef long off_t;
|
||||
|
||||
typedef int pid_t;
|
||||
|
||||
typedef unsigned id_t;
|
||||
|
||||
typedef long ssize_t;
|
||||
|
||||
typedef long time_t;
|
||||
|
||||
typedef unsigned int useconds_t;
|
||||
|
||||
typedef int suseconds_t;
|
||||
|
||||
typedef long clock_t;
|
||||
|
||||
typedef int clockid_t;
|
||||
|
||||
typedef void* timer_t;
|
||||
|
||||
typedef unsigned long int blkcnt_t;
|
||||
|
||||
typedef unsigned char u_char, uchar;
|
||||
typedef unsigned short u_short, ushort;
|
||||
typedef unsigned int u_int, uint;
|
||||
typedef unsigned long u_long, ulong;
|
||||
typedef long long quad_t;
|
||||
typedef unsigned long long u_quad_t;
|
||||
|
||||
#ifdef __linux__
|
||||
#define _SC_PAGE_SIZE 30
|
||||
#endif
|
||||
|
||||
@@ -16,6 +16,7 @@ pub extern crate float;
|
||||
pub extern crate grp;
|
||||
pub extern crate locale;
|
||||
pub extern crate netinet;
|
||||
pub extern crate pwd;
|
||||
pub extern crate semaphore;
|
||||
pub extern crate setjmp;
|
||||
pub extern crate signal;
|
||||
|
||||
@@ -33,8 +33,11 @@ mod sys;
|
||||
#[path = "redox/mod.rs"]
|
||||
mod sys;
|
||||
|
||||
pub mod rawfile;
|
||||
pub mod types;
|
||||
|
||||
pub use rawfile::RawFile;
|
||||
|
||||
use alloc::Vec;
|
||||
use core::{fmt, ptr};
|
||||
|
||||
@@ -61,6 +64,7 @@ pub unsafe fn c_str_mut<'a>(s: *mut c_char) -> &'a mut [u8] {
|
||||
}
|
||||
|
||||
pub unsafe fn c_str_n_mut<'a>(s: *mut c_char, n: usize) -> &'a mut [u8] {
|
||||
assert!(s != ptr::null_mut());
|
||||
use core::slice;
|
||||
|
||||
let mut size = 0;
|
||||
@@ -81,6 +85,7 @@ pub unsafe fn c_str<'a>(s: *const c_char) -> &'a [u8] {
|
||||
}
|
||||
|
||||
pub unsafe fn c_str_n<'a>(s: *const c_char, n: usize) -> &'a [u8] {
|
||||
assert!(s != ptr::null());
|
||||
use core::slice;
|
||||
|
||||
let mut size = 0;
|
||||
|
||||
@@ -122,15 +122,15 @@ pub fn getdents(fd: c_int, dirents: *mut dirent, bytes: usize) -> c_int {
|
||||
}
|
||||
|
||||
pub fn getegid() -> gid_t {
|
||||
e(unsafe { syscall!(GETEGID) })
|
||||
e(unsafe { syscall!(GETEGID) }) as gid_t
|
||||
}
|
||||
|
||||
pub fn geteuid() -> uid_t {
|
||||
e(unsafe { syscall!(GETEUID) })
|
||||
e(unsafe { syscall!(GETEUID) }) as uid_t
|
||||
}
|
||||
|
||||
pub fn getgid() -> gid_t {
|
||||
e(unsafe { syscall!(GETGID) })
|
||||
e(unsafe { syscall!(GETGID) }) as gid_t
|
||||
}
|
||||
|
||||
pub unsafe fn gethostname(mut name: *mut c_char, len: size_t) -> c_int {
|
||||
@@ -174,15 +174,15 @@ pub unsafe fn getpeername(
|
||||
}
|
||||
|
||||
pub fn getpgid(pid: pid_t) -> pid_t {
|
||||
e(unsafe { syscall!(GETPGID, pid) })
|
||||
e(unsafe { syscall!(GETPGID, pid) }) as pid_t
|
||||
}
|
||||
|
||||
pub fn getpid() -> pid_t {
|
||||
e(unsafe { syscall!(GETPID) })
|
||||
e(unsafe { syscall!(GETPID) }) as pid_t
|
||||
}
|
||||
|
||||
pub fn getppid() -> pid_t {
|
||||
e(unsafe { syscall!(GETPPID) })
|
||||
e(unsafe { syscall!(GETPPID) }) as pid_t
|
||||
}
|
||||
|
||||
pub unsafe fn getsockname(
|
||||
@@ -217,7 +217,7 @@ pub fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> c_int {
|
||||
}
|
||||
|
||||
pub fn getuid() -> uid_t {
|
||||
e(unsafe { syscall!(GETUID) })
|
||||
e(unsafe { syscall!(GETUID) }) as uid_t
|
||||
}
|
||||
|
||||
pub fn ioctl(fd: c_int, request: c_ulong, out: *mut c_void) -> c_int {
|
||||
|
||||
@@ -11,7 +11,7 @@ impl RawFile {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dup(&self, _buf: &[u8]) -> Result<RawFile, ()> {
|
||||
pub fn dup(&self) -> Result<RawFile, ()> {
|
||||
match dup(self.0) {
|
||||
-1 => Err(()),
|
||||
n => Ok(RawFile(n))
|
||||
@@ -38,9 +38,9 @@ impl Drop for RawFile {
|
||||
}
|
||||
|
||||
impl Deref for RawFile {
|
||||
type Target = usize;
|
||||
type Target = c_int;
|
||||
|
||||
fn deref(&self) -> &usize {
|
||||
fn deref(&self) -> &c_int {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ pub fn chmod(path: *const c_char, mode: mode_t) -> c_int {
|
||||
match syscall::open(path, O_WRONLY) {
|
||||
Err(err) => e(Err(err)) as c_int,
|
||||
Ok(fd) => {
|
||||
let res = syscall::fchmod(fd as usize, mode);
|
||||
let res = syscall::fchmod(fd as usize, mode as u16);
|
||||
let _ = syscall::close(fd);
|
||||
e(res) as c_int
|
||||
}
|
||||
@@ -215,7 +215,7 @@ pub fn fchdir(fd: c_int) -> c_int {
|
||||
}
|
||||
|
||||
pub fn fchmod(fd: c_int, mode: mode_t) -> c_int {
|
||||
e(syscall::fchmod(fd as usize, mode)) as c_int
|
||||
e(syscall::fchmod(fd as usize, mode as u16)) as c_int
|
||||
}
|
||||
|
||||
pub fn fchown(fd: c_int, owner: uid_t, group: gid_t) -> c_int {
|
||||
@@ -239,7 +239,7 @@ pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int {
|
||||
(*buf).st_dev = redox_buf.st_dev as dev_t;
|
||||
(*buf).st_ino = redox_buf.st_ino as ino_t;
|
||||
(*buf).st_nlink = redox_buf.st_nlink as nlink_t;
|
||||
(*buf).st_mode = redox_buf.st_mode;
|
||||
(*buf).st_mode = redox_buf.st_mode as mode_t;
|
||||
(*buf).st_uid = redox_buf.st_uid as uid_t;
|
||||
(*buf).st_gid = redox_buf.st_gid as gid_t;
|
||||
// TODO st_rdev
|
||||
@@ -494,11 +494,11 @@ pub fn isatty(fd: c_int) -> c_int {
|
||||
}
|
||||
|
||||
pub fn kill(pid: pid_t, sig: c_int) -> c_int {
|
||||
e(syscall::kill(pid, sig as usize)) as c_int
|
||||
e(syscall::kill(pid as usize, sig as usize)) as c_int
|
||||
}
|
||||
|
||||
pub fn killpg(pgrp: pid_t, sig: c_int) -> c_int {
|
||||
e(syscall::kill(-(pgrp as isize) as pid_t, sig as usize)) as c_int
|
||||
e(syscall::kill(-(pgrp as isize) as usize, sig as usize)) as c_int
|
||||
}
|
||||
|
||||
pub fn link(path1: *const c_char, path2: *const c_char) -> c_int {
|
||||
@@ -823,7 +823,7 @@ pub fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> pid_t {
|
||||
if !stat_loc.is_null() {
|
||||
*stat_loc = temp as c_int;
|
||||
}
|
||||
res
|
||||
res as pid_t
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-15
@@ -50,25 +50,25 @@ pub type wchar_t = i32;
|
||||
pub type wint_t = u32;
|
||||
pub type wctype_t = i64;
|
||||
|
||||
pub type off_t = i64;
|
||||
pub type mode_t = u16;
|
||||
pub type time_t = i64;
|
||||
pub type pid_t = usize;
|
||||
pub type id_t = usize;
|
||||
pub type gid_t = usize;
|
||||
pub type uid_t = usize;
|
||||
pub type dev_t = usize;
|
||||
pub type ino_t = usize;
|
||||
pub type nlink_t = usize;
|
||||
pub type blksize_t = isize;
|
||||
pub type blkcnt_t = u64;
|
||||
pub type off_t = c_long;
|
||||
pub type mode_t = c_int;
|
||||
pub type time_t = c_long;
|
||||
pub type pid_t = c_int;
|
||||
pub type id_t = c_uint;
|
||||
pub type gid_t = c_int;
|
||||
pub type uid_t = c_int;
|
||||
pub type dev_t = c_long;
|
||||
pub type ino_t = c_ulong;
|
||||
pub type nlink_t = c_ulong;
|
||||
pub type blksize_t = c_long;
|
||||
pub type blkcnt_t = c_ulong;
|
||||
|
||||
pub type useconds_t = c_uint;
|
||||
pub type suseconds_t = c_int;
|
||||
|
||||
pub type clock_t = i64;
|
||||
pub type clockid_t = i32;
|
||||
pub type timer_t = c_void;
|
||||
pub type clock_t = c_long;
|
||||
pub type clockid_t = c_int;
|
||||
pub type timer_t = *mut c_void;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "pwd"
|
||||
version = "0.1.0"
|
||||
authors = ["jD91mZM2 <me@krake.one>"]
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = { path = "../../cbindgen" }
|
||||
|
||||
[dependencies]
|
||||
errno = { path = "../errno" }
|
||||
fcntl = { path = "../fcntl" }
|
||||
platform = { path = "../platform" }
|
||||
@@ -0,0 +1,11 @@
|
||||
extern crate cbindgen;
|
||||
|
||||
use std::{env, fs};
|
||||
|
||||
fn main() {
|
||||
let crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
|
||||
fs::create_dir_all("../../target/include").expect("failed to create include directory");
|
||||
cbindgen::generate(crate_dir)
|
||||
.expect("failed to generate bindings")
|
||||
.write_to_file("../../target/include/pwd.h");
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
sys_includes = ["stddef.h", "sys/types.h"]
|
||||
include_guard = "_PWD_H"
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
|
||||
[enum]
|
||||
prefix_with_name = true
|
||||
@@ -0,0 +1,269 @@
|
||||
//! pwd implementation for relibc
|
||||
|
||||
#![no_std]
|
||||
#![feature(alloc)]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate errno;
|
||||
extern crate fcntl;
|
||||
extern crate platform;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::ptr;
|
||||
use platform::RawFile;
|
||||
use platform::types::*;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct passwd {
|
||||
pw_name: *mut c_char,
|
||||
pw_passwd: *mut c_char,
|
||||
pw_uid: uid_t,
|
||||
pw_gid: gid_t,
|
||||
pw_gecos: *mut c_char,
|
||||
pw_dir: *mut c_char,
|
||||
pw_shell: *mut c_char
|
||||
}
|
||||
|
||||
static mut PASSWD_BUF: *mut c_char = ptr::null_mut();
|
||||
static mut PASSWD: passwd = passwd {
|
||||
pw_name: ptr::null_mut(),
|
||||
pw_passwd: ptr::null_mut(),
|
||||
pw_uid: 0,
|
||||
pw_gid: 0,
|
||||
pw_gecos: ptr::null_mut(),
|
||||
pw_dir: ptr::null_mut(),
|
||||
pw_shell: ptr::null_mut()
|
||||
};
|
||||
|
||||
enum OptionPasswd {
|
||||
Error,
|
||||
NotFound,
|
||||
Found(*mut c_char)
|
||||
}
|
||||
|
||||
fn pwd_lookup<F>(out: *mut passwd, alloc: Option<(*mut c_char, size_t)>, mut callback: F) -> OptionPasswd
|
||||
where
|
||||
// TODO F: FnMut(impl Iterator<Item = &[u8]>) -> bool
|
||||
F: FnMut(&[&[u8]]) -> bool
|
||||
{
|
||||
let file = match RawFile::open("/etc/passwd\0".as_ptr() as *const c_char, fcntl::O_RDONLY, 0o644) {
|
||||
Ok(file) => file,
|
||||
Err(_) => return OptionPasswd::Error
|
||||
};
|
||||
|
||||
let mut buf = Vec::new();
|
||||
let mut newline = None;
|
||||
|
||||
loop {
|
||||
// TODO when nll becomes a thing:
|
||||
// let mut newline;
|
||||
|
||||
// WORKAROUND:
|
||||
if let Some(newline) = newline {
|
||||
buf.drain(..newline + 1);
|
||||
}
|
||||
|
||||
// Read until newline
|
||||
loop {
|
||||
newline = buf.iter().position(|b| *b == b'\n');
|
||||
|
||||
if newline.is_some() {
|
||||
break;
|
||||
}
|
||||
|
||||
let len = buf.len();
|
||||
|
||||
if len >= buf.capacity() {
|
||||
buf.reserve(1024);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let capacity = buf.capacity();
|
||||
buf.set_len(capacity);
|
||||
}
|
||||
|
||||
let read = platform::read(*file, &mut buf[len..]);
|
||||
if read == 0 {
|
||||
return OptionPasswd::NotFound;
|
||||
}
|
||||
if read < 0 {
|
||||
return OptionPasswd::Error;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
buf.set_len(len + read as usize);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse into passwd
|
||||
let newline = newline.unwrap(); // safe because it doesn't break the loop otherwise
|
||||
let line = &buf[..newline];
|
||||
let mut parts: [&[u8]; 7] = [&[]; 7];
|
||||
for (i, part) in line.splitn(7, |b| *b == b':').enumerate() {
|
||||
parts[i] = part;
|
||||
}
|
||||
|
||||
if !callback(&parts) {
|
||||
// TODO when nll becomes a thing:
|
||||
// buf.drain(..newline + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
let len = parts.iter()
|
||||
.enumerate()
|
||||
.filter(|(i, _)| *i != 2 && *i != 3)
|
||||
.map(|(_, part)| part.len() + 1)
|
||||
.sum();
|
||||
|
||||
if alloc.map(|(_, s)| len > s as usize).unwrap_or(false) {
|
||||
unsafe {
|
||||
platform::errno = errno::ERANGE;
|
||||
}
|
||||
return OptionPasswd::Error;
|
||||
}
|
||||
|
||||
let alloc = match alloc {
|
||||
Some((alloc, _)) => alloc,
|
||||
None => unsafe { platform::alloc(len) as *mut c_char }
|
||||
};
|
||||
// _ prefix so it won't complain about the trailing
|
||||
// _off += <thing>
|
||||
// in the macro that is never read
|
||||
let mut _off = 0;
|
||||
|
||||
let mut parts = parts.into_iter();
|
||||
|
||||
macro_rules! copy_into {
|
||||
($entry:expr) => {
|
||||
debug_assert!(_off as usize <= len);
|
||||
|
||||
let src = parts.next().unwrap_or(&(&[] as &[u8])); // this is madness
|
||||
let dst = unsafe { alloc.offset(_off) };
|
||||
|
||||
for (i, c) in src.iter().enumerate() {
|
||||
unsafe {
|
||||
*dst.offset(i as isize) = *c as c_char;
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
*dst.offset(src.len() as isize) = 0;
|
||||
|
||||
$entry = dst;
|
||||
}
|
||||
_off += src.len() as isize + 1;
|
||||
};
|
||||
($entry:expr, parse) => {
|
||||
unsafe {
|
||||
$entry = parts.next()
|
||||
.and_then(|part| core::str::from_utf8(part).ok())
|
||||
.and_then(|part| part.parse().ok())
|
||||
.unwrap_or(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copy_into!((*out).pw_name);
|
||||
copy_into!((*out).pw_passwd);
|
||||
copy_into!((*out).pw_uid, parse);
|
||||
copy_into!((*out).pw_gid, parse);
|
||||
copy_into!((*out).pw_gecos);
|
||||
copy_into!((*out).pw_dir);
|
||||
copy_into!((*out).pw_shell);
|
||||
|
||||
return OptionPasswd::Found(alloc);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn getpwnam_r(name: *const c_char, out: *mut passwd, buf: *mut c_char,
|
||||
size: size_t, result: *mut *mut passwd) -> c_int {
|
||||
match pwd_lookup(out, Some((buf, size)), |parts| {
|
||||
let part = parts.get(0).unwrap_or(&(&[] as &[u8]));
|
||||
for (i, c) in part.iter().enumerate() {
|
||||
// /etc/passwd should not contain any NUL bytes in the middle
|
||||
// of entries, but if this happens, it can't possibly match the
|
||||
// search query since it's NUL terminated.
|
||||
if *c == 0 || unsafe { *name.offset(i as isize) } != *c as c_char {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}) {
|
||||
OptionPasswd::Error => unsafe {
|
||||
*result = ptr::null_mut();
|
||||
-1
|
||||
},
|
||||
OptionPasswd::NotFound => unsafe {
|
||||
*result = ptr::null_mut();
|
||||
0
|
||||
},
|
||||
OptionPasswd::Found(_) => unsafe {
|
||||
*result = out;
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn getpwuid_r(uid: uid_t, out: *mut passwd, buf: *mut c_char,
|
||||
size: size_t, result: *mut *mut passwd) -> c_int {
|
||||
match pwd_lookup(out, Some((buf, size)), |parts| {
|
||||
let part = parts.get(2)
|
||||
.and_then(|part| core::str::from_utf8(part).ok())
|
||||
.and_then(|part| part.parse().ok());
|
||||
part == Some(uid)
|
||||
}) {
|
||||
OptionPasswd::Error => unsafe {
|
||||
*result = ptr::null_mut();
|
||||
-1
|
||||
},
|
||||
OptionPasswd::NotFound => unsafe {
|
||||
*result = ptr::null_mut();
|
||||
0
|
||||
},
|
||||
OptionPasswd::Found(_) => unsafe {
|
||||
*result = out;
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn getpwnam(name: *const c_char) -> *mut passwd {
|
||||
match pwd_lookup(unsafe { &mut PASSWD }, None, |parts| {
|
||||
let part = parts.get(0).unwrap_or(&(&[] as &[u8]));
|
||||
for (i, c) in part.iter().enumerate() {
|
||||
// /etc/passwd should not contain any NUL bytes in the middle
|
||||
// of entries, but if this happens, it can't possibly match the
|
||||
// search query since it's NUL terminated.
|
||||
if *c == 0 || unsafe { *name.offset(i as isize) } != *c as c_char {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}) {
|
||||
OptionPasswd::Error => ptr::null_mut(),
|
||||
OptionPasswd::NotFound => ptr::null_mut(),
|
||||
OptionPasswd::Found(buf) => unsafe {
|
||||
PASSWD_BUF = buf;
|
||||
&mut PASSWD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn getpwuid(uid: uid_t) -> *mut passwd {
|
||||
match pwd_lookup(unsafe { &mut PASSWD }, None, |parts| {
|
||||
let part = parts.get(2)
|
||||
.and_then(|part| core::str::from_utf8(part).ok())
|
||||
.and_then(|part| part.parse().ok());
|
||||
part == Some(uid)
|
||||
}) {
|
||||
OptionPasswd::Error => ptr::null_mut(),
|
||||
OptionPasswd::NotFound => ptr::null_mut(),
|
||||
OptionPasswd::Found(buf) => unsafe {
|
||||
PASSWD_BUF = buf;
|
||||
&mut PASSWD
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,7 @@ wchar/mbsrtowcs
|
||||
wchar/putwchar
|
||||
wchar/wcrtomb
|
||||
dirent
|
||||
pwd
|
||||
stdlib/alloc
|
||||
stdlib/bsearch
|
||||
stdlib/mktemp
|
||||
|
||||
@@ -67,6 +67,7 @@ EXPECT_BINS=\
|
||||
BINS=\
|
||||
$(EXPECT_BINS) \
|
||||
dirent \
|
||||
pwd \
|
||||
stdlib/alloc \
|
||||
stdlib/bsearch \
|
||||
stdlib/mktemp \
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void print(struct passwd *pwd) {
|
||||
printf("pw_name: %s\n", pwd->pw_name);
|
||||
printf("pw_password: %s\n", pwd->pw_passwd);
|
||||
printf("pw_uid: %u\n", pwd->pw_uid);
|
||||
printf("pw_gid: %u\n", pwd->pw_gid);
|
||||
printf("pw_gecos: %s\n", pwd->pw_gecos);
|
||||
printf("pw_dir: %s\n", pwd->pw_dir);
|
||||
printf("pw_shell: %s\n", pwd->pw_shell);
|
||||
}
|
||||
|
||||
int main() {
|
||||
puts("--- Checking getpwuid ---");
|
||||
errno = 0;
|
||||
struct passwd *pwd = getpwuid(0);
|
||||
if (errno != 0) {
|
||||
perror("getpwuid");
|
||||
return 1;
|
||||
}
|
||||
if (pwd != NULL) {
|
||||
print(pwd);
|
||||
}
|
||||
|
||||
puts("--- Checking getpwnam ---");
|
||||
errno = 0;
|
||||
pwd = getpwnam("nobody");
|
||||
if (errno != 0) {
|
||||
perror("getpwnam");
|
||||
return 1;
|
||||
}
|
||||
if (pwd != NULL) {
|
||||
print(pwd);
|
||||
}
|
||||
|
||||
puts("--- Checking getpwuid_r ---");
|
||||
struct passwd pwd2;
|
||||
struct passwd* result;
|
||||
char* buf = malloc(100);
|
||||
if (getpwuid_r(0, &pwd2, buf, 100, &result) < 0) {
|
||||
perror("getpwuid_r");
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
if (result != NULL) {
|
||||
if (result != &pwd2) {
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
print(&pwd2);
|
||||
}
|
||||
|
||||
puts("--- Checking getpwnam_r ---");
|
||||
if (getpwnam_r("nobody", &pwd2, buf, 100, &result) < 0) {
|
||||
perror("getpwuid_r");
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
if (result != NULL) {
|
||||
if (result != &pwd2) {
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
print(&pwd2);
|
||||
}
|
||||
free(buf);
|
||||
|
||||
puts("--- Checking getpwuid_r error handling ---");
|
||||
char buf2[1];
|
||||
if (getpwuid_r(0, &pwd2, buf2, 1, &result) == 0) {
|
||||
puts("This shouldn't have succeeded, but did!");
|
||||
return 1;
|
||||
}
|
||||
if (errno != ERANGE) {
|
||||
perror("getpwuid_r");
|
||||
return 1;
|
||||
}
|
||||
puts("Returned ERANGE because the buffer was too small 👍");
|
||||
}
|
||||
Reference in New Issue
Block a user