@@ -1164,8 +1164,87 @@ fn oid2name(oid: &Vec<c_int>) -> Result<String, SysctlError> {
1164
1164
}
1165
1165
}
1166
1166
1167
+ /// Get the next OID.
1168
+ #[ cfg( not( target_os = "macos" ) ) ]
1169
+ pub fn next_oid ( oid : & Vec < c_int > ) -> Result < Option < Vec < c_int > > , SysctlError > {
1170
+ // Request command for next oid
1171
+ let mut qoid: Vec < c_int > = vec ! [ 0 , 2 ] ;
1172
+ qoid. extend ( oid) ;
1173
+
1174
+ let mut len: usize = CTL_MAXNAME as usize * mem:: size_of :: < c_int > ( ) ;
1175
+
1176
+ // We get results in this vector
1177
+ let mut res: Vec < c_int > = vec ! [ 0 ; CTL_MAXNAME as usize ] ;
1178
+
1179
+ let ret = unsafe {
1180
+ sysctl (
1181
+ qoid. as_ptr ( ) ,
1182
+ qoid. len ( ) as u32 ,
1183
+ res. as_mut_ptr ( ) as * mut c_void ,
1184
+ & mut len,
1185
+ ptr:: null ( ) ,
1186
+ 0 ,
1187
+ )
1188
+ } ;
1189
+ if ret != 0 {
1190
+ let e = io:: Error :: last_os_error ( ) ;
1191
+
1192
+ if e. raw_os_error ( ) == Some ( libc:: ENOENT ) {
1193
+ return Ok ( None ) ;
1194
+ }
1195
+ return Err ( SysctlError :: IoError ( e) ) ;
1196
+ }
1197
+
1198
+ // len is in bytes, convert to number of c_ints
1199
+ len /= mem:: size_of :: < c_int > ( ) ;
1200
+
1201
+ // Trim result vector
1202
+ res. truncate ( len) ;
1203
+
1204
+ Ok ( Some ( res) )
1205
+ }
1206
+
1207
+ #[ cfg( target_os = "macos" ) ]
1208
+ pub fn next_oid ( oid : & Vec < c_int > ) -> Result < Option < Vec < c_int > > , SysctlError > {
1209
+ // Request command for next oid
1210
+ let mut qoid: Vec < c_int > = vec ! [ 0 , 2 ] ;
1211
+ qoid. extend ( oid) ;
1212
+
1213
+ let mut len: usize = CTL_MAXNAME as usize * mem:: size_of :: < c_int > ( ) ;
1214
+
1215
+ // We get results in this vector
1216
+ let mut res: Vec < c_int > = vec ! [ 0 ; CTL_MAXNAME as usize ] ;
1217
+
1218
+ let ret = unsafe {
1219
+ sysctl (
1220
+ qoid. as_mut_ptr ( ) ,
1221
+ qoid. len ( ) as u32 ,
1222
+ res. as_mut_ptr ( ) as * mut c_void ,
1223
+ & mut len,
1224
+ ptr:: null_mut ( ) ,
1225
+ 0 ,
1226
+ )
1227
+ } ;
1228
+ if ret != 0 {
1229
+ let e = io:: Error :: last_os_error ( ) ;
1230
+
1231
+ if e. raw_os_error ( ) == Some ( libc:: ENOENT ) {
1232
+ return Ok ( None ) ;
1233
+ }
1234
+ return Err ( SysctlError :: IoError ( e) ) ;
1235
+ }
1236
+
1237
+ // len is in bytes, convert to number of c_ints
1238
+ len /= mem:: size_of :: < c_int > ( ) ;
1239
+
1240
+ // Trim result vector
1241
+ res. truncate ( len) ;
1242
+
1243
+ Ok ( Some ( res) )
1244
+ }
1245
+
1167
1246
/// This struct represents a system control.
1168
- #[ derive( Debug , PartialEq ) ]
1247
+ #[ derive( Debug , Clone , PartialEq ) ]
1169
1248
pub struct Ctl {
1170
1249
oid : Vec < c_int > ,
1171
1250
}
@@ -1345,6 +1424,79 @@ impl Ctl {
1345
1424
}
1346
1425
}
1347
1426
1427
+ /// An iterator over Sysctl entries.
1428
+ pub struct CtlIter {
1429
+ // if we are iterating over a Node, only include OIDs
1430
+ // starting with this base. Set to None if iterating over all
1431
+ // OIDs.
1432
+ base : Ctl ,
1433
+ current : Ctl ,
1434
+ }
1435
+
1436
+ impl CtlIter {
1437
+ /// Return an iterator over the complete sysctl tree.
1438
+ pub fn root ( ) -> Self {
1439
+ CtlIter {
1440
+ base : Ctl { oid : vec ! [ ] } ,
1441
+ current : Ctl { oid : vec ! [ 1 ] } ,
1442
+ }
1443
+ }
1444
+
1445
+ /// Return an iterator over all sysctl entries below the given node.
1446
+ pub fn below ( node : Ctl ) -> Self {
1447
+ CtlIter {
1448
+ base : node. clone ( ) ,
1449
+ current : node,
1450
+ }
1451
+ }
1452
+ }
1453
+
1454
+ impl Iterator for CtlIter {
1455
+ type Item = Result < Ctl , SysctlError > ;
1456
+
1457
+ fn next ( & mut self ) -> Option < Self :: Item > {
1458
+ let oid = match next_oid ( & self . current . oid ) {
1459
+ Ok ( Some ( o) ) => o,
1460
+ Err ( e) => return Some ( Err ( e) ) ,
1461
+ Ok ( None ) => return None ,
1462
+ } ;
1463
+
1464
+ // We continue iterating as long as the oid starts with the base
1465
+ let cont = oid. starts_with ( & self . base . oid ) ;
1466
+
1467
+ self . current = Ctl { oid } ;
1468
+
1469
+ match cont {
1470
+ true => Some ( Ok ( self . current . clone ( ) ) ) ,
1471
+ false => None ,
1472
+ }
1473
+ }
1474
+ }
1475
+
1476
+ /// Ctl implements the IntoIterator trait to allow for easy iteration
1477
+ /// over nodes.
1478
+ ///
1479
+ /// # Example
1480
+ ///
1481
+ /// ```
1482
+ /// extern crate sysctl;
1483
+ /// use sysctl::Ctl;
1484
+ ///
1485
+ /// let kern = Ctl::new("kern");
1486
+ /// for ctl in kern {
1487
+ /// let name = ctl.name().expect("could not get name");
1488
+ /// println!("{}", name);
1489
+ /// }
1490
+ /// ```
1491
+ impl IntoIterator for Ctl {
1492
+ type Item = Result < Ctl , SysctlError > ;
1493
+ type IntoIter = CtlIter ;
1494
+
1495
+ fn into_iter ( self : Self ) -> Self :: IntoIter {
1496
+ CtlIter :: below ( self )
1497
+ }
1498
+ }
1499
+
1348
1500
#[ cfg( test) ]
1349
1501
mod tests {
1350
1502
@@ -1542,4 +1694,81 @@ mod tests {
1542
1694
assert ! ( false ) ;
1543
1695
}
1544
1696
}
1697
+
1698
+ #[ test]
1699
+ fn ctl_iterate_all ( ) {
1700
+ let root = CtlIter :: root ( ) ;
1701
+
1702
+ let all_ctls = root. into_iter ( )
1703
+ . filter_map ( Result :: ok) ;
1704
+
1705
+ for ctl in all_ctls {
1706
+ println ! ( "{:?}" , ctl. name( ) ) ;
1707
+ }
1708
+ }
1709
+
1710
+ #[ test]
1711
+ fn ctl_iterate ( ) {
1712
+ let output = Command :: new ( "sysctl" )
1713
+ . arg ( "security" )
1714
+ . output ( )
1715
+ . expect ( "failed to execute process" ) ;
1716
+ let expected = String :: from_utf8_lossy ( & output. stdout ) ;
1717
+
1718
+ let security = Ctl :: new ( "security" )
1719
+ . expect ( "could not get security node" ) ;
1720
+
1721
+ let ctls = CtlIter :: below ( security) ;
1722
+ let mut actual : Vec < String > = vec ! [ "" . to_string( ) ] ;
1723
+
1724
+ for ctl in ctls {
1725
+ let ctl = match ctl {
1726
+ Err ( _) => { continue ; } ,
1727
+ Ok ( s) => s,
1728
+ } ;
1729
+
1730
+ let name = match ctl. name ( ) {
1731
+ Ok ( s) => s,
1732
+ Err ( _) => { continue ; } ,
1733
+ } ;
1734
+
1735
+ let value = match ctl. value ( ) {
1736
+ Ok ( s) => s,
1737
+ Err ( _) => { continue ; } ,
1738
+ } ;
1739
+
1740
+ let formatted = match value {
1741
+ CtlValue :: None => "(none)" . to_owned ( ) ,
1742
+ CtlValue :: Int ( i) => format ! ( "{}" , i) ,
1743
+ CtlValue :: Uint ( i) => format ! ( "{}" , i) ,
1744
+ CtlValue :: Long ( i) => format ! ( "{}" , i) ,
1745
+ CtlValue :: Ulong ( i) => format ! ( "{}" , i) ,
1746
+ CtlValue :: U8 ( i) => format ! ( "{}" , i) ,
1747
+ CtlValue :: U16 ( i) => format ! ( "{}" , i) ,
1748
+ CtlValue :: U32 ( i) => format ! ( "{}" , i) ,
1749
+ CtlValue :: U64 ( i) => format ! ( "{}" , i) ,
1750
+ CtlValue :: S8 ( i) => format ! ( "{}" , i) ,
1751
+ CtlValue :: S16 ( i) => format ! ( "{}" , i) ,
1752
+ CtlValue :: S32 ( i) => format ! ( "{}" , i) ,
1753
+ CtlValue :: S64 ( i) => format ! ( "{}" , i) ,
1754
+ CtlValue :: Struct ( _) => "(opaque struct)" . to_owned ( ) ,
1755
+ CtlValue :: Node ( _) => "(node)" . to_owned ( ) ,
1756
+ CtlValue :: String ( s) => s. to_owned ( ) ,
1757
+ #[ cfg( not( target_os = "macos" ) ) ]
1758
+ CtlValue :: Temperature ( t) => format ! ( "{} °C" , t. celsius( ) ) ,
1759
+ } ;
1760
+
1761
+ match ctl. value_type ( ) . expect ( "could not get value type" ) {
1762
+ CtlType :: None => { continue ; } ,
1763
+ CtlType :: Struct => { continue ; } ,
1764
+ CtlType :: Node => { continue ; } ,
1765
+ #[ cfg( not( target_os = "macos" ) ) ]
1766
+ CtlType :: Temperature => { continue ; } ,
1767
+ _ => { } ,
1768
+ } ;
1769
+
1770
+ actual. push ( format ! ( "{}: {}" , name, formatted) ) ;
1771
+ }
1772
+ assert_eq ! ( actual. join( "\n " ) . trim( ) , expected. trim( ) ) ;
1773
+ }
1545
1774
}
0 commit comments