diff --git a/libc-test/build.rs b/libc-test/build.rs index 8fc9c94872412..585df0bc237af 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -1876,6 +1876,7 @@ fn test_freebsd(target: &str) { "sys/vmmeter.h", "sys/wait.h", "libprocstat.h", + "devstat.h", "syslog.h", "termios.h", "time.h", @@ -1918,7 +1919,9 @@ fn test_freebsd(target: &str) { } // Field is named `type` in C but that is a Rust keyword, // so these fields are translated to `type_` in the bindings. - "type_" if struct_ == "rtprio" || struct_ == "sockstat" => "type".to_string(), + "type_" if struct_ == "rtprio" => "type".to_string(), + "type_" if struct_ == "sockstat" => "type".to_string(), + "type_" if struct_ == "devstat_match_table" => "type".to_string(), s => s.to_string(), } }); @@ -2172,6 +2175,10 @@ fn test_freebsd(target: &str) { // https://github.com/gnzlbg/ctest/issues/68 "lio_listio" => true, + // It returns a `long double`, but it's a nightmare to bind correctly in rust + // for the moment, so it's a best effort thing... + "devstat_compute_etime" => true, + _ => false, } }); @@ -2244,6 +2251,11 @@ fn test_freebsd(target: &str) { // `__sem_base` is a private struct field ("semid_ds", "__sem_base") => true, + + // `snap_time` is a `long double`, but it's a nightmare to bind correctly in rust + // for the moment, so it's a best effort thing... + ("statinfo", "snap_time") => true, + _ => false, } }); diff --git a/src/unix/bsd/freebsdlike/freebsd/mod.rs b/src/unix/bsd/freebsdlike/freebsd/mod.rs index fe17a9b123927..13ab7abb6e3fc 100644 --- a/src/unix/bsd/freebsdlike/freebsd/mod.rs +++ b/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -39,10 +39,206 @@ pub type u_short = ::c_ushort; pub type caddr_t = *mut ::c_char; +// This is mosty a hack to keep the length somewhat similar. However, based on +// https://gcc.gnu.org/onlinedocs/gcc/Floating-Types.html, it might very well be incorrect. +cfg_if! { + if #[cfg(target_pointer_width = "32")] { + pub type c_longdouble = u128; + } else { + pub type c_longdouble = f64; + } +} + // It's an alias over "struct __kvm_t". However, its fields aren't supposed to be used directly, // making the type definition system dependent. Better not bind it exactly. pub type kvm_t = ::c_void; +#[cfg_attr(feature = "extra_traits", derive(Debug))] +#[repr(u32)] +pub enum devstat_support_flags { + DEVSTAT_ALL_SUPPORTED = 0x00, + DEVSTAT_NO_BLOCKSIZE = 0x01, + DEVSTAT_NO_ORDERED_TAGS = 0x02, + DEVSTAT_BS_UNAVAILABLE = 0x04, +} +impl ::Copy for devstat_support_flags {} +impl ::Clone for devstat_support_flags { + fn clone(&self) -> devstat_support_flags { + *self + } +} + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +#[repr(u32)] +pub enum devstat_trans_flags { + DEVSTAT_NO_DATA = 0x00, + DEVSTAT_READ = 0x01, + DEVSTAT_WRITE = 0x02, + DEVSTAT_FREE = 0x03, +} + +impl ::Copy for devstat_trans_flags {} +impl ::Clone for devstat_trans_flags { + fn clone(&self) -> devstat_trans_flags { + *self + } +} + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +#[repr(u32)] +pub enum devstat_tag_type { + DEVSTAT_TAG_SIMPLE = 0x00, + DEVSTAT_TAG_HEAD = 0x01, + DEVSTAT_TAG_ORDERED = 0x02, + DEVSTAT_TAG_NONE = 0x03, +} +impl ::Copy for devstat_tag_type {} +impl ::Clone for devstat_tag_type { + fn clone(&self) -> devstat_tag_type { + *self + } +} + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +#[repr(u32)] +pub enum devstat_match_flags { + DEVSTAT_MATCH_NONE = 0x00, + DEVSTAT_MATCH_TYPE = 0x01, + DEVSTAT_MATCH_IF = 0x02, + DEVSTAT_MATCH_PASS = 0x04, +} +impl ::Copy for devstat_match_flags {} +impl ::Clone for devstat_match_flags { + fn clone(&self) -> devstat_match_flags { + *self + } +} + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +#[repr(u32)] +pub enum devstat_priority { + DEVSTAT_PRIORITY_MIN = 0x000, + DEVSTAT_PRIORITY_OTHER = 0x020, + DEVSTAT_PRIORITY_PASS = 0x030, + DEVSTAT_PRIORITY_FD = 0x040, + DEVSTAT_PRIORITY_WFD = 0x050, + DEVSTAT_PRIORITY_TAPE = 0x060, + DEVSTAT_PRIORITY_CD = 0x090, + DEVSTAT_PRIORITY_DISK = 0x110, + DEVSTAT_PRIORITY_ARRAY = 0x120, + DEVSTAT_PRIORITY_MAX = 0xfff, +} +impl ::Copy for devstat_priority {} +impl ::Clone for devstat_priority { + fn clone(&self) -> devstat_priority { + *self + } +} + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +#[repr(u32)] +pub enum devstat_type_flags { + DEVSTAT_TYPE_DIRECT = 0x000, + DEVSTAT_TYPE_SEQUENTIAL = 0x001, + DEVSTAT_TYPE_PRINTER = 0x002, + DEVSTAT_TYPE_PROCESSOR = 0x003, + DEVSTAT_TYPE_WORM = 0x004, + DEVSTAT_TYPE_CDROM = 0x005, + DEVSTAT_TYPE_SCANNER = 0x006, + DEVSTAT_TYPE_OPTICAL = 0x007, + DEVSTAT_TYPE_CHANGER = 0x008, + DEVSTAT_TYPE_COMM = 0x009, + DEVSTAT_TYPE_ASC0 = 0x00a, + DEVSTAT_TYPE_ASC1 = 0x00b, + DEVSTAT_TYPE_STORARRAY = 0x00c, + DEVSTAT_TYPE_ENCLOSURE = 0x00d, + DEVSTAT_TYPE_FLOPPY = 0x00e, + DEVSTAT_TYPE_MASK = 0x00f, + DEVSTAT_TYPE_IF_SCSI = 0x010, + DEVSTAT_TYPE_IF_IDE = 0x020, + DEVSTAT_TYPE_IF_OTHER = 0x030, + DEVSTAT_TYPE_IF_MASK = 0x0f0, + DEVSTAT_TYPE_PASS = 0x100, +} +impl ::Copy for devstat_type_flags {} +impl ::Clone for devstat_type_flags { + fn clone(&self) -> devstat_type_flags { + *self + } +} + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +#[repr(u32)] +pub enum devstat_metric { + DSM_NONE, + DSM_TOTAL_BYTES, + DSM_TOTAL_BYTES_READ, + DSM_TOTAL_BYTES_WRITE, + DSM_TOTAL_TRANSFERS, + DSM_TOTAL_TRANSFERS_READ, + DSM_TOTAL_TRANSFERS_WRITE, + DSM_TOTAL_TRANSFERS_OTHER, + DSM_TOTAL_BLOCKS, + DSM_TOTAL_BLOCKS_READ, + DSM_TOTAL_BLOCKS_WRITE, + DSM_KB_PER_TRANSFER, + DSM_KB_PER_TRANSFER_READ, + DSM_KB_PER_TRANSFER_WRITE, + DSM_TRANSFERS_PER_SECOND, + DSM_TRANSFERS_PER_SECOND_READ, + DSM_TRANSFERS_PER_SECOND_WRITE, + DSM_TRANSFERS_PER_SECOND_OTHER, + DSM_MB_PER_SECOND, + DSM_MB_PER_SECOND_READ, + DSM_MB_PER_SECOND_WRITE, + DSM_BLOCKS_PER_SECOND, + DSM_BLOCKS_PER_SECOND_READ, + DSM_BLOCKS_PER_SECOND_WRITE, + DSM_MS_PER_TRANSACTION, + DSM_MS_PER_TRANSACTION_READ, + DSM_MS_PER_TRANSACTION_WRITE, + DSM_SKIP, + DSM_TOTAL_BYTES_FREE, + DSM_TOTAL_TRANSFERS_FREE, + DSM_TOTAL_BLOCKS_FREE, + DSM_KB_PER_TRANSFER_FREE, + DSM_MB_PER_SECOND_FREE, + DSM_TRANSFERS_PER_SECOND_FREE, + DSM_BLOCKS_PER_SECOND_FREE, + DSM_MS_PER_TRANSACTION_OTHER, + DSM_MS_PER_TRANSACTION_FREE, + DSM_BUSY_PCT, + DSM_QUEUE_LENGTH, + DSM_TOTAL_DURATION, + DSM_TOTAL_DURATION_READ, + DSM_TOTAL_DURATION_WRITE, + DSM_TOTAL_DURATION_FREE, + DSM_TOTAL_DURATION_OTHER, + DSM_TOTAL_BUSY_TIME, + DSM_MAX, +} +impl ::Copy for devstat_metric {} +impl ::Clone for devstat_metric { + fn clone(&self) -> devstat_metric { + *self + } +} + +#[cfg_attr(feature = "extra_traits", derive(Debug))] +#[repr(u32)] +pub enum devstat_select_mode { + DS_SELECT_ADD, + DS_SELECT_ONLY, + DS_SELECT_REMOVE, + DS_SELECT_ADDONLY, +} +impl ::Copy for devstat_select_mode {} +impl ::Clone for devstat_select_mode { + fn clone(&self) -> devstat_select_mode { + *self + } +} + s! { pub struct aiocb { pub aio_fildes: ::c_int, @@ -645,6 +841,101 @@ s! { pub ph1: u64, pub ph2: u64, } + + pub struct bintime { + pub sec: ::time_t, + pub frac: u64, + } + + pub struct clockinfo { + /// clock frequency + pub hz: ::c_int, + /// micro-seconds per hz tick + pub tick: ::c_int, + pub spare: ::c_int, + /// statistics clock frequency + pub stathz: ::c_int, + /// profiling clock frequency + pub profhz: ::c_int, + } + + pub struct __c_anonymous_stailq_entry_devstat { + pub stqe_next: *mut devstat, + } + + pub struct devstat { + /// Update sequence + pub sequence0: ::u_int, + /// Allocated entry + pub allocated: ::c_int, + /// started ops + pub start_count: ::u_int, + /// completed ops + pub end_count: ::u_int, + /// busy time unaccounted for since this time + pub busy_from: bintime, + pub dev_links: __c_anonymous_stailq_entry_devstat, + /// Devstat device number. + pub device_number: u32, + pub device_name: [::c_char; DEVSTAT_NAME_LEN as usize], + pub unit_number: ::c_int, + pub bytes: [u64; DEVSTAT_N_TRANS_FLAGS as usize], + pub operations: [u64; DEVSTAT_N_TRANS_FLAGS as usize], + pub duration: [bintime; DEVSTAT_N_TRANS_FLAGS as usize], + pub busy_time: bintime, + /// Time the device was created. + pub creation_time: bintime, + /// Block size, bytes + pub block_size: u32, + /// The number of simple, ordered, and head of queue tags sent. + pub tag_types: [u64; 3], + /// Which statistics are supported by a given device. + pub flags: devstat_support_flags, + /// Device type + pub device_type: devstat_type_flags, + /// Controls list pos. + pub priority: devstat_priority, + /// Identification for GEOM nodes + pub id: *const ::c_void, + /// Update sequence + pub sequence1: ::u_int, + } + + pub struct devstat_match { + pub match_fields: devstat_match_flags, + pub device_type: devstat_type_flags, + pub num_match_categories: ::c_int, + } + + pub struct devstat_match_table { + pub match_str: *const ::c_char, + pub type_: devstat_type_flags, + pub match_field: devstat_match_flags, + } + + pub struct device_selection { + pub device_number: u32, + pub device_name: [::c_char; DEVSTAT_NAME_LEN as usize], + pub unit_number: ::c_int, + pub selected: ::c_int, + pub bytes: u64, + pub position: ::c_int, + } + + pub struct devinfo { + pub devices: *mut devstat, + pub mem_ptr: *mut u8, + pub generation: ::c_long, + pub numdevs: ::c_int, + } + + pub struct statinfo { + pub cp_time: [::c_long; CPUSTATES as usize], + pub tk_nin: ::c_long, + pub tk_nout: ::c_long, + pub dinfo: *mut devinfo, + pub snap_time: c_longdouble, + } } s_no_extra_traits! { @@ -1499,6 +1790,10 @@ impl ::Clone for dot3Vendors { } } +// sys/devicestat.h +pub const DEVSTAT_N_TRANS_FLAGS: ::c_int = 4; +pub const DEVSTAT_NAME_LEN: ::c_int = 16; + pub const SIGEV_THREAD_ID: ::c_int = 4; pub const EXTATTR_NAMESPACE_EMPTY: ::c_int = 0; @@ -3125,6 +3420,26 @@ pub const PS_FST_FFLAG_DIRECT: ::c_int = 0x1000; pub const PS_FST_FFLAG_EXEC: ::c_int = 0x2000; pub const PS_FST_FFLAG_HASLOCK: ::c_int = 0x4000; +// time.h + +/// not on dst +pub const DST_NONE: ::c_int = 0; +/// USA style dst +pub const DST_USA: ::c_int = 1; +/// Australian style dst +pub const DST_AUST: ::c_int = 2; +/// Western European dst +pub const DST_WET: ::c_int = 3; +/// Middle European dst +pub const DST_MET: ::c_int = 4; +/// Eastern European dst +pub const DST_EET: ::c_int = 5; +/// Canada +pub const DST_CAN: ::c_int = 6; + +pub const CPUCLOCK_WHICH_PID: ::c_int = 0; +pub const CPUCLOCK_WHICH_TID: ::c_int = 1; + const_fn! { {const} fn _ALIGN(p: usize) -> usize { (p + _ALIGNBYTES) & !_ALIGNBYTES @@ -3597,6 +3912,9 @@ extern "C" { pub fn procctl(idtype: ::idtype_t, id: ::id_t, cmd: ::c_int, data: *mut ::c_void) -> ::c_int; pub fn getpagesize() -> ::c_int; + + pub fn adjtime(arg1: *const ::timeval, arg2: *mut ::timeval) -> ::c_int; + pub fn clock_getcpuclockid2(arg1: ::id_t, arg2: ::c_int, arg3: *mut clockid_t) -> ::c_int; } #[link(name = "kvm")] @@ -3808,6 +4126,43 @@ extern "C" { ) -> ::c_int; } +#[link(name = "devstat")] +extern "C" { + pub fn devstat_getnumdevs(kd: *mut kvm_t) -> ::c_int; + pub fn devstat_getgeneration(kd: *mut kvm_t) -> ::c_long; + pub fn devstat_getversion(kd: *mut kvm_t) -> ::c_int; + pub fn devstat_checkversion(kd: *mut kvm_t) -> ::c_int; + pub fn devstat_getdevs(kd: *mut kvm_t, stats: *mut statinfo) -> ::c_int; + pub fn devstat_selectdevs( + dev_select: *mut *mut device_selection, + num_selected: *mut ::c_int, + num_selections: *mut ::c_int, + select_generation: *mut ::c_long, + current_generation: ::c_long, + devices: *mut devstat, + numdevs: ::c_int, + matches: *mut devstat_match, + num_matches: ::c_int, + dev_selections: *mut *mut ::c_char, + num_dev_selections: ::c_int, + select_mode: devstat_select_mode, + maxshowdevs: ::c_int, + perf_select: ::c_int, + ) -> ::c_int; + pub fn devstat_buildmatch( + match_str: *mut ::c_char, + matches: *mut *mut devstat_match, + num_matches: *mut ::c_int, + ) -> ::c_int; + pub fn devstat_compute_statistics( + current: *mut devstat, + previous: *mut devstat, + etime: c_longdouble, + ... + ) -> ::c_int; + pub fn devstat_compute_etime(cur_time: *mut bintime, prev_time: *mut bintime) -> c_longdouble; +} + cfg_if! { if #[cfg(freebsd14)] { mod freebsd14;