Implement key_t, sys/ipc and sys/shm

This commit is contained in:
Wildan M
2026-05-20 18:51:53 +07:00
parent b07babc03c
commit bc6ea5ba99
11 changed files with 328 additions and 2 deletions
+14
View File
@@ -0,0 +1,14 @@
# POSIX header spec: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_types.h.html
#
# POSIX headers that require key_t:
# - sys/ipc.h
sys_includes = []
include_guard = "_RELIBC_BITS_KEY_T_H"
language = "C"
style = "type"
no_includes = true
cpp_compat = true
[export]
include = ["key_t"]
[enum]
prefix_with_name = true
+1
View File
@@ -0,0 +1 @@
pub type key_t = core::ffi::c_int;
+4 -2
View File
@@ -18,6 +18,8 @@ pub mod bits_id_t;
#[path = "bits_ino-t/mod.rs"]
pub mod bits_ino_t;
pub mod bits_iovec;
#[path = "bits_key-t/mod.rs"]
pub mod bits_key_t;
#[path = "bits_locale-t/mod.rs"]
pub mod bits_locale_t;
#[path = "bits_mode-t/mod.rs"]
@@ -132,14 +134,14 @@ pub mod sys_auxv;
pub mod sys_epoll;
pub mod sys_file;
pub mod sys_ioctl;
// TODO: sys/ipc.h
pub mod sys_ipc;
pub mod sys_mman;
// TODO: sys/msg.h
pub mod sys_ptrace;
pub mod sys_resource;
pub mod sys_select;
// TODO: sys/sem.h
// TODO: sys/shm.h
pub mod sys_shm;
pub mod sys_socket;
pub mod sys_stat;
pub mod sys_statvfs;
+22
View File
@@ -0,0 +1,22 @@
# POSIX header spec: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_ipc.h.html
#
# Spec quotations relating to includes:
# - The <sys/ipc.h> header shall define the uid_t, gid_t, mode_t, and key_t types as described in <sys/types.h>
sys_includes = []
include_guard = "_SYS_IPC_H"
after_includes = """
#include <bits/gid-t.h> // for gid_t from sys/types.h
#include <bits/uid-t.h> // for uid_t from sys/types.h
#include <bits/key-t.h> // for key_t from sys/types.h
#include <bits/mode-t.h> // for mode_t from sys/types.h
"""
language = "C"
style = "Tag"
[enum]
prefix_with_name = true
[export]
include = [
"ipc_perm",
]
+56
View File
@@ -0,0 +1,56 @@
use crate::{
c_str::CStr,
error::ResultExt,
header::sys_stat::stat,
out::Out,
platform::{
Pal, Sys,
types::{c_char, c_int, c_ushort, gid_t, key_t, mode_t, uid_t},
},
};
pub const IPC_R: u32 = 0o400;
pub const IPC_W: u32 = 0o200;
pub const IPC_M: u32 = 0o10000;
pub const IPC_RMID: i32 = 0;
pub const IPC_SET: i32 = 1;
pub const IPC_STAT: i32 = 2;
// pub const IPC_INFO: i32 = 3; non posix unimplemented
pub const IPC_CREAT: i32 = 0o1000;
pub const IPC_EXCL: i32 = 0o2000;
pub const IPC_NOWAIT: i32 = 0o4000;
pub const IPC_PRIVATE: key_t = 0;
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct ipc_perm {
pub __key: key_t,
pub uid: uid_t,
pub gid: gid_t,
pub cuid: uid_t,
pub cgid: gid_t,
pub mode: mode_t,
pub __seq: c_ushort,
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/ftok.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ftok(path: *const c_char, id: c_int) -> key_t {
let path = unsafe { CStr::from_ptr(path) };
let mut stat = stat::default();
if Sys::stat(path, Out::from_mut(&mut stat))
.map(|()| 0)
.or_minus_one_errno()
== -1
{
return -1;
}
// Borrowed from musl
return (stat.st_ino & 0xffff) as key_t
| ((stat.st_dev & 0xff) << 16) as key_t
| ((id & 0xff) << 24);
}
+15
View File
@@ -0,0 +1,15 @@
# POSIX header spec: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_shm.h.html
#
# Spec quotations relating to includes:
# - The <sys/shm.h> header shall define the type intptr_t as described in <stdint.h>
# - In addition, the <sys/shm.h> header shall include the <sys/ipc.h> header.
sys_includes = ["sys/ipc.h", "stdint.h"]
include_guard = "_SYS_SHM_H"
language = "C"
style = "Tag"
[enum]
prefix_with_name = true
[export.rename]
"ipc_perm" = "struct ipc_perm"
+178
View File
@@ -0,0 +1,178 @@
use core::mem;
use crate::{
error::ResultExt,
header::{
errno::EINVAL,
fcntl::{O_CREAT, O_EXCL, O_RDWR},
sys_ipc::{IPC_CREAT, IPC_EXCL, IPC_PRIVATE, IPC_RMID, IPC_SET, IPC_STAT, ipc_perm},
sys_mman::{MAP_SHARED, PROT_READ, PROT_WRITE, shm_open, shm_unlink},
sys_stat::{fchmod, fstat, stat},
unistd::ftruncate,
},
platform::{
ERRNO, Pal, Sys,
types::{c_char, c_int, c_void, mode_t, pid_t, size_t, time_t},
},
};
#[allow(non_camel_case_types)]
pub type shmatt_t = core::ffi::c_ushort;
pub const SHM_RDONLY: c_int = 0o10000;
pub const SHM_RND: c_int = 0o20000;
pub const SHMLBA: size_t = 4096;
pub const SHM_FAILED: *mut c_void = -1isize as *mut c_void;
#[repr(C)]
pub struct shmid_ds {
pub shm_perm: ipc_perm,
pub shm_segsz: size_t,
pub shm_lpid: pid_t,
pub shm_cpid: pid_t,
pub shm_nattch: shmatt_t,
pub shm_atime: time_t,
pub shm_dtime: time_t,
pub shm_ctime: time_t,
}
// needed because shmdt isn't tracking size
#[derive(Copy, Clone)]
#[repr(C)]
struct ShmHeader {
total_size: size_t,
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/shmget.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn shmget(key: i32, size: size_t, shmflg: c_int) -> c_int {
let path_str = if key == IPC_PRIVATE {
format!("/sysv_priv_{}\0", Sys::getpid())
} else {
format!("/sysv_key_{}\0", key)
};
let path_ptr = path_str.as_ptr() as *const c_char;
let mut oflag = O_RDWR;
if (shmflg & IPC_CREAT) != 0 {
oflag |= O_CREAT;
}
if (shmflg & IPC_EXCL) != 0 {
oflag |= O_EXCL;
}
let fd = unsafe { shm_open(path_ptr, oflag, 0o666) };
if fd < 0 {
return -1;
}
if (oflag & O_CREAT) != 0 {
let total_size = size + mem::size_of::<ShmHeader>();
if ftruncate(fd, total_size as i64) < 0 {
return -1;
}
}
unsafe {
let _ = shm_unlink(path_ptr);
}
fd
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/shmat.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn shmat(
shmid: c_int,
_shmaddr: *const c_void,
shmflg: c_int,
) -> *mut c_void {
let mut stat = stat::default();
if unsafe { fstat(shmid, &mut stat) } < 0 {
return SHM_FAILED;
}
let size = stat.st_size as usize;
let mut prot = PROT_READ;
if shmflg & SHM_RDONLY == 0 {
prot |= PROT_WRITE;
}
let res = unsafe { Sys::mmap(core::ptr::null_mut(), size, prot, MAP_SHARED, shmid, 0) };
let ptr = match res {
Ok(p) => p,
Err(_) => return SHM_FAILED,
};
let header = ptr as *mut ShmHeader;
unsafe {
(*header).total_size = size;
}
unsafe { ptr.add(mem::size_of::<ShmHeader>()) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/shmdt.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn shmdt(shmaddr: *const c_void) -> c_int {
if shmaddr.is_null() || shmaddr == SHM_FAILED {
return -1;
}
let base_ptr = unsafe { (shmaddr as *mut u8).sub(mem::size_of::<ShmHeader>()) };
let header = base_ptr as *mut ShmHeader;
let total_size = unsafe { (*header).total_size };
unsafe { Sys::munmap(base_ptr as *mut c_void, total_size) }
.map(|_| 0)
.or_minus_one_errno()
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/shmctl.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn shmctl(shmid: c_int, cmd: c_int, buf: *mut shmid_ds) -> c_int {
match cmd {
IPC_RMID => Sys::close(shmid).map(|_| 0).or_minus_one_errno(),
IPC_STAT => {
if buf.is_null() {
ERRNO.set(EINVAL);
return -1;
}
let mut stat = stat::default();
if unsafe { fstat(shmid, &mut stat) } < 0 {
return -1;
}
unsafe {
let buf = &mut *buf;
buf.shm_segsz =
(stat.st_size as size_t).saturating_sub(mem::size_of::<ShmHeader>());
buf.shm_cpid = stat.st_uid as pid_t;
buf.shm_lpid = stat.st_gid as pid_t;
buf.shm_atime = stat.st_atim.tv_sec;
buf.shm_dtime = stat.st_mtim.tv_sec;
buf.shm_ctime = stat.st_ctim.tv_sec;
buf.shm_nattch = stat.st_nlink as shmatt_t;
buf.shm_perm.uid = stat.st_uid;
buf.shm_perm.gid = stat.st_gid;
buf.shm_perm.mode = stat.st_mode & 0o777;
}
0
}
IPC_SET => {
if buf.is_null() {
ERRNO.set(EINVAL);
return -1;
}
let mode = unsafe { (*buf).shm_perm.mode & 0o777 };
fchmod(shmid, mode as mode_t)
}
_ => {
ERRNO.set(EINVAL);
-1
}
}
}
+2
View File
@@ -118,6 +118,8 @@ pub type nlink_t = c_ulong;
pub type blksize_t = c_long;
/// The `blkcnt_t` type provided in [`sys/types.h`](crate::header::sys_types).
pub type blkcnt_t = c_longlong;
/// The `key_t` type provided in [`sys/types.h`](crate::header::sys_types).
pub type key_t = c_int;
/// The `fsblkcnt_t` type provided in [`sys/types.h`](crate::header::sys_types).
pub type fsblkcnt_t = c_ulong;
+1
View File
@@ -138,6 +138,7 @@ EXPECT_NAMES=\
string/stpcpy \
string/stpncpy \
strings \
sys_shm/shm \
sys_socket/recv \
sys_socket/recvfrom \
sys_socket/unixrecv \
View File
+35
View File
@@ -0,0 +1,35 @@
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include "test_helpers.h"
int main(void)
{
int status;
key_t key = ftok("example_dir/1-never-gonna-give-you-up", 123);
size_t size = 1000;
int shmid = shmget(key, size, IPC_CREAT | IPC_EXCL | 0666);
ERROR_IF(shmget, shmid, == -1);
struct shmid_ds ds;
status = shmctl(shmid, IPC_STAT, &ds);
ERROR_IF(shmctl, status, == -1);
UNEXP_IF(shmctl, ds.shm_segsz, != size);
void *shmaddr = shmat(shmid, NULL, 0);
UNEXP_IF(shmat, shmaddr, == SHM_FAILED);
char *msg = "foo bar";
strcpy((char *)shmaddr, msg);
status = strcmp((char *)shmaddr, msg);
UNEXP_IF(strcmp, status, != 0);
status = shmdt(shmaddr);
ERROR_IF(shmdt, status, == -1);
status = shmctl(shmid, IPC_RMID, NULL);
ERROR_IF(shmctl, status, == -1);
}