1use std::fs::File;
4use std::io::{Read, Result};
5
6use nom::{space, line_ending};
7use parsers::{
8 map_result,
9 parse_u64,
10};
11
12const NET_DEV_FILE: &'static str = "/proc/net/dev";
13
14pub struct DeviceStatus {
18 pub interface: String,
20
21 pub receive_bytes: u64,
23 pub receive_packets: u64,
25 pub receive_errs: u64,
27 pub receive_drop: u64,
29 pub receive_fifo: u64,
31 pub receive_frame: u64,
33 pub receive_compressed: u64,
35 pub receive_multicast: u64,
37
38 pub transmit_bytes: u64,
40 pub transmit_packets: u64,
42 pub transmit_errs: u64,
44 pub transmit_drop: u64,
46 pub transmit_fifo: u64,
48 pub transmit_colls: u64,
50 pub transmit_carrier: u64,
52 pub transmit_compressed: u64,
54}
55
56named!(interface_stats<DeviceStatus>,
57 do_parse!(
58 opt!(space) >>
59 interface: take_until_and_consume!(":") >>
60 space >>
61 receive_bytes: terminated!(parse_u64, space) >>
62 receive_packets: terminated!(parse_u64, space) >>
63 receive_errs: terminated!(parse_u64, space) >>
64 receive_drop: terminated!(parse_u64, space) >>
65 receive_fifo: terminated!(parse_u64, space) >>
66 receive_frame: terminated!(parse_u64, space) >>
67 receive_compressed: terminated!(parse_u64, space) >>
68 receive_multicast: terminated!(parse_u64, space) >>
69 transmit_bytes: terminated!(parse_u64, space) >>
70 transmit_packets: terminated!(parse_u64, space) >>
71 transmit_errs: terminated!(parse_u64, space) >>
72 transmit_drop: terminated!(parse_u64, space) >>
73 transmit_fifo: terminated!(parse_u64, space) >>
74 transmit_colls: terminated!(parse_u64, space) >>
75 transmit_carrier: terminated!(parse_u64, space) >>
76 transmit_compressed: parse_u64 >>
77 (DeviceStatus {
78 interface: String::from_utf8_lossy(interface).to_string(),
79 receive_bytes: receive_bytes,
80 receive_packets: receive_packets,
81 receive_errs: receive_errs,
82 receive_drop: receive_drop,
83 receive_fifo: receive_fifo,
84 receive_frame: receive_frame,
85 receive_compressed: receive_compressed,
86 receive_multicast: receive_multicast,
87 transmit_bytes: transmit_bytes,
88 transmit_packets: transmit_packets,
89 transmit_errs: transmit_errs,
90 transmit_drop: transmit_drop,
91 transmit_fifo: transmit_fifo,
92 transmit_colls: transmit_colls,
93 transmit_carrier: transmit_carrier,
94 transmit_compressed: transmit_compressed,
95 })));
96
97named!(interface_list< Vec<DeviceStatus> >,
98 do_parse!(
99 interfaces: separated_list!(line_ending, interface_stats) >>
100 line_ending >>
101 (interfaces)));
102
103named!(empty_list< Vec<DeviceStatus> >,
104 value!(Vec::new(), eof!()));
105
106named!(parse_dev< Vec<DeviceStatus> >,
107 do_parse!(
108 count!(take_until_and_consume!("\n"), 2) >>
109 interfaces: alt_complete!(interface_list | empty_list) >>
110 (interfaces)));
111
112pub fn dev() -> Result<Vec<DeviceStatus>> {
114 let mut file = File::open(NET_DEV_FILE)?;
115
116 let mut buffer = vec![];
117 file.read_to_end(&mut buffer)?;
118
119 map_result(parse_dev(buffer.as_slice()))
120}
121
122#[cfg(test)]
123mod test {
124 use super::{dev, parse_dev};
125 use parsers::map_result;
126
127 #[test]
128 fn two_interfaces() {
129 let file = br#"Inter-| Receive | Transmit
130 face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
131 lo: 206950 2701 0 0 0 0 0 0 206950 2701 0 0 0 0 0 0
132wlp58s0: 631994599 596110 0 1 0 0 0 0 47170335 384943 0 0 0 0 0 0
133"#;
134 let interfaces = map_result(parse_dev(file)).unwrap();
135
136 assert!(interfaces.len() == 2);
137
138 assert!(interfaces[0].interface == "lo");
139 assert!(interfaces[0].receive_bytes == 206950);
140 assert!(interfaces[0].receive_packets == 2701);
141 assert!(interfaces[0].receive_errs == 0);
142 assert!(interfaces[0].receive_drop == 0);
143 assert!(interfaces[0].receive_fifo == 0);
144 assert!(interfaces[0].receive_frame == 0);
145 assert!(interfaces[0].receive_compressed == 0);
146 assert!(interfaces[0].receive_multicast == 0);
147 assert!(interfaces[0].transmit_bytes == 206950);
148 assert!(interfaces[0].transmit_packets == 2701);
149 assert!(interfaces[0].transmit_errs == 0);
150 assert!(interfaces[0].transmit_drop == 0);
151 assert!(interfaces[0].transmit_fifo == 0);
152 assert!(interfaces[0].transmit_colls == 0);
153 assert!(interfaces[0].transmit_carrier == 0);
154
155 assert!(interfaces[1].interface == "wlp58s0");
156 assert!(interfaces[1].receive_bytes == 631994599);
157 assert!(interfaces[1].receive_packets == 596110);
158 assert!(interfaces[1].receive_errs == 0);
159 assert!(interfaces[1].receive_drop == 1);
160 assert!(interfaces[1].receive_fifo == 0);
161 assert!(interfaces[1].receive_frame == 0);
162 assert!(interfaces[1].receive_multicast == 0);
163 assert!(interfaces[1].transmit_bytes == 47170335);
164 assert!(interfaces[1].transmit_packets == 384943);
165 assert!(interfaces[1].transmit_errs == 0);
166 assert!(interfaces[1].transmit_drop == 0);
167 assert!(interfaces[1].transmit_fifo == 0);
168 assert!(interfaces[1].transmit_colls == 0);
169 assert!(interfaces[1].transmit_carrier == 0);
170 assert!(interfaces[1].transmit_compressed == 0);
171 }
172
173 #[test]
174 fn no_interfaces() {
175 let file = br#"Inter-| Receive | Transmit
176 face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
177"#;
178 let interfaces = map_result(parse_dev(file)).unwrap();
179 assert!(interfaces.len() == 0);
180 }
181
182 #[test]
183 fn parse_native() {
184 dev().unwrap();
185 }
186}