tracing_journald/
socket.rs
1use std::io::{Error, Result};
4use std::mem::{size_of, zeroed};
5use std::os::unix::ffi::OsStrExt;
6use std::os::unix::net::UnixDatagram;
7use std::os::unix::prelude::{AsRawFd, RawFd};
8use std::path::Path;
9use std::ptr;
10
11use libc::*;
12
13const CMSG_BUFSIZE: usize = 64;
14
15#[repr(C)]
16union AlignedBuffer<T: Copy + Clone> {
17 buffer: T,
18 align: cmsghdr,
19}
20
21fn assert_cmsg_bufsize() {
22 let space_one_fd = unsafe { CMSG_SPACE(size_of::<RawFd>() as u32) };
23 assert!(
24 space_one_fd <= CMSG_BUFSIZE as u32,
25 "cmsghdr buffer too small (< {}) to hold a single fd",
26 space_one_fd
27 );
28}
29
30#[cfg(test)]
31#[test]
32fn cmsg_buffer_size_for_one_fd() {
33 assert_cmsg_bufsize()
34}
35
36pub(crate) fn send_one_fd_to<P: AsRef<Path>>(
37 socket: &UnixDatagram,
38 fd: RawFd,
39 path: P,
40) -> Result<usize> {
41 assert_cmsg_bufsize();
42
43 let mut addr: sockaddr_un = unsafe { zeroed() };
44 let path_bytes = path.as_ref().as_os_str().as_bytes();
45 if addr.sun_path.len() <= path_bytes.len() {
47 return Err(Error::from_raw_os_error(ENAMETOOLONG));
48 }
49
50 addr.sun_family = AF_UNIX as _;
51 unsafe {
52 std::ptr::copy_nonoverlapping(
53 path_bytes.as_ptr(),
54 addr.sun_path.as_mut_ptr() as *mut u8,
55 path_bytes.len(),
56 )
57 };
58
59 let mut msg: msghdr = unsafe { zeroed() };
60 msg.msg_name = &mut addr as *mut _ as *mut c_void;
62 msg.msg_namelen = size_of::<sockaddr_un>() as socklen_t;
63
64 msg.msg_iov = ptr::null_mut();
66 msg.msg_iovlen = 0;
67
68 let mut cmsg_buffer = AlignedBuffer {
70 buffer: ([0u8; CMSG_BUFSIZE]),
71 };
72 msg.msg_control = unsafe { cmsg_buffer.buffer.as_mut_ptr() as _ };
73 msg.msg_controllen = unsafe { CMSG_SPACE(size_of::<RawFd>() as _) as _ };
74
75 let cmsg: &mut cmsghdr =
76 unsafe { CMSG_FIRSTHDR(&msg).as_mut() }.expect("Control message buffer exhausted");
77
78 cmsg.cmsg_level = SOL_SOCKET;
79 cmsg.cmsg_type = SCM_RIGHTS;
80 cmsg.cmsg_len = unsafe { CMSG_LEN(size_of::<RawFd>() as _) as _ };
81
82 unsafe { ptr::write(CMSG_DATA(cmsg) as *mut RawFd, fd) };
83
84 let result = unsafe { sendmsg(socket.as_raw_fd(), &msg, libc::MSG_NOSIGNAL) };
85
86 if result < 0 {
87 Err(Error::last_os_error())
88 } else {
89 Ok(result as usize)
91 }
92}