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

jtmoon79 / super-speedy-syslog-searcher / 17700737642

13 Sep 2025 06:55PM UTC coverage: 57.925% (+0.02%) from 57.903%
17700737642

push

github

jtmoon79
(TOOLS) cargo fmt use nightly

11940 of 20613 relevant lines covered (57.92%)

22056.21 hits per line

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

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

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

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

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

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

50
#[doc(hidden)]
51
use crate::common::{
52
    max16,
53
    min16,
54
    FileOffset,
55
    FileSz,
56
    FileTypeFixedStruct,
57
};
58
use crate::data::datetime::{
59
    DateTimeL,
60
    FixedOffset,
61
    LocalResult,
62
    TimeZone,
63
};
64
#[cfg(any(debug_assertions, test))]
65
use crate::debug::printers::byte_to_char_noraw;
66
use crate::readers::blockreader::{
67
    BlockOffset,
68
    BlockReader,
69
    BlockSz,
70
};
71
use crate::readers::helpers::is_empty;
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 {
3,161✔
261
        match self {
3,161✔
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,
662✔
266
            FixedStructType::Fs_Linux_x86_Acct_v3 => linux_x86::ACCT_V3_SZ,
662✔
267
            FixedStructType::Fs_Linux_x86_Lastlog => linux_x86::LASTLOG_SZ,
52✔
268
            FixedStructType::Fs_Linux_x86_Utmpx => linux_x86::UTMPX_SZ,
1,017✔
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,
734✔
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
    }
3,161✔
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 {
120✔
284
        match self {
120✔
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,
113✔
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
    }
120✔
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 {
397✔
307
        match self {
397✔
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,
383✔
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
    }
397✔
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> {
277✔
330
        defn!("type {:?}", self);
277✔
331
        let tv_sec: tv_sec_type;
332
        let tv_usec: tv_usec_type;
333
        let size = self.size_tv();
277✔
334
        match self {
277✔
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);
270✔
365
                defo_tv_pair!(tv_sec, tv_usec);
270✔
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);
277✔
411
        defx!("return Some({:?})", tv_pair);
277✔
412

413
        Some(tv_pair)
277✔
414
    }
277✔
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
    use ::memoffset::offset_of;
436
    use ::const_format::assertcp_eq;
437

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

442
    // utmpx
443

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

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

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

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

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

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

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

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

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

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

613
    // timeval
614

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

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

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

639
    // lastlog
640

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

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

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

674
    // utmp == utmpx
675

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

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

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

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

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

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

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

887
    pub const ACCT_COMM: usize = 16;
888

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

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

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

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

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

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

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

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

1118
    // lastlog
1119

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

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

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

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

1159
    // utmp
1160

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

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

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

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

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

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

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

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

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

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

1367
    // acct
1368

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

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

1377
    pub const ACCT_COMM_SIZE: usize = 16;
1378

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

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

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

1476
    // timeval
1477

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

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

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

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

1505
    // lastlogx
1506

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

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

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

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

1544
    impl lastlogx {
1545
        pub fn ll_line(&self) -> &CStr {
5✔
1546
            unsafe { CStr::from_ptr(self.ll_line[..UTX_LINESIZE].as_ptr()) }
5✔
1547
        }
5✔
1548
        pub fn ll_host(&self) -> &CStr {
5✔
1549
            unsafe { CStr::from_ptr(self.ll_host[..UTX_HOSTSIZE].as_ptr()) }
5✔
1550
        }
5✔
1551
    }
1552

1553
    // utmpx
1554

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

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

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

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

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

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

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

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

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

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

1679
    // timeval
1680

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

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

1713
    // lastlog
1714

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

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

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

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

1764
    impl lastlog {
1765
        pub fn ll_line(&self) -> &CStr {
235✔
1766
            unsafe { CStr::from_ptr(self.ll_line[..UT_LINESIZE].as_ptr()) }
235✔
1767
        }
235✔
1768
        pub fn ll_host(&self) -> &CStr {
235✔
1769
            unsafe { CStr::from_ptr(self.ll_host[..UT_HOSTSIZE].as_ptr()) }
235✔
1770
        }
235✔
1771
    }
1772

1773
    // lastlogx
1774

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

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

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

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

1838
    impl lastlogx {
1839
        pub fn ll_line(&self) -> &CStr {
2✔
1840
            unsafe { CStr::from_ptr(self.ll_line[..UTX_LINESIZE].as_ptr()) }
2✔
1841
        }
2✔
1842
        pub fn ll_host(&self) -> &CStr {
2✔
1843
            unsafe { CStr::from_ptr(self.ll_host[..UTX_HOSTSIZE].as_ptr()) }
2✔
1844
        }
2✔
1845
    }
1846

1847
    // utmp
1848

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

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

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

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

1911
    // utmpx
1912

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

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

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

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

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

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

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

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

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

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

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

2100
    // lastlog
2101

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

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

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

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

2166
    // utmp
2167

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2469
// freebsd_x8664::utmpx
2470

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

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

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

2550
// linux_arm64aarch64::lastlog
2551

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

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

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

2621
// linux_arm64aarch64::utmpx
2622

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

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

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

2698
// linux_x86::acct
2699

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

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

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

2782
// linux_x86::acct_v3
2783

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

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

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

2868
// linux_x86::lastlog
2869

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

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

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

2939
// linux_x86::utmpx
2940

2941
impl FixedStructTrait for linux_x86::utmpx {
2942
    fn fixedstruct_type(&self) -> FixedStructType {
1,789✔
2943
        FixedStructType::Fs_Linux_x86_Utmpx
1,789✔
2944
    }
1,789✔
2945
    fn size(&self) -> usize {
1,316✔
2946
        linux_x86::UTMPX_SZ
1,316✔
2947
    }
1,316✔
2948

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

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

3022
// netbsd_x8632::acct
3023

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

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

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

3111
// netbsd_x8632::lastlogx
3112

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

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

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

3188
// netbsd_x8632::utmpx
3189

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

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

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

3273
// netbsd_x8664::lastlog
3274

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

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

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

3344
// netbsd_x8664::lastlogx
3345

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

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

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

3417
// netbsd_x8664::utmp
3418

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

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

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

3489
// netbsd_x8664::utmpx
3490

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

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

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

3568
// openbsd_x86::lastlog
3569

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

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

3639
// openbsd_x86::utmp
3640

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

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

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

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

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

3725
    let mut set = FixedStructTypeSet::new();
128✔
3726

3727
    const BONUS: Score = 15;
3728

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

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

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

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

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

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

3848
    Some(set)
128✔
3849
}
128✔
3850

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

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

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

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

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

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

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

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

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

4054
/// Convert [`DateTimeL`] instance to [`tv_sec_type`] and [`tv_usec_type`].
4055
///
4056
/// Return `Error` if `tv_sec` conversion fails.
4057
pub fn convert_datetime_tvpair(
97✔
4058
    dt: &DateTimeL,
97✔
4059
) -> tv_pair_type {
97✔
4060
    let tv_sec: tv_sec_type = dt.timestamp();
97✔
4061
    let tv_usec: tv_usec_type = match dt.timestamp_subsec_micros().try_into() {
97✔
4062
        Ok(val) => val,
97✔
4063
        Err(_err) => {
4064
            de_wrn!(
4065
                "failed to convert subsec_micros {} to tv_usec_type: {}",
4066
                dt.timestamp_subsec_micros(), _err,
4067
            );
4068
            // ignore overflow and continue; `tv_usec` merely supplements
4069
            // the more coarse `tv_sec`
4070
            0
4071
        }
4072
    };
4073

4074
    tv_pair_type(tv_sec, tv_usec)
97✔
4075
}
97✔
4076

4077
#[cfg(any(debug_assertions, test))]
4078
fn struct_field_to_string(buffer: &[u8], offset: usize, sz: usize) -> String {
11,828✔
4079
    let mut s = String::with_capacity(sz);
11,828✔
4080
    for i in offset..(offset + sz) {
141,735✔
4081
        s.push(byte_to_char_noraw(buffer[i]));
141,735✔
4082
    }
141,735✔
4083

4084
    s
11,828✔
4085
}
11,828✔
4086

4087
/// Helper to [`buffer_to_fixedstructptr`]
4088
/// [`deo!`] for the `$field`
4089
#[cfg(any(debug_assertions, test))]
4090
macro_rules! deo_field_dump {
4091
    ($as_fixedstruct:expr, $field: ident, $buffer: ident) => ({{
4092
        let fs = $as_fixedstruct;
4093

4094
        let base_ptr_offset: usize = std::ptr::addr_of!(*fs) as usize;
4095
        let field_ptr = std::ptr::addr_of!(fs.$field);
4096
        let field_offset = field_ptr as usize - base_ptr_offset;
4097
        let field_sz = std::mem::size_of_val(&fs.$field);
4098
        let field_offset_end = field_offset + field_sz;
4099
        let field_val_string = struct_field_to_string($buffer, field_offset, field_sz);
4100
        let field_name = stringify!($field);
4101

4102
        deo!("{:<20}: {:3}‥{:3} @{:p} | {}",
4103
             field_name, field_offset, field_offset_end, field_ptr, field_val_string);
4104
    }})
4105
}
4106

4107
/// Helper to [`buffer_to_fixedstructptr`]
4108
/// [`deo!`] for the `$field`
4109
#[cfg(any(debug_assertions, test))]
4110
macro_rules! deo_field_dump_num {
4111
    ($as_fixedstruct:expr, $field: ident, $buffer: ident, $typ: ty) => ({{
4112
        let fs = $as_fixedstruct;
4113
        let field_sz = std::mem::size_of_val(&fs.$field);
4114
        deo_field_dump_num_impl!(fs, $field, field_sz, $buffer, $typ);
4115
    }})
4116
}
4117

4118
/// Helper to [`buffer_to_fixedstructptr`]
4119
/// [`deo!`] for the `$field`
4120
///
4121
/// Useful for `packed` structs that cannot be referenced in a macro as
4122
/// `size_of_val!(struct.field)` (like in macro [`deo_field_dump_num`]).
4123
#[cfg(any(debug_assertions, test))]
4124
macro_rules! deo_field_dump_num_szof {
4125
    ($as_fixedstruct:expr, $field: ident, $buffer: ident, $typ: ty) => ({{
4126
        let fs = $as_fixedstruct;
4127
        let field_sz = std::mem::size_of::<$typ>();
4128
        deo_field_dump_num_impl!(fs, $field, field_sz, $buffer, $typ);
4129
    }})
4130
}
4131

4132
/// Helper to [`buffer_to_fixedstructptr`]
4133
/// [`deo!`] for the `$field`
4134
#[cfg(any(debug_assertions, test))]
4135
macro_rules! deo_field_dump_num_impl {
4136
    ($as_fixedstruct:expr, $field: ident, $field_sz: expr, $buffer: ident, $typ: ty) => ({{
4137
        let fs = $as_fixedstruct;
4138

4139
        let base_ptr_offset: usize = std::ptr::addr_of!(*fs) as usize;
4140
        let field_ptr = std::ptr::addr_of!(fs.$field);
4141
        let field_offset = field_ptr as usize - base_ptr_offset;
4142
        let field_offset_end = field_offset + $field_sz;
4143
        let field_val_string = struct_field_to_string($buffer, field_offset, $field_sz);
4144
        let field_name = stringify!($field);
4145
        let value: $typ = fs.$field;
4146

4147
        deo!("{:<20}: {:3}‥{:3} @{:p} | {:<20} 0x{:08X}",
4148
             field_name, field_offset, field_offset_end, field_ptr,
4149
             field_val_string, value);
4150
    }})
4151
}
4152

4153
/// Convert `[u8]` bytes to a [`FixedStructDynPtr`] instance specified by
4154
/// `fixedstructtype`.
4155
///
4156
/// A `buffer` of only null bytes (zero values) will return `None`.
4157
/// A `buffer` of only 0xFF bytes will return `None`.
4158
///
4159
/// unsafe.
4160
pub fn buffer_to_fixedstructptr(buffer: &[u8], fixedstructtype: FixedStructType) -> Option<FixedStructDynPtr>
1,147✔
4161
{
4162
    defn!("(buffer len {:?}, fixedstructtype {:?})", buffer.len(), fixedstructtype);
1,147✔
4163

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

4323
    #[cfg(any(debug_assertions, test))]
4324
    match fixedstructtype {
990✔
4325
        // print struct member offsets and bytes
4326
        // `addr_of!` used here due to unaligned references being a warning:
4327
        // credit https://stackoverflow.com/a/26271748/471376
4328
        FixedStructType::Fs_Freebsd_x8664_Utmpx => {
4✔
4329
            let utmpx: &freebsd_x8664::utmpx = entry.as_freebsd_x8664_utmpx();
4✔
4330

4✔
4331
            deo!("freebsd_x8664::utmpx offsets and bytes, size {}", utmpx.size());
4✔
4332
            deo_field_dump_num!(utmpx, ut_type, buffer, freebsd_x8664::c_short);
4✔
4333
            deo_field_dump!(utmpx, ut_tv, buffer);
4✔
4334
            deo_field_dump!(utmpx, ut_id, buffer);
4✔
4335
            deo_field_dump_num!(utmpx, ut_pid, buffer, freebsd_x8664::pid_t);
4✔
4336
            deo_field_dump!(utmpx, ut_user, buffer);
4✔
4337
            deo_field_dump!(utmpx, ut_line, buffer);
4✔
4338
            deo_field_dump!(utmpx, ut_host, buffer);
4✔
4339
            deo_field_dump!(utmpx, __ut_spare, buffer);
4✔
4340
        }
4✔
4341
        FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => {
3✔
4342
            let lastlog: &linux_arm64aarch64::lastlog = entry.as_linux_arm64aarch64_lastlog();
3✔
4343

3✔
4344
            deo!("linux_arm64aarch64::lastlog offsets and bytes, size {}", lastlog.size());
3✔
4345
            deo_field_dump_num!(lastlog, ll_time, buffer, linux_arm64aarch64::ll_time_t);
3✔
4346
            deo_field_dump!(lastlog, ll_line, buffer);
3✔
4347
            deo_field_dump!(lastlog, ll_host, buffer);
3✔
4348
        }
3✔
4349
        FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => {
3✔
4350
            let utmpx: &linux_arm64aarch64::utmpx = entry.as_linux_arm64aarch64_utmpx();
3✔
4351

3✔
4352
            deo!("linux_arm64aarch64::utmpx offsets and bytes, size {}", utmpx.size());
3✔
4353
            deo_field_dump_num!(utmpx, ut_type, buffer, linux_arm64aarch64::c_short);
3✔
4354
            deo_field_dump_num!(utmpx, ut_pid, buffer, linux_arm64aarch64::pid_t);
3✔
4355
            deo_field_dump!(utmpx, ut_line, buffer);
3✔
4356
            deo_field_dump!(utmpx, ut_id, buffer);
3✔
4357
            deo_field_dump!(utmpx, ut_user, buffer);
3✔
4358
            deo_field_dump!(utmpx, ut_host, buffer);
3✔
4359
            deo_field_dump_num!(utmpx, ut_exit, buffer, i32);
3✔
4360
            deo_field_dump_num!(utmpx, ut_session, buffer, i64);
3✔
4361
            deo_field_dump!(utmpx, ut_tv, buffer);
3✔
4362
            deo_field_dump!(utmpx, ut_addr_v6, buffer);
3✔
4363
            deo_field_dump!(utmpx, __glibc_reserved, buffer);
3✔
4364
        }
3✔
4365
        FixedStructType::Fs_Linux_x86_Acct => {
233✔
4366
            let acct: &linux_x86::acct = entry.as_linux_x86_acct();
233✔
4367

233✔
4368
            deo!("linux_x86::acct offsets and bytes, size {}", acct.size());
233✔
4369
            deo_field_dump_num!(acct, ac_flag, buffer, linux_x86::c_char);
233✔
4370
            deo_field_dump_num!(acct, ac_uid, buffer, u16);
233✔
4371
            deo_field_dump_num!(acct, ac_gid, buffer, u16);
233✔
4372
            deo_field_dump_num!(acct, ac_tty, buffer, u16);
233✔
4373
            deo_field_dump_num!(acct, ac_btime, buffer, linux_x86::b_time_t);
233✔
4374
            deo_field_dump_num!(acct, ac_utime, buffer, linux_x86::comp_t);
233✔
4375
            deo_field_dump_num!(acct, ac_stime, buffer, linux_x86::comp_t);
233✔
4376
            deo_field_dump_num!(acct, ac_etime, buffer, linux_x86::comp_t);
233✔
4377
            deo_field_dump_num!(acct, ac_mem, buffer, linux_x86::comp_t);
233✔
4378
            deo_field_dump_num!(acct, ac_io, buffer, linux_x86::comp_t);
233✔
4379
            deo_field_dump_num!(acct, ac_rw, buffer, linux_x86::comp_t);
233✔
4380
            deo_field_dump_num!(acct, ac_minflt, buffer, linux_x86::comp_t);
233✔
4381
            deo_field_dump_num!(acct, ac_majflt, buffer, linux_x86::comp_t);
233✔
4382
            deo_field_dump_num!(acct, ac_swaps, buffer, linux_x86::comp_t);
233✔
4383
            deo_field_dump_num!(acct, ac_exitcode, buffer, u32);
233✔
4384
            deo_field_dump!(acct, ac_comm, buffer);
233✔
4385
        }
233✔
4386
        FixedStructType::Fs_Linux_x86_Acct_v3 => {
233✔
4387
            let acct: &linux_x86::acct_v3 = entry.as_linux_x86_acct_v3();
233✔
4388

233✔
4389
            deo!("linux_x86::acct_v3 offsets and bytes, size {}", acct.size());
233✔
4390
            deo_field_dump_num!(acct, ac_flag, buffer, linux_x86::c_char);
233✔
4391
            deo_field_dump_num!(acct, ac_version, buffer, linux_x86::c_char);
233✔
4392
            deo_field_dump_num!(acct, ac_tty, buffer, u16);
233✔
4393
            deo_field_dump_num!(acct, ac_exitcode, buffer, u32);
233✔
4394
            deo_field_dump_num!(acct, ac_uid, buffer, u32);
233✔
4395
            deo_field_dump_num!(acct, ac_gid, buffer, u32);
233✔
4396
            deo_field_dump_num!(acct, ac_pid, buffer, u32);
233✔
4397
            deo_field_dump_num!(acct, ac_ppid, buffer, u32);
233✔
4398
            deo_field_dump_num!(acct, ac_btime, buffer, linux_x86::b_time_t);
233✔
4399
            deo_field_dump!(acct, ac_etime, buffer);
233✔
4400
            deo_field_dump_num!(acct, ac_utime, buffer, linux_x86::comp_t);
233✔
4401
            deo_field_dump_num!(acct, ac_stime, buffer, linux_x86::comp_t);
233✔
4402
            deo_field_dump_num!(acct, ac_mem, buffer, linux_x86::comp_t);
233✔
4403
            deo_field_dump_num!(acct, ac_io, buffer, linux_x86::comp_t);
233✔
4404
            deo_field_dump_num!(acct, ac_rw, buffer, linux_x86::comp_t);
233✔
4405
            deo_field_dump_num!(acct, ac_minflt, buffer, linux_x86::comp_t);
233✔
4406
            deo_field_dump_num!(acct, ac_majflt, buffer, linux_x86::comp_t);
233✔
4407
            deo_field_dump_num!(acct, ac_swaps, buffer, linux_x86::comp_t);
233✔
4408
            deo_field_dump!(acct, ac_comm, buffer);
233✔
4409
        }
233✔
4410
        FixedStructType::Fs_Linux_x86_Lastlog => {
10✔
4411
            let lastlog: &linux_x86::lastlog = entry.as_linux_x86_lastlog();
10✔
4412

10✔
4413
            deo!("linux_x86::lastlog offsets and bytes, size {}", lastlog.size());
10✔
4414
            deo_field_dump_num!(lastlog, ll_time, buffer, linux_x86::ll_time_t);
10✔
4415
            deo_field_dump!(lastlog, ll_line, buffer);
10✔
4416
            deo_field_dump!(lastlog, ll_host, buffer);
10✔
4417
        }
10✔
4418
        FixedStructType::Fs_Linux_x86_Utmpx => {
247✔
4419
            let utmpx: &linux_x86::utmpx = entry.as_linux_x86_utmpx();
247✔
4420

247✔
4421
            deo!("linux_x86::utmpx offsets and bytes, size {}", utmpx.size());
247✔
4422
            deo_field_dump_num!(utmpx, ut_type, buffer, linux_x86::c_short);
247✔
4423
            deo_field_dump_num!(utmpx, ut_pid, buffer, linux_x86::pid_t);
247✔
4424
            deo_field_dump!(utmpx, ut_line, buffer);
247✔
4425
            deo_field_dump!(utmpx, ut_id, buffer);
247✔
4426
            deo_field_dump!(utmpx, ut_user, buffer);
247✔
4427
            deo_field_dump!(utmpx, ut_host, buffer);
247✔
4428
            deo_field_dump!(utmpx, ut_exit, buffer);
247✔
4429
            deo_field_dump_num!(utmpx, ut_session, buffer, i32);
247✔
4430
            deo_field_dump!(utmpx, ut_tv, buffer);
247✔
4431
            deo_field_dump!(utmpx, ut_addr_v6, buffer);
247✔
4432
            deo_field_dump!(utmpx, __glibc_reserved, buffer);
247✔
4433
        }
247✔
4434
        FixedStructType::Fs_Netbsd_x8632_Acct => {
3✔
4435
            let acct: &netbsd_x8632::acct = entry.as_netbsd_x8632_acct();
3✔
4436

3✔
4437
            deo!("netbsd_x8664::acct offsets and bytes, size {}", acct.size());
3✔
4438
            deo_field_dump!(acct, ac_comm, buffer);
3✔
4439
            deo_field_dump_num_szof!(acct, ac_utime, buffer, netbsd_x8632::comp_t);
3✔
4440
            deo_field_dump_num_szof!(acct, ac_stime, buffer, netbsd_x8632::comp_t);
3✔
4441
            deo_field_dump_num_szof!(acct, ac_etime, buffer, netbsd_x8632::comp_t);
3✔
4442
            deo_field_dump_num_szof!(acct, ac_btime, buffer, netbsd_x8632::time_t);
3✔
4443
            deo_field_dump_num_szof!(acct, ac_uid, buffer, netbsd_x8632::uid_t);
3✔
4444
            deo_field_dump_num_szof!(acct, ac_gid, buffer, netbsd_x8632::gid_t);
3✔
4445
            deo_field_dump_num_szof!(acct, ac_mem, buffer, netbsd_x8632::comp_t);
3✔
4446
            deo_field_dump_num_szof!(acct, ac_io, buffer, netbsd_x8632::comp_t);
3✔
4447
            deo_field_dump_num_szof!(acct, ac_tty, buffer, netbsd_x8632::dev_t);
3✔
4448
            deo_field_dump_num_szof!(acct, ac_flag, buffer, netbsd_x8632::uint8_t);
3✔
4449
        }
3✔
4450
        FixedStructType::Fs_Netbsd_x8632_Lastlogx => {
3✔
4451
            let lastlogx: &netbsd_x8632::lastlogx = entry.as_netbsd_x8632_lastlogx();
3✔
4452

3✔
4453
            deo!("netbsd_x8632::lastlogx offsets and bytes, size {}", lastlogx.size());
3✔
4454
            deo_field_dump!(lastlogx, ll_tv, buffer);
3✔
4455
            deo_field_dump!(lastlogx, ll_line, buffer);
3✔
4456
            deo_field_dump!(lastlogx, ll_host, buffer);
3✔
4457
            deo_field_dump!(lastlogx, ll_ss, buffer);
3✔
4458
        }
3✔
4459
        FixedStructType::Fs_Netbsd_x8632_Utmpx => {
3✔
4460
            let utmpx: &netbsd_x8632::utmpx = entry.as_netbsd_x8632_utmpx();
3✔
4461

3✔
4462
            deo!("netbsd_x8632::utmpx offsets and bytes, size {}", utmpx.size());
3✔
4463
            deo_field_dump!(utmpx, ut_name, buffer);
3✔
4464
            deo_field_dump!(utmpx, ut_id, buffer);
3✔
4465
            deo_field_dump!(utmpx, ut_line, buffer);
3✔
4466
            deo_field_dump!(utmpx, ut_host, buffer);
3✔
4467
            deo_field_dump_num!(utmpx, ut_session, buffer, netbsd_x8632::uint16_t);
3✔
4468
            deo_field_dump_num!(utmpx, ut_type, buffer, netbsd_x8632::uint16_t);
3✔
4469
            deo_field_dump_num!(utmpx, ut_pid, buffer, netbsd_x8632::pid_t);
3✔
4470
            deo_field_dump!(utmpx, ut_exit, buffer);
3✔
4471
            deo_field_dump!(utmpx, ut_ss, buffer);
3✔
4472
            deo_field_dump!(utmpx, ut_tv, buffer);
3✔
4473
            deo_field_dump!(utmpx, ut_pad, buffer);
3✔
4474
        }
3✔
4475
        FixedStructType::Fs_Netbsd_x8664_Lastlog => {
233✔
4476
            let lastlog: &netbsd_x8664::lastlog = entry.as_netbsd_x8664_lastlog();
233✔
4477

233✔
4478
            deo!("netbsd_x8664::lastlog offsets and bytes, size {}", lastlog.size());
233✔
4479
            deo_field_dump_num!(lastlog, ll_time, buffer, netbsd_x8664::time_t);
233✔
4480
            deo_field_dump!(lastlog, ll_line, buffer);
233✔
4481
            deo_field_dump!(lastlog, ll_host, buffer);
233✔
4482
        }
233✔
4483
        FixedStructType::Fs_Netbsd_x8664_Lastlogx => {
3✔
4484
            let lastlogx: &netbsd_x8664::lastlogx = entry.as_netbsd_x8664_lastlogx();
3✔
4485

3✔
4486
            deo!("netbsd_x8664::lastlogx offsets and bytes, size {}", lastlogx.size());
3✔
4487
            deo_field_dump!(lastlogx, ll_tv, buffer);
3✔
4488
            deo_field_dump!(lastlogx, ll_line, buffer);
3✔
4489
            deo_field_dump!(lastlogx, ll_host, buffer);
3✔
4490
            deo_field_dump!(lastlogx, ll_ss, buffer);
3✔
4491
        }
3✔
4492
        FixedStructType::Fs_Netbsd_x8664_Utmp => {
3✔
4493
            let utmp: &netbsd_x8664::utmp = entry.as_netbsd_x8664_utmp();
3✔
4494

3✔
4495
            deo!("netbsd_x8664::utmp offsets and bytes, size {}", utmp.size());
3✔
4496
            deo_field_dump!(utmp, ut_line, buffer);
3✔
4497
            deo_field_dump!(utmp, ut_name, buffer);
3✔
4498
            deo_field_dump!(utmp, ut_host, buffer);
3✔
4499
            deo_field_dump_num!(utmp, ut_time, buffer, netbsd_x8664::time_t);
3✔
4500
        }
3✔
4501
        FixedStructType::Fs_Netbsd_x8664_Utmpx => {
3✔
4502
            let utmpx: &netbsd_x8664::utmpx = entry.as_netbsd_x8664_utmpx();
3✔
4503

3✔
4504
            deo!("netbsd_x8664::utmpx offsets and bytes, size {}", utmpx.size());
3✔
4505
            deo_field_dump!(utmpx, ut_user, buffer);
3✔
4506
            deo_field_dump!(utmpx, ut_id, buffer);
3✔
4507
            deo_field_dump!(utmpx, ut_line, buffer);
3✔
4508
            deo_field_dump!(utmpx, ut_host, buffer);
3✔
4509
            deo_field_dump_num!(utmpx, ut_session, buffer, netbsd_x8664::uint16_t);
3✔
4510
            deo_field_dump_num!(utmpx, ut_type, buffer, netbsd_x8664::uint16_t);
3✔
4511
            deo_field_dump_num!(utmpx, ut_pid, buffer, netbsd_x8664::pid_t);
3✔
4512
            deo_field_dump!(utmpx, ut_exit, buffer);
3✔
4513
            deo_field_dump!(utmpx, ut_tv, buffer);
3✔
4514
            deo_field_dump!(utmpx, ut_pad, buffer);
3✔
4515
        }
3✔
4516
        FixedStructType::Fs_Openbsd_x86_Lastlog => {
3✔
4517
            let lastlog: &openbsd_x86::lastlog = entry.as_openbsd_x86_lastlog();
3✔
4518

3✔
4519
            deo!("openbsd_x86::lastlog offsets and bytes, size {}", lastlog.size());
3✔
4520
            deo_field_dump_num!(lastlog, ll_time, buffer, openbsd_x86::time_t);
3✔
4521
            deo_field_dump!(lastlog, ll_line, buffer);
3✔
4522
            deo_field_dump!(lastlog, ll_host, buffer);
3✔
4523
        }
3✔
4524
        FixedStructType::Fs_Openbsd_x86_Utmp => {
3✔
4525
            let utmp: &openbsd_x86::utmp = entry.as_openbsd_x86_utmp();
3✔
4526

3✔
4527
            deo!("openbsd_x86::utmp offsets and bytes, size {}", utmp.size());
3✔
4528
            deo_field_dump!(utmp, ut_line, buffer);
3✔
4529
            deo_field_dump!(utmp, ut_name, buffer);
3✔
4530
            deo_field_dump!(utmp, ut_host, buffer);
3✔
4531
            deo_field_dump_num!(utmp, ut_time, buffer, openbsd_x86::time_t);
3✔
4532
        }
3✔
4533
    }
4534
    defx!("return entry with fixedstruct_type {:?}",
990✔
4535
          entry.fixedstruct_type());
990✔
4536

4537
    Some(entry)
990✔
4538
}
1,147✔
4539

4540
/// Helper to [`FixedStruct::as_bytes`].
4541
/// Write a byte `b` that is `u8` to the `buffer` at index `at`
4542
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4543
macro_rules! set_buffer_at_or_err_u8 {
4544
    ($buffer:ident, $at:ident, $b:expr) => ({{
4545
        if $at >= $buffer.len() {
4546
            return InfoAsBytes::Fail($at);
4547
        }
4548
        $buffer[$at] = $b;
4549
        $at += 1;
4550
    }})
4551
}
4552

4553
/// Helper to [`FixedStruct::as_bytes`].
4554
/// Write a byte `b` that is `i8` to the `buffer` at index `at`
4555
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4556
macro_rules! set_buffer_at_or_err_i8 {
4557
    ($buffer:ident, $at:ident, $c:expr) => ({{
4558
        let c_: u8 = match ($c).try_into() {
4559
            Ok(val) => val,
4560
            Err(_) => 0,
4561
        };
4562
        set_buffer_at_or_err_u8!($buffer, $at, c_);
4563
    }})
4564
}
4565

4566
/// Helper to [`FixedStruct::as_bytes`].
4567
/// Write a byte `b` that is `&[u8]` to the `buffer` at index `at`
4568
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4569
macro_rules! set_buffer_at_or_err_u8_array {
4570
    ($buffer:ident, $at:ident, $b:expr) => ({{
4571
        for b_ in $b.iter() {
4572
            set_buffer_at_or_err_u8!($buffer, $at, *b_);
4573
        }
4574
    }})
4575
}
4576

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

4588
/// Helper to [`FixedStruct::as_bytes`].
4589
/// Write a `string_` to the `buffer` starting `at` the given index.
4590
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4591
macro_rules! set_buffer_at_or_err_string {
4592
    ($buffer:ident, $at:ident, $string_:expr) => ({{
4593
        for b_ in $string_.as_bytes() {
4594
            set_buffer_at_or_err_u8!($buffer, $at, *b_);
4595
        }
4596
    }})
4597
}
4598

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

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

4638
/// Helper to [`FixedStruct::as_bytes`].
4639
/// Write the `ut_type` that is `i16` 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_i16 {
4642
    ($buffer:ident, $at:ident, $ut_type:expr) => ({{
4643
        set_buffer_at_or_err_ut_type!($buffer, $at, $ut_type, i16, UT_TYPE_VAL_TO_STR_LEN_i16)
4644
    }})
4645
}
4646

4647
/// Helper to [`FixedStruct::as_bytes`].
4648
/// Write the `ut_type` that is `u16` to the `buffer` at index `at`.
4649
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4650
macro_rules! set_buffer_at_or_err_ut_type_u16 {
4651
    ($buffer:ident, $at:ident, $ut_type:expr) => ({{
4652
        set_buffer_at_or_err_ut_type!($buffer, $at, $ut_type, u16, UT_TYPE_VAL_TO_STR_LEN_u16)
4653
    }})
4654
}
4655

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

4674
/// Helper to [`FixedStruct::as_bytes`].
4675
/// Write the `number` value of type `i64` into `buffer` at index `at`.
4676
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4677
macro_rules! set_buffer_at_or_err_number_f32 {
4678
    ($buffer:ident, $at:ident, $number:expr, $type_:ty) => ({{
4679
        // XXX: copy to local variable to avoid packed warning
4680
        let num = $number;
4681
        let number_string = format!("{}", num);
4682
        set_buffer_at_or_err_string!($buffer, $at, number_string);
4683
    }})
4684
}
4685

4686
/// Helper to [`FixedStruct::as_bytes`].
4687
/// Write the `number` value of type `i64` into `buffer` at index `at`.
4688
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4689
macro_rules! set_buffer_at_or_err_number_bin4 {
4690
    ($buffer:ident, $at:ident, $number:expr, $type_:ty) => ({{
4691
        let number_string = format!("0b{:04b}", $number);
4692
        set_buffer_at_or_err_string!($buffer, $at, number_string);
4693
    }})
4694
}
4695

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

4716
/// Helper to [`FixedStruct::as_bytes`].
4717
/// Write the `number`that is an IPv6 address into `buffer` at index `at`.
4718
/// If the index is out of bounds, return `InfoAsBytes::Fail`.
4719
macro_rules! set_buffer_at_or_err_ipv6 {
4720
    ($buffer:ident, $at:ident, $value:expr) => ({{
4721
        for b_ in format!("{:X}:{:X}:{:X}:{:X}",
4722
            &$value[0],
4723
            &$value[1],
4724
            &$value[2],
4725
            &$value[3],
4726
        ).as_str().bytes() {
4727
            set_buffer_at_or_err_u8!($buffer, $at, b_);
4728
        }
4729
    }})
4730
}
4731

4732
/// Helper to [`FixedStruct::from_fixedstructptr`]
4733
macro_rules! tv_or_err_tv_sec {
4734
    ($fixedstructptr: ident, $tv_sec: expr) => ({{
4735
        match $tv_sec.try_into() {
4736
            Ok(val) => val,
4737
            Err(err) => {
4738
                let err_str = format!(
4739
                    "{} failed to convert tv_sec {:?}; {}",
4740
                    stringify!($tv_sec), $tv_sec, err
4741
                );
4742
                de_err!("{}", err_str);
4743
                defx!("return Err {}", err);
4744
                return Result::Err(
4745
                    Error::new(ErrorKind::InvalidData, err_str)
4746
                );
4747
            }
4748
        }
4749
    }})
4750
}
4751

4752
/// Helper to [`FixedStruct::from_fixedstructptr`]
4753
macro_rules! tv_to_datetime_or_err {
4754
    ($tv_sec: ident, $tv_usec: ident, $tz_offset: ident) => ({{
4755
        match convert_tvpair_to_datetime(tv_pair_type($tv_sec, $tv_usec), $tz_offset) {
4756
            Ok(dt) => dt,
4757
            Err(err) => {
4758
                // `convert_tvpair_to_datetime` should have already debug printed an error
4759
                // so don't `de_err!` here
4760
                defx!("return Err {}", err);
4761
                return Result::Err(err);
4762
            }
4763
        }
4764
    }})
4765
}
4766

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

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

4819
/// Helper to [`FixedStruct::score_fixedstruct`]
4820
/// Increase score if the last byte of the buffer is null.
4821
/// Decrease score if the last byte of the buffer is not null.
4822
macro_rules! score_fixedstruct_cstr_null_terminator {
4823
    ($score:ident, $buffer:expr) => {{
4824
        if let Some(b) = $buffer.iter().nth($buffer.len() - 1) {
4825
            if *b == 0 {
4826
                $score += 10;
4827
            } else {
4828
                $score -= 10;
4829
            }
4830
        }
4831
        defo!(
4832
            "score_fixedstruct_cstr_null_terminator ({}): score={}",
4833
            stringify!($buffer), $score
4834
        );
4835
    }};
4836
}
4837

4838
/// Helper to [`FixedStruct::score_fixedstruct`]
4839
/// Increase score if all bytes are null.
4840
/// Decrease score if any bytes are not null.
4841
macro_rules! score_fixedstruct_buffer_all_null {
4842
    ($score:ident, $buffer:expr) => {{
4843
        let mut all_zero: bool = true;
4844
        if let Some(b) = $buffer.iter().nth($buffer.len() - 1) {
4845
            if *b != 0 {
4846
                $score -= 4;
4847
                all_zero = false;
4848
            }
4849
        }
4850
        if all_zero && $buffer.len() > 0 {
4851
            $score += 10;
4852
        }
4853
        defo!(
4854
            "score_fixedstruct_buffer_all_null ({}): score={}",
4855
            stringify!($buffer), $score
4856
        );
4857
    }};
4858
}
4859

4860
/// Helper to [`FixedStruct::score_fixedstruct`]
4861
/// Increase score if the value is not zero.
4862
/// Decrease score if the value is zero.
4863
macro_rules! score_fixedstruct_value_not_zero {
4864
    ($score:ident, $value:expr) => {{
4865
        if $value != 0 {
4866
            $score += 10;
4867
        } else {
4868
            $score -= 10;
4869
        }
4870
        defo!(
4871
            "score_fixedstruct_value_not_zero ({}): score={}",
4872
            stringify!($value), $score
4873
        );
4874
    }};
4875
}
4876

4877
/// Helper to [`FixedStruct::score_fixedstruct`]
4878
/// Increase score if the ut_type is a valid value.
4879
/// Decrease score if the ut_type is a invalid value.
4880
macro_rules! score_fixedstruct_ut_type {
4881
    ($score:ident, $value:expr, $ut_types:expr) => {{
4882
        for ut_type in $ut_types {
4883
            if $value == ut_type {
4884
                $score += 5;
4885
                if $value != 0 {
4886
                    $score += 10;
4887
                }
4888
                break;
4889
            }
4890
        }
4891
        defo!(
4892
            "score_fixedstruct_ut_type ({}): score={}",
4893
            stringify!($value), $score
4894
        );
4895
    }};
4896
}
4897

4898
/// Helper to [`FixedStruct::score_fixedstruct`]
4899
/// Increase score if the bits are valid flag(s).
4900
/// Decrease score if the bits are invalid flag(s).
4901
macro_rules! score_fixedstruct_ac_flags {
4902
    ($score:ident, $value:expr, $flags:expr) => {{
4903
        if $value == 0 {
4904
            $score += 2;
4905
        } else if (!$flags) & $value != 0 {
4906
            $score -= 30;
4907
        } else {
4908
            $score += 5;
4909
        }
4910
        defo!(
4911
            "score_fixedstruct_ac_flags ({}): score={} (value=0b{:08b}, flags=0b{:08b})",
4912
            stringify!($value), $score, $value, $flags
4913
        );
4914
    }};
4915
}
4916

4917
/// Datetime _2000-01-01 00:00:00_ is a reasonable past datetime to expect for
4918
/// FixedStruct files.
4919
/// Helper to [`score_fixedstruct_time_range`].
4920
///
4921
/// **TODO:** when were utmp/lastlog/etc. structs first introduced?
4922
const EPOCH_SECOND_LOW: tv_sec_type = 946684800;
4923

4924
/// Datetime _2038-01-19 03:14:06_ is a reasonable high datetime to expect for
4925
/// FixedStruct files.
4926
/// Helper to [`score_fixedstruct_time_range`].
4927
const EPOCH_SECOND_HIGH: tv_sec_type = 2147483647;
4928

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

4942
                0
4943
            }
4944
        };
4945
        if EPOCH_SECOND_LOW <= value_as && value_as <= EPOCH_SECOND_HIGH {
4946
            $score += 20;
4947
        } else {
4948
            $score -= 30;
4949
        }
4950
        if value_as == 0 {
4951
            $score -= 40;
4952
        }
4953
        defo!(
4954
            "score_fixedstruct_time_range ({}): score={}",
4955
            stringify!($value), $score
4956
        );
4957
    }};
4958
}
4959

4960
impl FixedStruct
4961
{
4962
    /// Create a new `FixedStruct`.
4963
    /// The `buffer` is passed to [`buffer_to_fixedstructptr`] which returns
4964
    /// `None` if only null bytes.
4965
    pub fn new(
32✔
4966
        fileoffset: FileOffset,
32✔
4967
        tz_offset: &FixedOffset,
32✔
4968
        buffer: &[u8],
32✔
4969
        fixedstruct_type: FixedStructType,
32✔
4970
    ) -> Result<FixedStruct, Error>
32✔
4971
    {
4972
        defn!();
32✔
4973
        let fs_ptr: FixedStructDynPtr = match buffer_to_fixedstructptr(buffer, fixedstruct_type) {
32✔
4974
            Some(val) => val,
30✔
4975
            None => {
4976
                defx!("buffer_to_fixedstructptr returned None; return None");
2✔
4977
                return Result::Err(
2✔
4978
                    Error::new(
2✔
4979
                        ErrorKind::InvalidData,
2✔
4980
                        "buffer_to_fixedstructptr returned None",
2✔
4981
                    )
2✔
4982
                );
2✔
4983
            }
4984
        };
4985
        defo!("fs_ptr {:?}", fs_ptr);
30✔
4986

4987
        FixedStruct::from_fixedstructptr(fileoffset, tz_offset, fs_ptr)
30✔
4988
    }
32✔
4989

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

5127
    pub fn len(self: &FixedStruct) -> usize
403✔
5128
    {
5129
        self.fixedstructptr.size()
403✔
5130
    }
403✔
5131

5132
    /// Clippy recommends `fn is_empty` since there is a `len()`.
5133
    pub fn is_empty(self: &FixedStruct) -> bool
×
5134
    {
5135
        self.len() == 0
×
5136
    }
×
5137

5138
    /// [`FileOffset`] at beginning of the `FixedStruct` (inclusive).
5139
    ///
5140
    /// [`FileOffset`]: crate::common::FileOffset
5141
    pub const fn fileoffset_begin(self: &FixedStruct) -> FileOffset
850✔
5142
    {
5143
        self.fileoffset
850✔
5144
    }
850✔
5145

5146
    /// [`FileOffset`] at one byte past ending of the `FixedStruct` (exclusive).
5147
    ///
5148
    /// [`FileOffset`]: crate::common::FileOffset
5149
    pub fn fileoffset_end(self: &FixedStruct) -> FileOffset
403✔
5150
    {
5151
        self.fileoffset + (self.len() as FileOffset)
403✔
5152
    }
403✔
5153

5154
    /// First [`BlockOffset`] of underlying [`Block`s] for the given
5155
    /// [`BlockSz`].
5156
    ///
5157
    /// [`BlockOffset`]: crate::readers::blockreader::BlockOffset
5158
    /// [`Block`s]: crate::readers::blockreader::Block
5159
    /// [`BlockSz`]: crate::readers::blockreader::BlockSz
5160
    pub const fn blockoffset_begin(&self, blocksz: BlockSz) -> BlockOffset {
267✔
5161
        BlockReader::block_offset_at_file_offset(
267✔
5162
            self.fileoffset_begin(),
267✔
5163
            blocksz
267✔
5164
        )
5165
    }
267✔
5166

5167
    /// Last [`BlockOffset`] of underlying [`Block`s] for the given
5168
    /// [`BlockSz`] (inclusive).
5169
    ///
5170
    /// [`BlockOffset`s]: crate::readers::blockreader::BlockOffset
5171
    /// [`Block`s]: crate::readers::blockreader::Block
5172
    /// [`BlockSz`]: crate::readers::blockreader::BlockSz
5173
    pub fn blockoffset_end(&self, blocksz: BlockSz) -> BlockOffset {
267✔
5174
        BlockReader::block_offset_at_file_offset(
267✔
5175
            self.fileoffset_end(),
267✔
5176
            blocksz
267✔
5177
        )
5178
    }
267✔
5179

5180
    /// Return a reference to [`self.dt`].
5181
    ///
5182
    /// [`self.dt`]: FixedStruct::dt
5183
    pub const fn dt(self: &FixedStruct) -> &DateTimeL
161✔
5184
    {
5185
        &self.dt
161✔
5186
    }
161✔
5187

5188
    /// Return a reference to [`self.tv_pair`].
5189
    ///
5190
    /// [`self.tv_pair`]: FixedStruct::tv_pair
5191
    pub const fn tv_pair(self: &FixedStruct) -> &tv_pair_type
1✔
5192
    {
5193
        &self.tv_pair
1✔
5194
    }
1✔
5195

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

5230
                score_fixedstruct_cstr!(score, utmpx.ut_line());
3✔
5231
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_line);
3✔
5232

5233
                score_fixedstruct_cstr!(score, utmpx.ut_host());
3✔
5234
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_host);
3✔
5235
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_host);
3✔
5236

5237
                score_fixedstruct_time_range!(score, utmpx.ut_tv.tv_sec);
3✔
5238

5239
                score_fixedstruct_buffer_all_null!(score, utmpx.__ut_spare);
3✔
5240

5241
                score_fixedstruct_ut_type!(score, utmpx.ut_type, freebsd_x8664::UT_TYPES);
12✔
5242
            }
5243
            FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => {
5244
                let lastlog: &linux_arm64aarch64::lastlog = fixedstructptr.as_linux_arm64aarch64_lastlog();
2✔
5245

5246
                score_fixedstruct_cstr!(score, lastlog.ll_line());
2✔
5247
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_line);
2✔
5248

5249
                score_fixedstruct_cstr!(score, lastlog.ll_host());
2✔
5250
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_host);
2✔
5251
                score_fixedstruct_cstr_null_terminator!(score, lastlog.ll_host);
2✔
5252

5253
                score_fixedstruct_time_range!(score, lastlog.ll_time);
2✔
5254
            }
5255
            FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => {
5256
                let utmpx: &linux_arm64aarch64::utmpx = fixedstructptr.as_linux_arm64aarch64_utmpx();
2✔
5257

5258
                score_fixedstruct_cstr!(score, utmpx.ut_line());
2✔
5259
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_line);
2✔
5260

5261
                score_fixedstruct_cstr!(score, utmpx.ut_user());
2✔
5262
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_user);
2✔
5263

5264
                score_fixedstruct_cstr!(score, utmpx.ut_host());
2✔
5265
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_host);
2✔
5266
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_host);
2✔
5267

5268
                score_fixedstruct_time_range!(score, utmpx.ut_tv.tv_sec);
2✔
5269

5270
                score_fixedstruct_buffer_all_null!(score, utmpx.__glibc_reserved);
2✔
5271

5272
                score_fixedstruct_ut_type!(score, utmpx.ut_type, linux_arm64aarch64::UT_TYPES);
6✔
5273
            }
5274
            FixedStructType::Fs_Linux_x86_Acct => {
5275
                let acct: &linux_x86::acct = fixedstructptr.as_linux_x86_acct();
232✔
5276

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

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

5282
                score_fixedstruct_buffer_all_null!(score, acct.ac_pad);
232✔
5283

5284
                score_fixedstruct_ac_flags!(score, acct.ac_flag, linux_x86::AC_FLAGS_MASK);
232✔
5285
            }
5286
            FixedStructType::Fs_Linux_x86_Acct_v3 => {
5287
                let acct: &linux_x86::acct_v3 = fixedstructptr.as_linux_x86_acct_v3();
232✔
5288

5289
                score_fixedstruct_cstr!(score, acct.ac_comm());
232✔
5290
                score_fixedstruct_cstr_no_data_after_null!(score, acct.ac_comm);
232✔
5291

5292
                score_fixedstruct_time_range!(score, acct.ac_btime);
232✔
5293

5294
                score_fixedstruct_value_not_zero!(score, acct.ac_version);
232✔
5295

5296
                score_fixedstruct_ac_flags!(score, acct.ac_flag, linux_x86::AC_FLAGS_MASK);
232✔
5297
            }
5298
            FixedStructType::Fs_Linux_x86_Lastlog => {
5299
                let lastlog: &linux_x86::lastlog = fixedstructptr.as_linux_x86_lastlog();
9✔
5300

5301
                score_fixedstruct_time_range!(score, lastlog.ll_time);
9✔
5302

5303
                score_fixedstruct_cstr!(score, lastlog.ll_line());
9✔
5304
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_line);
9✔
5305

5306
                score_fixedstruct_cstr!(score, lastlog.ll_host());
9✔
5307
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_host);
9✔
5308
                score_fixedstruct_cstr_null_terminator!(score, lastlog.ll_host);
9✔
5309
            }
5310
            FixedStructType::Fs_Linux_x86_Utmpx => {
5311
                let utmpx: &linux_x86::utmpx = fixedstructptr.as_linux_x86_utmpx();
216✔
5312

5313
                score_fixedstruct_cstr!(score, utmpx.ut_line());
216✔
5314
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_line);
216✔
5315

5316
                score_fixedstruct_cstr!(score, utmpx.ut_id());
216✔
5317
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_id);
216✔
5318

5319
                score_fixedstruct_cstr!(score, utmpx.ut_user());
216✔
5320
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_user);
216✔
5321
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_user);
216✔
5322

5323
                score_fixedstruct_cstr!(score, utmpx.ut_host());
216✔
5324
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_host);
216✔
5325
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_host);
216✔
5326

5327
                score_fixedstruct_time_range!(score, utmpx.ut_tv.tv_sec);
216✔
5328

5329
                score_fixedstruct_buffer_all_null!(score, utmpx.__glibc_reserved);
216✔
5330

5331
                score_fixedstruct_ut_type!(score, utmpx.ut_type, linux_x86::UT_TYPES);
1,550✔
5332
            }
5333
            FixedStructType::Fs_Netbsd_x8632_Acct => {
5334
                let acct: &netbsd_x8632::acct = fixedstructptr.as_netbsd_x8632_acct();
2✔
5335

5336
                score_fixedstruct_cstr!(score, acct.ac_comm());
2✔
5337
                score_fixedstruct_cstr_no_data_after_null!(score, acct.ac_comm);
2✔
5338

5339
                score_fixedstruct_time_range!(score, acct.ac_btime);
2✔
5340

5341
                score_fixedstruct_buffer_all_null!(score, acct.__gap1);
2✔
5342
                score_fixedstruct_buffer_all_null!(score, acct.__gap3);
2✔
5343

5344
                score_fixedstruct_ac_flags!(score, acct.ac_flag, netbsd_x8632::AC_FLAGS_MASK);
2✔
5345
            }
5346
            FixedStructType::Fs_Netbsd_x8632_Lastlogx => {
5347
                let lastlogx: &netbsd_x8632::lastlogx = fixedstructptr.as_netbsd_x8632_lastlogx();
2✔
5348

5349
                score_fixedstruct_cstr!(score, lastlogx.ll_line());
2✔
5350
                score_fixedstruct_cstr_no_data_after_null!(score, lastlogx.ll_line);
2✔
5351

5352
                score_fixedstruct_cstr!(score, lastlogx.ll_host());
2✔
5353
                score_fixedstruct_cstr_no_data_after_null!(score, lastlogx.ll_host);
2✔
5354
                score_fixedstruct_cstr_null_terminator!(score, lastlogx.ll_host);
2✔
5355

5356
                score_fixedstruct_time_range!(score, lastlogx.ll_tv.tv_sec);
2✔
5357
            }
5358
            FixedStructType::Fs_Netbsd_x8632_Utmpx => {
5359
                let utmpx: &netbsd_x8632::utmpx = fixedstructptr.as_netbsd_x8632_utmpx();
2✔
5360

5361
                score_fixedstruct_cstr!(score, utmpx.ut_name());
2✔
5362
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_name);
2✔
5363

5364
                score_fixedstruct_cstr!(score, utmpx.ut_id());
2✔
5365
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_id);
2✔
5366

5367
                score_fixedstruct_cstr!(score, utmpx.ut_line());
2✔
5368
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_line);
2✔
5369
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_line);
2✔
5370

5371
                score_fixedstruct_cstr!(score, utmpx.ut_host());
2✔
5372
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_host);
2✔
5373
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_host);
2✔
5374

5375
                score_fixedstruct_time_range!(score, utmpx.ut_tv.tv_sec);
2✔
5376

5377
                score_fixedstruct_buffer_all_null!(score, utmpx.ut_pad);
2✔
5378

5379
                score_fixedstruct_ut_type!(score, utmpx.ut_type, netbsd_x8632::UT_TYPES);
14✔
5380
            }
5381
            FixedStructType::Fs_Netbsd_x8664_Lastlog => {
5382
                let lastlog: &netbsd_x8664::lastlog = fixedstructptr.as_netbsd_x8664_lastlog();
232✔
5383

5384
                score_fixedstruct_cstr!(score, lastlog.ll_line());
232✔
5385
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_line);
232✔
5386

5387
                score_fixedstruct_cstr!(score, lastlog.ll_host());
232✔
5388
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_host);
232✔
5389

5390
                score_fixedstruct_time_range!(score, lastlog.ll_time);
232✔
5391
            }
5392
            FixedStructType::Fs_Netbsd_x8664_Lastlogx => {
5393
                let lastlogx: &netbsd_x8664::lastlogx = fixedstructptr.as_netbsd_x8664_lastlogx();
1✔
5394

5395
                score_fixedstruct_cstr!(score, lastlogx.ll_line());
1✔
5396
                score_fixedstruct_cstr_no_data_after_null!(score, lastlogx.ll_line);
1✔
5397

5398
                score_fixedstruct_cstr!(score, lastlogx.ll_host());
1✔
5399
                score_fixedstruct_cstr_no_data_after_null!(score, lastlogx.ll_host);
1✔
5400
                score_fixedstruct_cstr_null_terminator!(score, lastlogx.ll_host);
1✔
5401

5402
                score_fixedstruct_time_range!(score, lastlogx.ll_tv.tv_sec);
1✔
5403
            }
5404
            FixedStructType::Fs_Netbsd_x8664_Utmp => {
5405
                let utmp: &netbsd_x8664::utmp = fixedstructptr.as_netbsd_x8664_utmp();
2✔
5406

5407
                score_fixedstruct_cstr!(score, utmp.ut_line());
2✔
5408
                score_fixedstruct_cstr_no_data_after_null!(score, utmp.ut_line);
2✔
5409

5410
                score_fixedstruct_cstr!(score, utmp.ut_name());
2✔
5411
                score_fixedstruct_cstr_no_data_after_null!(score, utmp.ut_name);
2✔
5412

5413
                score_fixedstruct_cstr!(score, utmp.ut_host());
2✔
5414
                score_fixedstruct_cstr_no_data_after_null!(score, utmp.ut_host);
2✔
5415
                score_fixedstruct_cstr_null_terminator!(score, utmp.ut_host);
2✔
5416

5417
                score_fixedstruct_time_range!(score, utmp.ut_time);
2✔
5418
            }
5419
            FixedStructType::Fs_Netbsd_x8664_Utmpx => {
5420
                let utmpx: &netbsd_x8664::utmpx = fixedstructptr.as_netbsd_x8664_utmpx();
2✔
5421

5422
                score_fixedstruct_cstr!(score, utmpx.ut_user());
2✔
5423
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_user);
2✔
5424

5425
                score_fixedstruct_cstr!(score, utmpx.ut_id());
2✔
5426
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_id);
2✔
5427

5428
                score_fixedstruct_cstr!(score, utmpx.ut_line());
2✔
5429
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_line);
2✔
5430

5431
                score_fixedstruct_cstr!(score, utmpx.ut_host());
2✔
5432
                score_fixedstruct_cstr_no_data_after_null!(score, utmpx.ut_host);
2✔
5433
                score_fixedstruct_cstr_null_terminator!(score, utmpx.ut_host);
2✔
5434

5435
                score_fixedstruct_time_range!(score, utmpx.ut_tv.tv_sec);
2✔
5436

5437
                score_fixedstruct_buffer_all_null!(score, utmpx.__gap1);
2✔
5438
                score_fixedstruct_buffer_all_null!(score, utmpx.ut_pad);
2✔
5439

5440
                score_fixedstruct_ut_type!(score, utmpx.ut_type, netbsd_x8664::UT_TYPES);
16✔
5441
            }
5442
            FixedStructType::Fs_Openbsd_x86_Lastlog => {
5443
                let lastlog: &openbsd_x86::lastlog = fixedstructptr.as_openbsd_x86_lastlog();
2✔
5444

5445
                score_fixedstruct_time_range!(score, lastlog.ll_time);
2✔
5446

5447
                score_fixedstruct_cstr!(score, lastlog.ll_line());
2✔
5448
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_line);
2✔
5449

5450
                score_fixedstruct_cstr!(score, lastlog.ll_host());
2✔
5451
                score_fixedstruct_cstr_no_data_after_null!(score, lastlog.ll_host);
2✔
5452
                score_fixedstruct_cstr_null_terminator!(score, lastlog.ll_host);
2✔
5453
            }
5454
            FixedStructType::Fs_Openbsd_x86_Utmp => {
5455
                let utmp: &openbsd_x86::utmp = fixedstructptr.as_openbsd_x86_utmp();
2✔
5456

5457
                score_fixedstruct_cstr!(score, utmp.ut_line());
2✔
5458
                score_fixedstruct_cstr_no_data_after_null!(score, utmp.ut_line);
2✔
5459

5460
                score_fixedstruct_cstr!(score, utmp.ut_name());
2✔
5461
                score_fixedstruct_cstr_no_data_after_null!(score, utmp.ut_name);
2✔
5462

5463
                score_fixedstruct_cstr!(score, utmp.ut_host());
2✔
5464
                score_fixedstruct_cstr_no_data_after_null!(score, utmp.ut_host);
2✔
5465
                score_fixedstruct_cstr_null_terminator!(score, utmp.ut_host);
2✔
5466

5467
                score_fixedstruct_time_range!(score, utmp.ut_time);
2✔
5468
            }
5469
        }
5470

5471
        defx!("return score {}", score);
943✔
5472

5473
        score
943✔
5474
    }
943✔
5475

5476
    /// Efficient function to copy the `FixedStruct` into a single re-usable
5477
    /// buffer for printing.
5478
    ///
5479
    /// Copy the `FixedStruct` into the passed `buffer` as printable bytes.
5480
    /// When successful, returns a [`InfoAsBytes::Ok`] variant with
5481
    /// number of bytes copied, start index of datetime substring, and
5482
    /// end index of datetime substring.
5483
    ///
5484
    /// If copying fails, returns a [`InfoAsBytes::Fail`] variant with
5485
    /// number of bytes copied.
5486
    pub fn as_bytes(self: &FixedStruct, buffer: &mut [u8]) -> InfoAsBytes
35✔
5487
    {
5488
        let entry: &FixedStructDynPtr = &self.fixedstructptr;
35✔
5489
        let mut at: usize = 0;
35✔
5490
        let dt_beg: BufIndex;
5491
        let dt_end: BufIndex;
5492

5493
        match entry.fixedstruct_type() {
35✔
5494
            FixedStructType::Fs_Freebsd_x8664_Utmpx => {
5495
                let utmpx: &freebsd_x8664::utmpx = entry.as_freebsd_x8664_utmpx();
1✔
5496

5497
                // ut_type
5498
                set_buffer_at_or_err_str!(buffer, at, "ut_type ");
1✔
5499
                set_buffer_at_or_err_ut_type_i16!(buffer, at, utmpx.ut_type);
1✔
5500
                // ut_tv
5501
                set_buffer_at_or_err_str!(buffer, at,  " ut_tv ");
1✔
5502
                dt_beg = at;
1✔
5503
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_sec, freebsd_x8664::time_t);
1✔
5504
                set_buffer_at_or_err_u8!(buffer, at, b'.');
1✔
5505
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_usec, freebsd_x8664::subseconds_t);
1✔
5506
                dt_end = at;
1✔
5507
                // ut_id
5508
                set_buffer_at_or_err_str!(buffer, at, " ut_id '");
1✔
5509
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_id);
1✔
5510
                // ut_pid
5511
                set_buffer_at_or_err_str!(buffer, at, "' ut_pid ");
1✔
5512
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_pid, freebsd_x8664::pid_t);
1✔
5513
                // ut_user
5514
                set_buffer_at_or_err_str!(buffer, at, " ut_user '");
1✔
5515
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_user);
1✔
5516
                // ut_line
5517
                set_buffer_at_or_err_str!(buffer, at, "' ut_line ");
1✔
5518
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_line);
1✔
5519
                // ut_host
5520
                set_buffer_at_or_err_str!(buffer, at, "' ut_host '");
1✔
5521
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_host);
1✔
5522
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
1✔
5523
            }
5524
            FixedStructType::Fs_Linux_Arm64Aarch64_Lastlog => {
5525
                let lastlog: &linux_arm64aarch64::lastlog = entry.as_linux_arm64aarch64_lastlog();
1✔
5526

5527
                // ll_time
5528
                set_buffer_at_or_err_str!(buffer, at, "ll_time ");
1✔
5529
                dt_beg = at;
1✔
5530
                set_buffer_at_or_err_number!(buffer, at, lastlog.ll_time, linux_arm64aarch64::ll_time_t);
1✔
5531
                dt_end = at;
1✔
5532
                // ll_line
5533
                set_buffer_at_or_err_str!(buffer, at, " ll_line '");
1✔
5534
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_line);
1✔
5535
                // ll_host
5536
                set_buffer_at_or_err_str!(buffer, at, "' ll_host '");
1✔
5537
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_host);
1✔
5538
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
1✔
5539
            }
5540
            FixedStructType::Fs_Linux_Arm64Aarch64_Utmpx => {
5541
                let utmpx: &linux_arm64aarch64::utmpx = entry.as_linux_arm64aarch64_utmpx();
1✔
5542

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

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

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

5754
                // ll_time
5755
                set_buffer_at_or_err_str!(buffer, at, "ll_time ");
2✔
5756
                dt_beg = at;
2✔
5757
                set_buffer_at_or_err_number!(buffer, at, lastlog.ll_time, linux_x86::ll_time_t);
2✔
5758
                dt_end = at;
2✔
5759
                // ll_line
5760
                set_buffer_at_or_err_str!(buffer, at, " ll_line '");
2✔
5761
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_line);
2✔
5762
                // ll_host
5763
                set_buffer_at_or_err_str!(buffer, at, "' ll_host '");
2✔
5764
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_host);
2✔
5765
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
2✔
5766
            }
5767
            FixedStructType::Fs_Linux_x86_Utmpx => {
5768
                let utmpx: &linux_x86::utmpx = entry.as_linux_x86_utmpx();
20✔
5769

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

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

5888
                // ll_tv.tv_sec
5889
                set_buffer_at_or_err_str!(buffer, at, "ll_tv ");
1✔
5890
                dt_beg = at;
1✔
5891
                set_buffer_at_or_err_number!(buffer, at, lastlogx.ll_tv.tv_sec, i64);
1✔
5892
                set_buffer_at_or_err_u8!(buffer, at, b'.');
1✔
5893
                // ll_tv.tv_usec
5894
                set_buffer_at_or_err_number!(buffer, at, lastlogx.ll_tv.tv_usec, i32);
1✔
5895
                dt_end = at;
1✔
5896
                // ll_line
5897
                set_buffer_at_or_err_str!(buffer, at, " ll_line '");
1✔
5898
                set_buffer_at_or_err_cstrn!(buffer, at, lastlogx.ll_line);
1✔
5899
                // ll_host
5900
                set_buffer_at_or_err_str!(buffer, at, "' ll_host '");
1✔
5901
                set_buffer_at_or_err_cstrn!(buffer, at, lastlogx.ll_host);
1✔
5902
                // ll_ss
5903
                set_buffer_at_or_err_str!(buffer, at, "' ll_ss ");
1✔
5904
                set_buffer_at_or_err_cstrn!(buffer, at, lastlogx.ll_ss);
1✔
5905
            }
5906
            FixedStructType::Fs_Netbsd_x8632_Utmpx => {
5907
                let utmpx: &netbsd_x8632::utmpx = entry.as_netbsd_x8632_utmpx();
1✔
5908

5909
                // ut_name
5910
                set_buffer_at_or_err_str!(buffer, at, "ut_name '");
1✔
5911
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_name);
1✔
5912
                // ut_id
5913
                set_buffer_at_or_err_str!(buffer, at, "' ut_id '");
1✔
5914
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_id);
1✔
5915
                // ut_line
5916
                set_buffer_at_or_err_str!(buffer, at, "' ut_line '");
1✔
5917
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_line);
1✔
5918
                // ut_host
5919
                set_buffer_at_or_err_str!(buffer, at, "' ut_host '");
1✔
5920
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_host);
1✔
5921
                // ut_session
5922
                set_buffer_at_or_err_str!(buffer, at, "' ut_session '");
1✔
5923
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_session, netbsd_x8632::uint16_t);
1✔
5924
                // ut_type
5925
                set_buffer_at_or_err_str!(buffer, at, "' ut_type ");
1✔
5926
                set_buffer_at_or_err_ut_type_u16!(buffer, at, utmpx.ut_type);
1✔
5927
                // ut_pid
5928
                set_buffer_at_or_err_str!(buffer, at, " ut_pid ");
1✔
5929
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_pid, netbsd_x8632::pid_t);
1✔
5930
                // ut_exit.e_termination
5931
                set_buffer_at_or_err_str!(buffer, at, " e_termination ");
1✔
5932
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_exit.e_termination, netbsd_x8632::uint16_t);
1✔
5933
                // ut_exit.e_exit
5934
                set_buffer_at_or_err_str!(buffer, at, " e_exit ");
1✔
5935
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_exit.e_exit, netbsd_x8632::uint16_t);
1✔
5936
                // ut_ss
5937
                set_buffer_at_or_err_str!(buffer, at, " ut_ss '");
1✔
5938
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_ss);
1✔
5939
                // ut_tv.tv_sec
5940
                set_buffer_at_or_err_str!(buffer, at, "' ut_tv ");
1✔
5941
                dt_beg = at;
1✔
5942
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_sec, i64);
1✔
5943
                set_buffer_at_or_err_u8!(buffer, at, b'.');
1✔
5944
                // ut_tv.tv_usec
5945
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_usec, i32);
1✔
5946
                dt_end = at;
1✔
5947
            }
5948
            FixedStructType::Fs_Netbsd_x8664_Lastlog => {
5949
                let lastlog: &netbsd_x8664::lastlog = entry.as_netbsd_x8664_lastlog();
1✔
5950

5951
                // ll_time
5952
                set_buffer_at_or_err_str!(buffer, at, "ll_time ");
1✔
5953
                dt_beg = at;
1✔
5954
                set_buffer_at_or_err_number!(buffer, at, lastlog.ll_time, netbsd_x8664::time_t);
1✔
5955
                dt_end = at;
1✔
5956
                // ll_line
5957
                set_buffer_at_or_err_str!(buffer, at, " ll_line '");
1✔
5958
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_line);
1✔
5959
                // ll_host
5960
                set_buffer_at_or_err_str!(buffer, at, "' ll_host '");
1✔
5961
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_host);
1✔
5962
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
1✔
5963
            }
5964
            FixedStructType::Fs_Netbsd_x8664_Lastlogx => {
5965
                let lastlogx: &netbsd_x8664::lastlogx = entry.as_netbsd_x8664_lastlogx();
×
5966

5967
                // ll_tv.tv_sec
5968
                set_buffer_at_or_err_str!(buffer, at, "ll_tv ");
×
5969
                dt_beg = at;
×
5970
                set_buffer_at_or_err_number!(buffer, at, lastlogx.ll_tv.tv_sec, i64);
×
5971
                set_buffer_at_or_err_u8!(buffer, at, b'.');
×
5972
                // ll_tv.tv_usec
5973
                set_buffer_at_or_err_number!(buffer, at, lastlogx.ll_tv.tv_usec, i32);
×
5974
                dt_end = at;
×
5975
                // ll_line
5976
                set_buffer_at_or_err_str!(buffer, at, " ll_line '");
×
5977
                set_buffer_at_or_err_cstrn!(buffer, at, lastlogx.ll_line);
×
5978
                // ll_host
5979
                set_buffer_at_or_err_str!(buffer, at, "' ll_host '");
×
5980
                set_buffer_at_or_err_cstrn!(buffer, at, lastlogx.ll_host);
×
5981
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
×
5982
                // XXX: ll_ss is not printable
5983
            }
5984
            FixedStructType::Fs_Netbsd_x8664_Utmp => {
5985
                let utmp: &netbsd_x8664::utmp = entry.as_netbsd_x8664_utmp();
1✔
5986

5987
                // ut_line
5988
                set_buffer_at_or_err_str!(buffer, at, "ut_line '");
1✔
5989
                set_buffer_at_or_err_cstrn!(buffer, at, utmp.ut_line);
1✔
5990
                // ut_name
5991
                set_buffer_at_or_err_str!(buffer, at, "' ut_name '");
1✔
5992
                set_buffer_at_or_err_cstrn!(buffer, at, utmp.ut_name);
1✔
5993
                // ut_host
5994
                set_buffer_at_or_err_str!(buffer, at, "' ut_host '");
1✔
5995
                set_buffer_at_or_err_cstrn!(buffer, at, utmp.ut_host);
1✔
5996
                // ut_time
5997
                set_buffer_at_or_err_str!(buffer, at, "' ut_time ");
1✔
5998
                dt_beg = at;
1✔
5999
                set_buffer_at_or_err_number!(buffer, at, utmp.ut_time, netbsd_x8664::time_t);
1✔
6000
                dt_end = at;
1✔
6001
            }
6002
            FixedStructType::Fs_Netbsd_x8664_Utmpx => {
6003
                let utmpx: &netbsd_x8664::utmpx = entry.as_netbsd_x8664_utmpx();
1✔
6004

6005
                // ut_user
6006
                set_buffer_at_or_err_str!(buffer, at, "ut_user '");
1✔
6007
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_user);
1✔
6008
                // ut_id
6009
                set_buffer_at_or_err_str!(buffer, at, "' ut_id '");
1✔
6010
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_id);
1✔
6011
                // ut_line
6012
                set_buffer_at_or_err_str!(buffer, at, "' ut_line '");
1✔
6013
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_line);
1✔
6014
                // ut_host
6015
                set_buffer_at_or_err_str!(buffer, at, "' ut_host '");
1✔
6016
                set_buffer_at_or_err_cstrn!(buffer, at, utmpx.ut_host);
1✔
6017
                // ut_session
6018
                set_buffer_at_or_err_str!(buffer, at, "' ut_session '");
1✔
6019
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_session, netbsd_x8664::uint16_t);
1✔
6020
                // ut_type
6021
                set_buffer_at_or_err_str!(buffer, at, "' ut_type ");
1✔
6022
                set_buffer_at_or_err_ut_type_u16!(buffer, at, utmpx.ut_type);
1✔
6023
                
6024
                // ut_pid
6025
                set_buffer_at_or_err_str!(buffer, at, " ut_pid ");
1✔
6026
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_pid, i32);
1✔
6027
                // ut_exit.e_termination
6028
                set_buffer_at_or_err_str!(buffer, at, " e_termination ");
1✔
6029
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_exit.e_termination, netbsd_x8664::uint16_t);
1✔
6030
                // ut_exit.e_exit
6031
                set_buffer_at_or_err_str!(buffer, at, " e_exit ");
1✔
6032
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_exit.e_exit, netbsd_x8664::uint16_t);
1✔
6033
                // ut_tv.tv_sec
6034
                set_buffer_at_or_err_str!(buffer, at, " ut_tv ");
1✔
6035
                dt_beg = at;
1✔
6036
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_sec, i64);
1✔
6037
                set_buffer_at_or_err_u8!(buffer, at, b'.');
1✔
6038
                set_buffer_at_or_err_number!(buffer, at, utmpx.ut_tv.tv_usec, i32);
1✔
6039
                dt_end = at;
1✔
6040
            }
6041
            FixedStructType::Fs_Openbsd_x86_Lastlog => {
6042
                let lastlog: &openbsd_x86::lastlog = entry.as_openbsd_x86_lastlog();
1✔
6043

6044
                // ll_time
6045
                set_buffer_at_or_err_str!(buffer, at, "ll_time ");
1✔
6046
                dt_beg = at;
1✔
6047
                set_buffer_at_or_err_number!(buffer, at, lastlog.ll_time, openbsd_x86::time_t);
1✔
6048
                dt_end = at;
1✔
6049
                // ll_line
6050
                set_buffer_at_or_err_str!(buffer, at, " ll_line '");
1✔
6051
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_line);
1✔
6052
                // ll_host
6053
                set_buffer_at_or_err_str!(buffer, at, "' ll_host '");
1✔
6054
                set_buffer_at_or_err_cstrn!(buffer, at, lastlog.ll_host);
1✔
6055
                set_buffer_at_or_err_u8!(buffer, at, b'\'');
1✔
6056
            }
6057
            FixedStructType::Fs_Openbsd_x86_Utmp => {
6058
                let utmp: &openbsd_x86::utmp = entry.as_openbsd_x86_utmp();
1✔
6059

6060
                // ut_line
6061
                set_buffer_at_or_err_str!(buffer, at, "ut_line '");
1✔
6062
                set_buffer_at_or_err_cstrn!(buffer, at, utmp.ut_line);
1✔
6063
                // ut_name
6064
                set_buffer_at_or_err_str!(buffer, at, "' ut_name '");
1✔
6065
                set_buffer_at_or_err_cstrn!(buffer, at, utmp.ut_name);
1✔
6066
                // ut_host
6067
                set_buffer_at_or_err_str!(buffer, at, "' ut_host '");
1✔
6068
                set_buffer_at_or_err_cstrn!(buffer, at, utmp.ut_host);
1✔
6069
                // ut_time
6070
                set_buffer_at_or_err_str!(buffer, at, "' ut_time ");
1✔
6071
                dt_beg = at;
1✔
6072
                set_buffer_at_or_err_number!(buffer, at, utmp.ut_time, openbsd_x86::time_t);
1✔
6073
                dt_end = at;
1✔
6074
            }
6075
        }
6076
        // line end
6077
        set_buffer_at_or_err_u8!(buffer, at, b'\n');
35✔
6078
        // string end
6079
        set_buffer_at_or_err_u8!(buffer, at, b'\0');
35✔
6080

6081
        debug_assert_le!(dt_beg, dt_end);
35✔
6082
        debug_assert_le!(dt_end, at);
35✔
6083

6084
        InfoAsBytes::Ok(at, dt_beg, dt_end)
35✔
6085
    }
35✔
6086

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

6111
        buf
1✔
6112
    }
1✔
6113

6114
    // TODO fix non_snake_case
6115

6116
    /// `FixedStruct` to `String`.
6117
    #[doc(hidden)]
6118
    #[allow(non_snake_case)]
6119
    #[cfg(any(debug_assertions, test))]
6120
    pub fn to_String_raw(self: &FixedStruct) -> String
×
6121
    {
6122
        self.impl_to_String_raw(true)
×
6123
    }
×
6124

6125
    /// `FixedStruct` to `String` but using printable chars for
6126
    /// non-printable and/or formatting characters.
6127
    #[doc(hidden)]
6128
    #[allow(non_snake_case)]
6129
    #[cfg(any(debug_assertions, test))]
6130
    pub fn to_String_noraw(self: &FixedStruct) -> String
1✔
6131
    {
6132
        self.impl_to_String_raw(false)
1✔
6133
    }
1✔
6134
}
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