13
13
#![ cfg( CONFIG_PROC_FS ) ]
14
14
15
15
use core:: {
16
- iter :: { Iterator , Peekable } ,
16
+ fmt :: { self , Display } ,
17
17
marker:: PhantomData ,
18
- mem,
19
- ops:: { Deref , DerefMut } ,
20
- ptr,
18
+ mem, ptr,
21
19
} ;
22
20
23
- use crate :: { bindings, c_str, c_types, str:: CStr , types:: PointerWrapper , Result } ;
21
+ use crate :: {
22
+ bindings, c_str, c_types,
23
+ debugfs:: DebugFsDirEntry ,
24
+ str:: { CStr , CString } ,
25
+ types:: PointerWrapper ,
26
+ Result ,
27
+ } ;
24
28
25
29
/// Rust equivalent of the [`seq_operations`] interface on the C side.
26
30
///
@@ -54,22 +58,30 @@ use crate::{bindings, c_str, c_types, str::CStr, types::PointerWrapper, Result};
54
58
/// [`seq_operations`]: ../../../include/linux/seq_file.h
55
59
pub trait SeqOperations {
56
60
/// Type produced on each iteration.
57
- type Item ;
58
-
59
- /// Type created when the seq file is opened.
60
- type Iterator : Iterator < Item = Self :: Item > ;
61
+ type Item : Display ;
61
62
62
63
/// Wrapper used to store a pointer to `Self` on the C side.
63
- type DataWrapper : PointerWrapper + Deref < Target = Self > ;
64
+ type DataWrapper : PointerWrapper ;
64
65
65
66
/// Wrapper used to store a pointer to the iterator on the C side.
66
- type IteratorWrapper : PointerWrapper + DerefMut < Target = Peekable < Self :: Iterator > > ;
67
+ type IteratorWrapper : PointerWrapper ;
68
+
69
+ /// TODOABK
70
+ type OpenData : PointerWrapper + Sync ;
67
71
68
72
/// Called once each time the `seq_file` is opened.
69
- fn start ( & self ) -> Result < Self :: IteratorWrapper > ;
73
+ fn start ( data : & Self :: DataWrapper ) -> Option < Self :: IteratorWrapper > ;
70
74
71
- /// How the item will be displayed to the reader.
72
- fn display ( item : & Self :: Item ) -> & str ;
75
+ /// TODOABK: docs
76
+ fn next ( iterator : & mut Self :: IteratorWrapper ) -> bool ;
77
+
78
+ /// TODOABK: docs
79
+ fn current ( iterator : & Self :: IteratorWrapper ) -> Option < Self :: Item > ;
80
+
81
+ /// TODOABK: docs
82
+ fn open < ' a > (
83
+ open_data : <Self :: OpenData as PointerWrapper >:: Borrowed < ' a > ,
84
+ ) -> Result < Self :: DataWrapper > ;
73
85
}
74
86
75
87
extern "C" fn stop_callback < T : SeqOperations > (
@@ -105,21 +117,18 @@ extern "C" fn next_callback<T: SeqOperations>(
105
117
* pos += 1 ;
106
118
}
107
119
108
- if iterator. next ( ) . is_none ( ) {
109
- return ptr:: null_mut ( ) ;
110
- }
111
-
112
- match iterator. peek ( ) {
113
- Some ( _next) => T :: IteratorWrapper :: into_pointer ( iterator) as * mut _ ,
114
- None => ptr:: null_mut ( ) ,
120
+ if !T :: next ( & mut iterator) {
121
+ ptr:: null_mut ( )
122
+ } else {
123
+ T :: IteratorWrapper :: into_pointer ( iterator) as * mut _
115
124
}
116
125
}
117
126
118
127
extern "C" fn show_callback < T : SeqOperations > (
119
128
m : * mut bindings:: seq_file ,
120
129
v : * mut c_types:: c_void ,
121
130
) -> c_types:: c_int {
122
- const FORMAT : & CStr = c_str ! ( "%.*s " ) ;
131
+ const FORMAT : & CStr = c_str ! ( "%pA " ) ;
123
132
if v. is_null ( ) {
124
133
return 0 ;
125
134
}
@@ -128,18 +137,16 @@ extern "C" fn show_callback<T: SeqOperations>(
128
137
// or pointer generated by `T::IteratorWrapper::into_pointer`. We
129
138
// checked for null pointers above. The iterator is forgotten below
130
139
// so the pointer on the C side stays valid.
131
- let mut iterator = unsafe { T :: IteratorWrapper :: from_pointer ( v) } ;
132
- if let Some ( item) = iterator. peek ( ) {
133
- let s = T :: display ( item) ;
140
+ let iterator = unsafe { T :: IteratorWrapper :: from_pointer ( v) } ;
141
+ if let Some ( item) = T :: current ( & iterator) {
134
142
// SAFETY: Calling a C function. `FORMAT` is null terminated because
135
143
// it comes from a `CStr`. `s` does not need to be null terminated
136
144
// because we are only printing the first `s.len()` bytes.
137
145
unsafe {
138
146
bindings:: seq_printf (
139
147
m,
140
- FORMAT . as_char_ptr ( ) ,
141
- s. len ( ) ,
142
- s. as_ptr ( ) as * const u8 as * const c_types:: c_char ,
148
+ ( FORMAT as * const _ ) as * const _ ,
149
+ ( & format_args ! ( "{}" , item) as * const _ ) as * const _ ,
143
150
) ;
144
151
}
145
152
}
@@ -158,55 +165,64 @@ extern "C" fn start_callback<T: SeqOperations>(
158
165
// `T::DataWrapper::into_pointer`. We don't move the data in the wrapper
159
166
// so the pointer will remain valid for later calls.
160
167
let data_wrapper = unsafe { T :: DataWrapper :: from_pointer ( ( * m) . private ) } ;
161
- let iterator = data_wrapper . start ( ) . ok ( ) ;
168
+ let iterator = T :: start ( & data_wrapper ) ;
162
169
// Data is still used in the `proc_dir_entry`.
163
170
mem:: forget ( data_wrapper) ;
164
171
// SAFETY: The caller guarantees that `pos` points to a valid `loff_t`.
165
172
let pos = unsafe { * pos } ;
166
173
match iterator {
167
174
Some ( mut wrapper) => {
168
175
for _ in 0 ..pos {
169
- if wrapper . next ( ) . is_none ( ) {
176
+ if ! T :: next ( & mut wrapper ) {
170
177
return ptr:: null_mut ( ) ;
171
178
}
172
179
}
173
- match wrapper. peek ( ) {
174
- Some ( _next) => T :: IteratorWrapper :: into_pointer ( wrapper) as * mut _ ,
175
- None => ptr:: null_mut ( ) ,
176
- }
180
+ T :: IteratorWrapper :: into_pointer ( wrapper) as * mut _
177
181
}
178
182
None => ptr:: null_mut ( ) ,
179
183
}
180
184
}
181
185
182
186
pub ( crate ) struct SeqFileOperationsVTable < T > ( PhantomData < T > ) ;
183
187
184
- impl < T : SeqOperations > SeqFileOperationsVTable < T > {
188
+ impl < ' a , T , D : ' a > SeqFileOperationsVTable < T >
189
+ where
190
+ T : SeqOperations < DataWrapper = D > ,
191
+ D : PointerWrapper ,
192
+ {
185
193
const SEQ_VTABLE : bindings:: seq_operations = bindings:: seq_operations {
186
194
start : Some ( start_callback :: < T > ) ,
187
195
stop : Some ( stop_callback :: < T > ) ,
188
196
next : Some ( next_callback :: < T > ) ,
189
197
show : Some ( show_callback :: < T > ) ,
190
198
} ;
191
199
192
- // TODOABK: safety
193
- pub ( crate ) const unsafe fn seq_build ( ) -> & ' static bindings:: seq_operations {
194
- & Self :: SEQ_VTABLE
195
- }
196
-
197
200
extern "C" fn open_callback (
198
201
inode : * mut bindings:: inode ,
199
202
file : * mut bindings:: file ,
200
203
) -> c_types:: c_int {
201
204
// TODOABK: docs
202
- unsafe {
203
- bindings:: seq_open_private (
205
+ let result = unsafe {
206
+ bindings:: seq_open (
204
207
file,
205
208
& Self :: SEQ_VTABLE as * const _ as * mut bindings:: seq_operations ,
206
- // TODOABK: how to convert safely?
207
- mem:: size_of :: < T :: DataWrapper > ( ) as i32 ,
208
209
)
210
+ } ;
211
+ if result != 0 {
212
+ // Close file?
213
+ return result;
209
214
}
215
+
216
+ let open_data = unsafe { T :: OpenData :: borrow ( ( * inode) . i_private ) } ;
217
+
218
+ let data_wrapper = match T :: open ( open_data) {
219
+ Ok ( data) => data,
220
+ Err ( err) => return err. to_kernel_errno ( ) ,
221
+ } ;
222
+
223
+ unsafe { * ( ( * file) . private_data as * mut bindings:: seq_file ) } . private =
224
+ data_wrapper. into_pointer ( ) as * mut _ ;
225
+ result
210
226
}
211
227
212
228
const VTABLE : bindings:: file_operations = bindings:: file_operations {
@@ -244,9 +260,27 @@ impl<T: SeqOperations> SeqFileOperationsVTable<T> {
244
260
write : None ,
245
261
write_iter : None ,
246
262
} ;
263
+ }
247
264
248
- // TODOABK: safety
249
- pub ( crate ) const unsafe fn build ( ) -> & ' static bindings:: file_operations {
250
- & Self :: VTABLE
251
- }
265
+ /// TODOABK: docs
266
+ pub struct SeqFileDebugFsDirEntry < T : SeqOperations > {
267
+ _debugfs_entry : DebugFsDirEntry < T :: DataWrapper > ,
268
+ }
269
+
270
+ /// TODOABK: finish doc
271
+ pub fn debugfs_create_file < ' a , T , D : ' a > (
272
+ name : fmt:: Arguments < ' _ > ,
273
+ data : D ,
274
+ ) -> Result < SeqFileDebugFsDirEntry < T > >
275
+ where
276
+ T : SeqOperations < DataWrapper = D > ,
277
+ D : PointerWrapper + Clone ,
278
+ {
279
+ let name = CString :: try_from_fmt ( name) ?;
280
+ let debugfs_entry = unsafe {
281
+ DebugFsDirEntry :: create_file ( & name, data, & SeqFileOperationsVTable :: < T > :: VTABLE )
282
+ } ?;
283
+ Ok ( SeqFileDebugFsDirEntry {
284
+ _debugfs_entry : debugfs_entry,
285
+ } )
252
286
}
0 commit comments