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

jtmoon79 / super-speedy-syslog-searcher / 27922955121

22 Jun 2026 12:47AM UTC coverage: 68.533% (+0.5%) from 68.035%
27922955121

push

github

jtmoon79
(TOOLS) cargo-test.sh set S4_BUILD_REGEX=TEST

16289 of 23768 relevant lines covered (68.53%)

183617.27 hits per line

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

71.27
/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
    NLu8,
58
};
59
use crate::data::datetime::{
60
    DateTimeL,
61
    FixedOffset,
62
    LocalResult,
63
    TimeZone,
64
};
65
#[cfg(any(debug_assertions, test))]
66
use crate::debug::printers::byte_to_char_noraw;
67
use crate::readers::blockreader::{
68
    BlockOffset,
69
    BlockReader,
70
    BlockSz,
71
};
72
#[doc(hidden)]
73
use crate::{
74
    de_err,
75
    de_wrn,
76
    debug_panic,
77
};
78

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

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

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

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

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

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

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

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

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

183
    // Linux
184

185
    // Linux ARM64 (aarch64)
186

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

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

195
    // Linux x86
196

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

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

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

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

213
    // NetBSD
214

215
    // NetBSD 9 x86_32 (i686)
216

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

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

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

229
    // NetBSD 9 x86_64 (AMD64)
230

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

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

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

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

247
    // OpenBSD x86_32, x86_64
248

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

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

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

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

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

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

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

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

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

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

426
// freebsd_x8664
427

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

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

444
    // utmpx
445

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

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

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

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

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

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

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

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

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

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

615
    // timeval
616

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

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

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

641
    // lastlog
642

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

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

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

676
    // utmp == utmpx
677

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

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

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

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

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

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

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

889
    pub const ACCT_COMM: usize = 16;
890

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

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

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

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

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

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

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

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

1120
    // lastlog
1121

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

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

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

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

1161
    // utmp
1162

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

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

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

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

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

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

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

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

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

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

1369
    // acct
1370

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

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

1379
    pub const ACCT_COMM_SIZE: usize = 16;
1380

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

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

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

1478
    // timeval
1479

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

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

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

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

1507
    // lastlogx
1508

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

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

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

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

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

1555
    // utmpx
1556

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

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

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

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

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

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

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

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

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

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

1681
    // timeval
1682

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

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

1715
    // lastlog
1716

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

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

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

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

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

1775
    // lastlogx
1776

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

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

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

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

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

1849
    // utmp
1850

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

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

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

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

1913
    // utmpx
1914

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

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

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

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

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

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

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

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

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

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

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

2102
    // lastlog
2103

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

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

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

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

2168
    // utmp
2169

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2471
// freebsd_x8664::utmpx
2472

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

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

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

2552
// linux_arm64aarch64::lastlog
2553

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

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

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

2623
// linux_arm64aarch64::utmpx
2624

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

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

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

2700
// linux_x86::acct
2701

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

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

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

2784
// linux_x86::acct_v3
2785

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

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

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

2870
// linux_x86::lastlog
2871

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

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

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

2941
// linux_x86::utmpx
2942

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

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

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

3024
// netbsd_x8632::acct
3025

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

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

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

3113
// netbsd_x8632::lastlogx
3114

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

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

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

3190
// netbsd_x8632::utmpx
3191

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

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

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

3275
// netbsd_x8664::lastlog
3276

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

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

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

3346
// netbsd_x8664::lastlogx
3347

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

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

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

3419
// netbsd_x8664::utmp
3420

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

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

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

3491
// netbsd_x8664::utmpx
3492

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

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

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

3570
// openbsd_x86::lastlog
3571

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

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

3641
// openbsd_x86::utmp
3642

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

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

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

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

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

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

3729
    const BONUS: Score = 15;
3730

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

6076
    /// Create `String` from known bytes.
6077
    ///
6078
    /// `raw` is `true` means use byte characters as-is.
6079
    /// `raw` is `false` means replace formatting characters or non-printable
6080
    /// characters with pictoral representation (i.e. use
6081
    /// [`byte_to_char_noraw`]).
6082
    ///
6083
    /// XXX: very inefficient and not always correct! *only* intended to help
6084
    ///      humans visually inspect stderr output.
6085
    ///
6086
    /// [`byte_to_char_noraw`]: crate::debug::printers::byte_to_char_noraw
6087
    // XXX: this function is a lot of tedious work and duplicates
6088
    //      `fmt::Debug` and `as_bytes()`; consider removing it
6089
    #[doc(hidden)]
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
    /// `FixedStruct` to `String`.
6103
    #[doc(hidden)]
6104
    #[allow(non_snake_case)]
6105
    #[cfg(any(debug_assertions, test))]
6106
    pub fn to_String_raw(self: &FixedStruct) -> String
×
6107
    {
6108
        self.impl_to_string_raw(true)
×
6109
    }
×
6110

6111
    /// `FixedStruct` to `String` but using printable chars for
6112
    /// non-printable and/or formatting characters.
6113
    #[doc(hidden)]
6114
    #[cfg(any(debug_assertions, test))]
6115
    pub fn to_string_noraw(self: &FixedStruct) -> String
1✔
6116
    {
6117
        self.impl_to_string_raw(false)
1✔
6118
    }
1✔
6119
}
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