Skip to content

Commit 9843b8f

Browse files
Merge pull request #54 from andrewdavidmackenzie/fix_kmesg
Fix kmesg_buffer on macos - Fixes #39
2 parents 123d176 + 4b7801e commit 9843b8f

File tree

3 files changed

+27
-101
lines changed

3 files changed

+27
-101
lines changed

README.md

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,25 +64,15 @@ pub fn pidfdinfo<T: PIDFDInfo>(pid : i32, fd: i32) -> Result<T, String> (macos)
6464
pub fn pidrusage<T: PIDRUsage>(pid : i32) -> Result<T, String> (macos)
6565
```
6666

67-
## kmsgbuf
68-
I have also implemented this method - but the MAGIC_NUMBER returned is not correct,
69-
and upon investigation it seems that Apple/Darwin/Mach have changed totally how dmessage works in
70-
latest versions, moving away from using libproc to use kvm - with a total rewrite of dmesg.
71-
72-
I leave it in for now, but some serious revision of the library, with conditional compilation depending on
73-
which version of Mac OS X and/or Darwin will be required to get a version that works broadly :-(
74-
75-
See [Github issue](https://github.com/andrewdavidmackenzie/libproc-rs/issues/39)
76-
67+
## Kernel Message Buffer - kmsgbuf
7768
```
7869
pub fn kmsgbuf() -> Result<String, String>
7970
```
8071

8172
# Binaries
8273
`cargo build` builds the following binaries:
8374
- `procinfo` that takes a PID as an optional argument (uses it's own pid if none supplied) and returns information about the process on stdout
84-
- `dmesg` is a version of dmesg implemented in rust that uses libproc-rs. This must be run as root. Currently fails (see above and
85-
[bug](https://github.com/andrewdavidmackenzie/libproc-rs/issues/39)).
75+
- `dmesg` is a version of dmesg implemented in rust that uses libproc-rs.
8676

8777
# Platforms
8878
Mac OS X and work started on Linux.

src/dmesg.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ extern crate libc;
1212
use crate::libproc::libproc::kmesg_buffer;
1313

1414
fn main() {
15-
if let Ok(message) = kmesg_buffer::kmsgbuf() {
16-
println!("{}", message);
15+
match kmesg_buffer::kmsgbuf() {
16+
Ok(message) => print!("{}", message),
17+
Err(e) => eprintln!("{}", e)
1718
}
1819
}

src/libproc/kmesg_buffer.rs

Lines changed: 22 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,10 @@ extern crate errno;
22
extern crate libc;
33

44
#[cfg(target_os = "macos")]
5-
use std::fmt;
6-
#[cfg(target_os = "macos")]
7-
use std::{mem, ptr};
8-
9-
#[cfg(target_os = "macos")]
10-
use crate::libproc::helpers;
5+
use std::str;
116

127
#[cfg(target_os = "macos")]
13-
use self::libc::c_int;
8+
use self::libc::{c_int, c_void};
149

1510
#[cfg(target_os = "linux")]
1611
use std::fs::File;
@@ -23,101 +18,45 @@ use std::sync::mpsc::Receiver;
2318
#[cfg(target_os = "linux")]
2419
use std::{thread, time};
2520

26-
2721
// See https://opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/sys/msgbuf.h
2822
#[cfg(target_os = "macos")]
29-
const MAX_MSG_BSIZE: c_int = 1024 * 1024;
30-
#[cfg(target_os = "macos")]
31-
const MSG_MAGIC: c_int = 0x063_061;
32-
33-
// See /usr/include/sys/msgbuf.h on your Mac.
34-
#[cfg(target_os = "macos")]
35-
#[repr(C)]
36-
struct MessageBuffer {
37-
pub msg_magic: c_int,
38-
pub msg_size: c_int,
39-
pub msg_bufx: c_int,
40-
// write pointer
41-
pub msg_bufr: c_int,
42-
// read pointer
43-
pub msg_bufc: *mut u8, // buffer
44-
}
45-
46-
#[cfg(target_os = "macos")]
47-
impl Default for MessageBuffer {
48-
fn default() -> MessageBuffer {
49-
MessageBuffer {
50-
msg_magic: 0,
51-
msg_size: 0,
52-
msg_bufx: 0,
53-
msg_bufr: 0,
54-
msg_bufc: ptr::null_mut() as *mut u8,
55-
}
56-
}
57-
}
58-
59-
#[cfg(target_os = "macos")]
60-
impl fmt::Debug for MessageBuffer {
61-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62-
write!(f, "MessageBuffer {{ magic: 0x{:x}, size: {}, bufx: {}}}", self.msg_magic, self.msg_size, self.msg_bufx)
63-
}
64-
}
23+
const MAX_MSG_BSIZE: usize = 1024 * 1024;
6524

6625
// this extern block links to the libproc library
6726
// Original signatures of functions can be found at http://opensource.apple.com/source/Libc/Libc-594.9.4/darwin/libproc.c
6827
#[cfg(target_os = "macos")]
6928
#[link(name = "proc", kind = "dylib")]
7029
extern {
71-
fn proc_kmsgbuf(buffer: *mut MessageBuffer, buffersize: u32) -> c_int;
30+
fn proc_kmsgbuf(buffer: *mut c_void, buffersize: u32) -> c_int;
7231
}
7332

7433
/// Get the contents of the kernel message buffer
7534
///
7635
/// Entries are in the format:
7736
/// faclev,seqnum,timestamp[optional, ...];message\n
7837
/// TAGNAME=value (0 or more Tags)
79-
// See http://opensource.apple.com//source/system_cmds/system_cmds-336.6/dmesg.tproj/dmesg.c
38+
// See http://opensource.apple.com//source/system_cmds/system_cmds-336.6/dmesg.tproj/dmesg.c// See http://opensource.apple.com//source/system_cmds/system_cmds-336.6/dmesg.tproj/dmesg.c
8039
#[cfg(target_os = "macos")]
8140
pub fn kmsgbuf() -> Result<String, String> {
82-
let mut message_buffer: MessageBuffer = Default::default();
41+
let mut message_buffer: Vec<u8> = Vec::with_capacity(MAX_MSG_BSIZE);
42+
let buffer_ptr = message_buffer.as_mut_ptr() as *mut c_void;
8343
let ret: i32;
8444

8545
unsafe {
86-
ret = proc_kmsgbuf(&mut message_buffer, mem::size_of::<MessageBuffer>() as u32);
46+
ret = proc_kmsgbuf(buffer_ptr, message_buffer.capacity() as u32);
47+
if ret > 0 {
48+
message_buffer.set_len(ret as usize - 1);
49+
}
8750
}
8851

89-
if ret <= 0 {
90-
Err(helpers::get_errno_with_message(ret))
91-
} else if message_buffer.msg_magic != MSG_MAGIC {
92-
println!("Message buffer: {:?}", message_buffer);
93-
Err(format!("The magic number 0x{:x} is incorrect", message_buffer.msg_magic))
94-
} else {
95-
// Avoid starting beyond the end of the buffer
96-
if message_buffer.msg_bufx >= MAX_MSG_BSIZE {
97-
message_buffer.msg_bufx = 0;
98-
}
99-
let mut output: Vec<u8> = Vec::new();
100-
101-
// The message buffer is circular; start at the read pointer, and go to the write pointer - 1.
102-
unsafe {
103-
let mut ch: u8;
104-
let mut p: *mut u8 = message_buffer.msg_bufc.offset(message_buffer.msg_bufx as isize);
105-
let ep: *mut u8 = message_buffer.msg_bufc.offset((message_buffer.msg_bufx - 1) as isize);
106-
107-
while p != ep {
108-
// If at the end, then loop around to the start
109-
// TODO should use actual size (from struct element) - not the max size??
110-
if p == message_buffer.msg_bufc.offset(MAX_MSG_BSIZE as isize) {
111-
p = message_buffer.msg_bufc;
112-
}
113-
114-
ch = *p;
115-
output.push(ch);
116-
p = p.offset(1);
117-
}
52+
if !message_buffer.is_empty() {
53+
let msg = str::from_utf8(&message_buffer)
54+
.map_err(|_| "Could not convert kernel message buffer from utf8".to_string())?
55+
.parse().unwrap();
11856

119-
Ok(String::from_utf8(output).map_err(|_| "Could not convert to UTF-8")?)
120-
}
57+
Ok(msg)
58+
} else {
59+
Err("Could not read kernel message buffer".to_string())
12160
}
12261
}
12362

@@ -132,7 +71,7 @@ pub fn kmsgbuf() -> Result<String, String> {
13271
let duration = time::Duration::from_millis(1);
13372
let mut buf = String::new();
13473
while let Ok(line) = kmsg_channel.recv_timeout(duration) {
135-
buf.push_str(&line)
74+
buf.push_str(&line)
13675
}
13776

13877
Ok(buf)
@@ -148,8 +87,8 @@ fn spawn_kmsg_channel(file: File) -> Receiver<String> {
14887
let mut line = String::new();
14988
match reader.read_line(&mut line) {
15089
Ok(_) => {
151-
if tx.send(line).is_err() { break }
152-
},
90+
if tx.send(line).is_err() { break; }
91+
}
15392
_ => break
15493
}
15594
});
@@ -167,14 +106,10 @@ mod test {
167106
use super::kmsgbuf;
168107

169108
#[test]
170-
#[ignore]
171-
// TODO fix on macos: an error message is returned - https://github.com/andrewdavidmackenzie/libproc-rs/issues/39
172-
// Message buffer: MessageBuffer { magic: 0x3a657461, size: 1986947360, bufx: 1684630625}
173-
// thread 'libproc::kmesg_buffer::test::kmessagebuffer_test' panicked at 'The magic number 0x3a657461 is incorrect', src/libproc/kmesg_buffer.rs:194:33
174109
fn kmessagebuffer_test() {
175110
if am_root() {
176111
match kmsgbuf() {
177-
Ok(buffer) => println!("Buffer: {:?}", buffer),
112+
Ok(_) => { },
178113
Err(message) => panic!(message)
179114
}
180115
} else {

0 commit comments

Comments
 (0)