ptp_time/
lib.rs

1//! Safe Rust wrapper for Linux PTP (Precision Time Protocol) Hardware Clock driver.
2//!
3//! This crate provides a safe interface to the Linux PTP kernel driver,
4//! exposing the following ioctls:
5//! - `ptp_clock_caps` - Get clock capabilities
6//! - `ptp_sys_offset` - Get system offset measurements
7//! - `ptp_sys_offset_precise` - Get precise system offset measurements
8//! - `ptp_sys_offset_extended` - Get extended system offset measurements
9
10use std::{
11    fs::File,
12    io::{Error, Result},
13    mem::MaybeUninit,
14    os::{
15        fd::AsRawFd,
16        raw::c_ulong,
17    },
18    path::PathBuf,
19};
20
21pub mod ptp;
22use ptp::*;
23
24// PTP ioctl constants - These are standard Linux PTP driver ioctls
25// Based on linux/ptp_clock.h: PTP_CLK_MAGIC = '=' = 0x3D
26
27// Correct ioctl values partially calculated from the header file and partially
28// worked out by stracing chrony. If anyone can explain where the top 16 bits
29// come from I'd be grateful.
30
31// _IOR(PTP_CLK_MAGIC, 1, struct ptp_clock_caps) -> 0x80503d01
32// _IOW(PTP_CLK_MAGIC, 5, struct ptp_sys_offset) -> 0x43403d05
33// _IOWR(PTP_CLK_MAGIC, 8, struct ptp_sys_offset_precise) -> 0xc0403d08
34// _IOWR(PTP_CLK_MAGIC, 9, struct ptp_sys_offset_extended) -> 0xc4c03d09
35
36const PTP_CLOCK_GETCAPS: c_ulong = 0x80503d01; // _IOR(PTP_CLK_MAGIC, 1, struct ptp_clock_caps)
37const PTP_SYS_OFFSET: c_ulong = 0x43403d05;   // _IOW(PTP_CLK_MAGIC, 5, struct ptp_sys_offset)
38const PTP_SYS_OFFSET_PRECISE: c_ulong = 0xc0403d08; // _IOWR(PTP_CLK_MAGIC, 8, struct ptp_sys_offset_precise)
39const PTP_SYS_OFFSET_EXTENDED: c_ulong = 0xc4c03d09; // _IOWR(PTP_CLK_MAGIC, 9, struct ptp_sys_offset_extended)
40
41/// A safe wrapper for PTP hardware clock devices
42pub struct PtpDevice(File);
43
44impl PtpDevice {
45    /// Create a new PTP device from a path
46    pub fn new(path: PathBuf) -> Result<PtpDevice> {
47        Ok(PtpDevice(File::open(path)?))
48    }
49
50    /// Perform ioctl request and check result for possible errors
51    unsafe fn ioctl<T>(&self, request: c_ulong, value: &mut T) -> Result<()> {
52        match libc::ioctl(self.0.as_raw_fd(), request as _, value) {
53            0 => Ok(()),
54            _ => Err(Error::last_os_error()),
55        }
56    }
57
58    /// Perform ioctl request with uninitialized memory
59    unsafe fn ioctl_uninit<T>(&self, request: c_ulong) -> Result<T> {
60        let mut value: MaybeUninit<T> = MaybeUninit::uninit();
61        self.ioctl(request, &mut value)?;
62        Ok(unsafe { value.assume_init() })
63    }
64
65    /// Get the clock capabilities
66    pub fn get_caps(&self) -> Result<ptp_clock_caps> {
67        // Safety: PTP_CLOCK_GETCAPS writes ptp_clock_caps, for which memory is allocated and returned by ioctl_uninit
68        unsafe { self.ioctl_uninit(PTP_CLOCK_GETCAPS) }
69    }
70
71    /// Get system offset measurements
72    pub fn get_sys_offset(&self) -> Result<ptp_sys_offset> {
73        let mut offset = ptp_sys_offset::default();
74        // Safety: PTP_SYS_OFFSET expects and writes to a ptp_sys_offset, which lives for the duration of the call
75        unsafe { self.ioctl(PTP_SYS_OFFSET, &mut offset)? };
76        Ok(offset)
77    }
78
79    /// Get precise system offset measurements
80    pub fn get_sys_offset_precise(&self) -> Result<ptp_sys_offset_precise> {
81        let mut offset = ptp_sys_offset_precise::default();
82        // Safety: PTP_SYS_OFFSET_PRECISE expects and writes to a ptp_sys_offset_precise, which lives for the duration of the call
83        unsafe { self.ioctl(PTP_SYS_OFFSET_PRECISE, &mut offset)? };
84        Ok(offset)
85    }
86
87    /// Get extended system offset measurements
88    pub fn get_sys_offset_extended(&self) -> Result<ptp_sys_offset_extended> {
89        let mut offset = ptp_sys_offset_extended::default();
90        // Safety: PTP_SYS_OFFSET_EXTENDED expects and writes to a ptp_sys_offset_extended, which lives for the duration of the call
91        unsafe { self.ioctl(PTP_SYS_OFFSET_EXTENDED, &mut offset)? };
92        Ok(offset)
93    }
94}