mac-disk-monitor
Rust library and command-line tool to monitor disk activity on MacOS

Usage
Run the code below, then try plugging a USB dongle or opening a DMG file.
```rust
use macdiskmonitor::{stream_events, Action};
use std::sync::mpsc::channel;
use std::time::Duration;
fn main() {
let (action, receiver) = channel();
let (thread, receiver) = stream_events(receiver);
loop {
// poll for events every 1.5 seconds
match receiver.recv_timeout(Duration::from_millis(1500)) {
Ok(event) => match event {
Some(event) => {
println!("{}", event.to_json());
}
None => {
eprintln!("thread has stopped...");
}
},
Err(e) => {
eprintln!("Error: {}", e);
break;
}
}
}
action.send(Action::Stop).unwrap();
eprintln!("waiting for thread to stop...");
thread.join().unwrap().unwrap()
}
```
Context
This started as a pet project to practice rust.
It executes the command diskutil activity
in a thread and parses every stdout
line in real-time, extracting structured event data.
Developers should be able to subscribe to events and take action, for
example emitting a notification if a specific disk is mounted.
Development
This repo is in active development with best effort to classic
Test-Driven Development, commits happen generaly in this order:
- "TDD [red] - write a failing test that given an input expects an output"
- "TDD [green] - write the smallest and/or simplest code to make the test pass, probably via hardcoding expected value"
- "TDD [refactor] - write real code to make the test pass
Other than that, all other commits kind of follow conventional commits.
Test Data
Click here to see the test data used as input for the "unit" tests
```log
Begin monitoring DiskArbitration activity
*DiskAppeared ('disk4', DAVolumePath = 'file:///Volumes/my%20backups/', DAVolumeKind = 'hfs', DAVolumeName = 'Time Machine Backups') Time=20220108-20:22:05.1438
DiskAppeared ('disk3s2', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:22:05.1453
DiskAppeared ('disk3s1', DAVolumePath = '', DAVolumeKind = 'msdos', DAVolumeName = 'EFI') Time=20220108-20:22:05.1454
DiskAppeared ('disk3s3', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Boot OS X') Time=20220108-20:22:05.1455
DiskAppeared ('disk3', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:22:05.1456
DiskAppeared ((no BSD name), DAVolumePath = 'file:///System/Volumes/Data/home/', DAVolumeKind = 'autofs', DAVolumeName = '') Time=20220108-20:22:05.1457
DiskAppeared ('disk2s1', DAVolumePath = 'file:///Volumes/garuda-ext/', DAVolumeKind = 'hfs', DAVolumeName = 'garuda-ext') Time=20220108-20:22:05.1458
DiskAppeared ('disk2', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:22:05.1459
DiskAppeared ('disk0', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:22:05.1460
DiskAppeared ('disk0s1', DAVolumePath = '', DAVolumeKind = 'msdos', DAVolumeName = 'EFI') Time=20220108-20:22:05.1461
DiskAppeared ('disk0s2', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:22:05.1462
DiskAppeared ('disk1', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:22:05.1463
DiskAppeared ('disk1s1', DAVolumePath = 'file:///System/Volumes/Data/', DAVolumeKind = 'apfs', DAVolumeName = 'maindisk - Data') Time=20220108-20:22:05.1464
DiskAppeared ('disk1s2', DAVolumePath = '', DAVolumeKind = 'apfs', DAVolumeName = 'Preboot') Time=20220108-20:22:05.1465
DiskAppeared ('disk1s3', DAVolumePath = 'file:///Volumes/Recovery/', DAVolumeKind = 'apfs', DAVolumeName = 'Recovery') Time=20220108-20:22:05.1466
DiskAppeared ('disk1s4', DAVolumePath = 'file:///private/var/vm/', DAVolumeKind = 'apfs', DAVolumeName = 'VM') Time=20220108-20:22:05.1467
DiskAppeared ('disk1s5', DAVolumePath = 'file:///', DAVolumeKind = 'apfs', DAVolumeName = 'maindisk') Time=20220108-20:22:05.1469
DAIdle (no DADiskRef) Time=20220108-20:22:05.1470
DiskUnmountApproval ('disk4', DAVolumePath = 'file:///Volumes/my%20backups/', DAVolumeKind = 'hfs', DAVolumeName = 'Time Machine Backups') Comment=Approving Time=20220108-20:22:09.9084
DiskUnmountApproval ('disk4', DAVolumePath = 'file:///Volumes/my%20backups/', DAVolumeKind = 'hfs', DAVolumeName = 'Time Machine Backups') Comment=Approving Time=20220108-20:22:21.1909
DiskDescriptionChanged ('disk4', DAVolumePath = '') Time=20220108-20:22:21.5683
DAIdle (no DADiskRef) Time=20220108-20:22:21.5684
DiskDisappeared ('disk3', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:22:29.6767
DiskDisappeared ('disk4', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Time Machine Backups') Time=20220108-20:22:29.6768
DiskDisappeared ('disk3s3', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Boot OS X') Time=20220108-20:22:29.6770
DiskDisappeared ('disk3s2', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:22:29.6772
DiskDisappeared ('disk3s1', DAVolumePath = '', DAVolumeKind = 'msdos', DAVolumeName = 'EFI') Time=20220108-20:22:29.6773
DAIdle (no DADiskRef) Time=20220108-20:22:29.6774
DiskPeek ('disk3s1') Time=20220108-20:22:35.8607
DiskAppeared ('disk3s1', DAVolumePath = '', DAVolumeKind = 'msdos', DAVolumeName = 'EFI') Time=20220108-20:22:35.8673
DiskMountApproval ('disk3s1', DAVolumePath = '', DAVolumeKind = 'msdos', DAVolumeName = 'EFI') Comment=Approving Time=20220108-20:22:35.8686
DiskPeek ('disk3s3') Time=20220108-20:22:36.0009
DiskPeek ('disk3s2') Time=20220108-20:22:36.0011
DiskPeek ('disk3') Time=20220108-20:22:36.0014
DiskAppeared ('disk3s3', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Boot OS X') Time=20220108-20:22:36.0040
DiskMountApproval ('disk3s3', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Boot OS X') Comment=Approving Time=20220108-20:22:36.0065
DiskAppeared ('disk3s2', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:22:36.0116
DiskAppeared ('disk3', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:22:36.0118
DAIdle (no DADiskRef) Time=20220108-20:22:36.0119
DiskPeek ('disk4') Time=20220108-20:22:37.5920
DiskAppeared ('disk4', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Time Machine Backups') Time=20220108-20:22:37.5980
DiskMountApproval ('disk4', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Time Machine Backups') Comment=Approving Time=20220108-20:22:37.5985
DiskDescriptionChanged ('disk4', DAVolumePath = 'file:///Volumes/my%20backups/') Time=20220108-20:22:41.5508
DAIdle (no DADiskRef) Time=20220108-20:22:41.5509
DiskUnmountApproval ('disk4', DAVolumePath = 'file:///Volumes/my%20backups/', DAVolumeKind = 'hfs', DAVolumeName = 'Time Machine Backups') Comment=Approving Time=20220108-20:22:58.3459
DiskUnmountApproval ('disk4', DAVolumePath = 'file:///Volumes/my%20backups/', DAVolumeKind = 'hfs', DAVolumeName = 'Time Machine Backups') Comment=Approving Time=20220108-20:23:09.6402
DiskDescriptionChanged ('disk4', DAVolumePath = '') Time=20220108-20:23:10.0281
DAIdle (no DADiskRef) Time=20220108-20:23:10.0282
DiskDisappeared ('disk3', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:26:42.3640
DiskDisappeared ('disk4', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Time Machine Backups') Time=20220108-20:26:42.3642
DiskDisappeared ('disk3s3', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Boot OS X') Time=20220108-20:26:42.3643
DiskDisappeared ('disk3s2', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:26:42.3645
DiskDisappeared ('disk3s1', DAVolumePath = '', DAVolumeKind = 'msdos', DAVolumeName = 'EFI') Time=20220108-20:26:42.3647
DAIdle (no DADiskRef) Time=20220108-20:26:42.3647
DiskPeek ('disk3s1') Time=20220108-20:26:48.0983
DiskAppeared ('disk3s1', DAVolumePath = '', DAVolumeKind = 'msdos', DAVolumeName = 'EFI') Time=20220108-20:26:48.1052
DiskMountApproval ('disk3s1', DAVolumePath = '', DAVolumeKind = 'msdos', DAVolumeName = 'EFI') Comment=Approving Time=20220108-20:26:48.1069
DiskPeek ('disk3s3') Time=20220108-20:26:48.2289
DiskPeek ('disk3s2') Time=20220108-20:26:48.2291
DiskPeek ('disk3') Time=20220108-20:26:48.2292
DiskAppeared ('disk3s3', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Boot OS X') Time=20220108-20:26:48.2317
DiskMountApproval ('disk3s3', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Boot OS X') Comment=Approving Time=20220108-20:26:48.2345
DiskAppeared ('disk3s2', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:26:48.2418
DiskAppeared ('disk3', DAVolumePath = '', DAVolumeKind = '', DAVolumeName = '') Time=20220108-20:26:48.2419
DAIdle (no DADiskRef) Time=20220108-20:26:48.2420
DiskPeek ('disk4') Time=20220108-20:26:49.4535
DiskAppeared ('disk4', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Time Machine Backups') Time=20220108-20:26:49.4590
DiskMountApproval ('disk4', DAVolumePath = '', DAVolumeKind = 'hfs', DAVolumeName = 'Time Machine Backups') Comment=Approving Time=20220108-20:26:49.4594
DiskDescriptionChanged ('disk4', DAVolumePath = 'file:///Volumes/my%20backups/') Time=20220108-20:26:52.7814
**DAIdle (no DADiskRef) Time=20220108-20:26:52.7814
```