Implement key_t, sys/ipc and sys/shm
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
pub type key_t = core::ffi::c_int;
|
||||
+4
-2
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -138,6 +138,7 @@ EXPECT_NAMES=\
|
||||
string/stpcpy \
|
||||
string/stpncpy \
|
||||
strings \
|
||||
sys_shm/shm \
|
||||
sys_socket/recv \
|
||||
sys_socket/recvfrom \
|
||||
sys_socket/unixrecv \
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user