• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jtmoon79 / super-speedy-syslog-searcher / 20603980203

30 Dec 2025 07:10PM UTC coverage: 67.773% (-2.0%) from 69.779%
20603980203

push

github

jtmoon79
(CI) s4_* --venv

15621 of 23049 relevant lines covered (67.77%)

123479.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.61
/src/data/fixedstruct.rs
1
// src/data/fixedstruct.rs
2

3
//! Implement [`FixedStruct`] to represent Unix record-keeping C structs.
4
//! This includes [`acct`], [`lastlog`], [`lastlogx`],
5
//! [`utmp`], and [`utmpx`] formats for various operating systems and
6
//! architectures.
7
//!
8
//! [`acct`]: https://www.man7.org/linux/man-pages/man5/acct.5.html
9
//! [`lastlog`]: https://man7.org/linux/man-pages/man8/lastlog.8.html
10
//! [`lastlogx`]: https://man.netbsd.org/lastlogx.5
11
//! [`utmp`]: https://www.man7.org/linux/man-pages/man5/utmp.5.html
12
//! [`utmpx`]: https://man.netbsd.org/utmpx.5
13

14
#![allow(clippy::tabs_in_doc_comments)]
15

16
use core::panic;
17
use std::collections::HashMap;
18
use std::ffi::CStr;
19
use std::fmt;
20
use std::io::{
21
    Error,
22
    ErrorKind,
23
};
24

25
use ::const_format::assertcp;
26
#[allow(unused_imports)]
27
use ::more_asserts::{
28
    assert_ge,
29
    assert_gt,
30
    assert_le,
31
    assert_lt,
32
    debug_assert_ge,
33
    debug_assert_gt,
34
    debug_assert_le,
35
    debug_assert_lt,
36
};
37
#[allow(unused_imports)]
38
use ::si_trace_print::{
39
    defn,
40
    defo,
41
    defx,
42
    defñ,
43
    den,
44
    deo,
45
    dex,
46
    deñ,
47
};
48
use numtoa::NumToA; // adds `numtoa` method to numbers
49

50
#[doc(hidden)]
51
use crate::common::{
52
    max16,
53
    min16,
54
    FileOffset,
55
    FileSz,
56
    FileTypeFixedStruct,
57
};
58
use crate::data::datetime::{
59
    DateTimeL,
60
    FixedOffset,
61
    LocalResult,
62
    TimeZone,
63
};
64
#[cfg(any(debug_assertions, test))]
65
use crate::debug::printers::byte_to_char_noraw;
66
use crate::readers::blockreader::{
67
    BlockOffset,
68
    BlockReader,
69
    BlockSz,
70
};
71
#[doc(hidden)]
72
use crate::{
73
    de_err,
74
    de_wrn,
75
    debug_panic,
76
};
77

78
/// size of the `[u8]` buffer used for `numtoa` conversions
79
/// good up to `i64::MAX` or `i64::MIN` plus a little "just in case" head room
80
pub const NUMTOA_BUF_SZ: usize = 22;
81

82
/// A scoring system for the quality of the data in a [`FixedStruct`]. A higher
83
/// score means the data is more likely to be the [`FixedStructType`] expected.
84
pub type Score = i32;
85

86
/// Helper to [`FixedStructType::tv_pair_from_buffer`].
87
macro_rules! buffer_to_timeval {
88
    ($timeval_type:ty, $timeval_sz:expr, $buffer:ident, $tv_sec:ident, $tv_usec:ident) => {{
89
        {
90
            // ut_tv
91
            let size: usize = $timeval_sz;
92
            defo!("size {:?}", size);
93
            debug_assert_eq!($buffer.len(), size);
94
            let time_val: $timeval_type = unsafe { *($buffer.as_ptr() as *const $timeval_type) };
95
            // XXX: copy to local variable to avoid alignment warning
96
            //      see #82523 <https://github.com/rust-lang/rust/issues/82523>
97
            let _tv_sec = time_val.tv_sec;
98
            let _tv_usec = time_val.tv_usec;
99
            defo!("time_val.tv_sec {:?} .tv_usec {:?}", _tv_sec, _tv_usec);
100
            // ut_tv.tv_sec
101
            $tv_sec = match time_val.tv_sec.try_into() {
102
                Ok(val) => val,
103
                Err(_) => {
104
                    debug_panic!("tv_sec overflow: {:?}", _tv_sec);
105
                    return None;
106
                }
107
            };
108
            defo!("tv_sec {:?}", $tv_sec);
109
            // ut_tv.tv_usec
110
            $tv_usec = match time_val.tv_usec.try_into() {
111
                Ok(val) => val,
112
                Err(_) => {
113
                    debug_panic!("tv_usec overflow: {:?}", _tv_usec);
114

115
                    0
116
                }
117
            };
118
            defo!("tv_usec {:?}", $tv_usec);
119
        }
120
    }};
121
}
122

123
macro_rules! buffer_to_time_t {
124
    ($ll_time_t:ty, $ll_time_sz:expr, $buffer:ident, $tv_sec:ident) => {{
125
        {
126
            let size: usize = $ll_time_sz;
127
            defo!("size {:?}", size);
128
            debug_assert_eq!($buffer.len(), size);
129
            let ll_time: $ll_time_t = unsafe { *($buffer.as_ptr() as *const $ll_time_t) };
130
            defo!("ll_time {:?}", ll_time);
131
            $tv_sec = match ll_time.try_into() {
132
                Ok(val) => val,
133
                Err(_) => {
134
                    debug_panic!("tv_sec overflow from ll_time {:?}", ll_time);
135
                    return None;
136
                }
137
            };
138
            defo!("tv_sec {:?}", $tv_sec);
139
        }
140
    }};
141
}
142

143
/// Helper to [`FixedStructType::tv_pair_from_buffer`].
144
/// Debug print the `DateTimeL` conversion of a `tv_pair`.
145
macro_rules! defo_tv_pair {
146
    ($tv_sec:ident, $tv_usec:ident) => {{
147
        {
148
            #[cfg(any(debug_assertions, test))]
149
            {
150
                let tz_offset: FixedOffset = FixedOffset::east_opt(0).unwrap();
151
                let tv_pair = tv_pair_type($tv_sec, $tv_usec);
152
                match convert_tvpair_to_datetime(tv_pair, &tz_offset) {
153
                    Ok(_dt) => {
154
                        defo!("dt: {:?}", _dt);
155
                    }
156
                    Err(err) => {
157
                        de_err!("{:?}", err);
158
                        panic!("convert_tvpair_to_datetime({:?}) returned an error; {}", tv_pair, err);
159
                    }
160
                }
161
            }
162
        }
163
    }};
164
}
165

166
/// FixedStruct Implementation Type (name `FixedStructType` is taken).
167
///
168
/// The specific implementation of the FixedStruct. Each implementation of,
169
/// for example, a `utmp` struct, differs in fields and sizes among Operating
170
/// Systems FreeBSD, Linux, OpenBSD, and NetBSD. and also differ per CPU
171
/// architecture, e.g. x86_64 vs. i386 vs. ARM7
172
#[allow(non_camel_case_types)]
173
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
174
pub enum FixedStructType {
175

176
    // FreeBSD x86_64 (amd64), x86_32 (i686)
177

178
    /// corresponds to [`freebsd_x8664::utmpx`]
179
    #[allow(non_camel_case_types)]
180
    Fs_Freebsd_x8664_Utmpx,
181

182
    // Linux
183

184
    // Linux ARM64 (aarch64)
185

186
    /// corresponds to [`linux_arm64aarch64::lastlog`]
187
    #[allow(non_camel_case_types)]
188
    Fs_Linux_Arm64Aarch64_Lastlog,
189

190
    /// corresponds to [`linux_arm64aarch64::utmpx`]
191
    #[allow(non_camel_case_types)]
192
    Fs_Linux_Arm64Aarch64_Utmpx,
193

194
    // Linux x86
195

196
    /// corresponds to [`linux_x86::acct`]
197
    #[allow(non_camel_case_types)]
198
    Fs_Linux_x86_Acct,
199

200
    /// corresponds to [`linux_x86::acct_v3`]
201
    #[allow(non_camel_case_types)]
202
    Fs_Linux_x86_Acct_v3,
203

204
    /// corresponds to [`linux_x86::lastlog`]
205
    #[allow(non_camel_case_types)]
206
    Fs_Linux_x86_Lastlog,
207

208
    /// corresponds to [`linux_x86::utmpx`]
209
    #[allow(non_camel_case_types)]
210
    Fs_Linux_x86_Utmpx,
211

212
    // NetBSD
213

214
    // NetBSD 9 x86_32 (i686)
215

216
    /// corresponds to [`netbsd_x8632::acct`]
217
    #[allow(non_camel_case_types)]
218
    Fs_Netbsd_x8632_Acct,
219

220
    /// corresponds to [`netbsd_x8632::lastlogx`]
221
    #[allow(non_camel_case_types)]
222
    Fs_Netbsd_x8632_Lastlogx,
223

224
    /// corresponds to [`netbsd_x8632::utmpx`]
225
    #[allow(non_camel_case_types)]
226
    Fs_Netbsd_x8632_Utmpx,
227

228
    // NetBSD 9 x86_64 (AMD64)
229

230
    /// corresponds to [`netbsd_x8664::lastlog`]
231
    #[allow(non_camel_case_types)]
232
    Fs_Netbsd_x8664_Lastlog,
233

234
    /// corresponds to [`netbsd_x8664::lastlogx`]
235
    #[allow(non_camel_case_types)]
236
    Fs_Netbsd_x8664_Lastlogx,
237

238
    /// corresponds to [`netbsd_x8664::utmp`]
239
    #[allow(non_camel_case_types)]
240
    Fs_Netbsd_x8664_Utmp,
241

242
    /// corresponds to [`netbsd_x8664::utmpx`]
243
    #[allow(non_camel_case_types)]
244
    Fs_Netbsd_x8664_Utmpx,
245

246
    // OpenBSD x86_32, x86_64
247

248
    /// corresponds to [`openbsd_x86::lastlog`]
249
    #[allow(non_camel_case_types)]
250
    Fs_Openbsd_x86_Lastlog,
251

252
    /// corresponds to [`openbsd_x86::utmp`]
253
    #[allow(non_camel_case_types)]
254
    Fs_Openbsd_x86_Utmp,
255
}
256

257
impl FixedStructType {
258
    /// return the associated `FixedStructType`'s `SZ` value (size in bytes).
259
    pub const fn size(&self) -> usize {
9,751✔
260
        match self {
9,751✔
261
            FixedStructType::Fs_Freebsd_x8664_Utmpx => freebsd_x8664::UTMPX_SZ,
4✔
262
            FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => linux_arm64aarch64::LASTLOG_SZ,
3✔
263
            FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => linux_arm64aarch64::UTMPX_SZ,
3✔
264
            FixedStructType::Fs_Linux_x86_Acct => linux_x86::ACCT_SZ,
1,852✔
265
            FixedStructType::Fs_Linux_x86_Acct_v3 => linux_x86::ACCT_V3_SZ,
1,852✔
266
            FixedStructType::Fs_Linux_x86_Lastlog => linux_x86::LASTLOG_SZ,
52✔
267
            FixedStructType::Fs_Linux_x86_Utmpx => linux_x86::UTMPX_SZ,
3,377✔
268
            FixedStructType::Fs_Netbsd_x8632_Acct => netbsd_x8632::ACCT_SZ,
3✔
269
            FixedStructType::Fs_Netbsd_x8632_Lastlogx => netbsd_x8632::LASTLOGX_SZ,
3✔
270
            FixedStructType::Fs_Netbsd_x8632_Utmpx => netbsd_x8632::UTMPX_SZ,
3✔
271
            FixedStructType::Fs_Netbsd_x8664_Lastlog => netbsd_x8664::LASTLOG_SZ,
2,584✔
272
            FixedStructType::Fs_Netbsd_x8664_Lastlogx => netbsd_x8664::LASTLOGX_SZ,
3✔
273
            FixedStructType::Fs_Netbsd_x8664_Utmp => netbsd_x8664::UTMP_SZ,
3✔
274
            FixedStructType::Fs_Netbsd_x8664_Utmpx => netbsd_x8664::UTMPX_SZ,
3✔
275
            FixedStructType::Fs_Openbsd_x86_Lastlog => openbsd_x86::LASTLOG_SZ,
3✔
276
            FixedStructType::Fs_Openbsd_x86_Utmp => openbsd_x86::UTMP_SZ,
3✔
277
        }
278
    }
9,751✔
279

280
    /// return the associated `FixedStructType`'s offset to it's ***t***ime
281
    /// ***v***alue field
282
    pub const fn offset_tv(&self) -> usize {
190✔
283
        match self {
190✔
284
            FixedStructType::Fs_Freebsd_x8664_Utmpx => freebsd_x8664::UTMPX_TIMEVALUE_OFFSET,
×
285
            FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => linux_arm64aarch64::LASTLOG_TIMEVALUE_OFFSET,
×
286
            FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => linux_arm64aarch64::UTMPX_TIMEVALUE_OFFSET,
×
287
            FixedStructType::Fs_Linux_x86_Acct => linux_x86::ACCT_TIMEVALUE_OFFSET,
×
288
            FixedStructType::Fs_Linux_x86_Acct_v3 => linux_x86::ACCT_V3_TIMEVALUE_OFFSET,
×
289
            FixedStructType::Fs_Linux_x86_Lastlog => linux_x86::LASTLOG_TIMEVALUE_OFFSET,
7✔
290
            FixedStructType::Fs_Linux_x86_Utmpx => linux_x86::UTMPX_TIMEVALUE_OFFSET,
183✔
291
            FixedStructType::Fs_Netbsd_x8632_Acct => netbsd_x8632::ACCT_TIMEVALUE_OFFSET,
×
292
            FixedStructType::Fs_Netbsd_x8632_Lastlogx => netbsd_x8632::LASTLOGX_TIMEVALUE_OFFSET,
×
293
            FixedStructType::Fs_Netbsd_x8632_Utmpx => netbsd_x8632::UTMPX_TIMEVALUE_OFFSET,
×
294
            FixedStructType::Fs_Netbsd_x8664_Lastlog => netbsd_x8664::LASTLOG_TIMEVALUE_OFFSET,
×
295
            FixedStructType::Fs_Netbsd_x8664_Lastlogx => netbsd_x8664::LASTLOGX_TIMEVALUE_OFFSET,
×
296
            FixedStructType::Fs_Netbsd_x8664_Utmp => netbsd_x8664::UTMP_TIMEVALUE_OFFSET,
×
297
            FixedStructType::Fs_Netbsd_x8664_Utmpx => netbsd_x8664::UTMPX_TIMEVALUE_OFFSET,
×
298
            FixedStructType::Fs_Openbsd_x86_Lastlog => openbsd_x86::LASTLOG_TIMEVALUE_OFFSET,
×
299
            FixedStructType::Fs_Openbsd_x86_Utmp => openbsd_x86::UTMP_TIMEVALUE_OFFSET,
×
300
        }
301
    }
190✔
302

303
    /// return the associated `FixedStructType`'s size of it's
304
    /// ***t***ime ***v***alue in bytes
305
    pub const fn size_tv(&self) -> usize {
1,367✔
306
        match self {
1,367✔
307
            FixedStructType::Fs_Freebsd_x8664_Utmpx => freebsd_x8664::UTMPX_TIMEVALUE_SZ,
×
308
            FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => linux_arm64aarch64::LASTLOG_TIMEVALUE_SZ,
×
309
            FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => linux_arm64aarch64::UTMPX_TIMEVALUE_SZ,
×
310
            FixedStructType::Fs_Linux_x86_Acct => linux_x86::ACCT_TIMEVALUE_SZ,
×
311
            FixedStructType::Fs_Linux_x86_Acct_v3 => linux_x86::ACCT_V3_TIMEVALUE_SZ,
×
312
            FixedStructType::Fs_Linux_x86_Lastlog => linux_x86::LASTLOG_TIMEVALUE_SZ,
14✔
313
            FixedStructType::Fs_Linux_x86_Utmpx => linux_x86::UTMPX_TIMEVALUE_SZ,
1,353✔
314
            FixedStructType::Fs_Netbsd_x8632_Acct => netbsd_x8632::ACCT_TIMEVALUE_SZ,
×
315
            FixedStructType::Fs_Netbsd_x8632_Lastlogx => netbsd_x8632::LASTLOGX_TIMEVALUE_SZ,
×
316
            FixedStructType::Fs_Netbsd_x8632_Utmpx => netbsd_x8632::UTMPX_TIMEVALUE_SZ,
×
317
            FixedStructType::Fs_Netbsd_x8664_Lastlog => netbsd_x8664::LASTLOG_TIMEVALUE_SZ,
×
318
            FixedStructType::Fs_Netbsd_x8664_Lastlogx => netbsd_x8664::LASTLOGX_TIMEVALUE_SZ,
×
319
            FixedStructType::Fs_Netbsd_x8664_Utmp => netbsd_x8664::UTMP_TIMEVALUE_SZ,
×
320
            FixedStructType::Fs_Netbsd_x8664_Utmpx => netbsd_x8664::UTMPX_TIMEVALUE_SZ,
×
321
            FixedStructType::Fs_Openbsd_x86_Lastlog => openbsd_x86::LASTLOG_TIMEVALUE_SZ,
×
322
            FixedStructType::Fs_Openbsd_x86_Utmp => openbsd_x86::UTMP_TIMEVALUE_SZ,
×
323
        }
324
    }
1,367✔
325

326
    /// the datetime field as a pair of seconds and microseconds taken from
327
    /// raw bytes
328
    pub fn tv_pair_from_buffer(&self, buffer: &[u8]) -> Option<tv_pair_type> {
1,177✔
329
        defn!("type {:?}", self);
1,177✔
330
        let tv_sec: tv_sec_type;
331
        let tv_usec: tv_usec_type;
332
        let size = self.size_tv();
1,177✔
333
        match self {
1,177✔
334
            FixedStructType::Fs_Freebsd_x8664_Utmpx => {
335
                buffer_to_timeval!(freebsd_x8664::timeval, size, buffer, tv_sec, tv_usec);
×
336
                defo_tv_pair!(tv_sec, tv_usec);
×
337
            }
338
            FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => {
339
                buffer_to_time_t!(linux_arm64aarch64::ll_time_t, size, buffer, tv_sec);
×
340
                tv_usec = 0;
×
341
                defo_tv_pair!(tv_sec, tv_usec);
×
342
            }
343
            FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => {
344
                buffer_to_timeval!(linux_arm64aarch64::timeval, size, buffer, tv_sec, tv_usec);
×
345
                defo_tv_pair!(tv_sec, tv_usec);
×
346
            }
347
            FixedStructType::Fs_Linux_x86_Acct => {
348
                buffer_to_time_t!(linux_x86::b_time_t, size, buffer, tv_sec);
×
349
                tv_usec = 0;
×
350
                defo_tv_pair!(tv_sec, tv_usec);
×
351
            }
352
            FixedStructType::Fs_Linux_x86_Acct_v3 => {
353
                buffer_to_time_t!(linux_x86::b_time_t, size, buffer, tv_sec);
×
354
                tv_usec = 0;
×
355
                defo_tv_pair!(tv_sec, tv_usec);
×
356
            }
357
            FixedStructType::Fs_Linux_x86_Lastlog => {
358
                buffer_to_time_t!(linux_x86::ll_time_t, size, buffer, tv_sec);
7✔
359
                tv_usec = 0;
7✔
360
                defo_tv_pair!(tv_sec, tv_usec);
7✔
361
            }
362
            FixedStructType::Fs_Linux_x86_Utmpx => {
363
                buffer_to_timeval!(linux_x86::__timeval, size, buffer, tv_sec, tv_usec);
1,170✔
364
                defo_tv_pair!(tv_sec, tv_usec);
1,170✔
365
            }
366
            FixedStructType::Fs_Netbsd_x8632_Acct => {
367
                buffer_to_time_t!(netbsd_x8632::time_t, size, buffer, tv_sec);
×
368
                tv_usec = 0;
×
369
                defo_tv_pair!(tv_sec, tv_usec);
×
370
            }
371
            FixedStructType::Fs_Netbsd_x8632_Lastlogx => {
372
                buffer_to_timeval!(netbsd_x8632::timeval, size, buffer, tv_sec, tv_usec);
×
373
                defo_tv_pair!(tv_sec, tv_usec);
×
374
            }
375
            FixedStructType::Fs_Netbsd_x8632_Utmpx => {
376
                buffer_to_timeval!(netbsd_x8632::timeval, size, buffer, tv_sec, tv_usec);
×
377
                defo_tv_pair!(tv_sec, tv_usec);
×
378
            }
379
            FixedStructType::Fs_Netbsd_x8664_Lastlog => {
380
                buffer_to_time_t!(netbsd_x8664::time_t, size, buffer, tv_sec);
×
381
                tv_usec = 0;
×
382
                defo_tv_pair!(tv_sec, tv_usec);
×
383
            }
384
            FixedStructType::Fs_Netbsd_x8664_Lastlogx => {
385
                buffer_to_timeval!(netbsd_x8664::timeval, size, buffer, tv_sec, tv_usec);
×
386
                defo_tv_pair!(tv_sec, tv_usec);
×
387
            }
388
            FixedStructType::Fs_Netbsd_x8664_Utmp => {
389
                buffer_to_time_t!(netbsd_x8664::time_t, size, buffer, tv_sec);
×
390
                tv_usec = 0;
×
391
                defo_tv_pair!(tv_sec, tv_usec);
×
392
            }
393
            FixedStructType::Fs_Netbsd_x8664_Utmpx => {
394
                buffer_to_timeval!(netbsd_x8664::timeval, size, buffer, tv_sec, tv_usec);
×
395
                defo_tv_pair!(tv_sec, tv_usec);
×
396
            }
397
            FixedStructType::Fs_Openbsd_x86_Lastlog => {
398
                buffer_to_time_t!(openbsd_x86::time_t, size, buffer, tv_sec);
×
399
                tv_usec = 0;
×
400
                defo_tv_pair!(tv_sec, tv_usec);
×
401
            }
402
            FixedStructType::Fs_Openbsd_x86_Utmp => {
403
                buffer_to_time_t!(openbsd_x86::time_t, size, buffer, tv_sec);
×
404
                tv_usec = 0;
×
405
                defo_tv_pair!(tv_sec, tv_usec);
×
406
            }
407
        }
408

409
        let tv_pair = tv_pair_type(tv_sec, tv_usec);
1,177✔
410
        defx!("return Some({:?})", tv_pair);
1,177✔
411

412
        Some(tv_pair)
1,177✔
413
    }
1,177✔
414
}
415

416
// listing of specific FixedStruct implementations
417
// all listings should be in alphabetical order
418

419
// BUG: [2024/03/10] the `&CStr` wrappers do not protect against no
420
//      null-termination in the underlying buffer.
421
//      e.g. `freebsd_x8664::utmpx::ut_user()` may include the following field
422
//      `freebsd_x8664::utmpx::ut_line`.
423
//      This only affects debug printing and tests.
424

425
// freebsd_x8664
426

427
/// FixedStruct definitions found on FreeBSD 14.0 amd64 and FreeBSD 13.1 amd64
428
/// (x86_64).
429
#[allow(non_camel_case_types, unused)]
430
pub mod freebsd_x8664 {
431
    use crate::common::FileOffset;
432
    use std::ffi::CStr;
433
    use std::mem::size_of;
434
    // TODO: can `memoffset::offset_of` be replaced with native `offset_of`?
435
    //       see https://releases.rs/docs/1.82.0/
436
    use ::memoffset::offset_of;
437
    use ::const_format::assertcp_eq;
438

439
    pub type subseconds_t = std::ffi::c_longlong;
440
    // XXX: use `i64` to satisfy various cross-compilation targets
441
    pub type time_t = i64;
442

443
    // utmpx
444

445
    /// From [`/usr/include/sys/_timeval.h`]
446
    /// 
447
    /// ```C
448
    /// struct timeval {
449
    ///     time_t          tv_sec;         /* seconds */
450
    ///     suseconds_t     tv_usec;        /* and microseconds */
451
    /// };
452
    /// ```
453
    ///
454
    /// [`/usr/include/sys/_timeval.h`]: https://github.com/freebsd/freebsd-src/blob/release/12.4.0/sys/sys/_timeval.h#L46-L52
455
    #[derive(Clone, Copy)]
456
    #[repr(C, align(8))]
457
    #[allow(non_camel_case_types)]
458
    pub struct timeval {
459
        pub tv_sec: time_t,
460
        pub tv_usec: subseconds_t,
461
    }
462

463
    pub const TIMEVAL_SZ: usize = size_of::<timeval>();
464
    assertcp_eq!(TIMEVAL_SZ, 16);
465
    assertcp_eq!(offset_of!(timeval, tv_sec), 0);
466
    assertcp_eq!(offset_of!(timeval, tv_usec), 8);
467

468
    pub const UT_IDSIZE: usize = 8;
469
    pub const UT_USERSIZE: usize = 32;
470
    pub const UT_LINESIZE: usize = 16;
471
    pub const UT_HOSTSIZE: usize = 128;
472

473
    pub type c_char = std::ffi::c_char;
474
    pub type c_short = std::ffi::c_short;
475
    pub type c_ushort = std::ffi::c_ushort;
476
    pub type pid_t = std::ffi::c_int;
477

478
    /// From [`/usr/src/include/utmpx.h`] on FreeBSD 14.0 amd64
479
    ///
480
    /// ```C
481
    /// struct utmpx {
482
    ///     short           ut_type;        /* Type of entry. */
483
    ///     struct timeval  ut_tv;          /* Time entry was made. */
484
    ///     char            ut_id[8];       /* Record identifier. */
485
    ///     pid_t           ut_pid;         /* Process ID. */
486
    ///     char            ut_user[32];    /* User login name. */
487
    ///     char            ut_line[16];    /* Device name. */
488
    /// #if __BSD_VISIBLE
489
    ///     char            ut_host[128];   /* Remote hostname. */
490
    /// #else
491
    ///     char            __ut_host[128];
492
    /// #endif
493
    ///     char            __ut_spare[64];
494
    /// };
495
    /// ```
496
    ///
497
    /// Also see [FreeBSD 12.4 `utmpx.h`].
498
    /// Also see [_Replacing utmp.h with utmpx.h_].
499
    ///
500
    /// ---
501
    ///
502
    ///
503
    /// ```text
504
    /// timeval               sizeof  16
505
    /// timeval.tv_sec   @  0 sizeof   8
506
    /// timeval.tv_usec  @  8 sizeof   8
507
    ///
508
    /// utmpx                   sizeof 280
509
    /// utmpx.ut_type      @  0 sizeof   2
510
    /// utmpx.ut_tv        @  8 sizeof  16
511
    /// utmpx.ut_tv.tv_sec @  8 sizeof   8
512
    /// utmpx.ut_tv.tv_usec@ 16 sizeof   8
513
    /// utmpx.ut_id        @ 24 sizeof   8
514
    /// utmpx.ut_pid       @ 32 sizeof   4
515
    /// utmpx.ut_user      @ 36 sizeof  32
516
    /// utmpx.ut_line      @ 68 sizeof  16
517
    /// utmpx.ut_host      @ 84 sizeof 128
518
    /// ```
519
    ///
520
    /// [`/usr/src/include/utmpx.h`]: https://cgit.freebsd.org/src/tree/include/utmpx.h?h=stable/14
521
    /// [FreeBSD 12.4 `utmpx.h`]: https://github.com/freebsd/freebsd-src/blob/release/12.4.0/include/utmpx.h#L43-L56
522
    /// [_Replacing utmp.h with utmpx.h_]: https://lists.freebsd.org/pipermail/freebsd-arch/2010-January/009816.html
523
    #[derive(Clone, Copy)]
524
    #[allow(non_camel_case_types)]
525
    #[repr(C, align(8))]
526
    pub struct utmpx {
527
        pub ut_type: c_short,
528
        pub __gap1: [u8; 6],
529
        pub ut_tv: timeval,
530
        pub ut_id: [c_char; UT_IDSIZE],
531
        pub ut_pid: pid_t,
532
        pub ut_user: [c_char; UT_USERSIZE],
533
        pub ut_line: [c_char; UT_LINESIZE],
534
        pub ut_host: [c_char; UT_HOSTSIZE],
535
        pub __ut_spare: [c_char; 64],
536
    }
537

538
    pub const UTMPX_SZ: usize = size_of::<utmpx>();
539
    pub const UTMPX_SZ_FO: FileOffset = UTMPX_SZ as FileOffset;
540
    pub const UTMPX_TIMEVALUE_OFFSET: usize = offset_of!(utmpx, ut_tv);
541
    pub const UTMPX_TIMEVALUE_SZ: usize = TIMEVAL_SZ;
542
    pub const UTMPX_TIMEVALUE_OFFSET_TV_SEC: usize = UTMPX_TIMEVALUE_OFFSET + offset_of!(timeval, tv_sec);
543
    pub const UTMPX_TIMEVALUE_OFFSET_TV_USEC: usize = UTMPX_TIMEVALUE_OFFSET + offset_of!(timeval, tv_usec);
544
    assertcp_eq!(UTMPX_SZ, 280);
545
    assertcp_eq!(offset_of!(utmpx, ut_type), 0);
546
    assertcp_eq!(offset_of!(utmpx, __gap1), 2);
547
    assertcp_eq!(offset_of!(utmpx, ut_tv), 8);
548
    assertcp_eq!(offset_of!(utmpx, ut_id), 24);
549
    assertcp_eq!(offset_of!(utmpx, ut_pid), 32);
550
    assertcp_eq!(offset_of!(utmpx, ut_user), 36);
551
    assertcp_eq!(offset_of!(utmpx, ut_line), 68);
552
    assertcp_eq!(offset_of!(utmpx, ut_host), 84);
553
    assertcp_eq!(offset_of!(utmpx, __ut_spare), 212);
554

555
    /// Helpers for use in `fmt::Debug` trait.
556
    impl utmpx {
557
        pub fn ut_id(&self) -> &CStr {
2✔
558
            unsafe { CStr::from_ptr(self.ut_id[..UT_IDSIZE].as_ptr()) }
2✔
559
        }
2✔
560
        pub fn ut_user(&self) -> &CStr {
6✔
561
            unsafe { CStr::from_ptr(self.ut_user[..UT_USERSIZE].as_ptr()) }
6✔
562
        }
6✔
563
        pub fn ut_line(&self) -> &CStr {
5✔
564
            unsafe { CStr::from_ptr(self.ut_line[..UT_LINESIZE].as_ptr()) }
5✔
565
        }
5✔
566
        pub fn ut_host(&self) -> &CStr {
5✔
567
            unsafe { CStr::from_ptr(self.ut_host[..UT_HOSTSIZE].as_ptr()) }
5✔
568
        }
5✔
569
    }
570

571
    /// From [`include/utmpx.h`], FreeBSD 12.4
572
    /// ```C
573
    /// #define        EMPTY                0        /* No valid user accounting information. */
574
    /// #define        BOOT_TIME        1        /* Time of system boot. */
575
    /// #define        OLD_TIME        2        /* Time when system clock changed. */
576
    /// #define        NEW_TIME        3        /* Time after system clock changed. */
577
    /// #define        USER_PROCESS        4        /* A process. */
578
    /// #define        INIT_PROCESS        5        /* A process spawned by the init process. */
579
    /// #define        LOGIN_PROCESS        6        /* The session leader of a logged-in user. */
580
    /// #define        DEAD_PROCESS        7        /* A session leader who has exited. */
581
    /// #if __BSD_VISIBLE
582
    /// #define        SHUTDOWN_TIME        8        /* Time of system shutdown. */
583
    /// #endif
584
    /// 
585
    /// #if __BSD_VISIBLE
586
    /// #define        UTXDB_ACTIVE        0        /* Active login sessions. */
587
    /// #define        UTXDB_LASTLOGIN        1        /* Last login sessions. */
588
    /// #define        UTXDB_LOG        2        /* Log indexed by time. */
589
    /// #endif
590
    /// ```
591
    ///
592
    /// [`include/utmpx.h`]: https://github.com/freebsd/freebsd-src/blob/release/12.4.0/include/utmpx.h#L58C1-L74C7
593
    pub const UT_TYPES: [c_short; 9] = [
594
        0, 1, 2, 3, 4, 5, 6, 7, 8
595
    ];
596
}
597

598
/// FixedStruct definitions found on Linux running on ARM64 (aarch64)
599
/// architecture.
600
#[allow(non_camel_case_types)]
601
pub mod linux_arm64aarch64 {
602
    use crate::common::FileOffset;
603
    use std::ffi::CStr;
604
    use std::mem::size_of;
605
    use ::const_format::assertcp_eq;
606
    use ::memoffset::offset_of;
607

608
    pub type c_char = std::ffi::c_char;
609
    pub type c_short = std::ffi::c_short;
610
    pub type ll_time_t = std::ffi::c_longlong;
611
    pub type pid_t = std::ffi::c_int;
612
    pub type suseconds_t = std::ffi::c_longlong;
613

614
    // timeval
615

616
    /// ```text
617
    /// timeval               sizeof  16
618
    /// timeval.tv_sec   @  0 sizeof   8
619
    /// timeval.tv_usec  @  8 sizeof   8
620
    /// ```
621
    #[derive(Clone, Copy)]
622
    #[repr(C, align(8))]
623
    #[allow(non_camel_case_types)]
624
    pub struct timeval {
625
        pub tv_sec: i64,
626
        pub tv_usec: i64,
627
    }
628

629
    pub const TIMEVAL_SZ: usize = size_of::<timeval>();
630
    assertcp_eq!(TIMEVAL_SZ, 16);
631
    assertcp_eq!(offset_of!(timeval, tv_sec), 0);
632
    assertcp_eq!(offset_of!(timeval, tv_usec), 8);
633

634
    pub const UT_LINESIZE: usize = 32;
635
    pub const UT_IDSIZE: usize = 4;
636
    pub const UT_NAMESIZE: usize = 32;
637
    pub const UT_USERSIZE: usize = 32;
638
    pub const UT_HOSTSIZE: usize = 256;
639

640
    // lastlog
641

642
    /// ```text
643
    /// lastlog               sizeof 296
644
    /// lastlog.ll_time  @  0 sizeof   8
645
    /// lastlog.ll_line  @  8 sizeof  32
646
    /// lastlog.ll_host  @ 40 sizeof 256
647
    /// ```
648
    #[derive(Clone, Copy)]
649
    #[repr(C, align(8))]
650
    #[allow(non_camel_case_types)]
651
    pub struct lastlog {
652
        pub ll_time: ll_time_t,
653
        pub ll_line: [c_char; UT_LINESIZE],
654
        pub ll_host: [c_char; UT_HOSTSIZE],
655
    }
656

657
    impl lastlog {
658
        pub const fn ll_line(&self) -> &CStr {
5✔
659
            unsafe { CStr::from_ptr(self.ll_line.as_ptr()) }
5✔
660
        }
5✔
661
        pub const fn ll_host(&self) -> &CStr {
5✔
662
            unsafe { CStr::from_ptr(self.ll_host.as_ptr()) }
5✔
663
        }
5✔
664
    }
665

666
    pub const LASTLOG_SZ: usize = size_of::<lastlog>();
667
    pub const LASTLOG_SZ_FO: FileOffset = LASTLOG_SZ as FileOffset;
668
    pub const LASTLOG_TIMEVALUE_OFFSET: usize = offset_of!(lastlog, ll_time);
669
    pub const LASTLOG_TIMEVALUE_SZ: usize = size_of::<ll_time_t>();
670
    assertcp_eq!(LASTLOG_SZ, 296);
671
    assertcp_eq!(offset_of!(lastlog, ll_time), 0);
672
    assertcp_eq!(offset_of!(lastlog, ll_line), 8);
673
    assertcp_eq!(offset_of!(lastlog, ll_host), 40);
674

675
    // utmp == utmpx
676

677
    /// From [`man utmpx`]
678
    ///
679
    /// ```C
680
    /// /* Values for ut_type field, below */
681
    ///
682
    /// #define EMPTY         0 /* Record does not contain valid info
683
    /// (formerly known as UT_UNKNOWN on Linux) */
684
    /// #define RUN_LVL       1 /* Change in system run-level (see
685
    /// init(8)) */
686
    /// #define BOOT_TIME     2 /* Time of system boot (in ut_tv) */
687
    /// #define NEW_TIME      3 /* Time after system clock change
688
    /// (in ut_tv) */
689
    /// #define OLD_TIME      4 /* Time before system clock change
690
    /// (in ut_tv) */
691
    /// #define INIT_PROCESS  5 /* Process spawned by init(8) */
692
    /// #define LOGIN_PROCESS 6 /* Session leader process for user login */
693
    /// #define USER_PROCESS  7 /* Normal process */
694
    /// #define DEAD_PROCESS  8 /* Terminated process */
695
    /// #define ACCOUNTING    9 /* Not implemented */
696
    ///
697
    /// #define UT_LINESIZE      32
698
    /// #define UT_NAMESIZE      32
699
    /// #define UT_HOSTSIZE     256
700
    ///
701
    /// struct exit_status {          /* Type for ut_exit, below */
702
    /// short int e_termination;      /* Process termination status */
703
    /// short int e_exit;             /* Process exit status */
704
    /// };
705
    ///
706
    /// struct utmp {
707
    /// short   ut_type;              /* Type of record */
708
    /// pid_t   ut_pid;               /* PID of login process */
709
    /// char    ut_line[UT_LINESIZE]; /* Device name of tty - "/dev/" */
710
    /// char    ut_id[4];             /* Terminal name suffix,
711
    ///                                  or inittab(5) ID */
712
    /// char    ut_user[UT_NAMESIZE]; /* Username */
713
    /// char    ut_host[UT_HOSTSIZE]; /* Hostname for remote login, or
714
    ///                                  kernel version for run-level
715
    ///                                  messages */
716
    /// struct  exit_status ut_exit;  /* Exit status of a process
717
    ///                                  marked as DEAD_PROCESS; not
718
    ///                                  used by Linux init(8) */
719
    /// /* The ut_session and ut_tv fields must be the same size when
720
    /// compiled 32- and 64-bit.  This allows data files and shared
721
    /// memory to be shared between 32- and 64-bit applications. */
722
    /// #if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32
723
    /// int32_t ut_session;           /* Session ID (getsid(2)),
724
    ///                                  used for windowing */
725
    /// struct {
726
    ///     int32_t tv_sec;           /* Seconds */
727
    ///     int32_t tv_usec;          /* Microseconds */
728
    /// } ut_tv;                      /* Time entry was made */
729
    /// #else
730
    /// long   ut_session;           /* Session ID */
731
    /// struct timeval ut_tv;        /* Time entry was made */
732
    /// #endif
733
    ///
734
    /// int32_t ut_addr_v6[4];        /* Internet address of remote
735
    ///                                  host; IPv4 address uses
736
    ///                                  just ut_addr_v6[0] */
737
    /// char __unused[20];            /* Reserved for future use */
738
    /// };
739
    ///
740
    /// /* Backward compatibility hacks */
741
    /// #define ut_name ut_user
742
    /// #ifndef _NO_UT_TIME
743
    /// #define ut_time ut_tv.tv_sec
744
    /// #endif
745
    /// #define ut_xtime ut_tv.tv_sec
746
    /// #define ut_addr ut_addr_v6[0]
747
    /// ```
748
    ///
749
    /// ---
750
    ///
751
    /// ```text
752
    /// utmpx                   sizeof 400
753
    /// utmpx.ut_type      @  0 sizeof   2
754
    /// utmpx.ut_pid       @  4 sizeof   4
755
    /// utmpx.ut_line      @  8 sizeof  32
756
    /// utmpx.ut_id        @ 40 sizeof   4
757
    /// utmpx.ut_user      @ 44 sizeof  32
758
    /// utmpx.ut_host      @ 76 sizeof 256
759
    /// utmpx.ut_exit      @332 sizeof   4
760
    /// utmpx.ut_session   @336 sizeof   8
761
    /// utmpx.ut_tv        @344 sizeof  16
762
    /// utmpx.ut_tv.tv_sec @344 sizeof   8
763
    /// utmpx.ut_tv.tv_usec@352 sizeof   8
764
    /// utmpx.ut_addr      @360 sizeof   4
765
    /// utmpx.ut_addr_v6   @360 sizeof  16
766
    /// ```
767
    ///
768
    /// [`man utmpx`]: https://linux.die.net/man/5/utmpx
769
    #[derive(Clone, Copy)]
770
    #[repr(C, align(4))]
771
    #[allow(non_camel_case_types)]
772
    pub struct utmpx {
773
        pub ut_type: c_short,
774
        pub ut_pid: pid_t,
775
        pub ut_line: [c_char; UT_LINESIZE],
776
        pub ut_id: [c_char; UT_IDSIZE],
777
        pub ut_user: [c_char; UT_NAMESIZE],
778
        pub ut_host: [c_char; UT_HOSTSIZE],
779
        pub ut_exit: i32,
780
        pub ut_session: i64,
781
        pub ut_tv: timeval,
782
        pub ut_addr_v6: [i32; 4],
783
        pub __glibc_reserved: [c_char; 20],
784
    }
785

786
    impl utmpx {
787
        pub fn ut_line(&self) -> &CStr {
5✔
788
            unsafe { CStr::from_ptr(self.ut_line.as_ptr()) }
5✔
789
        }
5✔
790
        pub fn ut_id(&self) -> &CStr {
2✔
791
            unsafe { CStr::from_ptr(self.ut_id.as_ptr()) }
2✔
792
        }
2✔
793
        pub fn ut_user(&self) -> &CStr {
5✔
794
            unsafe { CStr::from_ptr(self.ut_user.as_ptr()) }
5✔
795
        }
5✔
796
        pub fn ut_host(&self) -> &CStr {
5✔
797
            unsafe { CStr::from_ptr(self.ut_host.as_ptr()) }
5✔
798
        }
5✔
799
    }
800

801
    pub const UTMPX_SZ: usize = size_of::<utmpx>();
802
    pub const UTMPX_SZ_FO: FileOffset = UTMPX_SZ as FileOffset;
803
    pub const UTMPX_TIMEVALUE_OFFSET: usize = offset_of!(utmpx, ut_tv);
804
    pub const UTMPX_TIMEVALUE_SZ: usize = TIMEVAL_SZ;
805
    assertcp_eq!(UTMPX_SZ, 400);
806
    assertcp_eq!(offset_of!(utmpx, ut_type), 0);
807
    assertcp_eq!(offset_of!(utmpx, ut_pid), 4);
808
    assertcp_eq!(offset_of!(utmpx, ut_line), 8);
809
    assertcp_eq!(offset_of!(utmpx, ut_id), 40);
810
    assertcp_eq!(offset_of!(utmpx, ut_user), 44);
811
    assertcp_eq!(offset_of!(utmpx, ut_host), 76);
812
    assertcp_eq!(offset_of!(utmpx, ut_exit), 332);
813
    assertcp_eq!(offset_of!(utmpx, ut_session), 336);
814
    assertcp_eq!(offset_of!(utmpx, ut_tv), 344);
815
    assertcp_eq!(offset_of!(utmpx, ut_addr_v6), 360);
816
    assertcp_eq!(offset_of!(utmpx, __glibc_reserved), 376);
817

818
    /// From [`utmpx.h`], Linux 6.1
819
    /// ```C
820
    /// #define EMPTY           0
821
    /// #define RUN_LVL         1
822
    /// #define BOOT_TIME       2
823
    /// #define NEW_TIME        3
824
    /// #define OLD_TIME        4
825
    /// #define INIT_PROCESS    5
826
    /// #define LOGIN_PROCESS   6
827
    /// #define USER_PROCESS    7
828
    /// #define DEAD_PROCESS    8
829
    /// ```
830
    ///
831
    /// [`utmpx.h`]: https://elixir.bootlin.com/musl/latest/source/include/utmpx.h
832
    pub const UT_TYPES: [c_short; 9] = [
833
        0, 1, 2, 3, 4, 5, 6, 7, 8
834
    ];
835
}
836

837
/// FixedStruct definitions found in `lastlog.h`, `utmp.h`, `utmpx.h`
838
/// from GNU glibc for Linux, architectures amd64 (x86_64), i686 (x86_32),
839
/// ARM6 (aarch64), and RISC-V (riscv64).
840
///
841
/// Found on Ubuntu 22.04 amd64 (x86_64) Linux 5.15, in files:
842
/// * `/usr/include/lastlog.h`
843
/// * `/usr/include/utmp.h`
844
/// * `/usr/include/utmpx.h`
845
/// * `/usr/include/x86_64-linux-gnu/bits/utmp.h`
846
/// * `/usr/include/x86_64-linux-gnu/bits/utmpx.h`
847
///
848
/// Confirmed the sizes and offsets are the same on:
849
/// * CentOS 7 amd64 (x86_64) Linux 3.10
850
/// * Ubuntu 16 i686 (x86_32) Linux 4.4
851
/// * Debian 11 ARM6 (aarch64) Linux 6.1
852
/// * Debian 13 RISC-V (riscv64) Linux 6.1
853
///
854
/// However, `struct timeval` differs on in size on x86_64/32 and ARM6. Yet the
855
/// `utmpx.ut_tv`, which is sometimes defined in-place and sometimes typed as a
856
/// `struct timeval` or `struct __timeval`, is the same size on both.
857
/// From the [code comment in `utmpx.h`]:
858
/// ```C
859
/// /* The fields ut_session and ut_tv must be the same size when compiled
860
///    32- and 64-bit.  This allows files and shared memory to be shared
861
///    between 32- and 64-bit applications.  */
862
/// ```
863
///
864
/// The `utmp` struct is exactly the same as the `utmpx` struct except for a few
865
/// different names. This mod defines `utmpx` and not `utmp`.
866
///
867
/// [code comment in `utmpx.h`]: https://elixir.bootlin.com/glibc/latest/source/sysdeps/gnu/bits/utmpx.h
868
#[allow(non_camel_case_types)]
869
pub mod linux_x86 {
870
    use crate::common::FileOffset;
871
    use std::ffi::CStr;
872
    use std::mem::size_of;
873
    use ::memoffset::offset_of;
874
    use ::const_format::assertcp_eq;
875

876
    pub type b_time_t = std::ffi::c_uint;
877
    pub type c_char = std::ffi::c_char;
878
    pub type c_short = std::ffi::c_short;
879
    pub type comp_t = std::ffi::c_ushort;
880
    pub type ll_time_t = std::ffi::c_int;
881
    pub type pid_t = std::ffi::c_int;
882
    pub type suseconds_t = std::ffi::c_longlong;
883
    pub type uint16_t = std::ffi::c_ushort;
884

885
    pub const PATH_ACCT: &str = "/var/log/account/acct";
886
    pub const PATH_PACCT: &str = "/var/log/account/pacct";
887

888
    pub const ACCT_COMM: usize = 16;
889

890
    pub const AFORK: c_char = 0x01;
891
    pub const ASU: c_char = 0x02;
892
    pub const ACOMPAT: c_char = 0x04;
893
    pub const ACORE: c_char = 0x08;
894
    pub const AXSIG: c_char = 0x10;
895

896
    pub const AC_FLAGS_MASK: c_char = AFORK | ASU | ACOMPAT | ACORE | AXSIG;
897

898
    /// from [`/usr/include/uapi/linux/acct.h`] on Ubuntu 22.04
899
    ///
900
    /// [`/usr/include/uapi/linux/acct.h`]: https://github.com/torvalds/linux/blob/v5.15/include/uapi/linux/acct.h#L75-L101
901
    ///
902
    /// ```C
903
    /// struct acct
904
    /// {
905
    ///   char ac_flag;                 /* Flags.  */
906
    ///   uint16_t ac_uid;              /* Real user ID.  */
907
    ///   uint16_t ac_gid;              /* Real group ID.  */
908
    ///   uint16_t ac_tty;              /* Controlling terminal.  */
909
    ///   uint32_t ac_btime;            /* Beginning time.  */
910
    ///   comp_t ac_utime;              /* User time.  */
911
    ///   comp_t ac_stime;              /* System time.  */
912
    ///   comp_t ac_etime;              /* Elapsed time.  */
913
    ///   comp_t ac_mem;                /* Average memory usage.  */
914
    ///   comp_t ac_io;                 /* Chars transferred.  */
915
    ///   comp_t ac_rw;                 /* Blocks read or written.  */
916
    ///   comp_t ac_minflt;             /* Minor pagefaults.  */
917
    ///   comp_t ac_majflt;             /* Major pagefaults.  */
918
    ///   comp_t ac_swaps;              /* Number of swaps.  */
919
    ///   uint32_t ac_exitcode;         /* Process exitcode.  */
920
    ///   char ac_comm[ACCT_COMM+1];    /* Command name.  */
921
    ///   char ac_pad[10];              /* Padding bytes.  */
922
    /// }; 
923
    ///
924
    /// #define AFORK                0x01        /* ... executed fork, but did not exec */
925
    /// #define ASU                0x02        /* ... used super-user privileges */
926
    /// #define ACOMPAT                0x04        /* ... used compatibility mode (VAX only not used) */
927
    /// #define ACORE                0x08        /* ... dumped core */
928
    /// #define AXSIG                0x10        /* ... was killed by a signal */
929
    /// ```
930
    ///
931
    /// ---
932
    ///
933
    /// ```text
934
    /// acct                 sizeof  64
935
    /// acct.ac_flag    @  0 sizeof   1
936
    /// acct.ac_uid     @  2 sizeof   2
937
    /// acct.ac_gid     @  4 sizeof   2
938
    /// acct.ac_tty     @  6 sizeof   2
939
    /// acct.ac_btime   @  8 sizeof   4
940
    /// acct.ac_utime   @ 12 sizeof   2
941
    /// acct.ac_stime   @ 14 sizeof   2
942
    /// acct.ac_etime   @ 16 sizeof   2
943
    /// acct.ac_mem     @ 18 sizeof   2
944
    /// acct.ac_io      @ 20 sizeof   2
945
    /// acct.ac_rw      @ 22 sizeof   2
946
    /// acct.ac_exitcode@ 32 sizeof   4
947
    /// acct.ac_comm    @ 36 sizeof  17
948
    /// ```
949
    #[derive(Clone, Copy)]
950
    #[repr(C, align(2))]
951
    #[allow(non_camel_case_types)]
952
    pub struct acct {
953
        pub ac_flag: c_char,
954
        pub ac_uid: uint16_t,
955
        pub ac_gid: uint16_t,
956
        pub ac_tty: uint16_t,
957
        pub ac_btime: b_time_t,
958
        pub ac_utime: comp_t,
959
        pub ac_stime: comp_t,
960
        pub ac_etime: comp_t,
961
        pub ac_mem: comp_t,
962
        pub ac_io: comp_t,
963
        pub ac_rw: comp_t,
964
        pub ac_minflt: comp_t,
965
        pub ac_majflt: comp_t,
966
        pub ac_swaps: comp_t,
967
        pub ac_exitcode: u32,
968
        pub ac_comm: [c_char; ACCT_COMM + 1],
969
        pub ac_pad: [c_char; 10],
970
    }
971

972
    pub const ACCT_SZ: usize = size_of::<acct>();
973
    pub const ACCT_SZ_FO: FileOffset = ACCT_SZ as FileOffset;
974
    pub const ACCT_TIMEVALUE_OFFSET: usize = offset_of!(acct, ac_btime);
975
    pub const ACCT_TIMEVALUE_SZ: usize = size_of::<b_time_t>();
976
    assertcp_eq!(ACCT_SZ, 64);
977
    assertcp_eq!(offset_of!(acct, ac_flag), 0);
978
    assertcp_eq!(offset_of!(acct, ac_uid), 2);
979
    assertcp_eq!(offset_of!(acct, ac_gid), 4);
980
    assertcp_eq!(offset_of!(acct, ac_tty), 6);
981
    assertcp_eq!(offset_of!(acct, ac_btime), 8);
982
    assertcp_eq!(offset_of!(acct, ac_utime), 12);
983
    assertcp_eq!(offset_of!(acct, ac_stime), 14);
984
    assertcp_eq!(offset_of!(acct, ac_etime), 16);
985
    assertcp_eq!(offset_of!(acct, ac_mem), 18);
986
    assertcp_eq!(offset_of!(acct, ac_io), 20);
987
    assertcp_eq!(offset_of!(acct, ac_rw), 22);
988
    assertcp_eq!(offset_of!(acct, ac_minflt), 24);
989
    assertcp_eq!(offset_of!(acct, ac_majflt), 26);
990
    assertcp_eq!(offset_of!(acct, ac_swaps), 28);
991
    assertcp_eq!(offset_of!(acct, ac_exitcode), 32);
992
    assertcp_eq!(offset_of!(acct, ac_comm), 36);
993
    assertcp_eq!(offset_of!(acct, ac_pad), 53);
994

995
    impl acct {
996
        pub fn ac_comm(&self) -> &CStr {
585✔
997
            unsafe { CStr::from_ptr(self.ac_comm.as_ptr()) }
585✔
998
        }
585✔
999
    }
1000

1001
    /// From [`/usr/include/uapi/linux/acct.h`] on Ubuntu 22.04
1002
    ///
1003
    /// [`/usr/include/uapi/linux/acct.h`]: https://github.com/torvalds/linux/blob/v5.15/include/uapi/linux/acct.h#L75-L101
1004
    ///
1005
    /// ```C
1006
    /// struct acct_v3
1007
    /// {
1008
    ///         char            ac_flag;                /* Flags */
1009
    ///         char            ac_version;             /* Always set to ACCT_VERSION */
1010
    ///         __u16           ac_tty;                 /* Control Terminal */
1011
    ///         __u32           ac_exitcode;            /* Exitcode */
1012
    ///         __u32           ac_uid;                 /* Real User ID */
1013
    ///         __u32           ac_gid;                 /* Real Group ID */
1014
    ///         __u32           ac_pid;                 /* Process ID */
1015
    ///         __u32           ac_ppid;                /* Parent Process ID */
1016
    ///         /* __u32 range means times from 1970 to 2106 */
1017
    ///         __u32           ac_btime;               /* Process Creation Time */
1018
    ///         float           ac_etime;               /* Elapsed Time */
1019
    ///         comp_t          ac_utime;               /* User Time */
1020
    ///         comp_t          ac_stime;               /* System Time */
1021
    ///         comp_t          ac_mem;                 /* Average Memory Usage */
1022
    ///         comp_t          ac_io;                  /* Chars Transferred */
1023
    ///         comp_t          ac_rw;                  /* Blocks Read or Written */
1024
    ///         comp_t          ac_minflt;              /* Minor Pagefaults */
1025
    ///         comp_t          ac_majflt;              /* Major Pagefaults */
1026
    ///         comp_t          ac_swaps;               /* Number of Swaps */
1027
    ///         char            ac_comm[ACCT_COMM];     /* Command Name */
1028
    /// };
1029
    ///
1030
    /// #define AFORK                0x01        /* ... executed fork, but did not exec */
1031
    /// #define ASU                0x02        /* ... used super-user privileges */
1032
    /// #define ACOMPAT                0x04        /* ... used compatibility mode (VAX only not used) */
1033
    /// #define ACORE                0x08        /* ... dumped core */
1034
    /// #define AXSIG                0x10        /* ... was killed by a signal */
1035
    /// ```
1036
    ///
1037
    /// ---
1038
    ///
1039
    /// ```text
1040
    /// acct_v3                  sizeof  64
1041
    /// acct_v3.ac_flag     @  0 sizeof   1
1042
    /// acct_v3.ac_version  @  1 sizeof   1
1043
    /// acct_v3.ac_tty      @  2 sizeof   2
1044
    /// acct_v3.ac_exitcode @  4 sizeof   4
1045
    /// acct_v3.ac_uid      @  8 sizeof   4
1046
    /// acct_v3.ac_gid      @ 12 sizeof   4
1047
    /// acct_v3.ac_pid      @ 16 sizeof   4
1048
    /// acct_v3.ac_ppid     @ 20 sizeof   4
1049
    /// acct_v3.ac_btime    @ 24 sizeof   4
1050
    /// acct_v3.ac_etime    @ 28 sizeof   4
1051
    /// acct_v3.ac_utime    @ 32 sizeof   2
1052
    /// acct_v3.ac_stime    @ 34 sizeof   2
1053
    /// acct_v3.ac_mem      @ 36 sizeof   2
1054
    /// acct_v3.ac_io       @ 38 sizeof   2
1055
    /// acct_v3.ac_rw       @ 40 sizeof   2
1056
    /// acct_v3.ac_minflt   @ 42 sizeof   2
1057
    /// acct_v3.ac_majflt   @ 44 sizeof   2
1058
    /// acct_v3.ac_swaps    @ 46 sizeof   2
1059
    /// acct_v3.ac_comm     @ 48 sizeof  16
1060
    /// ```
1061
    #[derive(Clone, Copy)]
1062
    #[repr(C, align(4))]
1063
    #[allow(non_camel_case_types)]
1064
    pub struct acct_v3 {
1065
        pub ac_flag: c_char,
1066
        pub ac_version: c_char,
1067
        pub ac_tty: u16,
1068
        pub ac_exitcode: u32,
1069
        pub ac_uid: u32,
1070
        pub ac_gid: u32,
1071
        pub ac_pid: u32,
1072
        pub ac_ppid: u32,
1073
        pub ac_btime: b_time_t,
1074
        pub ac_etime: f32,
1075
        pub ac_utime: comp_t,
1076
        pub ac_stime: comp_t,
1077
        pub ac_mem: comp_t,
1078
        pub ac_io: comp_t,
1079
        pub ac_rw: comp_t,
1080
        pub ac_minflt: comp_t,
1081
        pub ac_majflt: comp_t,
1082
        pub ac_swaps: comp_t,
1083
        pub ac_comm: [c_char; ACCT_COMM],
1084
    }
1085
    // XXX: not handling ACCT_BYTEORDER which changes the byte order
1086
    //      of the file
1087

1088
    pub const ACCT_V3_SZ: usize = size_of::<acct_v3>();
1089
    pub const ACCT_V3_SZ_FO: FileOffset = ACCT_V3_SZ as FileOffset;
1090
    pub const ACCT_V3_TIMEVALUE_OFFSET: usize = offset_of!(acct_v3, ac_btime);
1091
    pub const ACCT_V3_TIMEVALUE_SZ: usize = size_of::<b_time_t>();
1092
    assertcp_eq!(ACCT_V3_SZ, 64);
1093
    assertcp_eq!(offset_of!(acct_v3, ac_flag), 0);
1094
    assertcp_eq!(offset_of!(acct_v3, ac_version), 1);
1095
    assertcp_eq!(offset_of!(acct_v3, ac_tty), 2);
1096
    assertcp_eq!(offset_of!(acct_v3, ac_exitcode), 4);
1097
    assertcp_eq!(offset_of!(acct_v3, ac_uid), 8);
1098
    assertcp_eq!(offset_of!(acct_v3, ac_gid), 12);
1099
    assertcp_eq!(offset_of!(acct_v3, ac_pid), 16);
1100
    assertcp_eq!(offset_of!(acct_v3, ac_ppid), 20);
1101
    assertcp_eq!(offset_of!(acct_v3, ac_btime), 24);
1102
    assertcp_eq!(offset_of!(acct_v3, ac_etime), 28);
1103
    assertcp_eq!(offset_of!(acct_v3, ac_utime), 32);
1104
    assertcp_eq!(offset_of!(acct_v3, ac_stime), 34);
1105
    assertcp_eq!(offset_of!(acct_v3, ac_mem), 36);
1106
    assertcp_eq!(offset_of!(acct_v3, ac_io), 38);
1107
    assertcp_eq!(offset_of!(acct_v3, ac_rw), 40);
1108
    assertcp_eq!(offset_of!(acct_v3, ac_minflt), 42);
1109
    assertcp_eq!(offset_of!(acct_v3, ac_majflt), 44);
1110
    assertcp_eq!(offset_of!(acct_v3, ac_swaps), 46);
1111
    assertcp_eq!(offset_of!(acct_v3, ac_comm), 48);
1112

1113
    impl acct_v3 {
1114
        pub fn ac_comm(&self) -> &CStr {
584✔
1115
            unsafe { CStr::from_ptr(self.ac_comm.as_ptr()) }
584✔
1116
        }
584✔
1117
    }
1118

1119
    // lastlog
1120

1121
    pub const UT_LINESIZE: usize = 32;
1122
    pub const UT_IDSIZE: usize = 4;
1123
    pub const UT_NAMESIZE: usize = 32;
1124
    pub const UT_USERSIZE: usize = 32;
1125
    pub const UT_HOSTSIZE: usize = 256;
1126

1127
    /// ```text
1128
    /// lastlog               sizeof 292
1129
    /// lastlog.ll_time  @  0 sizeof   4
1130
    /// lastlog.ll_line  @  4 sizeof  32
1131
    /// lastlog.ll_host  @ 36 sizeof 256
1132
    /// ```
1133
    #[derive(Clone, Copy)]
1134
    #[repr(C, align(4))]
1135
    #[allow(non_camel_case_types)]
1136
    pub struct lastlog {
1137
        pub ll_time: ll_time_t,
1138
        pub ll_line: [c_char; UT_LINESIZE],
1139
        pub ll_host: [c_char; UT_HOSTSIZE],
1140
    }
1141

1142
    pub const LASTLOG_SZ: usize = size_of::<lastlog>();
1143
    pub const LASTLOG_SZ_FO: FileOffset = LASTLOG_SZ as FileOffset;
1144
    pub const LASTLOG_TIMEVALUE_OFFSET: usize = offset_of!(lastlog, ll_time);
1145
    pub const LASTLOG_TIMEVALUE_SZ: usize = size_of::<ll_time_t>();
1146
    assertcp_eq!(LASTLOG_SZ, 292);
1147
    assertcp_eq!(offset_of!(lastlog, ll_time), 0);
1148
    assertcp_eq!(offset_of!(lastlog, ll_line), 4);
1149
    assertcp_eq!(offset_of!(lastlog, ll_host), 36);
1150

1151
    impl lastlog {
1152
        pub const fn ll_line(&self) -> &CStr {
26✔
1153
            unsafe { CStr::from_ptr(self.ll_line.as_ptr()) }
26✔
1154
        }
26✔
1155
        pub const fn ll_host(&self) -> &CStr {
26✔
1156
            unsafe { CStr::from_ptr(self.ll_host.as_ptr()) }
26✔
1157
        }
26✔
1158
    }
1159

1160
    // utmp
1161

1162
    /// `utmp` == `utmpx` on this platform
1163
    ///
1164
    /// Strangely, the `timeval` on x86_64/32 is sizeof 16 and on ARM6 is
1165
    /// sizeof 8. Yet the `tutmpx.ut_tv`, sometimes typed as a  `__timeval`,
1166
    /// is sizeof 8 on both.
1167
    /// So this `__timeval` is sized to 8 so the `utmp` is the correct size.
1168
    ///
1169
    /// ```text
1170
    /// timeval               sizeof   8
1171
    /// timeval.tv_sec   @  0 sizeof   4
1172
    /// timeval.tv_usec  @  4 sizeof   4
1173
    /// ```
1174
    #[derive(Clone, Copy)]
1175
    #[repr(C, align(4))]
1176
    #[allow(non_camel_case_types)]
1177
    pub struct __timeval {
1178
        pub tv_sec: i32,
1179
        pub tv_usec: i32,
1180
    }
1181
    
1182
    pub const __TIMEVAL_SZ: usize = size_of::<__timeval>();
1183
    assertcp_eq!(__TIMEVAL_SZ, 8);
1184
    assertcp_eq!(offset_of!(__timeval, tv_sec), 0);
1185
    assertcp_eq!(offset_of!(__timeval, tv_usec), 4);
1186

1187
    #[derive(Clone, Copy)]
1188
    #[repr(C, align(2))]
1189
    #[allow(non_camel_case_types)]
1190
    pub struct __exit_status {
1191
        pub e_termination: i16,
1192
        pub e_exit: i16,
1193
    }
1194

1195
    pub const __EXIT_STATUS: usize = size_of::<__exit_status>();
1196
    assertcp_eq!(__EXIT_STATUS, 4);
1197
    assertcp_eq!(offset_of!(__exit_status, e_termination), 0);
1198
    assertcp_eq!(offset_of!(__exit_status, e_exit), 2);
1199

1200
    // TODO: [2024/02/16] add faillog struct.
1201
    //       `faillog` is from older CentOS releases so low priority.
1202
    //       https://unix.stackexchange.com/a/182107/21203
1203

1204
    /// The [`utmpx` struct].
1205
    ///
1206
    /// The `utmp` struct is the exact same.
1207
    ///
1208
    /// Taken from [`/usr/include/x86_64-linux-gnu/bits/utmpx.h`] on Ubuntu 22.04
1209
    /// x86_64:
1210
    /// 
1211
    /// ```C
1212
    /// /* The structure describing an entry in the user accounting database.  */
1213
    /// struct utmpx
1214
    /// {
1215
    ///   short int ut_type;            /* Type of login.  */
1216
    ///   __pid_t ut_pid;               /* Process ID of login process.  */
1217
    ///   char ut_line[__UT_LINESIZE]
1218
    ///     __attribute_nonstring__;    /* Devicename.  */
1219
    ///   char ut_id[4]
1220
    ///     __attribute_nonstring__;    /* Inittab ID.  */
1221
    ///   char ut_user[__UT_NAMESIZE]
1222
    ///     __attribute_nonstring__;    /* Username.  */
1223
    ///   char ut_host[__UT_HOSTSIZE]
1224
    ///     __attribute_nonstring__;    /* Hostname for remote login.  */
1225
    ///   struct __exit_status ut_exit; /* Exit status of a process marked
1226
    ///                                    as DEAD_PROCESS.  */
1227
    /// /* The fields ut_session and ut_tv must be the same size when compiled
1228
    ///    32- and 64-bit.  This allows files and shared memory to be shared
1229
    ///    between 32- and 64-bit applications.  */
1230
    /// #if __WORDSIZE_TIME64_COMPAT32
1231
    ///   __int32_t ut_session;         /* Session ID, used for windowing.  */
1232
    ///   struct
1233
    ///   {
1234
    ///     __int32_t tv_sec;           /* Seconds.  */
1235
    ///     __int32_t tv_usec;          /* Microseconds.  */
1236
    ///   } ut_tv;                      /* Time entry was made.  */
1237
    /// #else
1238
    ///   long int ut_session;          /* Session ID, used for windowing.  */
1239
    ///   struct timeval ut_tv;         /* Time entry was made.  */
1240
    /// #endif
1241
    ///   __int32_t ut_addr_v6[4];      /* Internet address of remote host.  */
1242
    ///   char __glibc_reserved[20];    /* Reserved for future use.  */
1243
    /// };
1244
    /// ```
1245
    ///
1246
    /// The prior code snippet is reprinted here by allowance of the
1247
    /// GNU Lesser General Public License version 2.
1248
    ///
1249
    /// ---
1250
    ///
1251
    /// ```text
1252
    /// utmpx                   sizeof 384
1253
    /// utmpx.ut_type      @  0 sizeof   2
1254
    /// utmpx.ut_pid       @  4 sizeof   4
1255
    /// utmpx.ut_line      @  8 sizeof  32
1256
    /// utmpx.ut_id        @ 40 sizeof   4
1257
    /// utmpx.ut_user      @ 44 sizeof  32
1258
    /// utmpx.ut_name      @ 44 sizeof  32
1259
    /// utmpx.ut_host      @ 76 sizeof 256
1260
    /// utmpx.ut_exit      @332 sizeof   4
1261
    /// utmpx.ut_session   @336 sizeof   4
1262
    /// utmpx.ut_time      @340 sizeof   4
1263
    /// utmpx.ut_xtime     @340 sizeof   4
1264
    /// utmpx.ut_tv        @340 sizeof   8
1265
    /// utmpx.ut_tv.tv_sec @340 sizeof   4
1266
    /// utmpx.ut_tv.tv_usec@344 sizeof   4
1267
    /// utmpx.ut_addr      @348 sizeof   4
1268
    /// utmpx.ut_addr_v6   @348 sizeof  16
1269
    /// ```
1270
    ///
1271
    /// [`utmpx` struct]: https://linux.die.net/man/5/utmpx
1272
    /// [`/usr/include/x86_64-linux-gnu/bits/utmpx.h`]: https://elixir.bootlin.com/glibc/latest/source/sysdeps/gnu/bits/utmpx.h
1273
    #[derive(Clone, Copy)]
1274
    #[repr(C, align(4))]
1275
    #[allow(non_camel_case_types)]
1276
    pub struct utmpx {
1277
        pub ut_type: c_short,
1278
        pub ut_pid: pid_t,
1279
        pub ut_line: [c_char; UT_LINESIZE],
1280
        pub ut_id: [c_char; UT_IDSIZE],
1281
        pub ut_user: [c_char; UT_USERSIZE],
1282
        pub ut_host: [c_char; UT_HOSTSIZE],
1283
        pub ut_exit: __exit_status,
1284
        pub ut_session: i32,
1285
        pub ut_tv: __timeval,
1286
        pub ut_addr_v6: [i32; 4],
1287
        /* private fields */
1288
        pub __glibc_reserved: [i8; 20],
1289
    }
1290

1291
    pub const UTMPX_SZ: usize = size_of::<utmpx>();
1292
    pub const UTMPX_SZ_FO: FileOffset = UTMPX_SZ as FileOffset;
1293
    pub const UTMPX_TIMEVALUE_OFFSET: usize = offset_of!(utmpx, ut_tv);
1294
    pub const UTMPX_TIMEVALUE_SZ: usize = __TIMEVAL_SZ;
1295
    assertcp_eq!(UTMPX_SZ, 384);
1296
    assertcp_eq!(offset_of!(utmpx, ut_type), 0);
1297
    assertcp_eq!(offset_of!(utmpx, ut_pid), 4);
1298
    assertcp_eq!(offset_of!(utmpx, ut_line), 8);
1299
    assertcp_eq!(offset_of!(utmpx, ut_id), 40);
1300
    assertcp_eq!(offset_of!(utmpx, ut_user), 44);
1301
    assertcp_eq!(offset_of!(utmpx, ut_host), 76);
1302
    assertcp_eq!(offset_of!(utmpx, ut_exit), 332);
1303
    assertcp_eq!(offset_of!(utmpx, ut_session), 336);
1304
    assertcp_eq!(offset_of!(utmpx, ut_tv), 340);
1305
    assertcp_eq!(offset_of!(utmpx, ut_addr_v6), 348);
1306
    assertcp_eq!(offset_of!(utmpx, __glibc_reserved), 364);
1307

1308
    /// helpers for `fmt::Debug` trait
1309
    ///
1310
    /// The slicing in each `CStr` function below is to due to
1311
    /// `__attribute_nonstring__` which means the field may not end with a
1312
    /// null byte.
1313
    impl utmpx {
1314
        pub fn ut_line(&self) -> &CStr {
2,820✔
1315
            unsafe { CStr::from_ptr(self.ut_line[..UT_LINESIZE].as_ptr()) }
2,820✔
1316
        }
2,820✔
1317
        pub fn ut_id(&self) -> &CStr {
2,819✔
1318
            unsafe { CStr::from_ptr(self.ut_id[..UT_IDSIZE].as_ptr()) }
2,819✔
1319
        }
2,819✔
1320
        pub fn ut_user(&self) -> &CStr {
2,820✔
1321
            unsafe { CStr::from_ptr(self.ut_user[..UT_USERSIZE].as_ptr()) }
2,820✔
1322
        }
2,820✔
1323
        pub fn ut_host(&self) -> &CStr {
2,820✔
1324
            unsafe { CStr::from_ptr(self.ut_host[..UT_HOSTSIZE].as_ptr()) }
2,820✔
1325
        }
2,820✔
1326
    }
1327

1328
    /// From [`utmpx.h`], Linux 6.1
1329
    /// ```C
1330
    /// #define EMPTY           0
1331
    /// #define RUN_LVL         1
1332
    /// #define BOOT_TIME       2
1333
    /// #define NEW_TIME        3
1334
    /// #define OLD_TIME        4
1335
    /// #define INIT_PROCESS    5
1336
    /// #define LOGIN_PROCESS   6
1337
    /// #define USER_PROCESS    7
1338
    /// #define DEAD_PROCESS    8
1339
    /// ```
1340
    ///
1341
    /// [`utmpx.h`]: https://elixir.bootlin.com/musl/latest/source/include/utmpx.h
1342
    pub const UT_TYPES: [c_short; 9] = [
1343
        0, 1, 2, 3, 4, 5, 6, 7, 8
1344
    ];
1345
}
1346

1347
/// FixedStruct definitions found on NetBSD 9.3 i686 (x86_32).
1348
/// These are slightly different than amd64 (x86_64).
1349
#[allow(non_camel_case_types, unused)]
1350
pub mod netbsd_x8632 {
1351
    use crate::common::FileOffset;
1352
    use std::ffi::CStr;
1353
    use std::ffi::CString;
1354
    use std::mem::size_of;
1355
    use ::memoffset::offset_of;
1356
    use ::const_format::assertcp_eq;
1357

1358
    pub type comp_t = std::ffi::c_ushort;
1359
    pub type c_char = std::ffi::c_char;
1360
    pub type uid_t = std::ffi::c_uint;
1361
    pub type gid_t = std::ffi::c_uint;
1362
    pub type dev_t = std::ffi::c_longlong;
1363
    pub type pid_t = std::ffi::c_int;
1364
    pub type time_t = std::ffi::c_longlong;
1365
    pub type uint8_t = std::ffi::c_uchar;
1366
    pub type uint16_t = std::ffi::c_ushort;
1367

1368
    // acct
1369

1370
    pub const AFORK: u8 = 0x01;
1371
    pub const ASU: u8 = 0x02;
1372
    pub const ACOMPAT: u8 = 0x04;
1373
    pub const ACORE: u8 = 0x08;
1374
    pub const AXSIG: u8 = 0x10;
1375

1376
    pub const AC_FLAGS_MASK: u8 = AFORK | ASU | ACOMPAT | ACORE | AXSIG;
1377

1378
    pub const ACCT_COMM_SIZE: usize = 16;
1379

1380
    /// From [`/usr/include/sys/acct.h`] on NetBSD 9.3:
1381
    ///
1382
    /// ```C
1383
    /// /*
1384
    ///  * Accounting structures; these use a comp_t type which is a 3 bits base 8
1385
    ///  * exponent, 13 bit fraction ``floating point'' number.  Units are 1/AHZ
1386
    ///  * seconds.
1387
    ///  */
1388
    /// typedef uint16_t comp_t;
1389
    /// 
1390
    /// struct acct {
1391
    ///         char      ac_comm[16];  /* command name */
1392
    ///         comp_t    ac_utime;     /* user time */
1393
    ///         comp_t    ac_stime;     /* system time */
1394
    ///         comp_t    ac_etime;     /* elapsed time */
1395
    ///         time_t    ac_btime;     /* starting time */
1396
    ///         uid_t     ac_uid;       /* user id */
1397
    ///         gid_t     ac_gid;       /* group id */
1398
    ///         uint16_t  ac_mem;       /* average memory usage */
1399
    ///         comp_t    ac_io;        /* count of IO blocks */
1400
    ///         dev_t     ac_tty;       /* controlling tty */
1401
    /// 
1402
    /// #define AFORK   0x01            /* fork'd but not exec'd */
1403
    /// #define ASU     0x02            /* used super-user permissions */
1404
    /// #define ACOMPAT 0x04            /* used compatibility mode */
1405
    /// #define ACORE   0x08            /* dumped core */
1406
    /// #define AXSIG   0x10            /* killed by a signal */
1407
    ///         uint8_t   ac_flag;      /* accounting flags */
1408
    /// };
1409
    ///
1410
    /// /*
1411
    ///  * 1/AHZ is the granularity of the data encoded in the comp_t fields.
1412
    ///  * This is not necessarily equal to hz.
1413
    ///  */
1414
    /// #define AHZ     64
1415
    /// ```
1416
    ///
1417
    /// ---
1418
    ///
1419
    /// ```text
1420
    /// acct                 sizeof  56
1421
    /// acct.ac_comm    @  0 sizeof  16
1422
    /// acct.ac_utime   @ 16 sizeof   2
1423
    /// acct.ac_stime   @ 18 sizeof   2
1424
    /// acct.ac_etime   @ 20 sizeof   2
1425
    /// acct.ac_btime   @ 24 sizeof   8
1426
    /// acct.ac_uid     @ 32 sizeof   4
1427
    /// acct.ac_gid     @ 36 sizeof   4
1428
    /// acct.ac_mem     @ 40 sizeof   2
1429
    /// acct.ac_io      @ 42 sizeof   2
1430
    /// acct.ac_tty     @ 44 sizeof   8
1431
    /// acct.ac_flag    @ 52 sizeof   1
1432
    /// ```
1433
    ///
1434
    /// [`/usr/include/sys/acct.h`]: https://github.com/NetBSD/src/blob/1ba34bb0dc133c215a143601c18a24053c0e16e3/sys/sys/acct.h#L49
1435
    #[derive(Clone, Copy)]
1436
    #[repr(C, packed)]
1437
    #[allow(non_camel_case_types)]
1438
    pub struct acct {
1439
        pub ac_comm: [c_char; ACCT_COMM_SIZE],
1440
        pub ac_utime: comp_t,
1441
        pub ac_stime: comp_t,
1442
        pub ac_etime: comp_t,
1443
        pub __gap1: [u8; 2],
1444
        pub ac_btime: time_t,
1445
        pub ac_uid: uid_t,
1446
        pub ac_gid: gid_t,
1447
        pub ac_mem: uint16_t,
1448
        pub ac_io: comp_t,
1449
        pub ac_tty: dev_t,
1450
        pub ac_flag: uint8_t,
1451
        pub __gap3: [u8; 3],
1452
    }
1453

1454
    pub const ACCT_SZ: usize = size_of::<acct>();
1455
    pub const ACCT_SZ_FO: FileOffset = ACCT_SZ as FileOffset;
1456
    pub const ACCT_TIMEVALUE_OFFSET: usize = offset_of!(acct, ac_btime);
1457
    pub const ACCT_TIMEVALUE_SZ: usize = size_of::<time_t>();
1458
    assertcp_eq!(ACCT_SZ, 56);
1459
    assertcp_eq!(offset_of!(acct, ac_comm), 0);
1460
    assertcp_eq!(offset_of!(acct, ac_utime), 16);
1461
    assertcp_eq!(offset_of!(acct, ac_stime), 18);
1462
    assertcp_eq!(offset_of!(acct, ac_etime), 20);
1463
    assertcp_eq!(offset_of!(acct, ac_btime), 24);
1464
    assertcp_eq!(offset_of!(acct, ac_uid), 32);
1465
    assertcp_eq!(offset_of!(acct, ac_gid), 36);
1466
    assertcp_eq!(offset_of!(acct, ac_mem), 40);
1467
    assertcp_eq!(offset_of!(acct, ac_io), 42);
1468
    assertcp_eq!(offset_of!(acct, ac_tty), 44);
1469
    assertcp_eq!(offset_of!(acct, ac_flag), 52);
1470

1471
    impl acct {
1472
        pub fn ac_comm(&self) -> &CStr {
5✔
1473
            unsafe { CStr::from_ptr(self.ac_comm.as_ptr()) }
5✔
1474
        }
5✔
1475
    }
1476

1477
    // timeval
1478

1479
    /// ```text
1480
    /// timeval               sizeof  12
1481
    /// timeval.tv_sec   @  0 sizeof   8
1482
    /// timeval.tv_usec  @  8 sizeof   4
1483
    /// ```
1484
    #[derive(Clone, Copy)]
1485
    // BUG: align(4) has no effect, must use `packed`
1486
    //      see rust-lang/rust#48159 <https://github.com/rust-lang/rust/issues/48159>
1487
    #[repr(C, packed)]
1488
    #[allow(non_camel_case_types)]
1489
    pub struct timeval {
1490
        pub tv_sec: i64,
1491
        pub tv_usec: i32,
1492
    }
1493

1494
    pub const TIMEVAL_SZ: usize = size_of::<timeval>();
1495
    assertcp_eq!(TIMEVAL_SZ, 12);
1496
    assertcp_eq!(offset_of!(timeval, tv_sec), 0);
1497
    assertcp_eq!(offset_of!(timeval, tv_usec), 8);
1498

1499
    // lastlog
1500
    // same size as `linux_x86::lastlog`
1501

1502
    pub const UT_NAMESIZE: usize = 8;
1503
    pub const UT_LINESIZE: usize = 8;
1504
    pub const UT_HOSTSIZE: usize = 16;
1505

1506
    // lastlogx
1507

1508
    pub const UTX_LINESIZE: usize = 32;
1509
    pub const UTX_HOSTSIZE: usize = 256;
1510
    pub const UTX_SSSIZE: usize = 128;
1511

1512
    /// ```text
1513
    /// lastlogx               sizeof 428
1514
    /// lastlogx.ll_tv    @  0 sizeof  12
1515
    /// lastlogx.ll_line  @ 12 sizeof  32
1516
    /// lastlogx.ll_host  @ 44 sizeof 256
1517
    /// lastlogx.ll_ss    @300 sizeof 128
1518
    /// ```
1519
    ///
1520
    // TODO: [2024/03/10] This struct is 428 bytes whereas the scraped lastlogx
1521
    //       file is 65536 bytes (not divisible by 428).
1522
    //       see Issue #243 <https://github.com/jtmoon79/super-speedy-syslog-searcher/issues/243>
1523
    #[derive(Clone, Copy)]
1524
    #[repr(C, packed)]
1525
    #[allow(non_camel_case_types)]
1526
    pub struct lastlogx {
1527
        pub ll_tv: timeval,
1528
        pub ll_line: [c_char; UTX_LINESIZE],
1529
        pub ll_host: [c_char; UTX_HOSTSIZE],
1530
        pub ll_ss: [u8; UTX_SSSIZE],
1531
    }
1532

1533
    pub const LASTLOGX_SZ: usize = size_of::<lastlogx>();
1534
    pub const LASTLOGX_SZ_FO: FileOffset = LASTLOGX_SZ as FileOffset;
1535
    pub const LASTLOGX_TIMEVALUE_OFFSET: usize = offset_of!(lastlogx, ll_tv);
1536
    pub const LASTLOGX_TIMEVALUE_SZ: usize = TIMEVAL_SZ;
1537
    assertcp_eq!(LASTLOGX_SZ, 428);
1538
    assertcp_eq!(offset_of!(lastlogx, ll_tv), 0);
1539
    assertcp_eq!(offset_of!(lastlogx, ll_line), 12);
1540
    assertcp_eq!(offset_of!(lastlogx, ll_host), 44);
1541
    assertcp_eq!(offset_of!(lastlogx, ll_ss), 300);
1542

1543
    pub const PATH_LASTLOGX: &str = "/var/log/lastlogx";
1544

1545
    impl lastlogx {
1546
        pub const fn ll_line(&self) -> &CStr {
5✔
1547
            unsafe { CStr::from_ptr(self.ll_line.as_slice().as_ptr()) }
5✔
1548
        }
5✔
1549
        pub const fn ll_host(&self) -> &CStr {
5✔
1550
            unsafe { CStr::from_ptr(self.ll_host.as_slice().as_ptr()) }
5✔
1551
        }
5✔
1552
    }
1553

1554
    // utmpx
1555

1556
    pub const UTX_USERSIZE: usize = 32;
1557
    pub const UTX_IDSIZE: usize = 4;
1558

1559
    #[derive(Clone, Copy)]
1560
    #[repr(C, align(4))]
1561
    #[allow(non_camel_case_types)]
1562
    pub struct ut_exit {
1563
        pub e_termination: uint16_t,
1564
        pub e_exit: uint16_t,
1565
    }
1566

1567
    assertcp_eq!(offset_of!(ut_exit, e_termination), 0);
1568
    assertcp_eq!(offset_of!(ut_exit, e_exit), 2);
1569

1570
    /// ```text
1571
    /// utmpx                   sizeof 516
1572
    /// utmpx.ut_user      @  0 sizeof  32
1573
    /// utmpx.ut_name      @  0 sizeof  32
1574
    /// utmpx.ut_id        @ 32 sizeof   4
1575
    /// utmpx.ut_line      @ 36 sizeof  32
1576
    /// utmpx.ut_host      @ 68 sizeof 256
1577
    /// utmpx.ut_session   @324 sizeof   2
1578
    /// utmpx.ut_type      @326 sizeof   2
1579
    /// utmpx.ut_pid       @328 sizeof   4
1580
    /// utmpx.ut_exit      @332 sizeof   4
1581
    /// utmpx.ut_ss        @336 sizeof 128
1582
    /// utmpx.ut_xtime     @464 sizeof   8
1583
    /// utmpx.ut_tv        @464 sizeof  12
1584
    /// utmpx.ut_tv.tv_sec @464 sizeof   8
1585
    /// utmpx.ut_tv.tv_usec@472 sizeof   4
1586
    /// utmpx.ut_pad       @476 sizeof  40
1587
    /// ```
1588
    #[derive(Clone, Copy)]
1589
    #[repr(C, align(4))]
1590
    #[allow(non_camel_case_types)]
1591
    pub struct utmpx {
1592
        pub ut_name: [c_char; UTX_USERSIZE],
1593
        pub ut_id: [c_char; UTX_IDSIZE],
1594
        pub ut_line: [c_char; UTX_LINESIZE],
1595
        pub ut_host: [c_char; UTX_HOSTSIZE],
1596
        pub ut_session: uint16_t,
1597
        pub ut_type: uint16_t,
1598
        pub ut_pid: pid_t,
1599
        pub ut_exit: ut_exit,
1600
        pub ut_ss: [u8; UTX_SSSIZE],
1601
        pub ut_tv: timeval,
1602
        pub ut_pad: [c_char; 40],
1603
    }
1604

1605
    pub const UTMPX_SZ: usize = size_of::<utmpx>();
1606
    pub const UTMPX_SZ_FO: FileOffset = UTMPX_SZ as FileOffset;
1607
    pub const UTMPX_TIMEVALUE_OFFSET: usize = offset_of!(utmpx, ut_tv);
1608
    pub const UTMPX_TIMEVALUE_SZ: usize = TIMEVAL_SZ;
1609
    assertcp_eq!(UTMPX_SZ, 516);
1610
    assertcp_eq!(offset_of!(utmpx, ut_name), 0);
1611
    assertcp_eq!(offset_of!(utmpx, ut_id), 32);
1612
    assertcp_eq!(offset_of!(utmpx, ut_line), 36);
1613
    assertcp_eq!(offset_of!(utmpx, ut_host), 68);
1614
    assertcp_eq!(offset_of!(utmpx, ut_session), 324);
1615
    assertcp_eq!(offset_of!(utmpx, ut_type), 326);
1616
    assertcp_eq!(offset_of!(utmpx, ut_pid), 328);
1617
    assertcp_eq!(offset_of!(utmpx, ut_exit), 332);
1618
    assertcp_eq!(offset_of!(utmpx, ut_ss), 336);
1619
    assertcp_eq!(offset_of!(utmpx, ut_tv), 464);
1620
    assertcp_eq!(offset_of!(utmpx, ut_pad), 476);
1621

1622
    pub const PATH_UTMPX: &str = "/var/run/utmpx";
1623
    pub const PATH_WTMPX: &str = "/var/log/wtmpx";
1624

1625
    /// Helpers for use in `fmt::Debug` trait.
1626
    impl utmpx {
1627
        pub fn ut_name(&self) -> &CStr {
5✔
1628
            unsafe { CStr::from_ptr(self.ut_name[..UTX_USERSIZE].as_ptr()) }
5✔
1629
        }
5✔
1630
        pub fn ut_id(&self) -> &CStr {
5✔
1631
            unsafe { CStr::from_ptr(self.ut_id[..UTX_IDSIZE].as_ptr()) }
5✔
1632
        }
5✔
1633
        pub fn ut_line(&self) -> &CStr {
5✔
1634
            unsafe { CStr::from_ptr(self.ut_line[..UTX_LINESIZE].as_ptr()) }
5✔
1635
        }
5✔
1636
        pub fn ut_host(&self) -> &CStr {
5✔
1637
            unsafe { CStr::from_ptr(self.ut_host[..UTX_HOSTSIZE].as_ptr()) }
5✔
1638
        }
5✔
1639
    }
1640

1641
    /// From [`utmpx.h`] in NetBSD 9.3
1642
    /// ```C
1643
    /// #define EMPTY                0
1644
    /// #define RUN_LVL                1
1645
    /// #define BOOT_TIME        2
1646
    /// #define OLD_TIME        3
1647
    /// #define NEW_TIME        4
1648
    /// #define INIT_PROCESS        5
1649
    /// #define LOGIN_PROCESS        6
1650
    /// #define USER_PROCESS        7
1651
    /// #define DEAD_PROCESS        8
1652
    ///
1653
    /// #if defined(_NETBSD_SOURCE)
1654
    /// #define ACCOUNTING        9
1655
    /// #define SIGNATURE        10
1656
    /// #define DOWN_TIME        11
1657
    /// ```
1658
    ///
1659
    /// [`utmpx.h`]: https://github.com/NetBSD/src/blob/1ba34bb0dc133c215a143601c18a24053c0e16e3/include/utmpx.h
1660
    pub const UT_TYPES: [uint16_t; 12] = [
1661
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11
1662
    ];
1663
}
1664

1665
/// FixedStruct definitions found on NetBSD 9.3 amd64 (x86_64).
1666
/// These are slightly different than i686 (x86_32).
1667
#[allow(non_camel_case_types, unused)]
1668
pub mod netbsd_x8664 {
1669
    use crate::common::FileOffset;
1670
    use std::ffi::CStr;
1671
    use std::mem::size_of;
1672
    use ::const_format::assertcp_eq;
1673
    use ::memoffset::offset_of;
1674

1675
    pub type c_char = std::ffi::c_char;
1676
    pub type pid_t = std::ffi::c_int;
1677
    pub type time_t = std::ffi::c_longlong;
1678
    pub type uint16_t = std::ffi::c_ushort;
1679

1680
    // timeval
1681

1682
    /// [from `time.h`]
1683
    /// ```C
1684
    /// struct timeval {
1685
    ///         time_t            tv_sec;                /* seconds */
1686
    ///         suseconds_t        tv_usec;        /* and microseconds */
1687
    /// };
1688
    /// ```
1689
    ///
1690
    /// ---
1691
    ///
1692
    /// ```text
1693
    /// timeval               sizeof  16
1694
    /// timeval.tv_sec   @  0 sizeof   8
1695
    /// timeval.tv_usec  @  8 sizeof   4
1696
    /// ```
1697
    ///
1698
    /// [from `time.h`]: https://github.com/NetBSD/src/blob/1ba34bb0dc133c215a143601c18a24053c0e16e3/sys/sys/time.h
1699
    #[derive(Clone, Copy)]
1700
    #[repr(C, align(4))]
1701
    #[allow(non_camel_case_types)]
1702
    pub struct timeval {
1703
        pub tv_sec: i64,
1704
        pub tv_usec: i32,
1705
        pub __pad: u32,
1706
    }
1707

1708
    pub const TIMEVAL_SZ: usize = size_of::<timeval>();
1709
    assertcp_eq!(TIMEVAL_SZ, 16);
1710
    assertcp_eq!(offset_of!(timeval, tv_sec), 0);
1711
    assertcp_eq!(offset_of!(timeval, tv_usec), 8);
1712
    assertcp_eq!(offset_of!(timeval, __pad), 12);
1713

1714
    // lastlog
1715

1716
    pub const UT_NAMESIZE: usize = 8;
1717
    pub const UT_LINESIZE: usize = 8;
1718
    pub const UT_HOSTSIZE: usize = 16;
1719

1720
    /// [from `utmp.h`]
1721
    /// ```C
1722
    /// #define        UT_NAMESIZE        8
1723
    /// #define        UT_LINESIZE        8
1724
    /// #define        UT_HOSTSIZE        16
1725
    ///
1726
    /// struct lastlog {
1727
    ///         time_t        ll_time;
1728
    ///         char        ll_line[UT_LINESIZE];
1729
    ///         char        ll_host[UT_HOSTSIZE];
1730
    /// };
1731
    /// ```
1732
    ///
1733
    /// ---
1734
    ///
1735
    /// ```text
1736
    /// lastlog               sizeof  32
1737
    /// lastlog.ll_time  @  0 sizeof   8
1738
    /// lastlog.ll_line  @  8 sizeof   8
1739
    /// lastlog.ll_host  @ 16 sizeof  16
1740
    /// ```
1741
    ///
1742
    /// Same struct and offsets were found on NetBSD 9.3 amd64 and i686.
1743
    ///
1744
    /// [from `utmp.h`]: https://github.com/NetBSD/src/blob/0d57c6f2979b7cf98608ef9ddbf6f739da0f8b42/include/utmp.h
1745
    #[derive(Clone, Copy)]
1746
    #[repr(C, align(8))]
1747
    #[allow(non_camel_case_types)]
1748
    pub struct lastlog {
1749
        pub ll_time: time_t,
1750
        pub ll_line: [c_char; UT_LINESIZE],
1751
        pub ll_host: [c_char; UT_HOSTSIZE],
1752
    }
1753

1754
    pub const LASTLOG_SZ: usize = size_of::<lastlog>();
1755
    pub const LASTLOG_SZ_FO: FileOffset = LASTLOG_SZ as FileOffset;
1756
    pub const LASTLOG_TIMEVALUE_OFFSET: usize = offset_of!(lastlog, ll_time);
1757
    pub const LASTLOG_TIMEVALUE_SZ: usize = size_of::<time_t>();
1758
    assertcp_eq!(LASTLOG_SZ, 32);
1759
    assertcp_eq!(offset_of!(lastlog, ll_time), 0);
1760
    assertcp_eq!(offset_of!(lastlog, ll_line), 8);
1761
    assertcp_eq!(offset_of!(lastlog, ll_host), 16);
1762

1763
    pub const PATH_LASTLOG: &str = "/var/log/lastlog";
1764

1765
    impl lastlog {
1766
        pub const fn ll_line(&self) -> &CStr {
585✔
1767
            unsafe { CStr::from_ptr(self.ll_line.as_slice().as_ptr()) }
585✔
1768
        }
585✔
1769
        pub const fn ll_host(&self) -> &CStr {
585✔
1770
            unsafe { CStr::from_ptr(self.ll_host.as_slice().as_ptr()) }
585✔
1771
        }
585✔
1772
    }
1773

1774
    // lastlogx
1775

1776
    pub const UTX_LINESIZE: usize = 32;
1777
    pub const UTX_HOSTSIZE: usize = 256;
1778
    pub const UTX_SSSIZE: usize = 128;
1779

1780
    /// [from `utmpx.h`]
1781
    /// ```C
1782
    /// #define _UTX_USERSIZE        32
1783
    /// #define _UTX_LINESIZE        32
1784
    /// #define        _UTX_IDSIZE        4
1785
    /// #define _UTX_HOSTSIZE        256
1786
    ///
1787
    /// #define ut_user ut_name
1788
    /// #define ut_xtime ut_tv.tv_sec
1789
    ///
1790
    /// #if defined(_NETBSD_SOURCE)
1791
    /// struct lastlogx {
1792
    ///         struct timeval ll_tv;                /* time entry was created */
1793
    ///         char ll_line[_UTX_LINESIZE];        /* tty name */
1794
    ///         char ll_host[_UTX_HOSTSIZE];        /* host name */
1795
    ///         struct sockaddr_storage ll_ss;        /* address where entry was made from */
1796
    /// };
1797
    /// #endif
1798
    /// ```
1799
    ///
1800
    /// ---
1801
    ///
1802
    /// ```text
1803
    /// lastlogx               sizeof 432
1804
    /// lastlogx.ll_tv    @  0 sizeof  16
1805
    /// lastlogx.ll_line  @ 16 sizeof  32
1806
    /// lastlogx.ll_host  @ 48 sizeof 256
1807
    /// lastlogx.ll_ss    @304 sizeof 128
1808
    /// ```
1809
    ///
1810
    /// Also see [`man lastlogx`].
1811
    ///
1812
    /// [from `utmpx.h`]: https://github.com/NetBSD/src/blob/0d57c6f2979b7cf98608ef9ddbf6f739da0f8b42/include/utmpx.h
1813
    /// [`man lastlogx`]: https://man.netbsd.org/lastlogx.5
1814
    // TODO: [2024/03/10] This struct is 432 bytes whereas lastlogx file is
1815
    //       65536 bytes (not divisble by 432).
1816
    //       see Issue #243 <https://github.com/jtmoon79/super-speedy-syslog-searcher/issues/243>
1817
    #[derive(Clone, Copy)]
1818
    #[repr(C, align(8))]
1819
    #[allow(non_camel_case_types)]
1820
    pub struct lastlogx {
1821
        pub ll_tv: timeval,
1822
        pub ll_line: [c_char; UTX_LINESIZE],
1823
        pub ll_host: [c_char; UTX_HOSTSIZE],
1824
        pub ll_ss: [u8; UTX_SSSIZE],
1825
    }
1826

1827
    pub const LASTLOGX_SZ: usize = size_of::<lastlogx>();
1828
    pub const LASTLOGX_SZ_FO: FileOffset = LASTLOG_SZ as FileOffset;
1829
    pub const LASTLOGX_TIMEVALUE_OFFSET: usize = offset_of!(lastlogx, ll_tv);
1830
    pub const LASTLOGX_TIMEVALUE_SZ: usize = TIMEVAL_SZ;
1831
    assertcp_eq!(LASTLOGX_SZ, 432);
1832
    assertcp_eq!(offset_of!(lastlogx, ll_tv), 0);
1833
    assertcp_eq!(offset_of!(lastlogx, ll_line), 16);
1834
    assertcp_eq!(offset_of!(lastlogx, ll_host), 48);
1835
    assertcp_eq!(offset_of!(lastlogx, ll_ss), 304);
1836

1837
    pub const PATH_LASTLOGX: &str = "/var/log/lastlogx";
1838

1839
    impl lastlogx {
1840
        pub const fn ll_line(&self) -> &CStr {
2✔
1841
            unsafe { CStr::from_ptr(self.ll_line.as_slice().as_ptr()) }
2✔
1842
        }
2✔
1843
        pub const fn ll_host(&self) -> &CStr {
2✔
1844
            unsafe { CStr::from_ptr(self.ll_host.as_slice().as_ptr()) }
2✔
1845
        }
2✔
1846
    }
1847

1848
    // utmp
1849

1850
    /// [from `utmp.h`]
1851
    /// ```C
1852
    /// #define        UT_NAMESIZE        8
1853
    /// #define        UT_LINESIZE        8
1854
    /// #define        UT_HOSTSIZE        16
1855
    ///
1856
    /// struct utmp {
1857
    ///         char        ut_line[UT_LINESIZE];
1858
    ///         char        ut_name[UT_NAMESIZE];
1859
    ///         char        ut_host[UT_HOSTSIZE];
1860
    ///         time_t        ut_time;
1861
    /// };
1862
    /// ```
1863
    ///
1864
    /// ---
1865
    ///
1866
    /// ```text
1867
    /// utmp                   sizeof  40
1868
    /// utmp.ut_line      @  0 sizeof   8
1869
    /// utmp.ut_name      @  8 sizeof   8
1870
    /// utmp.ut_host      @ 16 sizeof  16
1871
    /// utmp.ut_time      @ 32 sizeof   8
1872
    /// ```
1873
    ///
1874
    /// Same struct and offsets were found on NetBSD 9.3 amd64 and i686.
1875
    ///
1876
    /// [from `utmp.h`]: https://github.com/NetBSD/src/blob/0d57c6f2979b7cf98608ef9ddbf6f739da0f8b42/include/utmp.h
1877
    #[derive(Clone, Copy)]
1878
    #[repr(C, align(8))]
1879
    #[allow(non_camel_case_types)]
1880
    pub struct utmp {
1881
        pub ut_line: [c_char; UT_LINESIZE],
1882
        pub ut_name: [c_char; UT_NAMESIZE],
1883
        pub ut_host: [c_char; UT_HOSTSIZE],
1884
        pub ut_time: time_t,
1885
    }
1886

1887
    pub const UTMP_SZ: usize = size_of::<utmp>();
1888
    pub const UTMP_SZ_FO: FileOffset = UTMP_SZ as FileOffset;
1889
    pub const UTMP_TIMEVALUE_OFFSET: usize = offset_of!(utmp, ut_time);
1890
    pub const UTMP_TIMEVALUE_SZ: usize = size_of::<time_t>();
1891
    assertcp_eq!(UTMP_SZ, 40);
1892
    assertcp_eq!(offset_of!(utmp, ut_line), 0);
1893
    assertcp_eq!(offset_of!(utmp, ut_name), 8);
1894
    assertcp_eq!(offset_of!(utmp, ut_host), 16);
1895
    assertcp_eq!(offset_of!(utmp, ut_time), 32);
1896

1897
    pub const PATH_UTMP: &str = "/var/run/utmp";
1898
    pub const PATH_WTMP: &str = "/var/log/wtmp";
1899

1900
    impl utmp {
1901
        pub fn ut_line(&self) -> &CStr {
5✔
1902
            unsafe { CStr::from_ptr(self.ut_line[..UT_LINESIZE].as_ptr()) }
5✔
1903
        }
5✔
1904
        pub fn ut_name(&self) -> &CStr {
5✔
1905
            unsafe { CStr::from_ptr(self.ut_name[..UT_NAMESIZE].as_ptr()) }
5✔
1906
        }
5✔
1907
        pub fn ut_host(&self) -> &CStr {
5✔
1908
            unsafe { CStr::from_ptr(self.ut_host[..UT_HOSTSIZE].as_ptr()) }
5✔
1909
        }
5✔
1910
    }
1911

1912
    // utmpx
1913

1914
    pub const UTX_USERSIZE: usize = 32;
1915
    pub const UTX_IDSIZE: usize = 4;
1916

1917
    #[derive(Clone, Copy)]
1918
    #[repr(C, align(2))]
1919
    #[allow(non_camel_case_types)]
1920
    pub struct ut_exit {
1921
        pub e_termination: uint16_t,
1922
        pub e_exit: uint16_t,
1923
    }
1924

1925
    pub const UT_EXIT_SZ: usize = size_of::<ut_exit>();
1926
    assertcp_eq!(UT_EXIT_SZ, 4);
1927
    assertcp_eq!(offset_of!(ut_exit, e_termination), 0);
1928
    assertcp_eq!(offset_of!(ut_exit, e_exit), 2);
1929

1930
    /// [from `utmpx.h`]
1931
    /// ```C
1932
    /// #define _UTX_USERSIZE        32
1933
    /// #define _UTX_LINESIZE        32
1934
    /// #define        _UTX_IDSIZE        4
1935
    /// #define _UTX_HOSTSIZE        256
1936
    ///
1937
    /// #define ut_user ut_name
1938
    /// #define ut_xtime ut_tv.tv_sec
1939
    ///
1940
    /// struct utmpx {
1941
    ///         char ut_name[_UTX_USERSIZE];        /* login name */
1942
    ///         char ut_id[_UTX_IDSIZE];        /* inittab id */
1943
    ///         char ut_line[_UTX_LINESIZE];        /* tty name */
1944
    ///         char ut_host[_UTX_HOSTSIZE];        /* host name */
1945
    ///         uint16_t ut_session;                /* session id used for windowing */
1946
    ///         uint16_t ut_type;                /* type of this entry */
1947
    ///         pid_t ut_pid;                        /* process id creating the entry */
1948
    ///         struct {
1949
    ///                 uint16_t e_termination;        /* process termination signal */
1950
    ///                 uint16_t e_exit;        /* process exit status */
1951
    ///         } ut_exit;
1952
    ///         struct sockaddr_storage ut_ss;        /* address where entry was made from */
1953
    ///         struct timeval ut_tv;                /* time entry was created */
1954
    ///         uint8_t ut_pad[_UTX_PADSIZE];        /* reserved for future use */
1955
    /// };
1956
    /// ```
1957
    ///
1958
    /// ---
1959
    ///
1960
    /// ```text
1961
    /// EMPTY 0
1962
    /// RUN_LVL 1
1963
    /// BOOT_TIME 2
1964
    /// OLD_TIME 3
1965
    /// NEW_TIME 4
1966
    /// INIT_PROCESS 5
1967
    /// LOGIN_PROCESS 6
1968
    /// USER_PROCESS 7
1969
    /// DEAD_PROCESS 8
1970
    /// ACCOUNTING 9
1971
    /// SIGNATURE 10
1972
    /// DOWN_TIME 11
1973
    ///
1974
    /// UTX_USERSIZE 32
1975
    /// UTX_LINESIZE 32
1976
    /// UTX_IDSIZE 4
1977
    /// UTX_HOSTSIZE 256
1978
    ///
1979
    /// utmpx                   sizeof 520
1980
    /// utmpx.ut_user      @  0 sizeof  32
1981
    /// utmpx.ut_name      @  0 sizeof  32
1982
    /// utmpx.ut_id        @ 32 sizeof   4
1983
    /// utmpx.ut_line      @ 36 sizeof  32
1984
    /// utmpx.ut_host      @ 68 sizeof 256
1985
    /// utmpx.ut_session   @324 sizeof   2
1986
    /// utmpx.ut_type      @326 sizeof   2
1987
    /// utmpx.ut_pid       @328 sizeof   4
1988
    /// utmpx.ut_exit      @332 sizeof   4
1989
    /// utmpx.ut_xtime     @464 sizeof   8
1990
    /// utmpx.ut_tv        @464 sizeof  16
1991
    /// utmpx.ut_tv.tv_sec @464 sizeof   8
1992
    /// utmpx.ut_tv.tv_usec@472 sizeof   4
1993
    /// utmpx.ut_pad       @480 sizeof  36
1994
    /// ```
1995
    ///
1996
    /// [from `utmpx.h`]: https://github.com/NetBSD/src/blob/0d57c6f2979b7cf98608ef9ddbf6f739da0f8b42/include/utmpx.h
1997
    #[derive(Clone, Copy)]
1998
    #[repr(C, align(8))]
1999
    #[allow(non_camel_case_types)]
2000
    pub struct utmpx {
2001
        pub ut_user: [c_char; UTX_USERSIZE],
2002
        pub ut_id: [c_char; UTX_IDSIZE],
2003
        pub ut_line: [c_char; UTX_LINESIZE],
2004
        pub ut_host: [c_char; UTX_HOSTSIZE],
2005
        pub ut_session: uint16_t,
2006
        pub ut_type: uint16_t,
2007
        pub ut_pid: pid_t,
2008
        pub ut_exit: ut_exit,
2009
        pub __gap1: [c_char; 128],
2010
        pub ut_tv: timeval,
2011
        pub ut_pad: [c_char; 36],
2012
    }
2013

2014
    pub const UTMPX_SZ: usize = size_of::<utmpx>();
2015
    pub const UTMPX_SZ_FO: FileOffset = UTMPX_SZ as FileOffset;
2016
    pub const UTMPX_TIMEVALUE_OFFSET: usize = offset_of!(utmpx, ut_tv);
2017
    pub const UTMPX_TIMEVALUE_SZ: usize = TIMEVAL_SZ;
2018
    assertcp_eq!(UTMPX_SZ, 520);
2019
    assertcp_eq!(offset_of!(utmpx, ut_user), 0);
2020
    assertcp_eq!(offset_of!(utmpx, ut_id), 32);
2021
    assertcp_eq!(offset_of!(utmpx, ut_line), 36);
2022
    assertcp_eq!(offset_of!(utmpx, ut_host), 68);
2023
    assertcp_eq!(offset_of!(utmpx, ut_session), 324);
2024
    assertcp_eq!(offset_of!(utmpx, ut_type), 326);
2025
    assertcp_eq!(offset_of!(utmpx, ut_pid), 328);
2026
    assertcp_eq!(offset_of!(utmpx, ut_exit), 332);
2027
    assertcp_eq!(offset_of!(utmpx, ut_tv), 464);
2028
    assertcp_eq!(offset_of!(utmpx, ut_pad), 480);
2029

2030
    pub const PATH_UTMPX: &str = "/var/run/utmpx";
2031
    pub const PATH_WTMPX: &str = "/var/log/wtmpx";
2032

2033
    /// Helpers for use in `fmt::Debug` trait.
2034
    impl utmpx {
2035
        pub fn ut_user(&self) -> &CStr {
5✔
2036
            unsafe { CStr::from_ptr(self.ut_user[..UTX_USERSIZE].as_ptr()) }
5✔
2037
        }
5✔
2038
        pub fn ut_id(&self) -> &CStr {
5✔
2039
            unsafe { CStr::from_ptr(self.ut_id[..UTX_IDSIZE].as_ptr()) }
5✔
2040
        }
5✔
2041
        pub fn ut_line(&self) -> &CStr {
5✔
2042
            unsafe { CStr::from_ptr(self.ut_line[..UTX_LINESIZE].as_ptr()) }
5✔
2043
        }
5✔
2044
        pub fn ut_host(&self) -> &CStr {
5✔
2045
            unsafe { CStr::from_ptr(self.ut_host[..UTX_HOSTSIZE].as_ptr()) }
5✔
2046
        }
5✔
2047
    }
2048

2049
    /// From [`utmpx.h`] in NetBSD 9.3
2050
    /// ```C
2051
    /// #define EMPTY                0
2052
    /// #define RUN_LVL                1
2053
    /// #define BOOT_TIME        2
2054
    /// #define OLD_TIME        3
2055
    /// #define NEW_TIME        4
2056
    /// #define INIT_PROCESS        5
2057
    /// #define LOGIN_PROCESS        6
2058
    /// #define USER_PROCESS        7
2059
    /// #define DEAD_PROCESS        8
2060
    ///
2061
    /// #if defined(_NETBSD_SOURCE)
2062
    /// #define ACCOUNTING        9
2063
    /// #define SIGNATURE        10
2064
    /// #define DOWN_TIME        11
2065
    /// ```
2066
    ///
2067
    /// [`utmpx.h`]: https://github.com/NetBSD/src/blob/1ba34bb0dc133c215a143601c18a24053c0e16e3/include/utmpx.h
2068
    pub const UT_TYPES: [uint16_t; 12] = [
2069
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11
2070
    ];
2071
}
2072

2073
/// FixedStruct definitions found on OpenBSD 7.2 i386 (x86_32) and amd64
2074
/// (x86_64).
2075
///
2076
/// The same sizes were found for OpenBSD on i386 and amd64; see repository file
2077
/// `logs/OpenBSD7.4/x86_64/utmp-offsets_amd64_OpenBSD_7.4_.out`.
2078
///
2079
/// See [the 7.2 OpenBSD code base].
2080
/// See [`man utmp`].
2081
/// See [`utmp.h` from the OpenBSD 7.2 release].
2082
///
2083
/// [the 7.2 OpenBSD code base]: https://github.com/openbsd/src/blob/20248fc4cbb7c0efca41a8aafd40db7747023515/include/utmp.h
2084
/// [`man utmp`]: https://web.archive.org/web/20230607124838/https://man.openbsd.org/utmp.5
2085
/// [`utmp.h` from the OpenBSD 7.2 release]: https://github.com/openbsd/src/blob/20248fc4cbb7c0efca41a8aafd40db7747023515/include/utmp.h#L56-L67
2086
#[allow(non_camel_case_types, unused)]
2087
pub mod openbsd_x86 {
2088
    use crate::common::FileOffset;
2089
    use std::ffi::CStr;
2090
    use std::mem::size_of;
2091
    use ::const_format::assertcp_eq;
2092
    use ::memoffset::offset_of;
2093

2094
    pub type c_char = std::ffi::c_char;
2095
    pub type time_t = std::ffi::c_longlong;
2096

2097
    pub const UT_NAMESIZE: usize = 32;
2098
    pub const UT_LINESIZE: usize = 8;
2099
    pub const UT_HOSTSIZE: usize = 256;
2100

2101
    // lastlog
2102

2103
    /// From <https://github.com/openbsd/src/blob/20248fc4cbb7c0efca41a8aafd40db7747023515/include/utmp.h#L56C1-L61C1>
2104
    ///
2105
    /// ```C
2106
    /// #define        UT_NAMESIZE        32
2107
    /// #define        UT_LINESIZE        8
2108
    /// #define        UT_HOSTSIZE        256
2109
    ///
2110
    /// struct lastlog {
2111
    ///         time_t        ll_time;
2112
    ///         char        ll_line[UT_LINESIZE];
2113
    ///         char        ll_host[UT_HOSTSIZE];
2114
    /// };
2115
    /// ```
2116
    ///
2117
    /// ---
2118
    ///
2119
    /// ```text
2120
    /// lastlog               sizeof 272
2121
    /// lastlog.ll_time  @  0 sizeof   8
2122
    /// lastlog.ll_line  @  8 sizeof   8
2123
    /// lastlog.ll_host  @ 16 sizeof 256
2124
    /// ```
2125
    #[derive(Clone, Copy)]
2126
    #[repr(C, align(8))]
2127
    #[allow(non_camel_case_types)]
2128
    pub struct lastlog {
2129
        pub ll_time: time_t,
2130
        pub ll_line: [c_char; UT_LINESIZE],
2131
        pub ll_host: [c_char; UT_HOSTSIZE],
2132
    }
2133

2134
    pub const LASTLOG_SZ: usize = size_of::<lastlog>();
2135
    pub const LASTLOG_SZ_FO: FileOffset = LASTLOG_SZ as FileOffset;
2136
    pub const LASTLOG_TIMEVALUE_OFFSET: usize = offset_of!(lastlog, ll_time);
2137
    pub const LASTLOG_TIMEVALUE_SZ: usize = size_of::<time_t>();
2138
    assertcp_eq!(LASTLOG_SZ, 272);
2139
    assertcp_eq!(offset_of!(lastlog, ll_time), 0);
2140
    assertcp_eq!(offset_of!(lastlog, ll_line), 8);
2141
    assertcp_eq!(offset_of!(lastlog, ll_host), 16);
2142

2143
    pub const PATH_LASTLOG: &str = "/var/log/lastlog";
2144

2145
    /// Helpers for use in `fmt::Debug` trait.
2146
    ///
2147
    /// The slicing in each `CStr` function below is to due to:
2148
    /// ```C
2149
    /// /*
2150
    ///  * Note that these are *not* C strings and thus are not
2151
    ///  * guaranteed to be NUL-terminated.
2152
    /// */
2153
    /// ```
2154
    /// <https://github.com/openbsd/src/blob/20248fc4cbb7c0efca41a8aafd40db7747023515/include/utmp.h#L51-L54>
2155
    ///
2156
    /// to avoid the `CStr` constructor from reading past the end of the given
2157
    /// field into the next field.
2158
    impl lastlog {
2159
        pub const fn ll_line(&self) -> &CStr {
5✔
2160
            unsafe { CStr::from_ptr(self.ll_line.as_slice().as_ptr()) }
5✔
2161
        }
5✔
2162
        pub const fn ll_host(&self) -> &CStr {
5✔
2163
            unsafe { CStr::from_ptr(self.ll_host.as_slice().as_ptr()) }
5✔
2164
        }
5✔
2165
    }
2166

2167
    // utmp
2168

2169
    /// From <https://github.com/openbsd/src/blob/20248fc4cbb7c0efca41a8aafd40db7747023515/include/utmp.h#L62-L67>
2170
    ///
2171
    /// ```C
2172
    /// #define        UT_NAMESIZE        32
2173
    /// #define        UT_LINESIZE        8
2174
    /// #define        UT_HOSTSIZE        256
2175
    ///
2176
    /// struct utmp {
2177
    ///         char        ut_line[UT_LINESIZE];
2178
    ///         char        ut_name[UT_NAMESIZE];
2179
    ///         char        ut_host[UT_HOSTSIZE];
2180
    ///         time_t        ut_time;
2181
    /// };
2182
    /// ```
2183
    ///
2184
    /// ---
2185
    ///
2186
    /// ```text
2187
    /// utmp                   sizeof 304
2188
    /// utmp.ut_line      @  0 sizeof   8
2189
    /// utmp.ut_name      @  8 sizeof  32
2190
    /// utmp.ut_host      @ 40 sizeof 256
2191
    /// utmp.ut_time      @296 sizeof   8
2192
    /// ```
2193
    #[derive(Clone, Copy)]
2194
    #[repr(C, align(8))]
2195
    #[allow(non_camel_case_types)]
2196
    pub struct utmp {
2197
        pub ut_line: [c_char; UT_LINESIZE],
2198
        pub ut_name: [c_char; UT_NAMESIZE],
2199
        pub ut_host: [c_char; UT_HOSTSIZE],
2200
        pub ut_time: time_t,
2201
    }
2202

2203
    pub const UTMP_SZ: usize = size_of::<utmp>();
2204
    pub const UTMP_SZ_FO: FileOffset = UTMP_SZ as FileOffset;
2205
    pub const UTMP_TIMEVALUE_OFFSET: usize = offset_of!(utmp, ut_time);
2206
    pub const UTMP_TIMEVALUE_SZ: usize = size_of::<time_t>();
2207
    assertcp_eq!(UTMP_SZ, 304);
2208
    assertcp_eq!(offset_of!(utmp, ut_line), 0);
2209
    assertcp_eq!(offset_of!(utmp, ut_name), 8);
2210
    assertcp_eq!(offset_of!(utmp, ut_host), 40);
2211
    assertcp_eq!(offset_of!(utmp, ut_time), 296);
2212

2213
    pub const PATH_UTMP: &str = "/var/run/utmp";
2214
    pub const PATH_WTMP: &str = "/var/log/wtmp";
2215

2216
    /// Helpers for use in `fmt::Debug` trait.
2217
    ///
2218
    /// The slicing in each `CStr` function below is to due to:
2219
    /// ```C
2220
    /// /*
2221
    ///  * Note that these are *not* C strings and thus are not
2222
    ///  * guaranteed to be NUL-terminated.
2223
    /// */
2224
    /// ```
2225
    /// <https://github.com/openbsd/src/blob/20248fc4cbb7c0efca41a8aafd40db7747023515/include/utmp.h#L51-L54>
2226
    ///
2227
    /// to avoid the `CStr` constructor from reading past the end of the given
2228
    /// field into the next field.
2229
    impl utmp {
2230
        pub fn ut_line(&self) -> &CStr {
5✔
2231
            unsafe { CStr::from_ptr(self.ut_line[..UT_LINESIZE].as_ptr()) }
5✔
2232
        }
5✔
2233
        pub fn ut_name(&self) -> &CStr {
5✔
2234
            unsafe { CStr::from_ptr(self.ut_name[..UT_NAMESIZE].as_ptr()) }
5✔
2235
        }
5✔
2236
        pub fn ut_host(&self) -> &CStr {
5✔
2237
            unsafe { CStr::from_ptr(self.ut_host[..UT_HOSTSIZE].as_ptr()) }
5✔
2238
        }
5✔
2239
    }
2240
}
2241

2242
/// Maximum size among all `acct`/`lastlog`/`utmp`/etc. C structs
2243
pub const ENTRY_SZ_MAX: usize = max16(
2244
    freebsd_x8664::UTMPX_SZ,
2245
    linux_arm64aarch64::LASTLOG_SZ,
2246
    linux_arm64aarch64::UTMPX_SZ,
2247
    linux_x86::ACCT_SZ,
2248
    linux_x86::ACCT_V3_SZ,
2249
    linux_x86::LASTLOG_SZ,
2250
    linux_x86::UTMPX_SZ,
2251
    netbsd_x8632::ACCT_SZ,
2252
    netbsd_x8632::LASTLOGX_SZ,
2253
    netbsd_x8632::UTMPX_SZ,
2254
    netbsd_x8664::LASTLOG_SZ,
2255
    netbsd_x8664::LASTLOGX_SZ,
2256
    netbsd_x8664::UTMP_SZ,
2257
    netbsd_x8664::UTMPX_SZ,
2258
    openbsd_x86::LASTLOG_SZ,
2259
    openbsd_x86::UTMP_SZ,
2260
);
2261

2262
/// Minimum size among all `acct`/`lastlog`/`utmp`/etc. C structs
2263
pub const ENTRY_SZ_MIN: usize = min16(
2264
    freebsd_x8664::UTMPX_SZ,
2265
    linux_arm64aarch64::LASTLOG_SZ,
2266
    linux_arm64aarch64::UTMPX_SZ,
2267
    linux_x86::ACCT_SZ,
2268
    linux_x86::ACCT_V3_SZ,
2269
    linux_x86::LASTLOG_SZ,
2270
    linux_x86::UTMPX_SZ,
2271
    netbsd_x8632::ACCT_SZ,
2272
    netbsd_x8632::LASTLOGX_SZ,
2273
    netbsd_x8632::UTMPX_SZ,
2274
    netbsd_x8664::LASTLOG_SZ,
2275
    netbsd_x8664::LASTLOGX_SZ,
2276
    netbsd_x8664::UTMP_SZ,
2277
    netbsd_x8664::UTMPX_SZ,
2278
    openbsd_x86::LASTLOG_SZ,
2279
    openbsd_x86::UTMP_SZ,
2280
);
2281

2282
/// Maximum size among all time values for all C structs
2283
pub const TIMEVAL_SZ_MAX: usize = max16(
2284
    freebsd_x8664::TIMEVAL_SZ,
2285
    linux_arm64aarch64::LASTLOG_TIMEVALUE_SZ,
2286
    linux_arm64aarch64::UTMPX_TIMEVALUE_SZ,
2287
    linux_x86::ACCT_TIMEVALUE_SZ,
2288
    linux_x86::ACCT_V3_TIMEVALUE_SZ,
2289
    linux_x86::LASTLOG_TIMEVALUE_SZ,
2290
    linux_x86::UTMPX_TIMEVALUE_SZ,
2291
    netbsd_x8632::ACCT_TIMEVALUE_SZ,
2292
    netbsd_x8632::LASTLOGX_TIMEVALUE_SZ,
2293
    netbsd_x8632::UTMPX_TIMEVALUE_SZ,
2294
    netbsd_x8664::LASTLOG_TIMEVALUE_SZ,
2295
    netbsd_x8664::LASTLOGX_TIMEVALUE_SZ,
2296
    netbsd_x8664::UTMP_TIMEVALUE_SZ,
2297
    netbsd_x8664::UTMPX_TIMEVALUE_SZ,
2298
    openbsd_x86::LASTLOG_TIMEVALUE_SZ,
2299
    openbsd_x86::UTMP_TIMEVALUE_SZ,
2300
);
2301

2302
/// Map [`utmp.ut_type`] value, implied in the index offset, to it's `str`
2303
/// representation. These values and definitions appear consistent across all
2304
/// platforms, except NetBSD appends three values.
2305
///
2306
/// See [NetBSD 9.3 `utmpx.h`].
2307
///
2308
/// [`utmp.ut_type`]: https://www.man7.org/linux/man-pages/man5/utmp.5.html
2309
/// [NetBSD 9.3 `utmpx.h`]: https://github.com/NetBSD/src/blob/0d57c6f2979b7cf98608ef9ddbf6f739da0f8b42/include/utmpx.h
2310
pub const UT_TYPE_VAL_TO_STR: &[&str] = &[
2311
    "EMPTY", // 0
2312
    "RUN_LVL", // 1
2313
    "BOOT_TIME", // 2
2314
    "NEW_TIME", // 3
2315
    "OLD_TIME", // 4
2316
    "INIT_PROCESS", // 5
2317
    "LOGIN_PROCESS", // 6
2318
    "USER_PROCESS", // 7
2319
    "DEAD_PROCESS", // 8
2320
    // NetBSD adds these values
2321
    "ACCOUNTING", // 9
2322
    "SIGNATURE", // 10
2323
    "DOWN_TIME", // 11
2324
];
2325
/// Count of entries in [`UT_TYPE_VAL_TO_STR`].
2326
pub const UT_TYPE_VAL_TO_STR_LEN: usize = UT_TYPE_VAL_TO_STR.len();
2327
#[allow(non_upper_case_globals)]
2328
pub const UT_TYPE_VAL_TO_STR_LEN_i16: i16 = UT_TYPE_VAL_TO_STR.len() as i16;
2329
#[allow(non_upper_case_globals)]
2330
pub const UT_TYPE_VAL_TO_STR_LEN_u16: u16 = UT_TYPE_VAL_TO_STR.len() as u16;
2331

2332
/// common denominator **t**ime **v**alue type representing
2333
/// seconds since Unix epoch
2334
#[allow(non_camel_case_types)]
2335
pub type tv_sec_type = i64;
2336

2337
/// common denominator **t**ime **v**alue type representing additional
2338
/// sub-second microseconds since Unix epoch
2339
#[allow(non_camel_case_types)]
2340
pub type tv_usec_type = i64;
2341

2342
/// common nanoseconds type used as intermediate representation during
2343
/// conversion to [`DateTimeL`]
2344
///
2345
/// [`DateTimeL`]: crate::data::datetime::DateTimeL
2346
#[allow(non_camel_case_types)]
2347
pub type nsecs_type = u32;
2348

2349
#[allow(non_camel_case_types)]
2350
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
2351
/// **t**ime **v**alue pair type
2352
pub struct tv_pair_type(pub tv_sec_type, pub tv_usec_type);
2353

2354
impl std::fmt::Debug for tv_pair_type {
2355
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222,639✔
2356
        write!(f, "{}.{}", self.0, self.1)
222,639✔
2357
    }
222,639✔
2358
}
2359

2360
/// `Box` pointer to a `dyn`amically dispatched _Trait object_
2361
/// [`FixedStructTrait`].
2362
pub type FixedStructDynPtr = Box<dyn FixedStructTrait>;
2363

2364
/// An abstraction for representing varying fixed-size C structs.
2365
/// This includes record-keeping structs _acct_, _lastlog_, _utmp_ defined
2366
/// in the namespaces [`freebsd_x8664`], [`linux_arm64aarch64`], etc.
2367
/// Each specific definition defined in those namespaces must `impl`ement this
2368
/// trait.
2369
///
2370
/// Because this uses `dyn` trait then it must be an "Object safe trait".
2371
/// Being "Object safe trait" enforces limitations on behavior, e.g. cannot
2372
/// require trait `Sized` which implies cannot require trait `Clone`, among
2373
/// other limitations.
2374
///
2375
/// References to specific implementations of this Trait are stored as a Box
2376
/// pointer to the trait object, `Box<dyn FixedStructTrait>`, which is aliased
2377
/// as [`FixedStructDynPtr`]. This allows dynamic dispatching of the at runtime.
2378
///
2379
/// `Send` required for sending from file processing thread to main thread
2380
///
2381
/// `std::marker::Sync` required for `lazy_static!`
2382
///
2383
/// See <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
2384
pub trait FixedStructTrait
2385
where Self: Send,
2386
      Self: std::marker::Sync,
2387
{
2388
    /// the type of the struct
2389
    fn fixedstruct_type(&self) -> FixedStructType;
2390
    /// the size of the struct in bytes
2391
    fn size(&self) -> usize;
2392

2393
    // TODO: [2024/01/28] is there a more rustic way to combine these into one
2394
    //       `as_fixedstruct_type` that is just real smart? so I don't have to repeat
2395
    //       the same function names in each `impl` block, i.e. each impl block
2396
    //       only explicitly defines a few of the functions, the rest panic.
2397
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx;
2398
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog;
2399
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx;
2400
    fn as_linux_x86_acct(&self) -> &linux_x86::acct;
2401
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3;
2402
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog;
2403
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx;
2404
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct;
2405
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx;
2406
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx;
2407
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog;
2408
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx;
2409
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp;
2410
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx;
2411
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog;
2412
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp;
2413
}
2414

2415
impl fmt::Debug for dyn FixedStructTrait {
2416
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2,280✔
2417
        match self.fixedstruct_type() {
2,280✔
2418
            FixedStructType::Fs_Freebsd_x8664_Utmpx => {
2419
                self.as_freebsd_x8664_utmpx().fmt(f)
1✔
2420
            }
2421
            FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => {
2422
                self.as_linux_arm64aarch64_lastlog().fmt(f)
1✔
2423
            }
2424
            FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => {
2425
                self.as_linux_arm64aarch64_utmpx().fmt(f)
1✔
2426
            }
2427
            FixedStructType::Fs_Linux_x86_Acct => {
2428
                self.as_linux_x86_acct().fmt(f)
1✔
2429
            }
2430
            FixedStructType::Fs_Linux_x86_Acct_v3 => {
2431
                self.as_linux_x86_acct_v3().fmt(f)
1✔
2432
            }
2433
            FixedStructType::Fs_Linux_x86_Lastlog => {
2434
                self.as_linux_x86_lastlog().fmt(f)
15✔
2435
            }
2436
            FixedStructType::Fs_Linux_x86_Utmpx => {
2437
                self.as_linux_x86_utmpx().fmt(f)
2,252✔
2438
            }
2439
            FixedStructType::Fs_Netbsd_x8632_Acct => {
2440
                self.as_netbsd_x8632_acct().fmt(f)
1✔
2441
            }
2442
            FixedStructType::Fs_Netbsd_x8632_Lastlogx => {
2443
                self.as_netbsd_x8632_lastlogx().fmt(f)
1✔
2444
            }
2445
            FixedStructType::Fs_Netbsd_x8632_Utmpx => {
2446
                self.as_netbsd_x8632_utmpx().fmt(f)
1✔
2447
            }
2448
            FixedStructType::Fs_Netbsd_x8664_Lastlog => {
2449
                self.as_netbsd_x8664_lastlog().fmt(f)
1✔
2450
            }
2451
            FixedStructType::Fs_Netbsd_x8664_Lastlogx => {
2452
                self.as_netbsd_x8664_lastlogx().fmt(f)
×
2453
            }
2454
            FixedStructType::Fs_Netbsd_x8664_Utmp => {
2455
                self.as_netbsd_x8664_utmp().fmt(f)
1✔
2456
            }
2457
            FixedStructType::Fs_Netbsd_x8664_Utmpx => {
2458
                self.as_netbsd_x8664_utmpx().fmt(f)
1✔
2459
            }
2460
            FixedStructType::Fs_Openbsd_x86_Lastlog => {
2461
                self.as_openbsd_x86_lastlog().fmt(f)
1✔
2462
            }
2463
            FixedStructType::Fs_Openbsd_x86_Utmp => {
2464
                self.as_openbsd_x86_utmp().fmt(f)
1✔
2465
            }
2466
        }
2467
    }
2,280✔
2468
}
2469

2470
// freebsd_x8664::utmpx
2471

2472
impl FixedStructTrait for freebsd_x8664::utmpx {
2473
    fn fixedstruct_type(&self) -> FixedStructType {
13✔
2474
        FixedStructType::Fs_Freebsd_x8664_Utmpx
13✔
2475
    }
13✔
2476
    fn size(&self) -> usize {
9✔
2477
        freebsd_x8664::UTMPX_SZ
9✔
2478
    }
9✔
2479

2480
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
11✔
2481
        self
11✔
2482
    }
11✔
2483
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
2484
        panic!("as_linux_arm64aarch64_lastlog() called on freebsd_x8664::utmpx");
×
2485
    }
2486
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
2487
        panic!("as_linux_arm64aarch64_utmpx() called on freebsd_x8664::utmpx");
×
2488
    }
2489
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
2490
        panic!("as_linux_x86_acct() called on freebsd_x8664::utmpx");
×
2491
    }
2492
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
2493
        panic!("as_linux_x86_acct_v3() called on freebsd_x8664::utmpx");
×
2494
    }
2495
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
2496
        panic!("as_linux_x86_lastlog() called on freebsd_x8664::utmpx");
×
2497
    }
2498
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
2499
        panic!("as_linux_x86_utmpx() called on freebsd_x8664::utmpx");
×
2500
    }
2501
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
2502
        panic!("as_netbsd_x8632_acct() called on freebsd_x8664::utmpx");
×
2503
    }
2504
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
2505
        panic!("as_netbsd_x8632_lastlogx() called on freebsd_x8664::utmpx");
×
2506
    }
2507
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
2508
        panic!("as_netbsd_x8632_utmpx() called on freebsd_x8664::utmpx");
×
2509
    }
2510
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
2511
        panic!("as_netbsd_x8664_lastlog() called on freebsd_x8664::utmpx");
×
2512
    }
2513
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
2514
        panic!("as_netbsd_x8664_lastlogx() called on freebsd_x8664::utmpx");
×
2515
    }
2516
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
2517
        panic!("as_netbsd_x8664_utmp() called on freebsd_x8664::utmpx");
×
2518
    }
2519
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
2520
        panic!("as_netbsd_x8664_utmpx() called on freebsd_x8664::utmpx");
×
2521
    }
2522
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
2523
        panic!("as_openbsd_x86_lastlog() called on freebsd_x8664::utmpx");
×
2524
    }
2525
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
2526
        panic!("as_openbsd_x86_utmp() called on freebsd_x8664::utmpx");
×
2527
    }
2528
}
2529

2530
impl fmt::Debug for freebsd_x8664::utmpx {
2531
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
2532
        let ut_pid_s = match self.ut_type {
2✔
2533
            x if (0..UT_TYPE_VAL_TO_STR_LEN_i16).contains(&x) =>
2✔
2534
                format!("{} ({})", self.ut_type, UT_TYPE_VAL_TO_STR[self.ut_type as usize]),
2✔
2535
            _ => format!("{} (UNKNOWN)", self.ut_type),
×
2536
        };
2537
        f.debug_struct("freebsd_x8664::utmpx")
2✔
2538
            .field("size", &self.size())
2✔
2539
            .field("ut_type", &self.ut_type)
2✔
2540
            .field("ut_pid", &format_args!("{}", ut_pid_s))
2✔
2541
            .field("ut_line", &self.ut_line())
2✔
2542
            .field("ut_id", &self.ut_id())
2✔
2543
            .field("ut_user", &self.ut_user())
2✔
2544
            .field("ut_host", &self.ut_host())
2✔
2545
            .field("ut_tv.tv_sec", &self.ut_tv.tv_sec)
2✔
2546
            .field("ut_tv.tv_usec", &self.ut_tv.tv_usec)
2✔
2547
            .finish()
2✔
2548
    }
2✔
2549
}
2550

2551
// linux_arm64aarch64::lastlog
2552

2553
impl FixedStructTrait for linux_arm64aarch64::lastlog {
2554
    fn fixedstruct_type(&self) -> FixedStructType {
10✔
2555
        FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog
10✔
2556
    }
10✔
2557
    fn size(&self) -> usize {
7✔
2558
        linux_arm64aarch64::LASTLOG_SZ
7✔
2559
    }
7✔
2560

2561
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
2562
        panic!("as_freebsd_x8664_utmpx() called on freebsd_x8664::utmpx");
×
2563
    }
2564
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
9✔
2565
        self
9✔
2566
    }
9✔
2567
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
2568
        panic!("as_linux_arm64aarch64_utmpx() called on freebsd_x8664::utmpx");
×
2569
    }
2570
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
2571
        panic!("as_linux_x86_acct() called on freebsd_x8664::utmpx");
×
2572
    }
2573
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
2574
        panic!("as_linux_x86_acct_v3() called on freebsd_x8664::utmpx");
×
2575
    }
2576
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
2577
        panic!("as_linux_x86_lastlog() called on freebsd_x8664::utmpx");
×
2578
    }
2579
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
2580
        panic!("as_linux_x86_utmpx() called on freebsd_x8664::utmpx");
×
2581
    }
2582
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
2583
        panic!("as_netbsd_x8632_acct() called on freebsd_x8664::utmpx");
×
2584
    }
2585
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
2586
        panic!("as_netbsd_x8632_lastlogx() called on freebsd_x8664::utmpx");
×
2587
    }
2588
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
2589
        panic!("as_netbsd_x8632_utmpx() called on freebsd_x8664::utmpx");
×
2590
    }
2591
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
2592
        panic!("as_netbsd_x8664_lastlog() called on freebsd_x8664::utmpx");
×
2593
    }
2594
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
2595
        panic!("as_netbsd_x8664_lastlogx() called on freebsd_x8664::utmpx");
×
2596
    }
2597
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
2598
        panic!("as_netbsd_x8664_utmp() called on freebsd_x8664::utmpx");
×
2599
    }
2600
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
2601
        panic!("as_netbsd_x8664_utmpx() called on freebsd_x8664::utmpx");
×
2602
    }
2603
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
2604
        panic!("as_openbsd_x86_lastlog() called on freebsd_x8664::utmpx");
×
2605
    }
2606
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
2607
        panic!("as_openbsd_x86_utmp() called on freebsd_x8664::utmpx");
×
2608
    }
2609
}
2610

2611
impl fmt::Debug for linux_arm64aarch64::lastlog {
2612
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
2613
        f.debug_struct("linux_arm64aarch64::lastlog")
2✔
2614
            .field("size", &self.size())
2✔
2615
            .field("ll_time", &self.ll_time)
2✔
2616
            .field("ll_line", &self.ll_line())
2✔
2617
            .field("ll_host", &self.ll_host())
2✔
2618
            .finish()
2✔
2619
    }
2✔
2620
}
2621

2622
// linux_arm64aarch64::utmpx
2623

2624
impl FixedStructTrait for linux_arm64aarch64::utmpx {
2625
    fn fixedstruct_type(&self) -> FixedStructType {
10✔
2626
        FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx
10✔
2627
    }
10✔
2628
    fn size(&self) -> usize {
7✔
2629
        linux_arm64aarch64::UTMPX_SZ
7✔
2630
    }
7✔
2631

2632
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
2633
        panic!("as_freebsd_x8664_utmpx() called on linux_arm64aarch64::utmpx");
×
2634
    }
2635
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
2636
        panic!("as_linux_arm64aarch64_lastlog() called on linux_arm64aarch64::utmpx");
×
2637
    }
2638
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
9✔
2639
        self
9✔
2640
    }
9✔
2641
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
2642
        panic!("as_linux_x86_acct() called on linux_arm64aarch64::utmpx");
×
2643
    }
2644
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
2645
        panic!("as_linux_x86_acct_v3() called on linux_arm64aarch64::utmpx");
×
2646
    }
2647
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
2648
        panic!("as_linux_x86_lastlog() called on linux_arm64aarch64::utmpx");
×
2649
    }
2650
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
2651
        panic!("as_linux_x86_utmpx() called on linux_arm64aarch64::utmpx");
×
2652
    }
2653
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
2654
        panic!("as_netbsd_x8632_acct() called on linux_arm64aarch64::utmpx");
×
2655
    }
2656
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
2657
        panic!("as_netbsd_x8632_lastlogx() called on linux_arm64aarch64::utmpx");
×
2658
    }
2659
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
2660
        panic!("as_netbsd_x8632_utmpx() called on linux_arm64aarch64::utmpx");
×
2661
    }
2662
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
2663
        panic!("as_netbsd_x8664_lastlog() called on linux_arm64aarch64::utmpx");
×
2664
    }
2665
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
2666
        panic!("as_netbsd_x8664_lastlogx() called on linux_arm64aarch64::utmpx");
×
2667
    }
2668
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
2669
        panic!("as_netbsd_x8664_utmp() called on linux_arm64aarch64::utmpx");
×
2670
    }
2671
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
2672
        panic!("as_netbsd_x8664_utmpx() called on linux_arm64aarch64::utmpx");
×
2673
    }
2674
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
2675
        panic!("as_openbsd_x86_lastlog() called on linux_arm64aarch64::utmpx");
×
2676
    }
2677
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
2678
        panic!("as_openbsd_x86_utmp() called on linux_arm64aarch64::utmpx");
×
2679
    }
2680
}
2681

2682
impl fmt::Debug for linux_arm64aarch64::utmpx {
2683
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
2684
        f.debug_struct("linux_arm64aarch64::utmpx")
2✔
2685
            .field("size", &self.size())
2✔
2686
            .field("ut_type", &self.ut_type)
2✔
2687
            .field("ut_pid", &self.ut_pid)
2✔
2688
            .field("ut_line", &self.ut_line())
2✔
2689
            .field("ut_id", &self.ut_id())
2✔
2690
            .field("ut_user", &self.ut_user())
2✔
2691
            .field("ut_host", &self.ut_host())
2✔
2692
            .field("ut_tv.tv_sec", &self.ut_tv.tv_sec)
2✔
2693
            .field("ut_tv.tv_usec", &self.ut_tv.tv_usec)
2✔
2694
            .field("ut_addr_v6", &self.ut_addr_v6)
2✔
2695
            .finish()
2✔
2696
    }
2✔
2697
}
2698

2699
// linux_x86::acct
2700

2701
impl FixedStructTrait for linux_x86::acct {
2702
    fn fixedstruct_type(&self) -> FixedStructType {
2,910✔
2703
        FixedStructType::Fs_Linux_x86_Acct
2,910✔
2704
    }
2,910✔
2705
    fn size(&self) -> usize {
1,167✔
2706
        linux_x86::ACCT_SZ
1,167✔
2707
    }
1,167✔
2708

2709
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
2710
        panic!("as_freebsd_x8664_utmpx() called on linux_x86::acct");
×
2711
    }
2712
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
2713
        panic!("as_linux_arm64aarch64_lastlog() called on linux_x86::acct");
×
2714
    }
2715
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
2716
        panic!("as_linux_arm64aarch64_utmpx() called on linux_x86::acct");
×
2717
    }
2718
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
1,169✔
2719
        self
1,169✔
2720
    }
1,169✔
2721
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
2722
        panic!("as_linux_x86_acct_v3() called on linux_x86::acct");
×
2723
    }
2724
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
2725
        panic!("as_linux_x86_lastlog() called on linux_x86::acct");
×
2726
    }
2727
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
2728
        panic!("as_linux_x86_utmpx() called on linux_x86::acct");
×
2729
    }
2730
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
2731
        panic!("as_netbsd_x8632_acct() called on linux_x86::acct");
×
2732
    }
2733
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
2734
        panic!("as_netbsd_x8632_lastlogx() called on linux_x86::acct");
×
2735
    }
2736
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
2737
        panic!("as_netbsd_x8632_utmpx() called on linux_x86::acct");
×
2738
    }
2739
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
2740
        panic!("as_netbsd_x8664_lastlog() called on linux_x86::acct");
×
2741
    }
2742
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
2743
        panic!("as_netbsd_x8664_lastlogx() called on linux_x86::acct");
×
2744
    }
2745
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
2746
        panic!("as_netbsd_x8664_utmp() called on linux_x86::acct");
×
2747
    }
2748
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
2749
        panic!("as_netbsd_x8664_utmpx() called on linux_x86::acct");
×
2750
    }
2751
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
2752
        panic!("as_openbsd_x86_lastlog() called on linux_x86::acct");
×
2753
    }
2754
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
2755
        panic!("as_openbsd_x86_utmp() called on linux_x86::acct");
×
2756
    }
2757
}
2758

2759
impl fmt::Debug for linux_x86::acct {
2760
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
2761
        f.debug_struct("linux_x86::acct")
2✔
2762
            .field("size", &self.size())
2✔
2763
            .field("ac_flag", &self.ac_flag)
2✔
2764
            .field("ac_uid", &self.ac_uid)
2✔
2765
            .field("ac_gid", &self.ac_gid)
2✔
2766
            .field("ac_tty", &self.ac_tty)
2✔
2767
            .field("ac_btime", &self.ac_btime)
2✔
2768
            .field("ac_utime", &self.ac_utime)
2✔
2769
            .field("ac_stime", &self.ac_stime)
2✔
2770
            .field("ac_etime", &self.ac_etime)
2✔
2771
            .field("ac_mem", &self.ac_mem)
2✔
2772
            .field("ac_io", &self.ac_io)
2✔
2773
            .field("ac_rw", &self.ac_rw)
2✔
2774
            .field("ac_minflt", &self.ac_minflt)
2✔
2775
            .field("ac_majflt", &self.ac_majflt)
2✔
2776
            .field("ac_swaps", &self.ac_swaps)
2✔
2777
            .field("ac_exitcode", &self.ac_exitcode)
2✔
2778
            .field("ac_comm", &self.ac_comm())
2✔
2779
            .finish()
2✔
2780
    }
2✔
2781
}
2782

2783
// linux_x86::acct_v3
2784

2785
impl FixedStructTrait for linux_x86::acct_v3 {
2786
    fn fixedstruct_type(&self) -> FixedStructType {
2,910✔
2787
        FixedStructType::Fs_Linux_x86_Acct_v3
2,910✔
2788
    }
2,910✔
2789
    fn size(&self) -> usize {
1,167✔
2790
        linux_x86::ACCT_V3_SZ
1,167✔
2791
    }
1,167✔
2792

2793
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
2794
        panic!("as_freebsd_x8664_utmpx() called on linux_x86::acct_v3");
×
2795
    }
2796
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
2797
        panic!("as_linux_arm64aarch64_lastlog() called on linux_x86::acct_v3");
×
2798
    }
2799
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
2800
        panic!("as_linux_arm64aarch64_utmpx() called on linux_x86::acct_v3");
×
2801
    }
2802
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
2803
        panic!("as_linux_x86_acct() called on linux_x86::acct_v3");
×
2804
    }
2805
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
1,169✔
2806
        self
1,169✔
2807
    }
1,169✔
2808
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
2809
        panic!("as_linux_x86_lastlog() called on linux_x86::acct_v3");
×
2810
    }
2811
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
2812
        panic!("as_linux_x86_utmpx() called on linux_x86::acct_v3");
×
2813
    }
2814
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
2815
        panic!("as_netbsd_x8632_acct() called on linux_x86::acct_v3");
×
2816
    }
2817
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
2818
        panic!("as_netbsd_x8632_lastlogx() called on linux_x86::acct_v3");
×
2819
    }
2820
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
2821
        panic!("as_netbsd_x8632_utmpx() called on linux_x86::acct_v3");
×
2822
    }
2823
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
2824
        panic!("as_netbsd_x8664_lastlog() called on linux_x86::acct_v3");
×
2825
    }
2826
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
2827
        panic!("as_netbsd_x8664_lastlogx() called on linux_x86::acct_v3");
×
2828
    }
2829
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
2830
        panic!("as_netbsd_x8664_utmp() called on linux_x86::acct_v3");
×
2831
    }
2832
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
2833
        panic!("as_netbsd_x8664_utmpx() called on linux_x86::acct_v3");
×
2834
    }
2835
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
2836
        panic!("as_openbsd_x86_lastlog() called on linux_x86::acct_v3");
×
2837
    }
2838
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
2839
        panic!("as_openbsd_x86_utmp() called on linux_x86::acct_v3");
×
2840
    }
2841
}
2842

2843
impl fmt::Debug for linux_x86::acct_v3 {
2844
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
2845
        f.debug_struct("linux_x86::acct_v3")
2✔
2846
            .field("size", &self.size())
2✔
2847
            .field("ac_flag", &self.ac_flag)
2✔
2848
            .field("ac_tty", &self.ac_tty)
2✔
2849
            .field("ac_exitcode", &self.ac_exitcode)
2✔
2850
            .field("ac_uid", &self.ac_uid)
2✔
2851
            .field("ac_gid", &self.ac_gid)
2✔
2852
            .field("ac_pid", &self.ac_pid)
2✔
2853
            .field("ac_ppid", &self.ac_ppid)
2✔
2854
            .field("ac_btime", &self.ac_btime)
2✔
2855
            .field("ac_etime", &self.ac_etime)
2✔
2856
            .field("ac_utime", &self.ac_utime)
2✔
2857
            .field("ac_stime", &self.ac_stime)
2✔
2858
            .field("ac_mem", &self.ac_mem)
2✔
2859
            .field("ac_io", &self.ac_io)
2✔
2860
            .field("ac_rw", &self.ac_rw)
2✔
2861
            .field("ac_minflt", &self.ac_minflt)
2✔
2862
            .field("ac_majflt", &self.ac_majflt)
2✔
2863
            .field("ac_swaps", &self.ac_swaps)
2✔
2864
            .field("ac_comm", &self.ac_comm())
2✔
2865
            .finish()
2✔
2866
    }
2✔
2867
}
2868

2869
// linux_x86::lastlog
2870

2871
impl FixedStructTrait for linux_x86::lastlog {
2872
    fn fixedstruct_type(&self) -> FixedStructType {
67✔
2873
        FixedStructType::Fs_Linux_x86_Lastlog
67✔
2874
    }
67✔
2875
    fn size(&self) -> usize {
56✔
2876
        linux_x86::LASTLOG_SZ
56✔
2877
    }
56✔
2878

2879
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
2880
        panic!("as_freebsd_x8664_utmpx() called on linux_x86::lastlog");
×
2881
    }
2882
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
2883
        panic!("as_linux_arm64aarch64_lastlog() called on linux_x86::lastlog");
×
2884
    }
2885
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
2886
        panic!("as_linux_arm64aarch64_utmpx() called on linux_x86::lastlog");
×
2887
    }
2888
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
2889
        panic!("as_linux_x86_acct() called on linux_x86::lastlog");
×
2890
    }
2891
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
2892
        panic!("as_linux_x86_acct_v3() called on linux_x86::lastlog");
×
2893
    }
2894
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
45✔
2895
        self
45✔
2896
    }
45✔
2897
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
2898
        panic!("as_linux_x86_utmpx() called on linux_x86::lastlog");
×
2899
    }
2900
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
2901
        panic!("as_netbsd_x8632_acct() called on linux_x86::lastlog");
×
2902
    }
2903
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
2904
        panic!("as_netbsd_x8632_lastlogx() called on linux_x86::lastlog");
×
2905
    }
2906
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
2907
        panic!("as_netbsd_x8632_utmpx() called on linux_x86::lastlog");
×
2908
    }
2909
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
2910
        panic!("as_netbsd_x8664_lastlog() called on linux_x86::lastlog");
×
2911
    }
2912
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
2913
        panic!("as_netbsd_x8664_lastlogx() called on linux_x86::lastlog");
×
2914
    }
2915
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
2916
        panic!("as_netbsd_x8664_utmp() called on linux_x86::lastlog");
×
2917
    }
2918
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
2919
        panic!("as_netbsd_x8664_utmpx() called on linux_x86::lastlog");
×
2920
    }
2921
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
2922
        panic!("as_openbsd_x86_lastlog() called on linux_x86::lastlog");
×
2923
    }
2924
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
2925
        panic!("as_openbsd_x86_utmp() called on linux_x86::lastlog");
×
2926
    }
2927
}
2928

2929
impl fmt::Debug for linux_x86::lastlog {
2930
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16✔
2931
        f.debug_struct("linux_x86::lastlog")
16✔
2932
            .field("size", &self.size())
16✔
2933
            .field("ll_time", &self.ll_time)
16✔
2934
            .field("ll_line", &self.ll_line())
16✔
2935
            .field("ll_host", &self.ll_host())
16✔
2936
            .finish()
16✔
2937
    }
16✔
2938
}
2939

2940
// linux_x86::utmpx
2941

2942
impl FixedStructTrait for linux_x86::utmpx {
2943
    fn fixedstruct_type(&self) -> FixedStructType {
7,689✔
2944
        FixedStructType::Fs_Linux_x86_Utmpx
7,689✔
2945
    }
7,689✔
2946
    fn size(&self) -> usize {
222,464✔
2947
        linux_x86::UTMPX_SZ
222,464✔
2948
    }
222,464✔
2949

2950
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
2951
        panic!("as_freebsd_x8664_utmpx() called on linux_x86::utmpx");
×
2952
    }
2953
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
2954
        panic!("as_linux_arm64aarch64_lastlog() called on linux_x86::utmpx");
×
2955
    }
2956
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
2957
        panic!("as_linux_arm64aarch64_utmpx() called on linux_x86::utmpx");
×
2958
    }
2959
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
2960
        panic!("as_linux_x86_acct() called on linux_x86::utmpx");
×
2961
    }
2962
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
2963
        panic!("as_linux_x86_acct_v3() called on linux_x86::utmpx");
×
2964
    }
2965
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
2966
        panic!("as_linux_x86_lastlog() called on linux_x86::utmpx");
×
2967
    }
2968
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
5,996✔
2969
        self
5,996✔
2970
    }
5,996✔
2971
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
2972
        panic!("as_netbsd_x8632_acct() called on linux_x86::utmpx");
×
2973
    }
2974
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
2975
        panic!("as_netbsd_x8632_lastlogx() called on linux_x86::utmpx");
×
2976
    }
2977
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
2978
        panic!("as_netbsd_x8632_utmpx() called on linux_x86::utmpx");
×
2979
    }
2980
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
2981
        panic!("as_netbsd_x8664_lastlog() called on linux_x86::utmpx");
×
2982
    }
2983
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
2984
        panic!("as_netbsd_x8664_lastlogx() called on linux_x86::utmpx");
×
2985
    }
2986
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
2987
        panic!("as_netbsd_x8664_utmp() called on linux_x86::utmpx");
×
2988
    }
2989
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
2990
        panic!("as_netbsd_x8664_utmpx() called on linux_x86::utmpx");
×
2991
    }
2992
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
2993
        panic!("as_openbsd_x86_lastlog() called on linux_x86::utmpx");
×
2994
    }
2995
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
2996
        panic!("as_openbsd_x86_utmp() called on linux_x86::utmpx");
×
2997
    }
2998
}
2999

3000
impl fmt::Debug for linux_x86::utmpx {
3001
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2,253✔
3002
        let ut_pid_s = match self.ut_type {
2,253✔
3003
            x if x < UT_TYPE_VAL_TO_STR_LEN_i16 && x >= 0 => format!("{} ({})", self.ut_type, UT_TYPE_VAL_TO_STR[self.ut_type as usize]),
2,253✔
3004
            _ => format!("{} (UNKNOWN)", self.ut_type),
4✔
3005
        };
3006
        f.debug_struct("linux_x86::utmpx")
2,253✔
3007
            .field("size", &self.size())
2,253✔
3008
            .field("ut_type", &self.ut_type)
2,253✔
3009
            .field("ut_pid", &format_args!("{}", ut_pid_s))
2,253✔
3010
            .field("ut_line", &self.ut_line())
2,253✔
3011
            .field("ut_id", &self.ut_id())
2,253✔
3012
            .field("ut_user", &self.ut_user())
2,253✔
3013
            .field("ut_host", &self.ut_host())
2,253✔
3014
            .field("ut_exit_e_termination", &self.ut_exit.e_termination)
2,253✔
3015
            .field("ut_exit_e_exit", &self.ut_exit.e_exit)
2,253✔
3016
            .field("ut_session", &self.ut_session)
2,253✔
3017
            .field("ut_tv.tv_sec", &self.ut_tv.tv_sec)
2,253✔
3018
            .field("ut_tv.tv_usec", &self.ut_tv.tv_usec)
2,253✔
3019
            .finish()
2,253✔
3020
    }
2,253✔
3021
}
3022

3023
// netbsd_x8632::acct
3024

3025
impl FixedStructTrait for netbsd_x8632::acct {
3026
    fn fixedstruct_type(&self) -> FixedStructType {
10✔
3027
        FixedStructType::Fs_Netbsd_x8632_Acct
10✔
3028
    }
10✔
3029
    fn size(&self) -> usize {
7✔
3030
        netbsd_x8632::ACCT_SZ
7✔
3031
    }
7✔
3032

3033
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
3034
        panic!("as_freebsd_x8664_utmpx() called on netbsd_x8632::lastlog");
×
3035
    }
3036
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
3037
        panic!("as_linux_arm64aarch64_lastlog() called on netbsd_x8632::lastlog");
×
3038
    }
3039
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
3040
        panic!("as_linux_arm64aarch64_utmpx() called on netbsd_x8632::lastlog");
×
3041
    }
3042
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
3043
        panic!("as_linux_x86_acct() called on netbsd_x8632::lastlog");
×
3044
    }
3045
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
3046
        panic!("as_linux_x86_acct_v3() called on netbsd_x8632::lastlog");
×
3047
    }
3048
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
3049
        panic!("as_linux_x86_lastlog() called on netbsd_x8632::lastlog");
×
3050
    }
3051
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
3052
        panic!("as_linux_x86_utmpx() called on netbsd_x8632::lastlog");
×
3053
    }
3054
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
9✔
3055
        self
9✔
3056
    }
9✔
3057
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
3058
        panic!("as_netbsd_x8632_lastlogx() called on netbsd_x8632::lastlog");
×
3059
    }
3060
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
3061
        panic!("as_netbsd_x8632_utmpx() called on netbsd_x8632::lastlog");
×
3062
    }
3063
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
3064
        panic!("as_netbsd_x8664_lastlog() called on netbsd_x8632::lastlog");
×
3065
    }
3066
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
3067
        panic!("as_netbsd_x8664_lastlogx() called on netbsd_x8632::lastlog");
×
3068
    }
3069
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
3070
        panic!("as_netbsd_x8664_utmp() called on netbsd_x8632::lastlog");
×
3071
    }
3072
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
3073
        panic!("as_netbsd_x8664_utmpx() called on netbsd_x8632::lastlog");
×
3074
    }
3075
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
3076
        panic!("as_openbsd_x86_lastlog() called on netbsd_x8632::lastlog");
×
3077
    }
3078
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
3079
        panic!("as_openbsd_x86_utmp() called on netbsd_x8632::lastlog");
×
3080
    }
3081
}
3082

3083
impl fmt::Debug for netbsd_x8632::acct {
3084
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
3085
        let ac_utime = self.ac_utime;
2✔
3086
        let ac_stime = self.ac_stime;
2✔
3087
        let ac_etime = self.ac_etime;
2✔
3088
        let ac_btime = self.ac_btime;
2✔
3089
        let ac_uid = self.ac_uid;
2✔
3090
        let ac_gid = self.ac_gid;
2✔
3091
        let ac_mem = self.ac_mem;
2✔
3092
        let ac_io = self.ac_io;
2✔
3093
        let ac_tty = self.ac_tty;
2✔
3094
        let ac_flag = self.ac_flag;
2✔
3095
        f.debug_struct("netbsd_x8632::acct")
2✔
3096
            .field("size", &self.size())
2✔
3097
            .field("ac_comm", &self.ac_comm())
2✔
3098
            .field("ac_utime", &ac_utime)
2✔
3099
            .field("ac_stime", &ac_stime)
2✔
3100
            .field("ac_etime", &ac_etime)
2✔
3101
            .field("ac_btime", &ac_btime)
2✔
3102
            .field("ac_uid", &ac_uid)
2✔
3103
            .field("ac_gid", &ac_gid)
2✔
3104
            .field("ac_mem", &ac_mem)
2✔
3105
            .field("ac_io", &ac_io)
2✔
3106
            .field("ac_tty", &ac_tty)
2✔
3107
            .field("ac_flag", &ac_flag)
2✔
3108
            .finish()
2✔
3109
    }
2✔
3110
}
3111

3112
// netbsd_x8632::lastlogx
3113

3114
impl FixedStructTrait for netbsd_x8632::lastlogx {
3115
    fn fixedstruct_type(&self) -> FixedStructType {
10✔
3116
        FixedStructType::Fs_Netbsd_x8632_Lastlogx
10✔
3117
    }
10✔
3118
    fn size(&self) -> usize {
7✔
3119
        netbsd_x8632::LASTLOGX_SZ
7✔
3120
    }
7✔
3121

3122
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
3123
        panic!("as_freebsd_x8664_utmpx() called on netbsd_x8632::lastlogx");
×
3124
    }
3125
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
3126
        panic!("as_linux_arm64aarch64_lastlog() called on netbsd_x8632::lastlogx");
×
3127
    }
3128
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
3129
        panic!("as_linux_arm64aarch64_utmpx() called on netbsd_x8632::lastlogx");
×
3130
    }
3131
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
3132
        panic!("as_linux_x86_acct() called on netbsd_x8632::lastlogx");
×
3133
    }
3134
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
3135
        panic!("as_linux_x86_acct_v3() called on netbsd_x8632::lastlogx");
×
3136
    }
3137
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
3138
        panic!("as_linux_x86_lastlog() called on netbsd_x8632::lastlogx");
×
3139
    }
3140
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
3141
        panic!("as_linux_x86_utmpx() called on netbsd_x8632::lastlogx");
×
3142
    }
3143
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
3144
        panic!("as_netbsd_x8632_acct() called on netbsd_x8632::lastlogx");
×
3145
    }
3146
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
9✔
3147
        self
9✔
3148
    }
9✔
3149
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
3150
        panic!("as_netbsd_x8632_utmpx() called on netbsd_x8632::lastlogx");
×
3151
    }
3152
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
3153
        panic!("as_netbsd_x8664_lastlog() called on netbsd_x8632::lastlogx");
×
3154
    }
3155
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
3156
        panic!("as_netbsd_x8664_lastlogx() called on netbsd_x8632::lastlogx");
×
3157
    }
3158
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
3159
        panic!("as_netbsd_x8664_utmp() called on netbsd_x8632::lastlogx");
×
3160
    }
3161
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
3162
        panic!("as_netbsd_x8664_utmpx() called on netbsd_x8632::lastlogx");
×
3163
    }
3164
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
3165
        panic!("as_openbsd_x86_lastlog() called on netbsd_x8632::lastlogx");
×
3166
    }
3167
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
3168
        panic!("as_openbsd_x86_utmp() called on netbsd_x8632::lastlogx");
×
3169
    }
3170
}
3171

3172
impl fmt::Debug for netbsd_x8632::lastlogx {
3173
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
3174
        // XXX: copy to local to avoid Issue #82523; #rust-lang/rust/82523
3175
        let tv_sec = self.ll_tv.tv_sec;
2✔
3176
        // XXX: copy to local to avoid Issue #82523; #rust-lang/rust/82523
3177
        let tv_usec = self.ll_tv.tv_usec;
2✔
3178
        f.debug_struct("netbsd_x8632::lastlogx")
2✔
3179
            .field("size", &self.size())
2✔
3180
            .field("ll_tv.tv_sec", &tv_sec)
2✔
3181
            .field("ll_tv.tv_usec", &tv_usec)
2✔
3182
            .field("ll_line", &self.ll_line())
2✔
3183
            .field("ll_host", &self.ll_host())
2✔
3184
            .field("ll_ss", &self.ll_ss)
2✔
3185
            .finish()
2✔
3186
    }
2✔
3187
}
3188

3189
// netbsd_x8632::utmpx
3190

3191
impl FixedStructTrait for netbsd_x8632::utmpx {
3192
    fn fixedstruct_type(&self) -> FixedStructType {
10✔
3193
        FixedStructType::Fs_Netbsd_x8632_Utmpx
10✔
3194
    }
10✔
3195
    fn size(&self) -> usize {
7✔
3196
        netbsd_x8632::UTMPX_SZ
7✔
3197
    }
7✔
3198

3199
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
3200
        panic!("as_freebsd_x8664_utmpx() called on netbsd_x8632::utmpx");
×
3201
    }
3202
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
3203
        panic!("as_linux_arm64aarch64_lastlog() called on netbsd_x8632::utmpx");
×
3204
    }
3205
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
3206
        panic!("as_linux_arm64aarch64_utmpx() called on netbsd_x8632::utmpx");
×
3207
    }
3208
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
3209
        panic!("as_linux_x86_acct() called on netbsd_x8632::utmpx");
×
3210
    }
3211
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
3212
        panic!("as_linux_x86_acct_v3() called on netbsd_x8632::utmpx");
×
3213
    }
3214
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
3215
        panic!("as_linux_x86_lastlog() called on netbsd_x8632::utmpx");
×
3216
    }
3217
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
3218
        panic!("as_linux_x86_utmpx() called on netbsd_x8632::utmpx");
×
3219
    }
3220
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
3221
        panic!("as_netbsd_x8632_acct() called on netbsd_x8632::utmpx");
×
3222
    }
3223
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
3224
        panic!("as_netbsd_x8632_lastlogx() called on netbsd_x8632::utmpx");
×
3225
    }
3226
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
9✔
3227
        self
9✔
3228
    }
9✔
3229
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
3230
        panic!("as_netbsd_x8664_lastlog() called on netbsd_x8632::utmpx");
×
3231
    }
3232
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
3233
        panic!("as_netbsd_x8664_lastlogx() called on netbsd_x8632::utmpx");
×
3234
    }
3235
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
3236
        panic!("as_netbsd_x8664_utmp() called on netbsd_x8632::utmpx");
×
3237
    }
3238
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
3239
        panic!("as_netbsd_x8664_utmpx() called on netbsd_x8632::utmpx");
×
3240
    }
3241
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
3242
        panic!("as_openbsd_x86_lastlog() called on netbsd_x8632::utmpx");
×
3243
    }
3244
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
3245
        panic!("as_openbsd_x86_utmp() called on netbsd_x8632::utmpx");
×
3246
    }
3247
}
3248

3249
impl fmt::Debug for netbsd_x8632::utmpx {
3250
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
3251
        // XXX: copy to local to avoid Issue #82523; #rust-lang/rust/82523
3252
        let tv_sec = self.ut_tv.tv_sec;
2✔
3253
        // XXX: copy to local to avoid Issue #82523; #rust-lang/rust/82523
3254
        let tv_usec = self.ut_tv.tv_usec;
2✔
3255
        f.debug_struct("netbsd_x8632::utmpx")
2✔
3256
            .field("size", &self.size())
2✔
3257
            .field("ut_name", &self.ut_name())
2✔
3258
            .field("ut_id", &self.ut_id())
2✔
3259
            .field("ut_line", &self.ut_line())
2✔
3260
            .field("ut_host", &self.ut_host())
2✔
3261
            .field("ut_session", &self.ut_session)
2✔
3262
            .field("ut_type", &self.ut_type)
2✔
3263
            .field("ut_pid", &self.ut_pid)
2✔
3264
            .field("ut_exit.e_termination", &self.ut_exit.e_termination)
2✔
3265
            .field("ut_exit.e_exit", &self.ut_exit.e_exit)
2✔
3266
            .field("ut_ss", &self.ut_ss)
2✔
3267
            .field("ut_tv.tv_sec", &tv_sec)
2✔
3268
            .field("ut_tv.tv_usec", &tv_usec)
2✔
3269
            .field("ut_pad", &self.ut_pad)
2✔
3270
            .finish()
2✔
3271
    }
2✔
3272
}
3273

3274
// netbsd_x8664::lastlog
3275

3276
impl FixedStructTrait for netbsd_x8664::lastlog {
3277
    fn fixedstruct_type(&self) -> FixedStructType {
2,910✔
3278
        FixedStructType::Fs_Netbsd_x8664_Lastlog
2,910✔
3279
    }
2,910✔
3280
    fn size(&self) -> usize {
1,167✔
3281
        netbsd_x8664::LASTLOG_SZ
1,167✔
3282
    }
1,167✔
3283

3284
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
3285
        panic!("as_freebsd_x8664_utmpx() called on netbsd_x8664::lastlog");
×
3286
    }
3287
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
3288
        panic!("as_linux_arm64aarch64_lastlog() called on netbsd_x8664::lastlog");
×
3289
    }
3290
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
3291
        panic!("as_linux_arm64aarch64_utmpx() called on netbsd_x8664::lastlog");
×
3292
    }
3293
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
3294
        panic!("as_linux_x86_acct() called on netbsd_x8664::lastlog");
×
3295
    }
3296
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
3297
        panic!("as_linux_x86_acct_v3() called on netbsd_x8664::lastlog");
×
3298
    }
3299
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
3300
        panic!("as_linux_x86_lastlog() called on netbsd_x8664::lastlog");
×
3301
    }
3302
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
3303
        panic!("as_linux_x86_utmpx() called on netbsd_x8664::lastlog");
×
3304
    }
3305
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
3306
        panic!("as_netbsd_x8632_acct() called on netbsd_x8664::lastlog");
×
3307
    }
3308
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
3309
        panic!("as_netbsd_x8632_lastlogx() called on netbsd_x8664::lastlog");
×
3310
    }
3311
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
3312
        panic!("as_netbsd_x8632_utmpx() called on netbsd_x8664::lastlog");
×
3313
    }
3314
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
1,169✔
3315
        self
1,169✔
3316
    }
1,169✔
3317
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
3318
        panic!("as_netbsd_x8664_lastlogx() called on netbsd_x8664::lastlog");
×
3319
    }
3320
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
3321
        panic!("as_netbsd_x8664_utmp() called on netbsd_x8664::lastlog");
×
3322
    }
3323
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
3324
        panic!("as_netbsd_x8664_utmpx() called on netbsd_x8664::lastlog");
×
3325
    }
3326
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
3327
        panic!("as_openbsd_x86_lastlog() called on netbsd_x8664::lastlog");
×
3328
    }
3329
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
3330
        panic!("as_openbsd_x86_utmp() called on netbsd_x8664::lastlog");
×
3331
    }
3332
}
3333

3334
impl fmt::Debug for netbsd_x8664::lastlog {
3335
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
3336
        f.debug_struct("netbsd_x8664::lastlog")
2✔
3337
            .field("size", &self.size())
2✔
3338
            .field("ll_time", &self.ll_time)
2✔
3339
            .field("ll_line", &self.ll_line())
2✔
3340
            .field("ll_host", &self.ll_host())
2✔
3341
            .finish()
2✔
3342
    }
2✔
3343
}
3344

3345
// netbsd_x8664::lastlogx
3346

3347
impl FixedStructTrait for netbsd_x8664::lastlogx {
3348
    fn fixedstruct_type(&self) -> FixedStructType {
5✔
3349
        FixedStructType::Fs_Netbsd_x8664_Lastlogx
5✔
3350
    }
5✔
3351
    fn size(&self) -> usize {
5✔
3352
        netbsd_x8664::LASTLOGX_SZ
5✔
3353
    }
5✔
3354

3355
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
3356
        panic!("as_freebsd_x8664_utmpx() called on netbsd_x8664::lastlogx");
×
3357
    }
3358
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
3359
        panic!("as_linux_arm64aarch64_lastlog() called on netbsd_x8664::lastlogx");
×
3360
    }
3361
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
3362
        panic!("as_linux_arm64aarch64_utmpx() called on netbsd_x8664::lastlogx");
×
3363
    }
3364
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
3365
        panic!("as_linux_x86_acct() called on netbsd_x8664::lastlogx");
×
3366
    }
3367
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
3368
        panic!("as_linux_x86_acct_v3() called on netbsd_x8664::lastlogx");
×
3369
    }
3370
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
3371
        panic!("as_linux_x86_lastlog() called on netbsd_x8664::lastlogx");
×
3372
    }
3373
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
3374
        panic!("as_linux_x86_utmpx() called on netbsd_x8664::lastlogx");
×
3375
    }
3376
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
3377
        panic!("as_netbsd_x8632_acct() called on netbsd_x8664::lastlogx");
×
3378
    }
3379
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
3380
        panic!("as_netbsd_x8632_lastlogx() called on netbsd_x8664::lastlogx");
×
3381
    }
3382
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
3383
        panic!("as_netbsd_x8632_utmpx() called on netbsd_x8664::lastlogx");
×
3384
    }
3385
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
3386
        panic!("as_netbsd_x8664_lastlog() called on netbsd_x8664::lastlogx");
×
3387
    }
3388
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
5✔
3389
        self
5✔
3390
    }
5✔
3391
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
3392
        panic!("as_netbsd_x8664_utmp() called on netbsd_x8664::lastlogx");
×
3393
    }
3394
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
3395
        panic!("as_netbsd_x8664_utmpx() called on netbsd_x8664::lastlogx");
×
3396
    }
3397
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
3398
        panic!("as_openbsd_x86_lastlog() called on netbsd_x8664::lastlogx");
×
3399
    }
3400
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
3401
        panic!("as_openbsd_x86_utmp() called on netbsd_x8664::lastlogx");
×
3402
    }
3403
}
3404

3405
impl fmt::Debug for netbsd_x8664::lastlogx {
3406
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1✔
3407
        f.debug_struct("netbsd_x8664::lastlogx")
1✔
3408
            .field("size", &self.size())
1✔
3409
            .field("ll_tv.tv_sec", &self.ll_tv.tv_sec)
1✔
3410
            .field("ll_tv.tv_usec", &self.ll_tv.tv_usec)
1✔
3411
            .field("ll_line", &self.ll_line())
1✔
3412
            .field("ll_host", &self.ll_host())
1✔
3413
            .field("ll_ss", &self.ll_ss)
1✔
3414
            .finish()
1✔
3415
    }
1✔
3416
}
3417

3418
// netbsd_x8664::utmp
3419

3420
impl FixedStructTrait for netbsd_x8664::utmp {
3421
    fn fixedstruct_type(&self) -> FixedStructType {
10✔
3422
        FixedStructType::Fs_Netbsd_x8664_Utmp
10✔
3423
    }
10✔
3424
    fn size(&self) -> usize {
7✔
3425
        netbsd_x8664::UTMP_SZ
7✔
3426
    }
7✔
3427

3428
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
3429
        panic!("as_freebsd_x8664_utmpx() called on netbsd_x8664::utmp");
×
3430
    }
3431
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
3432
        panic!("as_linux_arm64aarch64_lastlog() called on netbsd_x8664::utmp");
×
3433
    }
3434
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
3435
        panic!("as_linux_arm64aarch64_utmpx() called on netbsd_x8664::utmp");
×
3436
    }
3437
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
3438
        panic!("as_linux_x86_acct() called on netbsd_x8664::utmp");
×
3439
    }
3440
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
3441
        panic!("as_linux_x86_acct_v3() called on netbsd_x8664::utmp");
×
3442
    }
3443
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
3444
        panic!("as_linux_x86_lastlog() called on netbsd_x8664::utmp");
×
3445
    }
3446
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
3447
        panic!("as_linux_x86_utmpx() called on netbsd_x8664::utmp");
×
3448
    }
3449
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
3450
        panic!("as_netbsd_x8632_acct() called on netbsd_x8664::utmp");
×
3451
    }
3452
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
3453
        panic!("as_netbsd_x8632_lastlogx() called on netbsd_x8664::utmp");
×
3454
    }
3455
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
3456
        panic!("as_netbsd_x8632_utmpx() called on netbsd_x8664::utmp");
×
3457
    }
3458
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
3459
        panic!("as_netbsd_x8664_lastlog() called on netbsd_x8664::utmp");
×
3460
    }
3461
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
3462
        panic!("as_netbsd_x8664_lastlogx() called on netbsd_x8664::utmp");
×
3463
    }
3464
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
9✔
3465
        self
9✔
3466
    }
9✔
3467
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
3468
        panic!("as_netbsd_x8664_utmpx() called on netbsd_x8664::utmp");
×
3469
    }
3470
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
3471
        panic!("as_openbsd_x86_lastlog() called on netbsd_x8664::utmp");
×
3472
    }
3473
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
3474
        panic!("as_openbsd_x86_utmp() called on netbsd_x8664::utmp");
×
3475
    }
3476
}
3477

3478
impl fmt::Debug for netbsd_x8664::utmp {
3479
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
3480
        f.debug_struct("netbsd_x8664::utmp")
2✔
3481
            .field("size", &self.size())
2✔
3482
            .field("ut_line", &self.ut_line())
2✔
3483
            .field("ut_name", &self.ut_name())
2✔
3484
            .field("ut_host", &self.ut_host())
2✔
3485
            .field("ut_time", &self.ut_time)
2✔
3486
            .finish()
2✔
3487
    }
2✔
3488
}
3489

3490
// netbsd_x8664::utmpx
3491

3492
impl FixedStructTrait for netbsd_x8664::utmpx {
3493
    fn fixedstruct_type(&self) -> FixedStructType {
10✔
3494
        FixedStructType::Fs_Netbsd_x8664_Utmpx
10✔
3495
    }
10✔
3496
    fn size(&self) -> usize {
7✔
3497
        netbsd_x8664::UTMPX_SZ
7✔
3498
    }
7✔
3499

3500
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
3501
        panic!("as_freebsd_x8664_utmpx() called on netbsd_x8664::utmpx");
×
3502
    }
3503
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
3504
        panic!("as_linux_arm64aarch64_lastlog() called on netbsd_x8664::utmpx");
×
3505
    }
3506
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
3507
        panic!("as_linux_arm64aarch64_utmpx() called on netbsd_x8664::utmpx");
×
3508
    }
3509
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
3510
        panic!("as_linux_x86_acct() called on netbsd_x8664::utmpx");
×
3511
    }
3512
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
3513
        panic!("as_linux_x86_acct_v3() called on netbsd_x8664::utmpx");
×
3514
    }
3515
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
3516
        panic!("as_linux_x86_lastlog() called on netbsd_x8664::utmpx");
×
3517
    }
3518
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
3519
        panic!("as_linux_x86_utmpx() called on netbsd_x8664::utmpx");
×
3520
    }
3521
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
3522
        panic!("as_netbsd_x8632_acct() called on netbsd_x8664::utmpx");
×
3523
    }
3524
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
3525
        panic!("as_netbsd_x8632_lastlogx() called on netbsd_x8664::utmpx");
×
3526
    }
3527
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
3528
        panic!("as_netbsd_x8632_utmpx() called on netbsd_x8664::utmpx");
×
3529
    }
3530
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
3531
        panic!("as_netbsd_x8664_lastlog() called on netbsd_x8664::utmpx");
×
3532
    }
3533
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
3534
        panic!("as_netbsd_x8664_lastlogx() called on netbsd_x8664::utmpx");
×
3535
    }
3536
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
3537
        panic!("as_netbsd_x8664_utmp() called on netbsd_x8664::utmpx");
×
3538
    }
3539
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
9✔
3540
        self
9✔
3541
    }
9✔
3542
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
3543
        panic!("as_openbsd_x86_lastlog() called on netbsd_x8664::utmpx");
×
3544
    }
3545
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
3546
        panic!("as_openbsd_x86_utmp() called on netbsd_x8664::utmpx");
×
3547
    }
3548
}
3549

3550
impl fmt::Debug for netbsd_x8664::utmpx {
3551
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
3552
        f.debug_struct("netbsd_x8664::utmpx")
2✔
3553
            .field("size", &self.size())
2✔
3554
            .field("ut_user", &self.ut_user())
2✔
3555
            .field("ut_id", &self.ut_id())
2✔
3556
            .field("ut_line", &self.ut_line())
2✔
3557
            .field("ut_host", &self.ut_host())
2✔
3558
            .field("ut_session", &self.ut_session)
2✔
3559
            .field("ut_type", &self.ut_type)
2✔
3560
            .field("ut_pid", &self.ut_pid)
2✔
3561
            .field("ut_exit.e_termination", &self.ut_exit.e_termination)
2✔
3562
            .field("ut_exit.e_exit", &self.ut_exit.e_exit)
2✔
3563
            .field("ut_tv.tv_sec", &self.ut_tv.tv_sec)
2✔
3564
            .field("ut_tv.tv_usec", &self.ut_tv.tv_usec)
2✔
3565
            .finish()
2✔
3566
    }
2✔
3567
}
3568

3569
// openbsd_x86::lastlog
3570

3571
impl FixedStructTrait for openbsd_x86::lastlog {
3572
    fn fixedstruct_type(&self) -> FixedStructType {
10✔
3573
        FixedStructType::Fs_Openbsd_x86_Lastlog
10✔
3574
    }
10✔
3575
    fn size(&self) -> usize {
7✔
3576
        openbsd_x86::LASTLOG_SZ
7✔
3577
    }
7✔
3578
    
3579
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
3580
        panic!("as_freebsd_x8664_utmpx() called on openbsd_x86::lastlog");
×
3581
    }
3582
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
3583
        panic!("as_linux_arm64aarch64_lastlog() called on openbsd_x86::lastlog");
×
3584
    }
3585
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
3586
        panic!("as_linux_arm64aarch64_utmpx() called on openbsd_x86::lastlog");
×
3587
    }
3588
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
3589
        panic!("as_linux_x86_acct() called on openbsd_x86::lastlog");
×
3590
    }
3591
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
3592
        panic!("as_linux_x86_acct_v3() called on openbsd_x86::lastlog");
×
3593
    }
3594
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
3595
        panic!("as_linux_x86_lastlog() called on openbsd_x86::lastlog");
×
3596
    }
3597
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
3598
        panic!("as_linux_x86_utmpx() called on openbsd_x86::lastlog");
×
3599
    }
3600
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
3601
        panic!("as_netbsd_x8632_acct() called on openbsd_x86::lastlog");
×
3602
    }
3603
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
3604
        panic!("as_netbsd_x8632_lastlogx() called on openbsd_x86::lastlog");
×
3605
    }
3606
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
3607
        panic!("as_netbsd_x8632_utmpx() called on openbsd_x86::lastlog");
×
3608
    }
3609
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
3610
        panic!("as_netbsd_x8664_lastlog() called on openbsd_x86::lastlog");
×
3611
    }
3612
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
3613
        panic!("as_netbsd_x8664_lastlogx() called on openbsd_x86::lastlog");
×
3614
    }
3615
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
3616
        panic!("as_netbsd_x8664_utmp() called on openbsd_x86::lastlog");
×
3617
    }
3618
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
3619
        panic!("as_netbsd_x8664_utmpx() called on openbsd_x86::lastlog");
×
3620
    }
3621
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
9✔
3622
        self
9✔
3623
    }
9✔
3624
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
×
3625
        panic!("as_openbsd_x86_utmp() called on openbsd_x86::lastlog");
×
3626
    }
3627
}
3628

3629
impl fmt::Debug for openbsd_x86::lastlog {
3630
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
3631
        f.debug_struct("openbsd_x86::lastlog")
2✔
3632
            .field("size", &self.size())
2✔
3633
            .field("ll_time", &self.ll_time)
2✔
3634
            .field("ll_line", &self.ll_line())
2✔
3635
            .field("ll_host", &self.ll_host())
2✔
3636
            .finish()
2✔
3637
    }
2✔
3638
}
3639

3640
// openbsd_x86::utmp
3641

3642
impl FixedStructTrait for openbsd_x86::utmp {
3643
    fn fixedstruct_type(&self) -> FixedStructType {
10✔
3644
        FixedStructType::Fs_Openbsd_x86_Utmp
10✔
3645
    }
10✔
3646
    fn size(&self) -> usize {
7✔
3647
        openbsd_x86::UTMP_SZ
7✔
3648
    }
7✔
3649
    
3650
    fn as_freebsd_x8664_utmpx(&self) -> &freebsd_x8664::utmpx {
×
3651
        panic!("as_freebsd_x8664_utmpx() called on openbsd_x86::utmp");
×
3652
    }
3653
    fn as_linux_arm64aarch64_lastlog(&self) -> &linux_arm64aarch64::lastlog {
×
3654
        panic!("as_linux_arm64aarch64_lastlog() called on openbsd_x86::utmp");
×
3655
    }
3656
    fn as_linux_arm64aarch64_utmpx(&self) -> &linux_arm64aarch64::utmpx {
×
3657
        panic!("as_linux_arm64aarch64_utmpx() called on openbsd_x86::utmp");
×
3658
    }
3659
    fn as_linux_x86_acct(&self) -> &linux_x86::acct {
×
3660
        panic!("as_linux_x86_acct() called on openbsd_x86::utmp");
×
3661
    }
3662
    fn as_linux_x86_acct_v3(&self) -> &linux_x86::acct_v3 {
×
3663
        panic!("as_linux_x86_acct_v3() called on openbsd_x86::utmp");
×
3664
    }
3665
    fn as_linux_x86_lastlog(&self) -> &linux_x86::lastlog {
×
3666
        panic!("as_linux_x86_lastlog() called on openbsd_x86::utmp");
×
3667
    }
3668
    fn as_linux_x86_utmpx(&self) -> &linux_x86::utmpx {
×
3669
        panic!("as_linux_x86_utmpx() called on openbsd_x86::utmp");
×
3670
    }
3671
    fn as_netbsd_x8632_acct(&self) -> &netbsd_x8632::acct {
×
3672
        panic!("as_netbsd_x8632_acct() called on openbsd_x86::utmp");
×
3673
    }
3674
    fn as_netbsd_x8632_lastlogx(&self) -> &netbsd_x8632::lastlogx {
×
3675
        panic!("as_netbsd_x8632_lastlogx() called on openbsd_x86::utmp");
×
3676
    }
3677
    fn as_netbsd_x8632_utmpx(&self) -> &netbsd_x8632::utmpx {
×
3678
        panic!("as_netbsd_x8632_utmpx() called on openbsd_x86::utmp");
×
3679
    }
3680
    fn as_netbsd_x8664_lastlog(&self) -> &netbsd_x8664::lastlog {
×
3681
        panic!("as_netbsd_x8664_lastlog() called on openbsd_x86::utmp");
×
3682
    }
3683
    fn as_netbsd_x8664_lastlogx(&self) -> &netbsd_x8664::lastlogx {
×
3684
        panic!("as_netbsd_x8664_lastlogx() called on openbsd_x86::utmp");
×
3685
    }
3686
    fn as_netbsd_x8664_utmp(&self) -> &netbsd_x8664::utmp {
×
3687
        panic!("as_netbsd_x8664_utmp() called on openbsd_x86::utmp");
×
3688
    }
3689
    fn as_netbsd_x8664_utmpx(&self) -> &netbsd_x8664::utmpx {
×
3690
        panic!("as_netbsd_x8664_utmpx() called on openbsd_x86::utmp");
×
3691
    }
3692
    fn as_openbsd_x86_lastlog(&self) -> &openbsd_x86::lastlog {
×
3693
        panic!("as_openbsd_x86_lastlog() called on openbsd_x86::utmp");
×
3694
    }
3695
    fn as_openbsd_x86_utmp(&self) -> &openbsd_x86::utmp {
9✔
3696
        self
9✔
3697
    }
9✔
3698
}
3699

3700
impl fmt::Debug for openbsd_x86::utmp {
3701
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2✔
3702
        f.debug_struct("openbsd_x86::utmp")
2✔
3703
            .field("size", &self.size())
2✔
3704
            .field("ut_line", &self.ut_line())
2✔
3705
            .field("ut_name", &self.ut_name())
2✔
3706
            .field("ut_host", &self.ut_host())
2✔
3707
            .field("ut_time", &self.ut_time)
2✔
3708
            .finish()
2✔
3709
    }
2✔
3710
}
3711

3712
pub (crate) type FixedStructTypeSet = HashMap<FixedStructType, Score>;
3713

3714
/// return all possible [`FixedStructType`] types based on the passed `filesz`.
3715
/// Give a score bonus to matching `FileTypeFixedStruct` types.
3716
pub(crate) fn filesz_to_types(filesz: FileSz, file_type_fixed_struct: &FileTypeFixedStruct)
198✔
3717
    -> Option<FixedStructTypeSet>
198✔
3718
{
3719
    defn!("({:?}, {:?})", filesz, file_type_fixed_struct);
198✔
3720

3721
    if filesz == 0 {
198✔
3722
        defx!("return None; filesz==0");
×
3723
        return None;
×
3724
    }
198✔
3725

3726
    let mut set = FixedStructTypeSet::new();
198✔
3727

3728
    const BONUS: Score = 15;
3729

3730
    // if the given `FileTypeFixedStruct` matches the size offset then
3731
    // it gets a bonus score.
3732
    match file_type_fixed_struct {
198✔
3733
        FileTypeFixedStruct::Acct => {
3734
            if filesz % linux_x86::ACCT_SZ_FO == 0 {
×
3735
                set.insert(FixedStructType::Fs_Linux_x86_Acct, BONUS);
×
3736
            }
×
3737
            if filesz % netbsd_x8632::ACCT_SZ_FO == 0 {
×
3738
                set.insert(FixedStructType::Fs_Netbsd_x8632_Acct, BONUS);
×
3739
            }
×
3740
        }
3741
        FileTypeFixedStruct::AcctV3 => {
3742
            if filesz % linux_x86::ACCT_V3_SZ_FO == 0 {
×
3743
                set.insert(FixedStructType::Fs_Linux_x86_Acct_v3, BONUS);
×
3744
            }
×
3745
        }
3746
        FileTypeFixedStruct::Lastlog => {
3747
            if filesz % linux_arm64aarch64::LASTLOG_SZ_FO == 0 {
2✔
3748
                set.insert(FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog, BONUS);
×
3749
            }
2✔
3750
            if filesz % linux_x86::LASTLOG_SZ_FO == 0 {
2✔
3751
                set.insert(FixedStructType::Fs_Linux_x86_Lastlog, BONUS);
2✔
3752
            }
2✔
3753
            if filesz % netbsd_x8664::LASTLOG_SZ_FO == 0 {
2✔
3754
                set.insert(FixedStructType::Fs_Netbsd_x8664_Lastlog, BONUS);
×
3755
            }
2✔
3756
            if filesz % openbsd_x86::LASTLOG_SZ_FO == 0 {
2✔
3757
                set.insert(FixedStructType::Fs_Openbsd_x86_Lastlog, BONUS);
×
3758
            }
2✔
3759
        }
3760
        FileTypeFixedStruct::Lastlogx => {
3761
            if filesz % netbsd_x8632::LASTLOGX_SZ_FO == 0 {
×
3762
                set.insert(FixedStructType::Fs_Netbsd_x8632_Lastlogx, BONUS);
×
3763
            }
×
3764
        }
3765
        FileTypeFixedStruct::Utmp => {
3766
            if filesz % netbsd_x8664::UTMP_SZ_FO == 0 {
70✔
3767
                set.insert(FixedStructType::Fs_Netbsd_x8664_Utmp, BONUS);
×
3768
            }
70✔
3769
            if filesz % openbsd_x86::UTMP_SZ_FO == 0 {
70✔
3770
                set.insert(FixedStructType::Fs_Openbsd_x86_Utmp, BONUS);
×
3771
            }
70✔
3772
        }
3773
        FileTypeFixedStruct::Utmpx => {
3774
            if filesz % freebsd_x8664::UTMPX_SZ_FO == 0 {
126✔
3775
                set.insert(FixedStructType::Fs_Freebsd_x8664_Utmpx, BONUS);
×
3776
            }
126✔
3777
            if filesz % linux_arm64aarch64::UTMPX_SZ_FO == 0 {
126✔
3778
                set.insert(FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx, BONUS);
×
3779
            }
126✔
3780
            if filesz % linux_x86::UTMPX_SZ_FO == 0 {
126✔
3781
                set.insert(FixedStructType::Fs_Linux_x86_Utmpx, BONUS);
121✔
3782
            }
121✔
3783

3784
            if filesz % netbsd_x8632::UTMPX_SZ_FO == 0 {
126✔
3785
                set.insert(FixedStructType::Fs_Netbsd_x8632_Utmpx, BONUS);
×
3786
            }
126✔
3787
            if filesz % netbsd_x8664::UTMPX_SZ_FO == 0 {
126✔
3788
                set.insert(FixedStructType::Fs_Netbsd_x8664_Utmpx, BONUS);
×
3789
            }
126✔
3790
        }
3791
    }
3792

3793
    // try _all_ types anyway; the file naming varies widely and follows
3794
    // general patterns but is not strict.
3795

3796
    if filesz % freebsd_x8664::UTMPX_SZ_FO == 0 {
198✔
3797
        set.entry(FixedStructType::Fs_Freebsd_x8664_Utmpx).or_insert(0);
×
3798
    }
198✔
3799
    if filesz % linux_arm64aarch64::LASTLOG_SZ_FO == 0 {
198✔
3800
        set.entry(FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog).or_insert(0);
×
3801
    }
198✔
3802
    if filesz % linux_arm64aarch64::UTMPX_SZ_FO == 0 {
198✔
3803
        set.entry(FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx).or_insert(0);
×
3804
    }
198✔
3805
    if filesz % linux_x86::ACCT_SZ_FO == 0 {
198✔
3806
        set.entry(FixedStructType::Fs_Linux_x86_Acct).or_insert(0);
191✔
3807
    }
191✔
3808
    if filesz % linux_x86::ACCT_V3_SZ_FO == 0 {
198✔
3809
        set.entry(FixedStructType::Fs_Linux_x86_Acct_v3).or_insert(0);
191✔
3810
    }
191✔
3811
    if filesz % linux_x86::LASTLOG_SZ_FO == 0 {
198✔
3812
        set.entry(FixedStructType::Fs_Linux_x86_Lastlog).or_insert(0);
7✔
3813
    }
191✔
3814
    if filesz % linux_x86::UTMPX_SZ_FO == 0 {
198✔
3815
        set.entry(FixedStructType::Fs_Linux_x86_Utmpx).or_insert(0);
191✔
3816
    }
191✔
3817
    if filesz % netbsd_x8632::ACCT_SZ_FO == 0 {
198✔
3818
        set.entry(FixedStructType::Fs_Netbsd_x8632_Acct).or_insert(0);
×
3819
    }
198✔
3820
    if filesz % netbsd_x8632::LASTLOGX_SZ_FO == 0 {
198✔
3821
        set.entry(FixedStructType::Fs_Netbsd_x8632_Lastlogx).or_insert(0);
×
3822
    }
198✔
3823
    if filesz % netbsd_x8632::UTMPX_SZ_FO == 0 {
198✔
3824
        set.entry(FixedStructType::Fs_Netbsd_x8632_Utmpx).or_insert(0);
×
3825
    }
198✔
3826
    if filesz % netbsd_x8664::LASTLOG_SZ_FO == 0 {
198✔
3827
        set.entry(FixedStructType::Fs_Netbsd_x8664_Lastlog).or_insert(0);
191✔
3828
    }
191✔
3829
    if filesz % netbsd_x8664::UTMP_SZ_FO == 0 {
198✔
3830
        set.entry(FixedStructType::Fs_Netbsd_x8664_Utmp).or_insert(0);
×
3831
    }
198✔
3832
    if filesz % netbsd_x8664::UTMPX_SZ_FO == 0 {
198✔
3833
        set.entry(FixedStructType::Fs_Netbsd_x8664_Utmpx).or_insert(0);
×
3834
    }
198✔
3835
    if filesz % openbsd_x86::LASTLOG_SZ_FO == 0 {
198✔
3836
        set.entry(FixedStructType::Fs_Openbsd_x86_Lastlog).or_insert(0);
×
3837
    }
198✔
3838
    if filesz % openbsd_x86::UTMP_SZ_FO == 0 {
198✔
3839
        set.entry(FixedStructType::Fs_Openbsd_x86_Utmp).or_insert(0);
×
3840
    }
198✔
3841

3842
    if set.is_empty() {
198✔
3843
        defx!("return None; set.is_empty");
×
3844
        return None;
×
3845
    }
198✔
3846

3847
    defx!("return {} types: {:?}", set.len(), set);
198✔
3848

3849
    Some(set)
198✔
3850
}
198✔
3851

3852
/// An entry for [pointing to a fixed-size C struct] with additional derived
3853
/// information.
3854
///
3855
/// [pointing to a fixed-size C struct]: self::FixedStructTrait
3856
pub struct FixedStruct
3857
{
3858
    /// A pointer to underlying fixed-sized structure entry data.
3859
    pub fixedstructptr: FixedStructDynPtr,
3860
    /// The `fixedstructtype` determines the runtime dispatching of various
3861
    /// methods specific to the fixed-sized structure type.
3862
    pub fixedstructtype: FixedStructType,
3863
    /// `FileTypeFixedStruct` is library-wide type passed in from the caller
3864
    /// It is used as a hint of the originating file.
3865
    pub filetypefixedstruct: FileTypeFixedStruct,
3866
    /// The byte offset into the file where the fixed-sized structure data
3867
    /// begins.
3868
    pub fileoffset: FileOffset,
3869
    /// The derived `DateTimeL` instance using function
3870
    /// [`convert_tvpair_to_datetime`].
3871
    dt: DateTimeL,
3872
    /// The derived tv_pair, equivalent to `dt` but as a `tv_sec` (seconds) and
3873
    /// `tv_usec` (fractional microseconds) pair.
3874
    /// Used early in the `FixedStruct` lifecycle for fast checking of
3875
    /// an entry's datetime without the conversion.
3876
    tv_pair: tv_pair_type,
3877
}
3878

3879
pub fn copy_fixedstructptr(entry: &FixedStructDynPtr) -> FixedStructDynPtr {
×
3880
    match entry.fixedstruct_type() {
×
3881
        FixedStructType::Fs_Freebsd_x8664_Utmpx => {
3882
            Box::new(*entry.as_freebsd_x8664_utmpx())
×
3883
        }
3884
        FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => {
3885
            Box::new(*entry.as_linux_arm64aarch64_lastlog())
×
3886
        }
3887
        FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => {
3888
            Box::new(*entry.as_linux_arm64aarch64_utmpx())
×
3889
        }
3890
        FixedStructType::Fs_Linux_x86_Acct => {
3891
            Box::new(*entry.as_linux_x86_acct())
×
3892
        }
3893
        FixedStructType::Fs_Linux_x86_Acct_v3 => {
3894
            Box::new(*entry.as_linux_x86_acct_v3())
×
3895
        }
3896
        FixedStructType::Fs_Linux_x86_Lastlog => {
3897
            Box::new(*entry.as_linux_x86_lastlog())
×
3898
        }
3899
        FixedStructType::Fs_Linux_x86_Utmpx => {
3900
            Box::new(*entry.as_linux_x86_utmpx())
×
3901
        }
3902
        FixedStructType::Fs_Netbsd_x8632_Acct => {
3903
            Box::new(*entry.as_netbsd_x8632_acct())
×
3904
        }
3905
        FixedStructType::Fs_Netbsd_x8632_Lastlogx => {
3906
            Box::new(*entry.as_netbsd_x8632_lastlogx())
×
3907
        }
3908
        FixedStructType::Fs_Netbsd_x8632_Utmpx => {
3909
            Box::new(*entry.as_netbsd_x8632_utmpx())
×
3910
        }
3911
        FixedStructType::Fs_Netbsd_x8664_Lastlog => {
3912
            Box::new(*entry.as_netbsd_x8664_lastlog())
×
3913
        }
3914
        FixedStructType::Fs_Netbsd_x8664_Lastlogx => {
3915
            Box::new(*entry.as_netbsd_x8664_lastlogx())
×
3916
        }
3917
        FixedStructType::Fs_Netbsd_x8664_Utmp => {
3918
            Box::new(*entry.as_netbsd_x8664_utmp())
×
3919
        }
3920
        FixedStructType::Fs_Netbsd_x8664_Utmpx => {
3921
            Box::new(*entry.as_netbsd_x8664_utmpx())
×
3922
        }
3923
        FixedStructType::Fs_Openbsd_x86_Lastlog => {
3924
            Box::new(*entry.as_openbsd_x86_lastlog())
×
3925
        }
3926
        FixedStructType::Fs_Openbsd_x86_Utmp => {
3927
            Box::new(*entry.as_openbsd_x86_utmp())
×
3928
        }
3929
    }
3930
}
×
3931

3932
impl Clone for FixedStruct {
3933
    /// Manually implemented `clone`.
3934
    ///
3935
    /// Cannot `#[derive(Clone)]` because that requires
3936
    /// trait `Sized` to be `impl` for all fields of `FixedStruct`.
3937
    /// But the `FixedStructTrait` trait is used as a `dyn` trait
3938
    /// object; it is dynamically sized (it is sized at runtime).
3939
    /// So a `FixedStructTrait` cannot `impl`ement `Sized` thus `FixedStruct` cannot
3940
    /// `impl`ement `Sized` thus must manually implement `clone`.
3941
    fn clone(self: &FixedStruct) -> Self {
×
3942
        defñ!("FixedStruct.clone()");
×
3943
        let fixedstructptr = copy_fixedstructptr(&self.fixedstructptr);
×
3944
        FixedStruct {
×
3945
            fixedstructptr,
×
3946
            fixedstructtype: self.fixedstructtype,
×
3947
            filetypefixedstruct: self.filetypefixedstruct,
×
3948
            fileoffset: self.fileoffset,
×
3949
            dt: self.dt,
×
3950
            tv_pair: self.tv_pair,
×
3951
        }
×
3952
    }
×
3953
}
3954

3955
impl fmt::Debug for FixedStruct
3956
{
3957
    fn fmt(
214,516✔
3958
        &self,
214,516✔
3959
        f: &mut fmt::Formatter,
214,516✔
3960
    ) -> fmt::Result {
214,516✔
3961
        f.debug_struct("FixedStruct")
214,516✔
3962
            .field("size", &self.fixedstructptr.size())
214,516✔
3963
            .field("type", &self.fixedstructtype)
214,516✔
3964
            .field("filetype", &self.filetypefixedstruct)
214,516✔
3965
            .field("fileoffset", &self.fileoffset)
214,516✔
3966
            .field("dt", &self.dt)
214,516✔
3967
            .field("tv_pair", &self.tv_pair)
214,516✔
3968
            .finish()
214,516✔
3969
    }
214,516✔
3970
}
3971

3972
/// Index into a `[u8]` buffer. Used by [`as_bytes`].
3973
///
3974
/// [`as_bytes`]: self::FixedStruct::as_bytes
3975
pub type BufIndex = usize;
3976

3977
/// Information returned from [`as_bytes`].
3978
///
3979
/// Variant `Ok` holds
3980
/// - number of bytes copied
3981
/// - start index of datetime substring
3982
/// - end index of datetime substring
3983
///
3984
/// Variant `Fail` holds number of bytes copied
3985
///
3986
/// [`as_bytes`]: self::FixedStruct::as_bytes
3987
pub enum InfoAsBytes {
3988
    Ok(usize, BufIndex, BufIndex),
3989
    Fail(usize),
3990
}
3991

3992
/// Convert `timeval` types [`tv_sec_type`] and [`tv_usec_type`] to a
3993
/// [`DateTimeL`] instance.
3994
///
3995
/// Allow lossy microsecond conversion.
3996
/// Return `Error` if `tv_sec` conversion fails.
3997
pub fn convert_tvpair_to_datetime(
2,313✔
3998
    tv_pair: tv_pair_type,
2,313✔
3999
    tz_offset: &FixedOffset,
2,313✔
4000
) -> Result<DateTimeL, Error>{
2,313✔
4001
    let tv_usec = tv_pair.1;
2,313✔
4002
    // Firstly, convert i64 to i32 for passing to `timestamp_opt`.
4003
    let mut nsec: nsecs_type = match tv_usec.try_into() {
2,313✔
4004
        Ok(val) => val,
2,311✔
4005
        Err(_err) => {
2✔
4006
            de_wrn!("failed to convert tv_usec 0x{:X} to nsecs_type: {}", tv_usec, _err);
2✔
4007
            // ignore overflow and continue; `tv_usec` merely supplements
4008
            // the more coarse `tv_sec`
4009
            0
2✔
4010
        }
4011
    };
4012
    // Secondly, multiply by 1000 to get nanoseconds.
4013
    nsec = match nsec.checked_mul(1000) {
2,313✔
4014
        Some(val) => val,
2,309✔
4015
        None => {
4016
            de_wrn!("failed to multiply nsec 0x{:X} * 1000: overflow", nsec);
4✔
4017
            // ignore overflow and continue; `tv_usec` merely supplements
4018
            // the more coarse `tv_sec`
4019
            0
4✔
4020
        }
4021
    };
4022

4023
    let tv_sec = tv_pair.0;
2,313✔
4024
    defñ!("{:?}.timestamp({}, {})", tz_offset, tv_sec, nsec);
2,313✔
4025
    match tz_offset.timestamp_opt(
2,313✔
4026
        tv_sec, nsec
2,313✔
4027
    ) {
2,313✔
4028
        LocalResult::None => {
4029
            // try again with zero nanoseconds
4030
            match tz_offset.timestamp_opt(tv_sec, 0) {
2✔
4031
                LocalResult::None => {
4032
                    let err_s = format!(
2✔
4033
                        "failed to convert tv_sec 0x{:08X} to DateTime from tz_offset {}",
2✔
4034
                        tv_sec, tz_offset,
4035
                    );
4036
                    de_wrn!("{}", err_s);
2✔
4037

4038
                    Result::Err(
2✔
4039
                        Error::new(
2✔
4040
                            ErrorKind::InvalidData,
2✔
4041
                            err_s,
2✔
4042
                        )
2✔
4043
                    )
2✔
4044
                }
4045
                LocalResult::Single(dt) => Ok(dt),
×
4046
                LocalResult::Ambiguous(dt, _) => Ok(dt),
×
4047
            }
4048
        }
4049
        LocalResult::Single(dt) => Ok(dt),
2,311✔
4050
        // nothing can disambiguate this so just take the first datetime
4051
        LocalResult::Ambiguous(dt, _) => Ok(dt),
×
4052
    }
4053
}
2,313✔
4054

4055
/// Convert [`DateTimeL`] instance to [`tv_sec_type`] and [`tv_usec_type`].
4056
///
4057
/// Return `Error` if `tv_sec` conversion fails.
4058
pub fn convert_datetime_tvpair(
97✔
4059
    dt: &DateTimeL,
97✔
4060
) -> tv_pair_type {
97✔
4061
    let tv_sec: tv_sec_type = dt.timestamp();
97✔
4062
    let tv_usec: tv_usec_type = dt.timestamp_subsec_micros().into();
97✔
4063

4064
    tv_pair_type(tv_sec, tv_usec)
97✔
4065
}
97✔
4066

4067
#[cfg(any(debug_assertions, test))]
4068
fn struct_field_to_string(buffer: &[u8], offset: usize, sz: usize) -> String {
35,028✔
4069
    let mut s = String::with_capacity(sz);
35,028✔
4070
    for b_ in buffer.iter().skip(offset).take(sz) {
536,635✔
4071
        s.push(byte_to_char_noraw(*b_));
536,635✔
4072
    }
536,635✔
4073

4074
    s
35,028✔
4075
}
35,028✔
4076

4077
/// Helper to [`buffer_to_fixedstructptr`]
4078
/// [`deo!`] for the `$field`
4079
#[cfg(any(debug_assertions, test))]
4080
macro_rules! deo_field_dump {
4081
    ($as_fixedstruct:expr, $field: ident, $buffer: ident) => ({{
4082
        let fs = $as_fixedstruct;
4083

4084
        let base_ptr_offset: usize = std::ptr::addr_of!(*fs) as usize;
4085
        let field_ptr = std::ptr::addr_of!(fs.$field);
4086
        let field_offset = field_ptr as usize - base_ptr_offset;
4087
        let field_sz = std::mem::size_of_val(&fs.$field);
4088
        let field_offset_end = field_offset + field_sz;
4089
        let field_val_string = struct_field_to_string($buffer, field_offset, field_sz);
4090
        let field_name = stringify!($field);
4091

4092
        deo!("{:<20}: {:3}‥{:3} @{:p} | {}",
4093
             field_name, field_offset, field_offset_end, field_ptr, field_val_string);
4094
    }})
4095
}
4096

4097
/// Helper to [`buffer_to_fixedstructptr`]
4098
/// [`deo!`] for the `$field`
4099
#[cfg(any(debug_assertions, test))]
4100
macro_rules! deo_field_dump_num {
4101
    ($as_fixedstruct:expr, $field: ident, $buffer: ident, $typ: ty) => ({{
4102
        let fs = $as_fixedstruct;
4103
        let field_sz = std::mem::size_of_val(&fs.$field);
4104
        deo_field_dump_num_impl!(fs, $field, field_sz, $buffer, $typ);
4105
    }})
4106
}
4107

4108
/// Helper to [`buffer_to_fixedstructptr`]
4109
/// [`deo!`] for the `$field`
4110
///
4111
/// Useful for `packed` structs that cannot be referenced in a macro as
4112
/// `size_of_val!(struct.field)` (like in macro [`deo_field_dump_num`]).
4113
#[cfg(any(debug_assertions, test))]
4114
macro_rules! deo_field_dump_num_szof {
4115
    ($as_fixedstruct:expr, $field: ident, $buffer: ident, $typ: ty) => ({{
4116
        let fs = $as_fixedstruct;
4117
        let field_sz = std::mem::size_of::<$typ>();
4118
        deo_field_dump_num_impl!(fs, $field, field_sz, $buffer, $typ);
4119
    }})
4120
}
4121

4122
/// Helper to [`buffer_to_fixedstructptr`]
4123
/// [`deo!`] for the `$field`
4124
#[cfg(any(debug_assertions, test))]
4125
macro_rules! deo_field_dump_num_impl {
4126
    ($as_fixedstruct:expr, $field: ident, $field_sz: expr, $buffer: ident, $typ: ty) => ({{
4127
        let fs = $as_fixedstruct;
4128

4129
        let base_ptr_offset: usize = std::ptr::addr_of!(*fs) as usize;
4130
        let field_ptr = std::ptr::addr_of!(fs.$field);
4131
        let field_offset = field_ptr as usize - base_ptr_offset;
4132
        let field_offset_end = field_offset + $field_sz;
4133
        let field_val_string = struct_field_to_string($buffer, field_offset, $field_sz);
4134
        let field_name = stringify!($field);
4135
        let value: $typ = fs.$field;
4136

4137
        deo!("{:<20}: {:3}‥{:3} @{:p} | {:<20} 0x{:08X}",
4138
             field_name, field_offset, field_offset_end, field_ptr,
4139
             field_val_string, value);
4140
    }})
4141
}
4142

4143
/// Convert `[u8]` bytes to a [`FixedStructDynPtr`] instance specified by
4144
/// `fixedstructtype`.
4145
///
4146
/// A `buffer` of only null bytes (zero values) will return `None`.
4147
/// A `buffer` of only 0xFF bytes will return `None`.
4148
///
4149
/// unsafe.
4150
pub fn buffer_to_fixedstructptr(buffer: &[u8], fixedstructtype: FixedStructType) -> Option<FixedStructDynPtr>
4,057✔
4151
{
4152
    defn!("(buffer len {:?}, fixedstructtype {:?})", buffer.len(), fixedstructtype);
4,057✔
4153

4154
    let sz: usize = fixedstructtype.size();
4,057✔
4155
    if buffer.len() < sz {
4,057✔
4156
        if cfg!(debug_assertions) && ! cfg!(test)
1✔
4157
        {
4158
            debug_panic!(
×
4159
                "buffer to small; {} bytes but fixedstruct type {:?} is {} bytes",
×
4160
                buffer.len(), fixedstructtype, sz,
×
4161
            );
4162
        }
1✔
4163
        defx!("return None");
1✔
4164
        return None;
1✔
4165
    }
4,056✔
4166
    let slice_ = &buffer[..sz];
4,056✔
4167
    // check for all zero bytes
4168
    if slice_.iter().all(|&x| x == 0) {
65,459✔
4169
        defx!("buffer[0‥{}] is all 0x00 bytes; return None", slice_.len());
1,038✔
4170
        return None;
1,038✔
4171
    }
3,018✔
4172
    // check for all 0xFF bytes
4173
    if slice_.iter().all(|&x| x == 0xFF) {
8,700✔
4174
        defx!("buffer[0‥{}] is all 0xFF bytes; return None", slice_.len());
78✔
4175
        return None;
78✔
4176
    }
2,940✔
4177
    #[cfg(debug_assertions)]
4178
    {
4179
        // print buffer bytes to the console
4180
        const LEN: usize = 16;
4181
        defo!("\nbuffer[‥{}] ({} bytes per line)\n[", sz, LEN);
2,940✔
4182
        let _lock = si_trace_print::printers::GLOBAL_LOCK_PRINTER.lock().unwrap();
2,940✔
4183
        for (i, b_) in slice_.iter().enumerate().take(sz) {
547,560✔
4184
            eprint!("{:?}, ", *b_ as char);
547,560✔
4185
            if i != 0 && i % LEN == 0 {
547,560✔
4186
                eprintln!();
31,301✔
4187
            }
516,259✔
4188
        }
4189
        eprintln!("\n]");
2,940✔
4190
        for (i, b_) in slice_.iter().enumerate().take(sz) {
547,560✔
4191
            eprint!("{}", byte_to_char_noraw(*b_));
547,560✔
4192
            if i != 0 && i % LEN == 0 {
547,560✔
4193
                eprintln!();
31,301✔
4194
            }
516,259✔
4195
        }
4196
        eprintln!();
2,940✔
4197
    }
4198
    let entry: FixedStructDynPtr = match fixedstructtype {
2,940✔
4199
        FixedStructType::Fs_Freebsd_x8664_Utmpx => {
4200
            unsafe {
4✔
4201
                Box::new(
4✔
4202
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<freebsd_x8664::utmpx>())
4✔
4203
                )
4✔
4204
            }
4✔
4205
        }
4206
        FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => {
4207
            unsafe {
4208
                Box::new(
3✔
4209
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<linux_arm64aarch64::lastlog>())
3✔
4210
                )
3✔
4211
            }
4212
        }
4213
        FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => {
4214
            unsafe {
4215
                Box::new(
3✔
4216
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<linux_arm64aarch64::utmpx>())
3✔
4217
                )
3✔
4218
            }
4219
        }
4220
        FixedStructType::Fs_Linux_x86_Acct => {
4221
            unsafe {
4222
                Box::new(
583✔
4223
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<linux_x86::acct>())
583✔
4224
                )
583✔
4225
            }
4226
        }
4227
        FixedStructType::Fs_Linux_x86_Acct_v3 => {
4228
            unsafe {
4229
                Box::new(
583✔
4230
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<linux_x86::acct_v3>())
583✔
4231
                )
583✔
4232
            }
4233
        }
4234
        FixedStructType::Fs_Linux_x86_Lastlog => {
4235
            unsafe {
4236
                Box::new(
10✔
4237
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<linux_x86::lastlog>())
10✔
4238
                )
10✔
4239
            }
4240
        }
4241
        FixedStructType::Fs_Linux_x86_Utmpx => {
4242
            unsafe {
4243
                Box::new(
1,147✔
4244
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<linux_x86::utmpx>())
1,147✔
4245
                )
1,147✔
4246
            }
4247
        }
4248
        FixedStructType::Fs_Netbsd_x8632_Acct => {
4249
            unsafe {
4250
                Box::new(
3✔
4251
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<netbsd_x8632::acct>())
3✔
4252
                )
3✔
4253
            }
4254
        }
4255
        FixedStructType::Fs_Netbsd_x8632_Lastlogx => {
4256
            unsafe {
4257
                Box::new(
3✔
4258
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<netbsd_x8632::lastlogx>())
3✔
4259
                )
3✔
4260
            }
4261
        }
4262
        FixedStructType::Fs_Netbsd_x8632_Utmpx => {
4263
            unsafe {
4264
                Box::new(
3✔
4265
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<netbsd_x8632::utmpx>())
3✔
4266
                )
3✔
4267
            }
4268
        }
4269
        FixedStructType::Fs_Netbsd_x8664_Lastlog => {
4270
            unsafe {
4271
                Box::new(
583✔
4272
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<netbsd_x8664::lastlog>())
583✔
4273
                )
583✔
4274
            }
4275
        }
4276
        FixedStructType::Fs_Netbsd_x8664_Lastlogx => {
4277
            unsafe {
4278
                Box::new(
3✔
4279
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<netbsd_x8664::lastlogx>())
3✔
4280
                )
3✔
4281
            }
4282
        }
4283
        FixedStructType::Fs_Netbsd_x8664_Utmp => {
4284
            unsafe {
4285
                Box::new(
3✔
4286
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<netbsd_x8664::utmp>())
3✔
4287
                )
3✔
4288
            }
4289
        }
4290
        FixedStructType::Fs_Netbsd_x8664_Utmpx => {
4291
            unsafe {
4292
                Box::new(
3✔
4293
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<netbsd_x8664::utmpx>())
3✔
4294
                )
3✔
4295
            }
4296
        }
4297
        FixedStructType::Fs_Openbsd_x86_Lastlog => {
4298
            unsafe {
4299
                Box::new(
3✔
4300
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<openbsd_x86::lastlog>())
3✔
4301
                )
3✔
4302
            }
4303
        }
4304
        FixedStructType::Fs_Openbsd_x86_Utmp => {
4305
            unsafe {
4306
                Box::new(
3✔
4307
                    std::ptr::read_unaligned(slice_.as_ptr().cast::<openbsd_x86::utmp>())
3✔
4308
                )
3✔
4309
            }
4310
        }
4311
    };
4312

4313
    #[cfg(any(debug_assertions, test))]
4314
    match fixedstructtype {
2,940✔
4315
        // print struct member offsets and bytes
4316
        // `addr_of!` used here due to unaligned references being a warning:
4317
        // credit https://stackoverflow.com/a/26271748/471376
4318
        FixedStructType::Fs_Freebsd_x8664_Utmpx => {
4✔
4319
            let utmpx: &freebsd_x8664::utmpx = entry.as_freebsd_x8664_utmpx();
4✔
4320

4✔
4321
            deo!("freebsd_x8664::utmpx offsets and bytes, size {}", utmpx.size());
4✔
4322
            deo_field_dump_num!(utmpx, ut_type, buffer, freebsd_x8664::c_short);
4✔
4323
            deo_field_dump!(utmpx, ut_tv, buffer);
4✔
4324
            deo_field_dump!(utmpx, ut_id, buffer);
4✔
4325
            deo_field_dump_num!(utmpx, ut_pid, buffer, freebsd_x8664::pid_t);
4✔
4326
            deo_field_dump!(utmpx, ut_user, buffer);
4✔
4327
            deo_field_dump!(utmpx, ut_line, buffer);
4✔
4328
            deo_field_dump!(utmpx, ut_host, buffer);
4✔
4329
            deo_field_dump!(utmpx, __ut_spare, buffer);
4✔
4330
        }
4✔
4331
        FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => {
3✔
4332
            let lastlog: &linux_arm64aarch64::lastlog = entry.as_linux_arm64aarch64_lastlog();
3✔
4333

3✔
4334
            deo!("linux_arm64aarch64::lastlog offsets and bytes, size {}", lastlog.size());
3✔
4335
            deo_field_dump_num!(lastlog, ll_time, buffer, linux_arm64aarch64::ll_time_t);
3✔
4336
            deo_field_dump!(lastlog, ll_line, buffer);
3✔
4337
            deo_field_dump!(lastlog, ll_host, buffer);
3✔
4338
        }
3✔
4339
        FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => {
3✔
4340
            let utmpx: &linux_arm64aarch64::utmpx = entry.as_linux_arm64aarch64_utmpx();
3✔
4341

3✔
4342
            deo!("linux_arm64aarch64::utmpx offsets and bytes, size {}", utmpx.size());
3✔
4343
            deo_field_dump_num!(utmpx, ut_type, buffer, linux_arm64aarch64::c_short);
3✔
4344
            deo_field_dump_num!(utmpx, ut_pid, buffer, linux_arm64aarch64::pid_t);
3✔
4345
            deo_field_dump!(utmpx, ut_line, buffer);
3✔
4346
            deo_field_dump!(utmpx, ut_id, buffer);
3✔
4347
            deo_field_dump!(utmpx, ut_user, buffer);
3✔
4348
            deo_field_dump!(utmpx, ut_host, buffer);
3✔
4349
            deo_field_dump_num!(utmpx, ut_exit, buffer, i32);
3✔
4350
            deo_field_dump_num!(utmpx, ut_session, buffer, i64);
3✔
4351
            deo_field_dump!(utmpx, ut_tv, buffer);
3✔
4352
            deo_field_dump!(utmpx, ut_addr_v6, buffer);
3✔
4353
            deo_field_dump!(utmpx, __glibc_reserved, buffer);
3✔
4354
        }
3✔
4355
        FixedStructType::Fs_Linux_x86_Acct => {
583✔
4356
            let acct: &linux_x86::acct = entry.as_linux_x86_acct();
583✔
4357

583✔
4358
            deo!("linux_x86::acct offsets and bytes, size {}", acct.size());
583✔
4359
            deo_field_dump_num!(acct, ac_flag, buffer, linux_x86::c_char);
583✔
4360
            deo_field_dump_num!(acct, ac_uid, buffer, u16);
583✔
4361
            deo_field_dump_num!(acct, ac_gid, buffer, u16);
583✔
4362
            deo_field_dump_num!(acct, ac_tty, buffer, u16);
583✔
4363
            deo_field_dump_num!(acct, ac_btime, buffer, linux_x86::b_time_t);
583✔
4364
            deo_field_dump_num!(acct, ac_utime, buffer, linux_x86::comp_t);
583✔
4365
            deo_field_dump_num!(acct, ac_stime, buffer, linux_x86::comp_t);
583✔
4366
            deo_field_dump_num!(acct, ac_etime, buffer, linux_x86::comp_t);
583✔
4367
            deo_field_dump_num!(acct, ac_mem, buffer, linux_x86::comp_t);
583✔
4368
            deo_field_dump_num!(acct, ac_io, buffer, linux_x86::comp_t);
583✔
4369
            deo_field_dump_num!(acct, ac_rw, buffer, linux_x86::comp_t);
583✔
4370
            deo_field_dump_num!(acct, ac_minflt, buffer, linux_x86::comp_t);
583✔
4371
            deo_field_dump_num!(acct, ac_majflt, buffer, linux_x86::comp_t);
583✔
4372
            deo_field_dump_num!(acct, ac_swaps, buffer, linux_x86::comp_t);
583✔
4373
            deo_field_dump_num!(acct, ac_exitcode, buffer, u32);
583✔
4374
            deo_field_dump!(acct, ac_comm, buffer);
583✔
4375
        }
583✔
4376
        FixedStructType::Fs_Linux_x86_Acct_v3 => {
583✔
4377
            let acct: &linux_x86::acct_v3 = entry.as_linux_x86_acct_v3();
583✔
4378

583✔
4379
            deo!("linux_x86::acct_v3 offsets and bytes, size {}", acct.size());
583✔
4380
            deo_field_dump_num!(acct, ac_flag, buffer, linux_x86::c_char);
583✔
4381
            deo_field_dump_num!(acct, ac_version, buffer, linux_x86::c_char);
583✔
4382
            deo_field_dump_num!(acct, ac_tty, buffer, u16);
583✔
4383
            deo_field_dump_num!(acct, ac_exitcode, buffer, u32);
583✔
4384
            deo_field_dump_num!(acct, ac_uid, buffer, u32);
583✔
4385
            deo_field_dump_num!(acct, ac_gid, buffer, u32);
583✔
4386
            deo_field_dump_num!(acct, ac_pid, buffer, u32);
583✔
4387
            deo_field_dump_num!(acct, ac_ppid, buffer, u32);
583✔
4388
            deo_field_dump_num!(acct, ac_btime, buffer, linux_x86::b_time_t);
583✔
4389
            deo_field_dump!(acct, ac_etime, buffer);
583✔
4390
            deo_field_dump_num!(acct, ac_utime, buffer, linux_x86::comp_t);
583✔
4391
            deo_field_dump_num!(acct, ac_stime, buffer, linux_x86::comp_t);
583✔
4392
            deo_field_dump_num!(acct, ac_mem, buffer, linux_x86::comp_t);
583✔
4393
            deo_field_dump_num!(acct, ac_io, buffer, linux_x86::comp_t);
583✔
4394
            deo_field_dump_num!(acct, ac_rw, buffer, linux_x86::comp_t);
583✔
4395
            deo_field_dump_num!(acct, ac_minflt, buffer, linux_x86::comp_t);
583✔
4396
            deo_field_dump_num!(acct, ac_majflt, buffer, linux_x86::comp_t);
583✔
4397
            deo_field_dump_num!(acct, ac_swaps, buffer, linux_x86::comp_t);
583✔
4398
            deo_field_dump!(acct, ac_comm, buffer);
583✔
4399
        }
583✔
4400
        FixedStructType::Fs_Linux_x86_Lastlog => {
10✔
4401
            let lastlog: &linux_x86::lastlog = entry.as_linux_x86_lastlog();
10✔
4402

10✔
4403
            deo!("linux_x86::lastlog offsets and bytes, size {}", lastlog.size());
10✔
4404
            deo_field_dump_num!(lastlog, ll_time, buffer, linux_x86::ll_time_t);
10✔
4405
            deo_field_dump!(lastlog, ll_line, buffer);
10✔
4406
            deo_field_dump!(lastlog, ll_host, buffer);
10✔
4407
        }
10✔
4408
        FixedStructType::Fs_Linux_x86_Utmpx => {
1,147✔
4409
            let utmpx: &linux_x86::utmpx = entry.as_linux_x86_utmpx();
1,147✔
4410

1,147✔
4411
            deo!("linux_x86::utmpx offsets and bytes, size {}", utmpx.size());
1,147✔
4412
            deo_field_dump_num!(utmpx, ut_type, buffer, linux_x86::c_short);
1,147✔
4413
            deo_field_dump_num!(utmpx, ut_pid, buffer, linux_x86::pid_t);
1,147✔
4414
            deo_field_dump!(utmpx, ut_line, buffer);
1,147✔
4415
            deo_field_dump!(utmpx, ut_id, buffer);
1,147✔
4416
            deo_field_dump!(utmpx, ut_user, buffer);
1,147✔
4417
            deo_field_dump!(utmpx, ut_host, buffer);
1,147✔
4418
            deo_field_dump!(utmpx, ut_exit, buffer);
1,147✔
4419
            deo_field_dump_num!(utmpx, ut_session, buffer, i32);
1,147✔
4420
            deo_field_dump!(utmpx, ut_tv, buffer);
1,147✔
4421
            deo_field_dump!(utmpx, ut_addr_v6, buffer);
1,147✔
4422
            deo_field_dump!(utmpx, __glibc_reserved, buffer);
1,147✔
4423
        }
1,147✔
4424
        FixedStructType::Fs_Netbsd_x8632_Acct => {
3✔
4425
            let acct: &netbsd_x8632::acct = entry.as_netbsd_x8632_acct();
3✔
4426

3✔
4427
            deo!("netbsd_x8664::acct offsets and bytes, size {}", acct.size());
3✔
4428
            deo_field_dump!(acct, ac_comm, buffer);
3✔
4429
            deo_field_dump_num_szof!(acct, ac_utime, buffer, netbsd_x8632::comp_t);
3✔
4430
            deo_field_dump_num_szof!(acct, ac_stime, buffer, netbsd_x8632::comp_t);
3✔
4431
            deo_field_dump_num_szof!(acct, ac_etime, buffer, netbsd_x8632::comp_t);
3✔
4432
            deo_field_dump_num_szof!(acct, ac_btime, buffer, netbsd_x8632::time_t);
3✔
4433
            deo_field_dump_num_szof!(acct, ac_uid, buffer, netbsd_x8632::uid_t);
3✔
4434
            deo_field_dump_num_szof!(acct, ac_gid, buffer, netbsd_x8632::gid_t);
3✔
4435
            deo_field_dump_num_szof!(acct, ac_mem, buffer, netbsd_x8632::comp_t);
3✔
4436
            deo_field_dump_num_szof!(acct, ac_io, buffer, netbsd_x8632::comp_t);
3✔
4437
            deo_field_dump_num_szof!(acct, ac_tty, buffer, netbsd_x8632::dev_t);
3✔
4438
            deo_field_dump_num_szof!(acct, ac_flag, buffer, netbsd_x8632::uint8_t);
3✔
4439
        }
3✔
4440
        FixedStructType::Fs_Netbsd_x8632_Lastlogx => {
3✔
4441
            let lastlogx: &netbsd_x8632::lastlogx = entry.as_netbsd_x8632_lastlogx();
3✔
4442

3✔
4443
            deo!("netbsd_x8632::lastlogx offsets and bytes, size {}", lastlogx.size());
3✔
4444
            deo_field_dump!(lastlogx, ll_tv, buffer);
3✔
4445
            deo_field_dump!(lastlogx, ll_line, buffer);
3✔
4446
            deo_field_dump!(lastlogx, ll_host, buffer);
3✔
4447
            deo_field_dump!(lastlogx, ll_ss, buffer);
3✔
4448
        }
3✔
4449
        FixedStructType::Fs_Netbsd_x8632_Utmpx => {
3✔
4450
            let utmpx: &netbsd_x8632::utmpx = entry.as_netbsd_x8632_utmpx();
3✔
4451

3✔
4452
            deo!("netbsd_x8632::utmpx offsets and bytes, size {}", utmpx.size());
3✔
4453
            deo_field_dump!(utmpx, ut_name, buffer);
3✔
4454
            deo_field_dump!(utmpx, ut_id, buffer);
3✔
4455
            deo_field_dump!(utmpx, ut_line, buffer);
3✔
4456
            deo_field_dump!(utmpx, ut_host, buffer);
3✔
4457
            deo_field_dump_num!(utmpx, ut_session, buffer, netbsd_x8632::uint16_t);
3✔
4458
            deo_field_dump_num!(utmpx, ut_type, buffer, netbsd_x8632::uint16_t);
3✔
4459
            deo_field_dump_num!(utmpx, ut_pid, buffer, netbsd_x8632::pid_t);
3✔
4460
            deo_field_dump!(utmpx, ut_exit, buffer);
3✔
4461
            deo_field_dump!(utmpx, ut_ss, buffer);
3✔
4462
            deo_field_dump!(utmpx, ut_tv, buffer);
3✔
4463
            deo_field_dump!(utmpx, ut_pad, buffer);
3✔
4464
        }
3✔
4465
        FixedStructType::Fs_Netbsd_x8664_Lastlog => {
583✔
4466
            let lastlog: &netbsd_x8664::lastlog = entry.as_netbsd_x8664_lastlog();
583✔
4467

583✔
4468
            deo!("netbsd_x8664::lastlog offsets and bytes, size {}", lastlog.size());
583✔
4469
            deo_field_dump_num!(lastlog, ll_time, buffer, netbsd_x8664::time_t);
583✔
4470
            deo_field_dump!(lastlog, ll_line, buffer);
583✔
4471
            deo_field_dump!(lastlog, ll_host, buffer);
583✔
4472
        }
583✔
4473
        FixedStructType::Fs_Netbsd_x8664_Lastlogx => {
3✔
4474
            let lastlogx: &netbsd_x8664::lastlogx = entry.as_netbsd_x8664_lastlogx();
3✔
4475

3✔
4476
            deo!("netbsd_x8664::lastlogx offsets and bytes, size {}", lastlogx.size());
3✔
4477
            deo_field_dump!(lastlogx, ll_tv, buffer);
3✔
4478
            deo_field_dump!(lastlogx, ll_line, buffer);
3✔
4479
            deo_field_dump!(lastlogx, ll_host, buffer);
3✔
4480
            deo_field_dump!(lastlogx, ll_ss, buffer);
3✔
4481
        }
3✔
4482
        FixedStructType::Fs_Netbsd_x8664_Utmp => {
3✔
4483
            let utmp: &netbsd_x8664::utmp = entry.as_netbsd_x8664_utmp();
3✔
4484

3✔
4485
            deo!("netbsd_x8664::utmp offsets and bytes, size {}", utmp.size());
3✔
4486
            deo_field_dump!(utmp, ut_line, buffer);
3✔
4487
            deo_field_dump!(utmp, ut_name, buffer);
3✔
4488
            deo_field_dump!(utmp, ut_host, buffer);
3✔
4489
            deo_field_dump_num!(utmp, ut_time, buffer, netbsd_x8664::time_t);
3✔
4490
        }
3✔
4491
        FixedStructType::Fs_Netbsd_x8664_Utmpx => {
3✔
4492
            let utmpx: &netbsd_x8664::utmpx = entry.as_netbsd_x8664_utmpx();
3✔
4493

3✔
4494
            deo!("netbsd_x8664::utmpx offsets and bytes, size {}", utmpx.size());
3✔
4495
            deo_field_dump!(utmpx, ut_user, buffer);
3✔
4496
            deo_field_dump!(utmpx, ut_id, buffer);
3✔
4497
            deo_field_dump!(utmpx, ut_line, buffer);
3✔
4498
            deo_field_dump!(utmpx, ut_host, buffer);
3✔
4499
            deo_field_dump_num!(utmpx, ut_session, buffer, netbsd_x8664::uint16_t);
3✔
4500
            deo_field_dump_num!(utmpx, ut_type, buffer, netbsd_x8664::uint16_t);
3✔
4501
            deo_field_dump_num!(utmpx, ut_pid, buffer, netbsd_x8664::pid_t);
3✔
4502
            deo_field_dump!(utmpx, ut_exit, buffer);
3✔
4503
            deo_field_dump!(utmpx, ut_tv, buffer);
3✔
4504
            deo_field_dump!(utmpx, ut_pad, buffer);
3✔
4505
        }
3✔
4506
        FixedStructType::Fs_Openbsd_x86_Lastlog => {
3✔
4507
            let lastlog: &openbsd_x86::lastlog = entry.as_openbsd_x86_lastlog();
3✔
4508

3✔
4509
            deo!("openbsd_x86::lastlog offsets and bytes, size {}", lastlog.size());
3✔
4510
            deo_field_dump_num!(lastlog, ll_time, buffer, openbsd_x86::time_t);
3✔
4511
            deo_field_dump!(lastlog, ll_line, buffer);
3✔
4512
            deo_field_dump!(lastlog, ll_host, buffer);
3✔
4513
        }
3✔
4514
        FixedStructType::Fs_Openbsd_x86_Utmp => {
3✔
4515
            let utmp: &openbsd_x86::utmp = entry.as_openbsd_x86_utmp();
3✔
4516

3✔
4517
            deo!("openbsd_x86::utmp offsets and bytes, size {}", utmp.size());
3✔
4518
            deo_field_dump!(utmp, ut_line, buffer);
3✔
4519
            deo_field_dump!(utmp, ut_name, buffer);
3✔
4520
            deo_field_dump!(utmp, ut_host, buffer);
3✔
4521
            deo_field_dump_num!(utmp, ut_time, buffer, openbsd_x86::time_t);
3✔
4522
        }
3✔
4523
    }
4524
    defx!("return entry with fixedstruct_type {:?}",
2,940✔
4525
          entry.fixedstruct_type());
2,940✔
4526

4527
    Some(entry)
2,940✔
4528
}
4,057✔
4529

4530
/// Helper to [`FixedStruct::as_bytes`].
4531
/// Write a byte `b` that is `u8` to the `buffer` at index `at`
4532
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4533
macro_rules! set_buffer_at_or_err_u8 {
4534
    ($buffer:ident, $at:ident, $b:expr) => ({{
4535
        if $at >= $buffer.len() {
4536
            return InfoAsBytes::Fail($at);
4537
        }
4538
        $buffer[$at] = $b;
4539
        $at += 1;
4540
    }})
4541
}
4542

4543
/// Helper to [`FixedStruct::as_bytes`].
4544
/// Write a byte `b` that is `i8` to the `buffer` at index `at`
4545
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4546
macro_rules! set_buffer_at_or_err_i8 {
4547
    ($buffer:ident, $at:ident, $c:expr) => ({{
4548
        let c_: u8 = match ($c).try_into() {
4549
            Ok(val) => val,
4550
            Err(_) => 0,
4551
        };
4552
        set_buffer_at_or_err_u8!($buffer, $at, c_);
4553
    }})
4554
}
4555

4556
/// Helper to [`FixedStruct::as_bytes`].
4557
/// Write a byte `b` that is `&[u8]` to the `buffer` at index `at`
4558
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4559
macro_rules! set_buffer_at_or_err_u8_array {
4560
    ($buffer:ident, $at:ident, $b:expr) => ({{
4561
        for b_ in $b.iter() {
4562
            set_buffer_at_or_err_u8!($buffer, $at, *b_);
4563
        }
4564
    }})
4565
}
4566

4567
/// Helper to [`FixedStruct::as_bytes`].
4568
/// Write a `str_` to the `buffer` starting `at` the given index.
4569
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4570
macro_rules! set_buffer_at_or_err_str {
4571
    ($buffer:ident, $at:ident, $str_:expr) => ({{
4572
        for b_ in $str_.bytes() {
4573
            set_buffer_at_or_err_u8!($buffer, $at, b_);
4574
        }
4575
    }})
4576
}
4577

4578
/// Helper to [`FixedStruct::as_bytes`].
4579
/// Write a `string_` to the `buffer` starting `at` the given index.
4580
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4581
macro_rules! set_buffer_at_or_err_string {
4582
    ($buffer:ident, $at:ident, $string_:expr) => ({{
4583
        for b_ in $string_.as_bytes() {
4584
            set_buffer_at_or_err_u8!($buffer, $at, *b_);
4585
        }
4586
    }})
4587
}
4588

4589
/// Helper to [`FixedStruct::as_bytes`].
4590
/// Write a `cstr` that may be missing ending '\0' to the `buffer` starting at
4591
/// the given index `at` up to `cstr_len` bytes.
4592
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4593
macro_rules! set_buffer_at_or_err_cstrn {
4594
    ($buffer:ident, $at:ident, $cstr:expr) => ({{
4595
        let cstr_sz = std::mem::size_of_val(& $cstr);
4596
        for (i, b_) in $cstr.iter().enumerate() {
4597
            if b_ == &0 || i == cstr_sz {
4598
                break;
4599
            }
4600
            set_buffer_at_or_err_i8!($buffer, $at, *b_);
4601
        }
4602
    }})
4603
}
4604

4605
/// Helper to [`FixedStruct::as_bytes`].
4606
/// Write the `ut_type` that is `i16` to the `buffer` at index`at`.
4607
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4608
macro_rules! set_buffer_at_or_err_ut_type {
4609
    ($buffer:ident, $at:ident, $ut_type:expr, $type_:ty, $len:ident) => ({{
4610
        #[allow(non_camel_case_types)]
4611
        {
4612
            // sanity check passed number type is 2 bytes or less so `buffer_num` is enough
4613
            assertcp!(std::mem::size_of::<$type_>() <= 2);
4614
        }
4615
        let mut buffer_num = [0u8; 8];
4616
        match &$ut_type {
4617
            n if &0 <= n && n < &$len => {
4618
                set_buffer_at_or_err_str!($buffer, $at, UT_TYPE_VAL_TO_STR[*n as usize]);
4619
            }
4620
            n_ => {
4621
                let num = n_.numtoa(10, &mut buffer_num);
4622
                set_buffer_at_or_err_u8_array!($buffer, $at, num);
4623
            },
4624
        }
4625
    }})
4626
}
4627

4628
/// Helper to [`FixedStruct::as_bytes`].
4629
/// Write the `ut_type` that is `i16` to the `buffer` at index`at`.
4630
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4631
macro_rules! set_buffer_at_or_err_ut_type_i16 {
4632
    ($buffer:ident, $at:ident, $ut_type:expr) => ({{
4633
        set_buffer_at_or_err_ut_type!($buffer, $at, $ut_type, i16, UT_TYPE_VAL_TO_STR_LEN_i16)
4634
    }})
4635
}
4636

4637
/// Helper to [`FixedStruct::as_bytes`].
4638
/// Write the `ut_type` that is `u16` to the `buffer` at index `at`.
4639
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4640
macro_rules! set_buffer_at_or_err_ut_type_u16 {
4641
    ($buffer:ident, $at:ident, $ut_type:expr) => ({{
4642
        set_buffer_at_or_err_ut_type!($buffer, $at, $ut_type, u16, UT_TYPE_VAL_TO_STR_LEN_u16)
4643
    }})
4644
}
4645

4646
/// Helper to [`FixedStruct::as_bytes`].
4647
/// Write the `number` value of type `$type_` into `buffer` at index `at`.
4648
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4649
macro_rules! set_buffer_at_or_err_number {
4650
    ($buffer:ident, $at:ident, $number:expr, $type_:ty) => ({{
4651
        #[allow(non_camel_case_types)]
4652
        {
4653
            // sanity check passed number type is 8 bytes or less so `buffer_num` is enough
4654
            assertcp!(std::mem::size_of::<$type_>() <= 8);
4655
        }
4656
        let mut buffer_num = [0u8; 22];
4657
        // XXX: copy to local variable to avoid packed warning
4658
        let num_val = $number;
4659
        let num = num_val.numtoa(10, &mut buffer_num);
4660
        set_buffer_at_or_err_u8_array!($buffer, $at, num);
4661
    }})
4662
}
4663

4664
/// Helper to [`FixedStruct::as_bytes`].
4665
/// Write the `number` value of type `i64` into `buffer` at index `at`.
4666
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4667
macro_rules! set_buffer_at_or_err_number_f32 {
4668
    ($buffer:ident, $at:ident, $number:expr, $type_:ty) => ({{
4669
        // XXX: copy to local variable to avoid packed warning
4670
        let num = $number;
4671
        let number_string = format!("{}", num);
4672
        set_buffer_at_or_err_string!($buffer, $at, number_string);
4673
    }})
4674
}
4675

4676
/// Helper to [`FixedStruct::as_bytes`].
4677
/// Write the `number` value of type `i64` into `buffer` at index `at`.
4678
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4679
macro_rules! set_buffer_at_or_err_number_bin4 {
4680
    ($buffer:ident, $at:ident, $number:expr, $type_:ty) => ({{
4681
        let number_string = format!("0b{:04b}", $number);
4682
        set_buffer_at_or_err_string!($buffer, $at, number_string);
4683
    }})
4684
}
4685

4686
/// Helper to [`FixedStruct::as_bytes`].
4687
/// Write the `number`that is an IPv4 address into `buffer` at index `at`.
4688
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4689
macro_rules! set_buffer_at_or_err_ipv4 {
4690
    ($buffer:ident, $at:ident, $value:expr) => ({{
4691
        // separate each octet of the IPv4 address
4692
        let o0: u8 = (($value >> 24) & 0xFF) as u8;
4693
        let o1: u8 = (($value >> 16) & 0xFF) as u8;
4694
        let o2: u8 = (($value >> 8) & 0xFF) as u8;
4695
        let o3: u8 = ($value & 0xFF) as u8;
4696
        // write each octet to the buffer
4697
        for (i, b_) in (&[o3, o2, o1, o0]).iter().enumerate() {
4698
            set_buffer_at_or_err_number!($buffer, $at, *b_, u8);
4699
            if i != 3 {
4700
                set_buffer_at_or_err_u8!($buffer, $at, b'.');
4701
            }
4702
        }
4703
    }})
4704
}
4705

4706
/// Helper to [`FixedStruct::as_bytes`].
4707
/// Write the `number`that is an IPv6 address into `buffer` at index `at`.
4708
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4709
macro_rules! set_buffer_at_or_err_ipv6 {
4710
    ($buffer:ident, $at:ident, $value:expr) => ({{
4711
        for b_ in format!("{:X}:{:X}:{:X}:{:X}",
4712
            &$value[0],
4713
            &$value[1],
4714
            &$value[2],
4715
            &$value[3],
4716
        ).as_str().bytes() {
4717
            set_buffer_at_or_err_u8!($buffer, $at, b_);
4718
        }
4719
    }})
4720
}
4721

4722
/// Helper to [`FixedStruct::from_fixedstructptr`]
4723
macro_rules! tv_or_err_tv_sec {
4724
    ($fixedstructptr: ident, $tv_sec: expr) => ({{
4725
        match $tv_sec.try_into() {
4726
            Ok(val) => val,
4727
            Err(err) => {
4728
                let err_str = format!(
4729
                    "{} failed to convert tv_sec {:?}; {}",
4730
                    stringify!($tv_sec), $tv_sec, err
4731
                );
4732
                de_err!("{}", err_str);
4733
                defx!("return Err {}", err);
4734
                return Result::Err(
4735
                    Error::new(ErrorKind::InvalidData, err_str)
4736
                );
4737
            }
4738
        }
4739
    }})
4740
}
4741

4742
/// Helper to [`FixedStruct::from_fixedstructptr`]
4743
macro_rules! tv_to_datetime_or_err {
4744
    ($tv_sec: ident, $tv_usec: ident, $tz_offset: ident) => ({{
4745
        match convert_tvpair_to_datetime(tv_pair_type($tv_sec, $tv_usec), $tz_offset) {
4746
            Ok(dt) => dt,
4747
            Err(err) => {
4748
                // `convert_tvpair_to_datetime` should have already debug printed an error
4749
                // so don't `de_err!` here
4750
                defx!("return Err {}", err);
4751
                return Result::Err(err);
4752
            }
4753
        }
4754
    }})
4755
}
4756

4757
/// Helper to [`FixedStruct::score_fixedstruct`]
4758
/// Increase score if the buffer appears to be a valid C string (has
4759
/// typical ASCII characters found in such strings).
4760
macro_rules! score_fixedstruct_cstr {
4761
    ($score:ident, $cstr:expr) => {{
4762
        let cstr_: &CStr = $cstr;
4763
        if !cstr_.is_empty() {
4764
            $score += 1;
4765
            for c in cstr_.to_bytes().iter() {
4766
                match c {
4767
                    // all visible ASCII characters <128
4768
                    &(b' '..=b'~') => $score += 2,
4769
                    // 0xFF is very likely bad data
4770
                    0xFF => $score -= 5,
4771
                    _ => $score -= 3,
4772
                }
4773
            }
4774
        }
4775
        defo!(
4776
            "score_fixedstruct_cstr ({}): score={}",
4777
            stringify!($cstr), $score
4778
        );
4779
    }};
4780
}
4781

4782
/// Helper to [`FixedStruct::score_fixedstruct`]
4783
/// Decrease score if bytes after the first null byte are not null.
4784
/// Non-null bytes after the first null byte mean the field is not a C string.
4785
macro_rules! score_fixedstruct_cstr_no_data_after_null {
4786
    ($score:ident, $buffer:expr) => {{
4787
        let mut found_null: bool = false;
4788
        for b in $buffer.iter() {
4789
            if *b == 0 {
4790
                found_null = true;
4791
                continue;
4792
            }
4793
            if !found_null {
4794
                continue;
4795
            }
4796
            match b {
4797
                // there is a non-null byte after the prior null bytes
4798
                _ if *b != 0 => $score -= 5,
4799
                _ => {}
4800
            }
4801
        }
4802
        defo!(
4803
            "score_fixedstruct_cstr_no_data_after_null ({}): score={}",
4804
            stringify!($buffer), $score
4805
        );
4806
    }};
4807
}
4808

4809
/// Helper to [`FixedStruct::score_fixedstruct`]
4810
/// Increase score if the last byte of the buffer is null.
4811
/// Decrease score if the last byte of the buffer is not null.
4812
macro_rules! score_fixedstruct_cstr_null_terminator {
4813
    ($score:ident, $buffer:expr) => {{
4814
        if let Some(b) = $buffer.iter().nth($buffer.len() - 1) {
4815
            if *b == 0 {
4816
                $score += 10;
4817
            } else {
4818
                $score -= 10;
4819
            }
4820
        }
4821
        defo!(
4822
            "score_fixedstruct_cstr_null_terminator ({}): score={}",
4823
            stringify!($buffer), $score
4824
        );
4825
    }};
4826
}
4827

4828
/// Helper to [`FixedStruct::score_fixedstruct`]
4829
/// Increase score if all bytes are null.
4830
/// Decrease score if any bytes are not null.
4831
macro_rules! score_fixedstruct_buffer_all_null {
4832
    ($score:ident, $buffer:expr) => {{
4833
        let mut all_zero: bool = true;
4834
        if let Some(b) = $buffer.iter().nth($buffer.len() - 1) {
4835
            if *b != 0 {
4836
                $score -= 4;
4837
                all_zero = false;
4838
            }
4839
        }
4840
        if all_zero && $buffer.len() > 0 {
4841
            $score += 10;
4842
        }
4843
        defo!(
4844
            "score_fixedstruct_buffer_all_null ({}): score={}",
4845
            stringify!($buffer), $score
4846
        );
4847
    }};
4848
}
4849

4850
/// Helper to [`FixedStruct::score_fixedstruct`]
4851
/// Increase score if the value is not zero.
4852
/// Decrease score if the value is zero.
4853
macro_rules! score_fixedstruct_value_not_zero {
4854
    ($score:ident, $value:expr) => {{
4855
        if $value != 0 {
4856
            $score += 10;
4857
        } else {
4858
            $score -= 10;
4859
        }
4860
        defo!(
4861
            "score_fixedstruct_value_not_zero ({}): score={}",
4862
            stringify!($value), $score
4863
        );
4864
    }};
4865
}
4866

4867
/// Helper to [`FixedStruct::score_fixedstruct`]
4868
/// Increase score if the ut_type is a valid value.
4869
/// Decrease score if the ut_type is a invalid value.
4870
macro_rules! score_fixedstruct_ut_type {
4871
    ($score:ident, $value:expr, $ut_types:expr) => {{
4872
        for ut_type in $ut_types {
4873
            if $value == ut_type {
4874
                $score += 5;
4875
                if $value != 0 {
4876
                    $score += 10;
4877
                }
4878
                break;
4879
            }
4880
        }
4881
        defo!(
4882
            "score_fixedstruct_ut_type ({}): score={}",
4883
            stringify!($value), $score
4884
        );
4885
    }};
4886
}
4887

4888
/// Helper to [`FixedStruct::score_fixedstruct`]
4889
/// Increase score if the bits are valid flag(s).
4890
/// Decrease score if the bits are invalid flag(s).
4891
macro_rules! score_fixedstruct_ac_flags {
4892
    ($score:ident, $value:expr, $flags:expr) => {{
4893
        if $value == 0 {
4894
            $score += 2;
4895
        } else if (!$flags) & $value != 0 {
4896
            $score -= 30;
4897
        } else {
4898
            $score += 5;
4899
        }
4900
        defo!(
4901
            "score_fixedstruct_ac_flags ({}): score={} (value=0b{:08b}, flags=0b{:08b})",
4902
            stringify!($value), $score, $value, $flags
4903
        );
4904
    }};
4905
}
4906

4907
/// Datetime _2000-01-01 00:00:00_ is a reasonable past datetime to expect for
4908
/// FixedStruct files.
4909
/// Helper to [`score_fixedstruct_time_range`].
4910
///
4911
/// **TODO:** when were utmp/lastlog/etc. structs first introduced?
4912
const EPOCH_SECOND_LOW: tv_sec_type = 946684800;
4913

4914
/// Datetime _2038-01-19 03:14:06_ is a reasonable high datetime to expect for
4915
/// FixedStruct files.
4916
/// Helper to [`score_fixedstruct_time_range`].
4917
const EPOCH_SECOND_HIGH: tv_sec_type = 2147483647;
4918

4919
/// Helper to [`FixedStruct::score_fixedstruct`].
4920
/// Increase the score if the datetime (presumed to be Unix Epoch seconds)
4921
/// is within a reasonable range. Decrease if it's outside of that range.
4922
/// Decrease the score further if the value is zero.
4923
macro_rules! score_fixedstruct_time_range {
4924
    ($score:ident, $value:expr) => {{
4925
        // XXX: copy to local to avoid warning about alignment
4926
        let val = $value;
4927
        let value_as: tv_sec_type = match val.try_into() {
4928
            Ok(val_) => val_,
4929
            Err(_err) => {
4930
                de_err!("failed to convert {:?} to tv_sec_type; {}", val, _err);
4931

4932
                0
4933
            }
4934
        };
4935
        if (EPOCH_SECOND_LOW..=EPOCH_SECOND_HIGH).contains(&value_as) {
4936
            $score += 20;
4937
        } else {
4938
            $score -= 30;
4939
        }
4940
        if value_as == 0 {
4941
            $score -= 40;
4942
        }
4943
        defo!(
4944
            "score_fixedstruct_time_range ({}): score={}",
4945
            stringify!($value), $score
4946
        );
4947
    }};
4948
}
4949

4950
impl FixedStruct
4951
{
4952
    /// Create a new `FixedStruct`.
4953
    /// The `buffer` is passed to [`buffer_to_fixedstructptr`] which returns
4954
    /// `None` if only null bytes.
4955
    pub fn new(
582✔
4956
        fileoffset: FileOffset,
582✔
4957
        tz_offset: &FixedOffset,
582✔
4958
        buffer: &[u8],
582✔
4959
        fixedstruct_type: FixedStructType,
582✔
4960
    ) -> Result<FixedStruct, Error>
582✔
4961
    {
4962
        defn!();
582✔
4963
        let fs_ptr: FixedStructDynPtr = match buffer_to_fixedstructptr(buffer, fixedstruct_type) {
582✔
4964
            Some(val) => val,
580✔
4965
            None => {
4966
                defx!("buffer_to_fixedstructptr returned None; return None");
2✔
4967
                return Result::Err(
2✔
4968
                    Error::new(
2✔
4969
                        ErrorKind::InvalidData,
2✔
4970
                        "buffer_to_fixedstructptr returned None",
2✔
4971
                    )
2✔
4972
                );
2✔
4973
            }
4974
        };
4975
        defo!("fs_ptr {:?}", fs_ptr);
580✔
4976

4977
        FixedStruct::from_fixedstructptr(fileoffset, tz_offset, fs_ptr)
580✔
4978
    }
582✔
4979

4980
    /// Create a new `FixedStruct` from a `FixedStructDynPtr`.
4981
    pub fn from_fixedstructptr(
1,131✔
4982
        fileoffset: FileOffset,
1,131✔
4983
        tz_offset: &FixedOffset,
1,131✔
4984
        fixedstructptr: FixedStructDynPtr,
1,131✔
4985
    ) -> Result<FixedStruct, Error>
1,131✔
4986
    {
4987
        defn!("fixedstructptr {:?}", fixedstructptr);
1,131✔
4988
        let tv_sec: tv_sec_type;
4989
        let tv_usec: tv_usec_type;
4990
        let fixedstructtype: FixedStructType = fixedstructptr.fixedstruct_type();
1,131✔
4991
        let filetypefixedstruct: FileTypeFixedStruct;
4992
        match fixedstructtype {
1,131✔
4993
            FixedStructType::Fs_Freebsd_x8664_Utmpx => {
1✔
4994
                filetypefixedstruct = FileTypeFixedStruct::Utmpx;
1✔
4995
                let fixedstructptr: &freebsd_x8664::utmpx = fixedstructptr.as_freebsd_x8664_utmpx();
1✔
4996
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ut_tv.tv_sec);
1✔
4997
                tv_usec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ut_tv.tv_usec);
1✔
4998
            }
1✔
4999
            FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => {
1✔
5000
                filetypefixedstruct = FileTypeFixedStruct::Lastlog;
1✔
5001
                let fixedstructptr: &linux_arm64aarch64::lastlog = fixedstructptr.as_linux_arm64aarch64_lastlog();
1✔
5002
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ll_time);
1✔
5003
                tv_usec = 0;
1✔
5004
            }
1✔
5005
            FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => {
1✔
5006
                filetypefixedstruct = FileTypeFixedStruct::Utmpx;
1✔
5007
                let fixedstructptr: &linux_arm64aarch64::utmpx = fixedstructptr.as_linux_arm64aarch64_utmpx();
1✔
5008
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ut_tv.tv_sec);
1✔
5009
                tv_usec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ut_tv.tv_usec);
1✔
5010
            }
1✔
5011
            FixedStructType::Fs_Linux_x86_Acct => {
1✔
5012
                filetypefixedstruct = FileTypeFixedStruct::Acct;
1✔
5013
                let fixedstructptr: &linux_x86::acct = fixedstructptr.as_linux_x86_acct();
1✔
5014
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ac_btime);
1✔
5015
                tv_usec = 0;
1✔
5016
            }
1✔
5017
            FixedStructType::Fs_Linux_x86_Acct_v3 => {
1✔
5018
                filetypefixedstruct = FileTypeFixedStruct::AcctV3;
1✔
5019
                let fixedstructptr: &linux_x86::acct_v3 = fixedstructptr.as_linux_x86_acct_v3();
1✔
5020
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ac_btime);
1✔
5021
                tv_usec = 0;
1✔
5022
            }
1✔
5023
            FixedStructType::Fs_Linux_x86_Lastlog => {
8✔
5024
                filetypefixedstruct = FileTypeFixedStruct::Lastlog;
8✔
5025
                let fixedstructptr: &linux_x86::lastlog = fixedstructptr.as_linux_x86_lastlog();
8✔
5026
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ll_time);
8✔
5027
                tv_usec = 0;
8✔
5028
            }
8✔
5029
            FixedStructType::Fs_Linux_x86_Utmpx => {
1,110✔
5030
                filetypefixedstruct = FileTypeFixedStruct::Utmpx;
1,110✔
5031
                let fixedstructptr: &linux_x86::utmpx = fixedstructptr.as_linux_x86_utmpx();
1,110✔
5032
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ut_tv.tv_sec);
1,110✔
5033
                tv_usec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ut_tv.tv_usec);
1,110✔
5034
            }
1,110✔
5035
            FixedStructType::Fs_Netbsd_x8632_Acct => {
1✔
5036
                filetypefixedstruct = FileTypeFixedStruct::Acct;
1✔
5037
                let fixedstructptr: &netbsd_x8632::acct = fixedstructptr.as_netbsd_x8632_acct();
1✔
5038
                let ac_btime = fixedstructptr.ac_btime;
1✔
5039
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, ac_btime);
1✔
5040
                tv_usec = 0;
1✔
5041
            }
1✔
5042
            FixedStructType::Fs_Netbsd_x8632_Lastlogx => {
1✔
5043
                filetypefixedstruct = FileTypeFixedStruct::Lastlogx;
1✔
5044
                let fixedstructptr: &netbsd_x8632::lastlogx = fixedstructptr.as_netbsd_x8632_lastlogx();
1✔
5045
                // XXX: copy to local to avoid Issue #82523; #rust-lang/rust/82523
1✔
5046
                let tv_sec_ = fixedstructptr.ll_tv.tv_sec;
1✔
5047
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, tv_sec_);
1✔
5048
                // XXX: copy to local to avoid Issue #82523; #rust-lang/rust/82523
1✔
5049
                let tv_usec_ = fixedstructptr.ll_tv.tv_usec;
1✔
5050
                tv_usec = tv_or_err_tv_sec!(fixedstructptr,  tv_usec_);
1✔
5051
            }
1✔
5052
            FixedStructType::Fs_Netbsd_x8632_Utmpx => {
1✔
5053
                filetypefixedstruct = FileTypeFixedStruct::Utmpx;
1✔
5054
                let fixedstructptr: &netbsd_x8632::utmpx = fixedstructptr.as_netbsd_x8632_utmpx();
1✔
5055
                // XXX: copy to local to avoid Issue #82523; #rust-lang/rust/82523
1✔
5056
                let tv_sec_ = fixedstructptr.ut_tv.tv_sec;
1✔
5057
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, tv_sec_);
1✔
5058
                // XXX: copy to local to avoid Issue #82523; #rust-lang/rust/82523
1✔
5059
                let tv_usec_ = fixedstructptr.ut_tv.tv_usec;
1✔
5060
                tv_usec = tv_or_err_tv_sec!(fixedstructptr, tv_usec_);
1✔
5061
            }
1✔
5062
            FixedStructType::Fs_Netbsd_x8664_Lastlog => {
1✔
5063
                filetypefixedstruct = FileTypeFixedStruct::Lastlog;
1✔
5064
                let fixedstructptr: &netbsd_x8664::lastlog = fixedstructptr.as_netbsd_x8664_lastlog();
1✔
5065
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ll_time);
1✔
5066
                tv_usec = 0;
1✔
5067
            }
1✔
5068
            FixedStructType::Fs_Netbsd_x8664_Lastlogx => {
×
5069
                filetypefixedstruct = FileTypeFixedStruct::Lastlogx;
×
5070
                let fixedstructptr: &netbsd_x8664::lastlogx = fixedstructptr.as_netbsd_x8664_lastlogx();
×
5071
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ll_tv.tv_sec);
×
5072
                tv_usec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ll_tv.tv_usec);
×
5073
            }
×
5074
            FixedStructType::Fs_Netbsd_x8664_Utmp => {
1✔
5075
                filetypefixedstruct = FileTypeFixedStruct::Utmp;
1✔
5076
                let fixedstructptr: &netbsd_x8664::utmp = fixedstructptr.as_netbsd_x8664_utmp();
1✔
5077
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ut_time);
1✔
5078
                tv_usec = 0;
1✔
5079
            }
1✔
5080
            FixedStructType::Fs_Netbsd_x8664_Utmpx => {
1✔
5081
                filetypefixedstruct = FileTypeFixedStruct::Utmpx;
1✔
5082
                let fixedstructptr: &netbsd_x8664::utmpx = fixedstructptr.as_netbsd_x8664_utmpx();
1✔
5083
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ut_tv.tv_sec);
1✔
5084
                tv_usec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ut_tv.tv_usec);
1✔
5085
            }
1✔
5086
            FixedStructType::Fs_Openbsd_x86_Lastlog => {
1✔
5087
                filetypefixedstruct = FileTypeFixedStruct::Lastlog;
1✔
5088
                let fixedstructptr: &openbsd_x86::lastlog = fixedstructptr.as_openbsd_x86_lastlog();
1✔
5089
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ll_time);
1✔
5090
                tv_usec = 0;
1✔
5091
            }
1✔
5092
            FixedStructType::Fs_Openbsd_x86_Utmp => {
1✔
5093
                filetypefixedstruct = FileTypeFixedStruct::Utmp;
1✔
5094
                let fixedstructptr: &openbsd_x86::utmp = fixedstructptr.as_openbsd_x86_utmp();
1✔
5095
                tv_sec = tv_or_err_tv_sec!(fixedstructptr, fixedstructptr.ut_time);
1✔
5096
                tv_usec = 0;
1✔
5097
            }
1✔
5098
        }
5099
        let dt: DateTimeL = tv_to_datetime_or_err!(tv_sec, tv_usec, tz_offset);
1,131✔
5100
        defo!("FixedStruct {{ dt {:?} }}", dt);
1,131✔
5101
        let tv_pair: tv_pair_type = tv_pair_type(tv_sec, tv_usec);
1,131✔
5102
        defx!("FixedStruct {{ tv_pair {:?} }}", tv_pair);
1,131✔
5103
        Result::Ok(
1,131✔
5104
            FixedStruct {
1,131✔
5105
                fixedstructptr,
1,131✔
5106
                fixedstructtype,
1,131✔
5107
                filetypefixedstruct,
1,131✔
5108
                fileoffset,
1,131✔
5109
                dt,
1,131✔
5110
                tv_pair,
1,131✔
5111
            }
1,131✔
5112
        )
1,131✔
5113
    }
1,131✔
5114

5115
    pub fn len(self: &FixedStruct) -> usize
4,003✔
5116
    {
5117
        self.fixedstructptr.size()
4,003✔
5118
    }
4,003✔
5119

5120
    /// Clippy recommends `fn is_empty` since there is a `len()`.
5121
    pub fn is_empty(self: &FixedStruct) -> bool
×
5122
    {
5123
        self.len() == 0
×
5124
    }
×
5125

5126
    /// [`FileOffset`] at beginning of the `FixedStruct` (inclusive).
5127
    ///
5128
    /// [`FileOffset`]: crate::common::FileOffset
5129
    pub const fn fileoffset_begin(self: &FixedStruct) -> FileOffset
5,150✔
5130
    {
5131
        self.fileoffset
5,150✔
5132
    }
5,150✔
5133

5134
    /// [`FileOffset`] at one byte past ending of the `FixedStruct` (exclusive).
5135
    ///
5136
    /// [`FileOffset`]: crate::common::FileOffset
5137
    pub fn fileoffset_end(self: &FixedStruct) -> FileOffset
4,003✔
5138
    {
5139
        self.fileoffset + (self.len() as FileOffset)
4,003✔
5140
    }
4,003✔
5141

5142
    /// First [`BlockOffset`] of underlying [`Block`s] for the given
5143
    /// [`BlockSz`].
5144
    ///
5145
    /// [`BlockOffset`]: crate::readers::blockreader::BlockOffset
5146
    /// [`Block`s]: crate::readers::blockreader::Block
5147
    /// [`BlockSz`]: crate::readers::blockreader::BlockSz
5148
    pub const fn blockoffset_begin(&self, blocksz: BlockSz) -> BlockOffset {
2,067✔
5149
        BlockReader::block_offset_at_file_offset(
2,067✔
5150
            self.fileoffset_begin(),
2,067✔
5151
            blocksz
2,067✔
5152
        )
5153
    }
2,067✔
5154

5155
    /// Last [`BlockOffset`] of underlying [`Block`s] for the given
5156
    /// [`BlockSz`] (inclusive).
5157
    ///
5158
    /// [`BlockOffset`s]: crate::readers::blockreader::BlockOffset
5159
    /// [`Block`s]: crate::readers::blockreader::Block
5160
    /// [`BlockSz`]: crate::readers::blockreader::BlockSz
5161
    pub fn blockoffset_end(&self, blocksz: BlockSz) -> BlockOffset {
2,067✔
5162
        BlockReader::block_offset_at_file_offset(
2,067✔
5163
            self.fileoffset_end(),
2,067✔
5164
            blocksz
2,067✔
5165
        )
5166
    }
2,067✔
5167

5168
    /// Return a reference to [`self.dt`].
5169
    ///
5170
    /// [`self.dt`]: FixedStruct::dt
5171
    pub const fn dt(self: &FixedStruct) -> &DateTimeL
75,671✔
5172
    {
5173
        &self.dt
75,671✔
5174
    }
75,671✔
5175

5176
    /// Return a reference to [`self.tv_pair`].
5177
    ///
5178
    /// [`self.tv_pair`]: FixedStruct::tv_pair
5179
    pub const fn tv_pair(self: &FixedStruct) -> &tv_pair_type
1✔
5180
    {
5181
        &self.tv_pair
1✔
5182
    }
1✔
5183

5184
    /// Create a score for this FixedStruct entry
5185
    ///
5186
    /// The scoring system is a simple heuristic to determine the likelihood that
5187
    /// the FixedStruct entry is a valid version of the given `FixedStructType`.
5188
    /// The particulars of the score are just a guess; they seemed to work well in limited
5189
    /// testing.
5190
    ///
5191
    /// Scoring is necessary because a file's exact fixedstruct type often
5192
    /// cannot be determined from the name and file size alone.
5193
    ///
5194
    /// This function is used by [`FixedStructReader::score_file`].
5195
    ///
5196
    /// [`FixedStructReader::score_file`]: crate::readers::fixedstructreader::FixedStructReader::score_file
5197
    // XXX: I considered also checking for matching platform. However, the platforms
5198
    //      embedded in each namespace, e.g. `linux_x86`, may be the same for many
5199
    //      platforms, e.g. `linux_x86` may be used for both 32-bit and 64-bit x86, and on various
5200
    //      ARM and RISC architectures.
5201
    pub fn score_fixedstruct(fixedstructptr: &FixedStructDynPtr, bonus: Score) -> Score {
2,343✔
5202
        defn!();
2,343✔
5203
        defo!("fixedstructptr.entry_type() = {:?}", fixedstructptr.fixedstruct_type());
2,343✔
5204
        defo!("fixedstructptr.size() = {:?}", fixedstructptr.size());
2,343✔
5205
        let mut score: Score = 0;
2,343✔
5206
        defo!("score = {:?}", score);
2,343✔
5207
        if bonus > 0 {
2,343✔
5208
            score += bonus;
217✔
5209
            defo!("score += bonus {:?}", score);
217✔
5210
        }
2,126✔
5211
        match fixedstructptr.fixedstruct_type() {
2,343✔
5212
            FixedStructType::Fs_Freebsd_x8664_Utmpx => {
5213
                let utmpx: &freebsd_x8664::utmpx = fixedstructptr.as_freebsd_x8664_utmpx();
3✔
5214
                score_fixedstruct_cstr!(score, utmpx.ut_user());
3✔
5215
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_user);
3✔
5216
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_user);
3✔
5217

5218
                score_fixedstruct_cstr!(score, utmpx.ut_line());
3✔
5219
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_line);
3✔
5220

5221
                score_fixedstruct_cstr!(score, utmpx.ut_host());
3✔
5222
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_host);
3✔
5223
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_host);
3✔
5224

5225
                score_fixedstruct_time_range!(score, utmpx.ut_tv.tv_sec);
3✔
5226

5227
                score_fixedstruct_buffer_all_null!(score, utmpx.__ut_spare);
3✔
5228

5229
                score_fixedstruct_ut_type!(score, utmpx.ut_type, freebsd_x8664::UT_TYPES);
12✔
5230
            }
5231
            FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => {
5232
                let lastlog: &linux_arm64aarch64::lastlog = fixedstructptr.as_linux_arm64aarch64_lastlog();
2✔
5233

5234
                score_fixedstruct_cstr!(score, lastlog.ll_line());
2✔
5235
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_line);
2✔
5236

5237
                score_fixedstruct_cstr!(score, lastlog.ll_host());
2✔
5238
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_host);
2✔
5239
                score_fixedstruct_cstr_null_terminator!(score, lastlog.ll_host);
2✔
5240

5241
                score_fixedstruct_time_range!(score, lastlog.ll_time);
2✔
5242
            }
5243
            FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => {
5244
                let utmpx: &linux_arm64aarch64::utmpx = fixedstructptr.as_linux_arm64aarch64_utmpx();
2✔
5245

5246
                score_fixedstruct_cstr!(score, utmpx.ut_line());
2✔
5247
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_line);
2✔
5248

5249
                score_fixedstruct_cstr!(score, utmpx.ut_user());
2✔
5250
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_user);
2✔
5251

5252
                score_fixedstruct_cstr!(score, utmpx.ut_host());
2✔
5253
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_host);
2✔
5254
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_host);
2✔
5255

5256
                score_fixedstruct_time_range!(score, utmpx.ut_tv.tv_sec);
2✔
5257

5258
                score_fixedstruct_buffer_all_null!(score, utmpx.__glibc_reserved);
2✔
5259

5260
                score_fixedstruct_ut_type!(score, utmpx.ut_type, linux_arm64aarch64::UT_TYPES);
6✔
5261
            }
5262
            FixedStructType::Fs_Linux_x86_Acct => {
5263
                let acct: &linux_x86::acct = fixedstructptr.as_linux_x86_acct();
582✔
5264

5265
                score_fixedstruct_cstr!(score, acct.ac_comm());
582✔
5266
                score_fixedstruct_cstr_no_data_after_null!(score, acct.ac_comm);
582✔
5267

5268
                score_fixedstruct_time_range!(score, acct.ac_btime);
582✔
5269

5270
                score_fixedstruct_buffer_all_null!(score, acct.ac_pad);
582✔
5271

5272
                score_fixedstruct_ac_flags!(score, acct.ac_flag, linux_x86::AC_FLAGS_MASK);
582✔
5273
            }
5274
            FixedStructType::Fs_Linux_x86_Acct_v3 => {
5275
                let acct: &linux_x86::acct_v3 = fixedstructptr.as_linux_x86_acct_v3();
582✔
5276

5277
                score_fixedstruct_cstr!(score, acct.ac_comm());
582✔
5278
                score_fixedstruct_cstr_no_data_after_null!(score, acct.ac_comm);
582✔
5279

5280
                score_fixedstruct_time_range!(score, acct.ac_btime);
582✔
5281

5282
                score_fixedstruct_value_not_zero!(score, acct.ac_version);
582✔
5283

5284
                score_fixedstruct_ac_flags!(score, acct.ac_flag, linux_x86::AC_FLAGS_MASK);
582✔
5285
            }
5286
            FixedStructType::Fs_Linux_x86_Lastlog => {
5287
                let lastlog: &linux_x86::lastlog = fixedstructptr.as_linux_x86_lastlog();
9✔
5288

5289
                score_fixedstruct_time_range!(score, lastlog.ll_time);
9✔
5290

5291
                score_fixedstruct_cstr!(score, lastlog.ll_line());
9✔
5292
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_line);
9✔
5293

5294
                score_fixedstruct_cstr!(score, lastlog.ll_host());
9✔
5295
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_host);
9✔
5296
                score_fixedstruct_cstr_null_terminator!(score, lastlog.ll_host);
9✔
5297
            }
5298
            FixedStructType::Fs_Linux_x86_Utmpx => {
5299
                let utmpx: &linux_x86::utmpx = fixedstructptr.as_linux_x86_utmpx();
566✔
5300

5301
                score_fixedstruct_cstr!(score, utmpx.ut_line());
566✔
5302
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_line);
566✔
5303

5304
                score_fixedstruct_cstr!(score, utmpx.ut_id());
566✔
5305
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_id);
566✔
5306

5307
                score_fixedstruct_cstr!(score, utmpx.ut_user());
566✔
5308
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_user);
566✔
5309
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_user);
566✔
5310

5311
                score_fixedstruct_cstr!(score, utmpx.ut_host());
566✔
5312
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_host);
566✔
5313
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_host);
566✔
5314

5315
                score_fixedstruct_time_range!(score, utmpx.ut_tv.tv_sec);
566✔
5316

5317
                score_fixedstruct_buffer_all_null!(score, utmpx.__glibc_reserved);
566✔
5318

5319
                score_fixedstruct_ut_type!(score, utmpx.ut_type, linux_x86::UT_TYPES);
4,240✔
5320
            }
5321
            FixedStructType::Fs_Netbsd_x8632_Acct => {
5322
                let acct: &netbsd_x8632::acct = fixedstructptr.as_netbsd_x8632_acct();
2✔
5323

5324
                score_fixedstruct_cstr!(score, acct.ac_comm());
2✔
5325
                score_fixedstruct_cstr_no_data_after_null!(score, acct.ac_comm);
2✔
5326

5327
                score_fixedstruct_time_range!(score, acct.ac_btime);
2✔
5328

5329
                score_fixedstruct_buffer_all_null!(score, acct.__gap1);
2✔
5330
                score_fixedstruct_buffer_all_null!(score, acct.__gap3);
2✔
5331

5332
                score_fixedstruct_ac_flags!(score, acct.ac_flag, netbsd_x8632::AC_FLAGS_MASK);
2✔
5333
            }
5334
            FixedStructType::Fs_Netbsd_x8632_Lastlogx => {
5335
                let lastlogx: &netbsd_x8632::lastlogx = fixedstructptr.as_netbsd_x8632_lastlogx();
2✔
5336

5337
                score_fixedstruct_cstr!(score, lastlogx.ll_line());
2✔
5338
                score_fixedstruct_cstr_no_data_after_null!(score, lastlogx.ll_line);
2✔
5339

5340
                score_fixedstruct_cstr!(score, lastlogx.ll_host());
2✔
5341
                score_fixedstruct_cstr_no_data_after_null!(score, lastlogx.ll_host);
2✔
5342
                score_fixedstruct_cstr_null_terminator!(score, lastlogx.ll_host);
2✔
5343

5344
                score_fixedstruct_time_range!(score, lastlogx.ll_tv.tv_sec);
2✔
5345
            }
5346
            FixedStructType::Fs_Netbsd_x8632_Utmpx => {
5347
                let utmpx: &netbsd_x8632::utmpx = fixedstructptr.as_netbsd_x8632_utmpx();
2✔
5348

5349
                score_fixedstruct_cstr!(score, utmpx.ut_name());
2✔
5350
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_name);
2✔
5351

5352
                score_fixedstruct_cstr!(score, utmpx.ut_id());
2✔
5353
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_id);
2✔
5354

5355
                score_fixedstruct_cstr!(score, utmpx.ut_line());
2✔
5356
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_line);
2✔
5357
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_line);
2✔
5358

5359
                score_fixedstruct_cstr!(score, utmpx.ut_host());
2✔
5360
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_host);
2✔
5361
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_host);
2✔
5362

5363
                score_fixedstruct_time_range!(score, utmpx.ut_tv.tv_sec);
2✔
5364

5365
                score_fixedstruct_buffer_all_null!(score, utmpx.ut_pad);
2✔
5366

5367
                score_fixedstruct_ut_type!(score, utmpx.ut_type, netbsd_x8632::UT_TYPES);
14✔
5368
            }
5369
            FixedStructType::Fs_Netbsd_x8664_Lastlog => {
5370
                let lastlog: &netbsd_x8664::lastlog = fixedstructptr.as_netbsd_x8664_lastlog();
582✔
5371

5372
                score_fixedstruct_cstr!(score, lastlog.ll_line());
582✔
5373
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_line);
582✔
5374

5375
                score_fixedstruct_cstr!(score, lastlog.ll_host());
582✔
5376
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_host);
582✔
5377

5378
                score_fixedstruct_time_range!(score, lastlog.ll_time);
582✔
5379
            }
5380
            FixedStructType::Fs_Netbsd_x8664_Lastlogx => {
5381
                let lastlogx: &netbsd_x8664::lastlogx = fixedstructptr.as_netbsd_x8664_lastlogx();
1✔
5382

5383
                score_fixedstruct_cstr!(score, lastlogx.ll_line());
1✔
5384
                score_fixedstruct_cstr_no_data_after_null!(score, lastlogx.ll_line);
1✔
5385

5386
                score_fixedstruct_cstr!(score, lastlogx.ll_host());
1✔
5387
                score_fixedstruct_cstr_no_data_after_null!(score, lastlogx.ll_host);
1✔
5388
                score_fixedstruct_cstr_null_terminator!(score, lastlogx.ll_host);
1✔
5389

5390
                score_fixedstruct_time_range!(score, lastlogx.ll_tv.tv_sec);
1✔
5391
            }
5392
            FixedStructType::Fs_Netbsd_x8664_Utmp => {
5393
                let utmp: &netbsd_x8664::utmp = fixedstructptr.as_netbsd_x8664_utmp();
2✔
5394

5395
                score_fixedstruct_cstr!(score, utmp.ut_line());
2✔
5396
                score_fixedstruct_cstr_no_data_after_null!(score, utmp.ut_line);
2✔
5397

5398
                score_fixedstruct_cstr!(score, utmp.ut_name());
2✔
5399
                score_fixedstruct_cstr_no_data_after_null!(score, utmp.ut_name);
2✔
5400

5401
                score_fixedstruct_cstr!(score, utmp.ut_host());
2✔
5402
                score_fixedstruct_cstr_no_data_after_null!(score, utmp.ut_host);
2✔
5403
                score_fixedstruct_cstr_null_terminator!(score, utmp.ut_host);
2✔
5404

5405
                score_fixedstruct_time_range!(score, utmp.ut_time);
2✔
5406
            }
5407
            FixedStructType::Fs_Netbsd_x8664_Utmpx => {
5408
                let utmpx: &netbsd_x8664::utmpx = fixedstructptr.as_netbsd_x8664_utmpx();
2✔
5409

5410
                score_fixedstruct_cstr!(score, utmpx.ut_user());
2✔
5411
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_user);
2✔
5412

5413
                score_fixedstruct_cstr!(score, utmpx.ut_id());
2✔
5414
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_id);
2✔
5415

5416
                score_fixedstruct_cstr!(score, utmpx.ut_line());
2✔
5417
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_line);
2✔
5418

5419
                score_fixedstruct_cstr!(score, utmpx.ut_host());
2✔
5420
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_host);
2✔
5421
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_host);
2✔
5422

5423
                score_fixedstruct_time_range!(score, utmpx.ut_tv.tv_sec);
2✔
5424

5425
                score_fixedstruct_buffer_all_null!(score, utmpx.__gap1);
2✔
5426
                score_fixedstruct_buffer_all_null!(score, utmpx.ut_pad);
2✔
5427

5428
                score_fixedstruct_ut_type!(score, utmpx.ut_type, netbsd_x8664::UT_TYPES);
16✔
5429
            }
5430
            FixedStructType::Fs_Openbsd_x86_Lastlog => {
5431
                let lastlog: &openbsd_x86::lastlog = fixedstructptr.as_openbsd_x86_lastlog();
2✔
5432

5433
                score_fixedstruct_time_range!(score, lastlog.ll_time);
2✔
5434

5435
                score_fixedstruct_cstr!(score, lastlog.ll_line());
2✔
5436
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_line);
2✔
5437

5438
                score_fixedstruct_cstr!(score, lastlog.ll_host());
2✔
5439
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_host);
2✔
5440
                score_fixedstruct_cstr_null_terminator!(score, lastlog.ll_host);
2✔
5441
            }
5442
            FixedStructType::Fs_Openbsd_x86_Utmp => {
5443
                let utmp: &openbsd_x86::utmp = fixedstructptr.as_openbsd_x86_utmp();
2✔
5444

5445
                score_fixedstruct_cstr!(score, utmp.ut_line());
2✔
5446
                score_fixedstruct_cstr_no_data_after_null!(score, utmp.ut_line);
2✔
5447

5448
                score_fixedstruct_cstr!(score, utmp.ut_name());
2✔
5449
                score_fixedstruct_cstr_no_data_after_null!(score, utmp.ut_name);
2✔
5450

5451
                score_fixedstruct_cstr!(score, utmp.ut_host());
2✔
5452
                score_fixedstruct_cstr_no_data_after_null!(score, utmp.ut_host);
2✔
5453
                score_fixedstruct_cstr_null_terminator!(score, utmp.ut_host);
2✔
5454

5455
                score_fixedstruct_time_range!(score, utmp.ut_time);
2✔
5456
            }
5457
        }
5458

5459
        defx!("return score {}", score);
2,343✔
5460

5461
        score
2,343✔
5462
    }
2,343✔
5463

5464
    /// Efficient function to copy the `FixedStruct` into a single re-usable
5465
    /// buffer for printing.
5466
    ///
5467
    /// Copy the `FixedStruct` into the passed `buffer` as printable bytes.
5468
    /// When successful, returns a [`InfoAsBytes::Ok`] variant with
5469
    /// number of bytes copied, start index of datetime substring, and
5470
    /// end index of datetime substring.
5471
    ///
5472
    /// If copying fails, returns a [`InfoAsBytes::Fail`] variant with
5473
    /// number of bytes copied.
5474
    pub fn as_bytes(self: &FixedStruct, buffer: &mut [u8]) -> InfoAsBytes
935✔
5475
    {
5476
        let entry: &FixedStructDynPtr = &self.fixedstructptr;
935✔
5477
        let mut at: usize = 0;
935✔
5478
        let dt_beg: BufIndex;
5479
        let dt_end: BufIndex;
5480

5481
        match entry.fixedstruct_type() {
935✔
5482
            FixedStructType::Fs_Freebsd_x8664_Utmpx => {
5483
                let utmpx: &freebsd_x8664::utmpx = entry.as_freebsd_x8664_utmpx();
1✔
5484

5485
                // ut_type
5486
                set_buffer_at_or_err_str!(buffer, at, "ut_type ");
1✔
5487
                set_buffer_at_or_err_ut_type_i16!(buffer, at, utmpx.ut_type);
1✔
5488
                // ut_tv
5489
                set_buffer_at_or_err_str!(buffer, at,  " ut_tv ");
1✔
5490
                dt_beg = at;
1✔
5491
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_sec, freebsd_x8664::time_t);
1✔
5492
                set_buffer_at_or_err_u8!(buffer, at, b'.');
1✔
5493
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_usec, freebsd_x8664::subseconds_t);
1✔
5494
                dt_end = at;
1✔
5495
                // ut_id
5496
                set_buffer_at_or_err_str!(buffer, at, " ut_id '");
1✔
5497
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_id);
1✔
5498
                // ut_pid
5499
                set_buffer_at_or_err_str!(buffer, at, "' ut_pid ");
1✔
5500
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_pid, freebsd_x8664::pid_t);
1✔
5501
                // ut_user
5502
                set_buffer_at_or_err_str!(buffer, at, " ut_user '");
1✔
5503
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_user);
1✔
5504
                // ut_line
5505
                set_buffer_at_or_err_str!(buffer, at, "' ut_line ");
1✔
5506
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_line);
1✔
5507
                // ut_host
5508
                set_buffer_at_or_err_str!(buffer, at, "' ut_host '");
1✔
5509
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_host);
1✔
5510
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
1✔
5511
            }
5512
            FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => {
5513
                let lastlog: &linux_arm64aarch64::lastlog = entry.as_linux_arm64aarch64_lastlog();
1✔
5514

5515
                // ll_time
5516
                set_buffer_at_or_err_str!(buffer, at, "ll_time ");
1✔
5517
                dt_beg = at;
1✔
5518
                set_buffer_at_or_err_number!(buffer, at, lastlog.ll_time, linux_arm64aarch64::ll_time_t);
1✔
5519
                dt_end = at;
1✔
5520
                // ll_line
5521
                set_buffer_at_or_err_str!(buffer, at, " ll_line '");
1✔
5522
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_line);
1✔
5523
                // ll_host
5524
                set_buffer_at_or_err_str!(buffer, at, "' ll_host '");
1✔
5525
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_host);
1✔
5526
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
1✔
5527
            }
5528
            FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => {
5529
                let utmpx: &linux_arm64aarch64::utmpx = entry.as_linux_arm64aarch64_utmpx();
1✔
5530

5531
                // ut_type
5532
                set_buffer_at_or_err_str!(buffer, at, "ut_type ");
1✔
5533
                set_buffer_at_or_err_ut_type_i16!(buffer, at, utmpx.ut_type);
1✔
5534
                // ut_pid
5535
                set_buffer_at_or_err_str!(buffer, at, " ut_pid ");
1✔
5536
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_pid, linux_arm64aarch64::pid_t);
1✔
5537
                // ut_line
5538
                set_buffer_at_or_err_str!(buffer, at, " ut_line '");
1✔
5539
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_line);
1✔
5540
                // ut_id
5541
                set_buffer_at_or_err_str!(buffer, at, "' ut_id '");
1✔
5542
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_id);
1✔
5543
                // ut_user
5544
                set_buffer_at_or_err_str!(buffer, at, "' ut_user '");
1✔
5545
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_user);
1✔
5546
                // ut_host
5547
                set_buffer_at_or_err_str!(buffer, at, "' ut_host '");
1✔
5548
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_host);
1✔
5549
                // ut_exit
5550
                set_buffer_at_or_err_str!(buffer, at, "' ut_exit ");
1✔
5551
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_exit, i32);
1✔
5552
                // ut_session
5553
                set_buffer_at_or_err_str!(buffer, at, " ut_session '");
1✔
5554
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_session, i64);
1✔
5555
                // ut_tv.tv_sec
5556
                set_buffer_at_or_err_str!(buffer, at, "' ut_tv ");
1✔
5557
                dt_beg = at;
1✔
5558
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_sec, i64);
1✔
5559
                set_buffer_at_or_err_u8!(buffer, at, b'.');
1✔
5560
                // ut_tv.tv_usec
5561
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_usec, i64);
1✔
5562
                dt_end = at;
1✔
5563
                // if ut_addr_v6 is all zeros then this is an IPv4 address
5564
                if utmpx.ut_addr_v6[1..4].iter().all(|&x| x == 0) {
3✔
5565
                    // ut_addr
5566
                    set_buffer_at_or_err_str!(buffer, at, " ut_addr ");
1✔
5567
                    set_buffer_at_or_err_ipv4!(buffer, at, utmpx.ut_addr_v6[0]);
1✔
5568
                } else {
5569
                    // ut_addr_v6
5570
                    set_buffer_at_or_err_str!(buffer, at, " ut_addr_v6 ");
×
5571
                    set_buffer_at_or_err_ipv6!(buffer, at, utmpx.ut_addr_v6);
×
5572
                }
5573
            }
5574
            FixedStructType::Fs_Linux_x86_Acct => {
5575
                let acct: &linux_x86::acct = entry.as_linux_x86_acct();
1✔
5576

5577
                // ac_flag
5578
                set_buffer_at_or_err_str!(buffer, at, "ac_flag ");
1✔
5579
                set_buffer_at_or_err_number_bin4!(buffer, at, acct.ac_flag, linux_x86::c_char);
1✔
5580
                if acct.ac_flag != 0 {
1✔
5581
                    set_buffer_at_or_err_str!(buffer, at, " (");
1✔
5582
                    if acct.ac_flag & linux_x86::AFORK != 0 {
1✔
5583
                        set_buffer_at_or_err_str!(buffer, at, "AFORK|");
×
5584
                    }
1✔
5585
                    if acct.ac_flag & linux_x86::ASU != 0 {
1✔
5586
                        set_buffer_at_or_err_str!(buffer, at, "ASU|");
1✔
5587
                    }
×
5588
                    if acct.ac_flag & linux_x86::ACOMPAT != 0 {
1✔
5589
                        set_buffer_at_or_err_str!(buffer, at, "ACOMPAT|");
×
5590
                    }
1✔
5591
                    if acct.ac_flag & linux_x86::ACORE != 0 {
1✔
5592
                        set_buffer_at_or_err_str!(buffer, at, "ACORE|");
×
5593
                    }
1✔
5594
                    if acct.ac_flag & linux_x86::AXSIG != 0 {
1✔
5595
                        set_buffer_at_or_err_str!(buffer, at, "AXSIG|");
×
5596
                    }
1✔
5597
                    // overwrite trailing '|' with ')'
5598
                    if buffer[at - 1] == b'|' {
1✔
5599
                        at -= 1;
1✔
5600
                    }
1✔
5601
                    set_buffer_at_or_err_str!(buffer, at, ")");
1✔
5602
                }
×
5603
                // ac_uid
5604
                set_buffer_at_or_err_str!(buffer, at, " ac_uid ");
1✔
5605
                set_buffer_at_or_err_number!(buffer, at, acct.ac_uid, linux_x86::uint16_t);
1✔
5606
                // ac_gid
5607
                set_buffer_at_or_err_str!(buffer, at, " ac_gid ");
1✔
5608
                set_buffer_at_or_err_number!(buffer, at, acct.ac_gid, linux_x86::uint16_t);
1✔
5609
                // ac_tty
5610
                set_buffer_at_or_err_str!(buffer, at, " ac_tty ");
1✔
5611
                set_buffer_at_or_err_number!(buffer, at, acct.ac_tty, linux_x86::uint16_t);
1✔
5612
                // ac_btime
5613
                set_buffer_at_or_err_str!(buffer, at, " ac_btime ");
1✔
5614
                dt_beg = at;
1✔
5615
                set_buffer_at_or_err_number!(buffer, at, acct.ac_btime, linux_x86::b_time_t);
1✔
5616
                dt_end = at;
1✔
5617
                // ac_utime
5618
                set_buffer_at_or_err_str!(buffer, at, " ac_utime ");
1✔
5619
                set_buffer_at_or_err_number!(buffer, at, acct.ac_utime, linux_x86::comp_t);
1✔
5620
                // ac_stime
5621
                set_buffer_at_or_err_str!(buffer, at, " ac_stime ");
1✔
5622
                set_buffer_at_or_err_number!(buffer, at, acct.ac_stime, linux_x86::comp_t);
1✔
5623
                // ac_etime
5624
                set_buffer_at_or_err_str!(buffer, at, " ac_etime ");
1✔
5625
                set_buffer_at_or_err_number!(buffer, at, acct.ac_etime, linux_x86::comp_t);
1✔
5626
                // ac_mem
5627
                set_buffer_at_or_err_str!(buffer, at, " ac_mem ");
1✔
5628
                set_buffer_at_or_err_number!(buffer, at, acct.ac_mem, linux_x86::comp_t);
1✔
5629
                // ac_io
5630
                set_buffer_at_or_err_str!(buffer, at, " ac_io ");
1✔
5631
                set_buffer_at_or_err_number!(buffer, at, acct.ac_io, linux_x86::comp_t);
1✔
5632
                // ac_rw
5633
                set_buffer_at_or_err_str!(buffer, at, " ac_rw ");
1✔
5634
                set_buffer_at_or_err_number!(buffer, at, acct.ac_rw, linux_x86::comp_t);
1✔
5635
                // ac_minflt
5636
                set_buffer_at_or_err_str!(buffer, at, " ac_minflt ");
1✔
5637
                set_buffer_at_or_err_number!(buffer, at, acct.ac_minflt, linux_x86::comp_t);
1✔
5638
                // ac_majflt
5639
                set_buffer_at_or_err_str!(buffer, at, " ac_majflt ");
1✔
5640
                set_buffer_at_or_err_number!(buffer, at, acct.ac_majflt, linux_x86::comp_t);
1✔
5641
                // ac_swaps
5642
                set_buffer_at_or_err_str!(buffer, at, " ac_swaps ");
1✔
5643
                set_buffer_at_or_err_number!(buffer, at, acct.ac_swaps, linux_x86::comp_t);
1✔
5644
                // ac_exitcode
5645
                set_buffer_at_or_err_str!(buffer, at, " ac_exitcode ");
1✔
5646
                set_buffer_at_or_err_number!(buffer, at, acct.ac_exitcode, u32);
1✔
5647
                // ac_comm
5648
                set_buffer_at_or_err_str!(buffer, at, " ac_comm '");
1✔
5649
                set_buffer_at_or_err_cstrn!(buffer, at, acct.ac_comm);
1✔
5650
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
1✔
5651
            }
5652
            FixedStructType::Fs_Linux_x86_Acct_v3 => {
5653
                let acct_v3: &linux_x86::acct_v3 = entry.as_linux_x86_acct_v3();
1✔
5654

5655
                // ac_flag
5656
                set_buffer_at_or_err_str!(buffer, at, "ac_flag ");
1✔
5657
                set_buffer_at_or_err_number_bin4!(buffer, at, acct_v3.ac_flag, linux_x86::c_char);
1✔
5658
                if acct_v3.ac_flag != 0 {
1✔
5659
                    set_buffer_at_or_err_str!(buffer, at, " (");
1✔
5660
                    if acct_v3.ac_flag & linux_x86::AFORK != 0 {
1✔
5661
                        set_buffer_at_or_err_str!(buffer, at, "AFORK|");
1✔
5662
                    }
×
5663
                    if acct_v3.ac_flag & linux_x86::ASU != 0 {
1✔
5664
                        set_buffer_at_or_err_str!(buffer, at, "ASU|");
×
5665
                    }
1✔
5666
                    if acct_v3.ac_flag & linux_x86::ACOMPAT != 0 {
1✔
5667
                        set_buffer_at_or_err_str!(buffer, at, "ACOMPAT|");
×
5668
                    }
1✔
5669
                    if acct_v3.ac_flag & linux_x86::ACORE != 0 {
1✔
5670
                        set_buffer_at_or_err_str!(buffer, at, "ACORE|");
×
5671
                    }
1✔
5672
                    if acct_v3.ac_flag & linux_x86::AXSIG != 0 {
1✔
5673
                        set_buffer_at_or_err_str!(buffer, at, "AXSIG|");
×
5674
                    }
1✔
5675
                    // overwrite trailing '|' with ')'
5676
                    if buffer[at - 1] == b'|' {
1✔
5677
                        at -= 1;
1✔
5678
                    }
1✔
5679
                    set_buffer_at_or_err_str!(buffer, at, ")");
1✔
5680
                }
×
5681
                // ac_version
5682
                set_buffer_at_or_err_str!(buffer, at, " ac_version ");
1✔
5683
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_version, linux_x86::c_char);
1✔
5684
                // ac_tty
5685
                set_buffer_at_or_err_str!(buffer, at, " ac_tty ");
1✔
5686
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_tty, u16);
1✔
5687
                // ac_exitcode
5688
                set_buffer_at_or_err_str!(buffer, at, " ac_exitcode ");
1✔
5689
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_exitcode, u32);
1✔
5690
                // ac_uid
5691
                set_buffer_at_or_err_str!(buffer, at, " ac_uid ");
1✔
5692
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_uid, u32);
1✔
5693
                // ac_gid
5694
                set_buffer_at_or_err_str!(buffer, at, " ac_gid ");
1✔
5695
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_gid, u32);
1✔
5696
                // ac_pid
5697
                set_buffer_at_or_err_str!(buffer, at, " ac_pid ");
1✔
5698
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_pid, u32);
1✔
5699
                // ac_ppid
5700
                set_buffer_at_or_err_str!(buffer, at, " ac_ppid ");
1✔
5701
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_ppid, u32);
1✔
5702
                // ac_btime
5703
                set_buffer_at_or_err_str!(buffer, at, " ac_btime ");
1✔
5704
                dt_beg = at;
1✔
5705
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_btime, linux_x86::b_time_t);
1✔
5706
                dt_end = at;
1✔
5707
                // ac_etime
5708
                set_buffer_at_or_err_str!(buffer, at, " ac_etime ");
1✔
5709
                set_buffer_at_or_err_number_f32!(buffer, at, acct_v3.ac_etime, f32);
1✔
5710
                // ac_utime
5711
                set_buffer_at_or_err_str!(buffer, at, " ac_utime ");
1✔
5712
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_utime, linux_x86::comp_t);
1✔
5713
                // ac_stime
5714
                set_buffer_at_or_err_str!(buffer, at, " ac_stime ");
1✔
5715
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_stime, linux_x86::comp_t);
1✔
5716
                // ac_mem
5717
                set_buffer_at_or_err_str!(buffer, at, " ac_mem ");
1✔
5718
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_mem, linux_x86::comp_t);
1✔
5719
                // ac_io
5720
                set_buffer_at_or_err_str!(buffer, at, " ac_io ");
1✔
5721
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_io, linux_x86::comp_t);
1✔
5722
                // ac_rw
5723
                set_buffer_at_or_err_str!(buffer, at, " ac_rw ");
1✔
5724
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_rw, linux_x86::comp_t);
1✔
5725
                // ac_minflt
5726
                set_buffer_at_or_err_str!(buffer, at, " ac_minflt ");
1✔
5727
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_minflt, linux_x86::comp_t);
1✔
5728
                // ac_majflt
5729
                set_buffer_at_or_err_str!(buffer, at, " ac_majflt ");
1✔
5730
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_majflt, linux_x86::comp_t);
1✔
5731
                // ac_swaps
5732
                set_buffer_at_or_err_str!(buffer, at, " ac_swaps ");
1✔
5733
                set_buffer_at_or_err_number!(buffer, at, acct_v3.ac_swaps, linux_x86::comp_t);
1✔
5734
                // ac_comm
5735
                set_buffer_at_or_err_str!(buffer, at, " ac_comm '");
1✔
5736
                set_buffer_at_or_err_cstrn!(buffer, at, acct_v3.ac_comm);
1✔
5737
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
1✔
5738
            }
5739
            FixedStructType::Fs_Linux_x86_Lastlog => {
5740
                let lastlog: &linux_x86::lastlog = entry.as_linux_x86_lastlog();
2✔
5741

5742
                // ll_time
5743
                set_buffer_at_or_err_str!(buffer, at, "ll_time ");
2✔
5744
                dt_beg = at;
2✔
5745
                set_buffer_at_or_err_number!(buffer, at, lastlog.ll_time, linux_x86::ll_time_t);
2✔
5746
                dt_end = at;
2✔
5747
                // ll_line
5748
                set_buffer_at_or_err_str!(buffer, at, " ll_line '");
2✔
5749
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_line);
2✔
5750
                // ll_host
5751
                set_buffer_at_or_err_str!(buffer, at, "' ll_host '");
2✔
5752
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_host);
2✔
5753
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
2✔
5754
            }
5755
            FixedStructType::Fs_Linux_x86_Utmpx => {
5756
                let utmpx: &linux_x86::utmpx = entry.as_linux_x86_utmpx();
920✔
5757

5758
                // ut_type
5759
                set_buffer_at_or_err_str!(buffer, at, "ut_type ");
920✔
5760
                set_buffer_at_or_err_ut_type_i16!(buffer, at, utmpx.ut_type);
920✔
5761
                // ut_pid
5762
                set_buffer_at_or_err_str!(buffer, at, " ut_pid ");
920✔
5763
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_pid, linux_x86::pid_t);
920✔
5764
                // ut_line
5765
                set_buffer_at_or_err_str!(buffer, at, " ut_line '");
920✔
5766
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_line);
920✔
5767
                // ut_id
5768
                set_buffer_at_or_err_str!(buffer, at, "' ut_id '");
920✔
5769
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_id);
920✔
5770
                // ut_user
5771
                set_buffer_at_or_err_str!(buffer, at, "' ut_user '");
920✔
5772
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_user);
920✔
5773
                // ut_host
5774
                set_buffer_at_or_err_str!(buffer, at, "' ut_host '");
920✔
5775
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_host);
920✔
5776
                // ut_exit.e_termination
5777
                set_buffer_at_or_err_str!(buffer, at, "' e_termination ");
920✔
5778
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_exit.e_termination, i16);
920✔
5779
                // ut_exit.e_exit
5780
                set_buffer_at_or_err_str!(buffer, at, " e_exit ");
920✔
5781
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_exit.e_exit, i16);
920✔
5782
                // ut_session
5783
                set_buffer_at_or_err_str!(buffer, at, " ut_session '");
920✔
5784
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_session, i32);
920✔
5785
                // ut_tv.tv_sec
5786
                set_buffer_at_or_err_str!(buffer, at, "' ut_xtime ");
920✔
5787
                dt_beg = at;
920✔
5788
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_sec, i32);
920✔
5789
                set_buffer_at_or_err_u8!(buffer, at, b'.');
920✔
5790
                // ut_tv.tv_usec
5791
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_usec, i32);
920✔
5792
                dt_end = at;
920✔
5793
                // if ut_addr_v6 is all zeros then this is an IPv4 address
5794
                if utmpx.ut_addr_v6[1..4].iter().all(|&x| x == 0) {
2,760✔
5795
                    // ut_addr
5796
                    set_buffer_at_or_err_str!(buffer, at, " ut_addr ");
920✔
5797
                    set_buffer_at_or_err_ipv4!(buffer, at, utmpx.ut_addr_v6[0]);
920✔
5798
                } else {
5799
                    // ut_addr_v6
5800
                    set_buffer_at_or_err_str!(buffer, at, " ut_addr_v6 ");
×
5801
                    set_buffer_at_or_err_ipv6!(buffer, at, utmpx.ut_addr_v6);
×
5802
                }
5803
            }
5804
            FixedStructType::Fs_Netbsd_x8632_Acct => {
5805
                let acct: &netbsd_x8632::acct = entry.as_netbsd_x8632_acct();
1✔
5806

5807
                // ac_comm
5808
                set_buffer_at_or_err_str!(buffer, at, "ac_comm '");
1✔
5809
                set_buffer_at_or_err_cstrn!(buffer, at, acct.ac_comm);
1✔
5810
                // ac_utime
5811
                set_buffer_at_or_err_str!(buffer, at, "' ac_utime ");
1✔
5812
                // TODO: need to handle `comp_t` values specially; from `acct.h`:
5813
                //       /*
5814
                //        * Accounting structures; these use a comp_t type which is a 3 bits base 8
5815
                //        * exponent, 13 bit fraction ``floating point'' number.  Units are 1/AHZ
5816
                //        * seconds.
5817
                //        */
5818
                set_buffer_at_or_err_number!(buffer, at, acct.ac_utime, netbsd_x8632::comp_t);
1✔
5819
                // ac_stime
5820
                set_buffer_at_or_err_str!(buffer, at, " ac_stime ");
1✔
5821
                set_buffer_at_or_err_number!(buffer, at, acct.ac_stime, netbsd_x8632::comp_t);
1✔
5822
                // ac_etime
5823
                set_buffer_at_or_err_str!(buffer, at, " ac_etime ");
1✔
5824
                set_buffer_at_or_err_number!(buffer, at, acct.ac_etime, netbsd_x8632::comp_t);
1✔
5825
                // ac_btime
5826
                set_buffer_at_or_err_str!(buffer, at, " ac_btime ");
1✔
5827
                dt_beg = at;
1✔
5828
                set_buffer_at_or_err_number!(buffer, at, acct.ac_btime, netbsd_x8632::time_t);
1✔
5829
                dt_end = at;
1✔
5830
                // ac_uid
5831
                set_buffer_at_or_err_str!(buffer, at, " ac_uid ");
1✔
5832
                set_buffer_at_or_err_number!(buffer, at, acct.ac_uid, netbsd_x8632::uid_t);
1✔
5833
                // ac_gid
5834
                set_buffer_at_or_err_str!(buffer, at, " ac_gid ");
1✔
5835
                set_buffer_at_or_err_number!(buffer, at, acct.ac_gid, netbsd_x8632::gid_t);
1✔
5836
                // ac_mem
5837
                set_buffer_at_or_err_str!(buffer, at, " ac_mem ");
1✔
5838
                set_buffer_at_or_err_number!(buffer, at, acct.ac_mem, netbsd_x8632::uint16_t);
1✔
5839
                // ac_io
5840
                set_buffer_at_or_err_str!(buffer, at, " ac_io ");
1✔
5841
                set_buffer_at_or_err_number!(buffer, at, acct.ac_io, netbsd_x8632::comp_t);
1✔
5842
                // ac_tty
5843
                set_buffer_at_or_err_str!(buffer, at, " ac_tty ");
1✔
5844
                set_buffer_at_or_err_number!(buffer, at, acct.ac_tty, netbsd_x8632::dev_t);
1✔
5845
                // ac_flag is a bitfield
5846
                // see https://man.netbsd.org/acct.5
5847
                set_buffer_at_or_err_str!(buffer, at, " ac_flag ");
1✔
5848
                set_buffer_at_or_err_number_bin4!(buffer, at, acct.ac_flag, netbsd_x8632::uint8_t);
1✔
5849
                if acct.ac_flag != 0 {
1✔
5850
                    set_buffer_at_or_err_str!(buffer, at, " (");
1✔
5851
                    if acct.ac_flag & netbsd_x8632::AFORK != 0 {
1✔
5852
                        set_buffer_at_or_err_str!(buffer, at, "AFORK|");
×
5853
                    }
1✔
5854
                    if acct.ac_flag & netbsd_x8632::ASU != 0 {
1✔
5855
                        set_buffer_at_or_err_str!(buffer, at, "ASU|");
1✔
5856
                    }
×
5857
                    if acct.ac_flag & netbsd_x8632::ACOMPAT != 0 {
1✔
5858
                        set_buffer_at_or_err_str!(buffer, at, "ACOMPAT|");
×
5859
                    }
1✔
5860
                    if acct.ac_flag & netbsd_x8632::ACORE != 0 {
1✔
5861
                        set_buffer_at_or_err_str!(buffer, at, "ACORE|");
×
5862
                    }
1✔
5863
                    if acct.ac_flag & netbsd_x8632::AXSIG != 0 {
1✔
5864
                        set_buffer_at_or_err_str!(buffer, at, "AXSIG|");
×
5865
                    }
1✔
5866
                    // overwrite trailing '|' with ')'
5867
                    if buffer[at - 1] == b'|' {
1✔
5868
                        at -= 1;
1✔
5869
                    }
1✔
5870
                    set_buffer_at_or_err_str!(buffer, at, ")");
1✔
5871
                }
×
5872
            }
5873
            FixedStructType::Fs_Netbsd_x8632_Lastlogx => {
5874
                let lastlogx: &netbsd_x8632::lastlogx = entry.as_netbsd_x8632_lastlogx();
1✔
5875

5876
                // ll_tv.tv_sec
5877
                set_buffer_at_or_err_str!(buffer, at, "ll_tv ");
1✔
5878
                dt_beg = at;
1✔
5879
                set_buffer_at_or_err_number!(buffer, at, lastlogx.ll_tv.tv_sec, i64);
1✔
5880
                set_buffer_at_or_err_u8!(buffer, at, b'.');
1✔
5881
                // ll_tv.tv_usec
5882
                set_buffer_at_or_err_number!(buffer, at, lastlogx.ll_tv.tv_usec, i32);
1✔
5883
                dt_end = at;
1✔
5884
                // ll_line
5885
                set_buffer_at_or_err_str!(buffer, at, " ll_line '");
1✔
5886
                set_buffer_at_or_err_cstrn!(buffer, at, lastlogx.ll_line);
1✔
5887
                // ll_host
5888
                set_buffer_at_or_err_str!(buffer, at, "' ll_host '");
1✔
5889
                set_buffer_at_or_err_cstrn!(buffer, at, lastlogx.ll_host);
1✔
5890
                // ll_ss
5891
                set_buffer_at_or_err_str!(buffer, at, "' ll_ss ");
1✔
5892
                set_buffer_at_or_err_cstrn!(buffer, at, lastlogx.ll_ss);
1✔
5893
            }
5894
            FixedStructType::Fs_Netbsd_x8632_Utmpx => {
5895
                let utmpx: &netbsd_x8632::utmpx = entry.as_netbsd_x8632_utmpx();
1✔
5896

5897
                // ut_name
5898
                set_buffer_at_or_err_str!(buffer, at, "ut_name '");
1✔
5899
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_name);
1✔
5900
                // ut_id
5901
                set_buffer_at_or_err_str!(buffer, at, "' ut_id '");
1✔
5902
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_id);
1✔
5903
                // ut_line
5904
                set_buffer_at_or_err_str!(buffer, at, "' ut_line '");
1✔
5905
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_line);
1✔
5906
                // ut_host
5907
                set_buffer_at_or_err_str!(buffer, at, "' ut_host '");
1✔
5908
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_host);
1✔
5909
                // ut_session
5910
                set_buffer_at_or_err_str!(buffer, at, "' ut_session '");
1✔
5911
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_session, netbsd_x8632::uint16_t);
1✔
5912
                // ut_type
5913
                set_buffer_at_or_err_str!(buffer, at, "' ut_type ");
1✔
5914
                set_buffer_at_or_err_ut_type_u16!(buffer, at, utmpx.ut_type);
1✔
5915
                // ut_pid
5916
                set_buffer_at_or_err_str!(buffer, at, " ut_pid ");
1✔
5917
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_pid, netbsd_x8632::pid_t);
1✔
5918
                // ut_exit.e_termination
5919
                set_buffer_at_or_err_str!(buffer, at, " e_termination ");
1✔
5920
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_exit.e_termination, netbsd_x8632::uint16_t);
1✔
5921
                // ut_exit.e_exit
5922
                set_buffer_at_or_err_str!(buffer, at, " e_exit ");
1✔
5923
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_exit.e_exit, netbsd_x8632::uint16_t);
1✔
5924
                // ut_ss
5925
                set_buffer_at_or_err_str!(buffer, at, " ut_ss '");
1✔
5926
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_ss);
1✔
5927
                // ut_tv.tv_sec
5928
                set_buffer_at_or_err_str!(buffer, at, "' ut_tv ");
1✔
5929
                dt_beg = at;
1✔
5930
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_sec, i64);
1✔
5931
                set_buffer_at_or_err_u8!(buffer, at, b'.');
1✔
5932
                // ut_tv.tv_usec
5933
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_usec, i32);
1✔
5934
                dt_end = at;
1✔
5935
            }
5936
            FixedStructType::Fs_Netbsd_x8664_Lastlog => {
5937
                let lastlog: &netbsd_x8664::lastlog = entry.as_netbsd_x8664_lastlog();
1✔
5938

5939
                // ll_time
5940
                set_buffer_at_or_err_str!(buffer, at, "ll_time ");
1✔
5941
                dt_beg = at;
1✔
5942
                set_buffer_at_or_err_number!(buffer, at, lastlog.ll_time, netbsd_x8664::time_t);
1✔
5943
                dt_end = at;
1✔
5944
                // ll_line
5945
                set_buffer_at_or_err_str!(buffer, at, " ll_line '");
1✔
5946
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_line);
1✔
5947
                // ll_host
5948
                set_buffer_at_or_err_str!(buffer, at, "' ll_host '");
1✔
5949
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_host);
1✔
5950
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
1✔
5951
            }
5952
            FixedStructType::Fs_Netbsd_x8664_Lastlogx => {
5953
                let lastlogx: &netbsd_x8664::lastlogx = entry.as_netbsd_x8664_lastlogx();
×
5954

5955
                // ll_tv.tv_sec
5956
                set_buffer_at_or_err_str!(buffer, at, "ll_tv ");
×
5957
                dt_beg = at;
×
5958
                set_buffer_at_or_err_number!(buffer, at, lastlogx.ll_tv.tv_sec, i64);
×
5959
                set_buffer_at_or_err_u8!(buffer, at, b'.');
×
5960
                // ll_tv.tv_usec
5961
                set_buffer_at_or_err_number!(buffer, at, lastlogx.ll_tv.tv_usec, i32);
×
5962
                dt_end = at;
×
5963
                // ll_line
5964
                set_buffer_at_or_err_str!(buffer, at, " ll_line '");
×
5965
                set_buffer_at_or_err_cstrn!(buffer, at, lastlogx.ll_line);
×
5966
                // ll_host
5967
                set_buffer_at_or_err_str!(buffer, at, "' ll_host '");
×
5968
                set_buffer_at_or_err_cstrn!(buffer, at, lastlogx.ll_host);
×
5969
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
×
5970
                // XXX: ll_ss is not printable
5971
            }
5972
            FixedStructType::Fs_Netbsd_x8664_Utmp => {
5973
                let utmp: &netbsd_x8664::utmp = entry.as_netbsd_x8664_utmp();
1✔
5974

5975
                // ut_line
5976
                set_buffer_at_or_err_str!(buffer, at, "ut_line '");
1✔
5977
                set_buffer_at_or_err_cstrn!(buffer, at, utmp.ut_line);
1✔
5978
                // ut_name
5979
                set_buffer_at_or_err_str!(buffer, at, "' ut_name '");
1✔
5980
                set_buffer_at_or_err_cstrn!(buffer, at, utmp.ut_name);
1✔
5981
                // ut_host
5982
                set_buffer_at_or_err_str!(buffer, at, "' ut_host '");
1✔
5983
                set_buffer_at_or_err_cstrn!(buffer, at, utmp.ut_host);
1✔
5984
                // ut_time
5985
                set_buffer_at_or_err_str!(buffer, at, "' ut_time ");
1✔
5986
                dt_beg = at;
1✔
5987
                set_buffer_at_or_err_number!(buffer, at, utmp.ut_time, netbsd_x8664::time_t);
1✔
5988
                dt_end = at;
1✔
5989
            }
5990
            FixedStructType::Fs_Netbsd_x8664_Utmpx => {
5991
                let utmpx: &netbsd_x8664::utmpx = entry.as_netbsd_x8664_utmpx();
1✔
5992

5993
                // ut_user
5994
                set_buffer_at_or_err_str!(buffer, at, "ut_user '");
1✔
5995
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_user);
1✔
5996
                // ut_id
5997
                set_buffer_at_or_err_str!(buffer, at, "' ut_id '");
1✔
5998
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_id);
1✔
5999
                // ut_line
6000
                set_buffer_at_or_err_str!(buffer, at, "' ut_line '");
1✔
6001
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_line);
1✔
6002
                // ut_host
6003
                set_buffer_at_or_err_str!(buffer, at, "' ut_host '");
1✔
6004
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_host);
1✔
6005
                // ut_session
6006
                set_buffer_at_or_err_str!(buffer, at, "' ut_session '");
1✔
6007
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_session, netbsd_x8664::uint16_t);
1✔
6008
                // ut_type
6009
                set_buffer_at_or_err_str!(buffer, at, "' ut_type ");
1✔
6010
                set_buffer_at_or_err_ut_type_u16!(buffer, at, utmpx.ut_type);
1✔
6011
                
6012
                // ut_pid
6013
                set_buffer_at_or_err_str!(buffer, at, " ut_pid ");
1✔
6014
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_pid, i32);
1✔
6015
                // ut_exit.e_termination
6016
                set_buffer_at_or_err_str!(buffer, at, " e_termination ");
1✔
6017
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_exit.e_termination, netbsd_x8664::uint16_t);
1✔
6018
                // ut_exit.e_exit
6019
                set_buffer_at_or_err_str!(buffer, at, " e_exit ");
1✔
6020
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_exit.e_exit, netbsd_x8664::uint16_t);
1✔
6021
                // ut_tv.tv_sec
6022
                set_buffer_at_or_err_str!(buffer, at, " ut_tv ");
1✔
6023
                dt_beg = at;
1✔
6024
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_sec, i64);
1✔
6025
                set_buffer_at_or_err_u8!(buffer, at, b'.');
1✔
6026
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_usec, i32);
1✔
6027
                dt_end = at;
1✔
6028
            }
6029
            FixedStructType::Fs_Openbsd_x86_Lastlog => {
6030
                let lastlog: &openbsd_x86::lastlog = entry.as_openbsd_x86_lastlog();
1✔
6031

6032
                // ll_time
6033
                set_buffer_at_or_err_str!(buffer, at, "ll_time ");
1✔
6034
                dt_beg = at;
1✔
6035
                set_buffer_at_or_err_number!(buffer, at, lastlog.ll_time, openbsd_x86::time_t);
1✔
6036
                dt_end = at;
1✔
6037
                // ll_line
6038
                set_buffer_at_or_err_str!(buffer, at, " ll_line '");
1✔
6039
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_line);
1✔
6040
                // ll_host
6041
                set_buffer_at_or_err_str!(buffer, at, "' ll_host '");
1✔
6042
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_host);
1✔
6043
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
1✔
6044
            }
6045
            FixedStructType::Fs_Openbsd_x86_Utmp => {
6046
                let utmp: &openbsd_x86::utmp = entry.as_openbsd_x86_utmp();
1✔
6047

6048
                // ut_line
6049
                set_buffer_at_or_err_str!(buffer, at, "ut_line '");
1✔
6050
                set_buffer_at_or_err_cstrn!(buffer, at, utmp.ut_line);
1✔
6051
                // ut_name
6052
                set_buffer_at_or_err_str!(buffer, at, "' ut_name '");
1✔
6053
                set_buffer_at_or_err_cstrn!(buffer, at, utmp.ut_name);
1✔
6054
                // ut_host
6055
                set_buffer_at_or_err_str!(buffer, at, "' ut_host '");
1✔
6056
                set_buffer_at_or_err_cstrn!(buffer, at, utmp.ut_host);
1✔
6057
                // ut_time
6058
                set_buffer_at_or_err_str!(buffer, at, "' ut_time ");
1✔
6059
                dt_beg = at;
1✔
6060
                set_buffer_at_or_err_number!(buffer, at, utmp.ut_time, openbsd_x86::time_t);
1✔
6061
                dt_end = at;
1✔
6062
            }
6063
        }
6064
        // line end
6065
        set_buffer_at_or_err_u8!(buffer, at, b'\n');
935✔
6066
        // string end
6067
        set_buffer_at_or_err_u8!(buffer, at, b'\0');
935✔
6068

6069
        debug_assert_le!(dt_beg, dt_end);
935✔
6070
        debug_assert_le!(dt_end, at);
935✔
6071

6072
        InfoAsBytes::Ok(at, dt_beg, dt_end)
935✔
6073
    }
935✔
6074

6075
    /// Create `String` from known bytes.
6076
    ///
6077
    /// `raw` is `true` means use byte characters as-is.
6078
    /// `raw` is `false` means replace formatting characters or non-printable
6079
    /// characters with pictoral representation (i.e. use
6080
    /// [`byte_to_char_noraw`]).
6081
    ///
6082
    /// XXX: very inefficient and not always correct! *only* intended to help
6083
    ///      humans visually inspect stderr output.
6084
    ///
6085
    /// [`byte_to_char_noraw`]: crate::debug::printers::byte_to_char_noraw
6086
    // XXX: this function is a lot of tedious work and duplicates
6087
    //      `fmt::Debug` and `as_bytes()`; consider removing it
6088
    #[doc(hidden)]
6089
    #[allow(non_snake_case)]
6090
    #[cfg(any(debug_assertions, test))]
6091
    fn impl_to_String_raw(
1✔
6092
        self: &FixedStruct,
1✔
6093
        _raw: bool,
1✔
6094
    ) -> String
1✔
6095
    {
6096
        let mut buf: String = String::with_capacity(100);
1✔
6097
        buf.push_str("(incomplete function impl_to_String_raw)");
1✔
6098

6099
        buf
1✔
6100
    }
1✔
6101

6102
    // TODO fix non_snake_case
6103

6104
    /// `FixedStruct` to `String`.
6105
    #[doc(hidden)]
6106
    #[allow(non_snake_case)]
6107
    #[cfg(any(debug_assertions, test))]
6108
    pub fn to_String_raw(self: &FixedStruct) -> String
×
6109
    {
6110
        self.impl_to_String_raw(true)
×
6111
    }
×
6112

6113
    /// `FixedStruct` to `String` but using printable chars for
6114
    /// non-printable and/or formatting characters.
6115
    #[doc(hidden)]
6116
    #[allow(non_snake_case)]
6117
    #[cfg(any(debug_assertions, test))]
6118
    pub fn to_String_noraw(self: &FixedStruct) -> String
1✔
6119
    {
6120
        self.impl_to_String_raw(false)
1✔
6121
    }
1✔
6122
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc