1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Seq file bindings. 4 //! 5 //! C header: [`include/linux/seq_file.h`](srctree/include/linux/seq_file.h) 6 7 use crate::{bindings, c_str, types::NotThreadSafe, types::Opaque}; 8 9 /// A utility for generating the contents of a seq file. 10 #[repr(transparent)] 11 pub struct SeqFile { 12 inner: Opaque<bindings::seq_file>, 13 _not_send: NotThreadSafe, 14 } 15 16 impl SeqFile { 17 /// Creates a new [`SeqFile`] from a raw pointer. 18 /// 19 /// # Safety 20 /// 21 /// The caller must ensure that for the duration of 'a the following is satisfied: 22 /// * The pointer points at a valid `struct seq_file`. 23 /// * The `struct seq_file` is not accessed from any other thread. 24 pub unsafe fn from_raw<'a>(ptr: *mut bindings::seq_file) -> &'a SeqFile { 25 // SAFETY: The caller ensures that the reference is valid for 'a. There's no way to trigger 26 // a data race by using the `&SeqFile` since this is the only thread accessing the seq_file. 27 // 28 // CAST: The layout of `struct seq_file` and `SeqFile` is compatible. 29 unsafe { &*ptr.cast() } 30 } 31 32 /// Used by the [`seq_print`] macro. 33 pub fn call_printf(&self, args: core::fmt::Arguments<'_>) { 34 // SAFETY: Passing a void pointer to `Arguments` is valid for `%pA`. 35 unsafe { 36 bindings::seq_printf( 37 self.inner.get(), 38 c_str!("%pA").as_char_ptr(), 39 &args as *const _ as *const core::ffi::c_void, 40 ); 41 } 42 } 43 } 44 45 /// Write to a [`SeqFile`] with the ordinary Rust formatting syntax. 46 #[macro_export] 47 macro_rules! seq_print { 48 ($m:expr, $($arg:tt)+) => ( 49 $m.call_printf(format_args!($($arg)+)) 50 ); 51 } 52 pub use seq_print; 53