nixv/
kernel.rs

1// Copyright (C) 2019 - Will Glozer. All rights reserved.
2
3use std::ffi::CStr;
4use std::fs;
5use std::mem::zeroed;
6use std::str::from_utf8;
7use crate::Version;
8
9#[cfg(not(target_os = "linux"))]
10pub fn version() -> Option<Version> {
11    Version::parse(&release()?)
12}
13
14#[cfg(target_os = "linux")]
15pub fn version() -> Option<Version> {
16    ubuntu(read("/proc/version_signature")).or_else(|| {
17        debian(read("/proc/version")).or_else(|| {
18            Version::parse(&release()?)
19        })
20    })
21}
22
23pub(crate) fn release() -> Option<String> {
24    Some(unsafe {
25        let mut buf = zeroed();
26        match libc::uname(&mut buf) {
27            0 => CStr::from_ptr(buf.release[..].as_ptr()),
28            _ => return None,
29        }.to_string_lossy().to_string()
30    })
31}
32
33#[allow(dead_code)]
34pub(crate) fn debian(line: Option<String>) -> Option<Version> {
35    let line   = line?;
36    let marker = "Debian ";
37    let index  = line.rfind(marker)? + marker.len();
38    Version::parse(&line[index..])
39}
40
41#[allow(dead_code)]
42pub(crate) fn ubuntu(line: Option<String>) -> Option<Version> {
43    let (name, version) = triple(&line?)?;
44    match name.as_str() {
45        "Ubuntu" => Some(version),
46        _        => None,
47    }
48}
49
50fn triple(line: &str) -> Option<(String, Version)> {
51    let mut split = line.splitn(3, char::is_whitespace);
52    let name      = split.next()?;
53    let _         = split.next()?;
54    let upstream  = split.next()?;
55    let version   = Version::parse(&upstream)?;
56    Some((name.to_string(), version))
57}
58
59#[allow(dead_code)]
60fn read(path: &str) -> Option<String> {
61    match from_utf8(&fs::read(path).ok()?) {
62        Ok(line) => Some(line.to_string()),
63        Err(_)   => None,
64    }
65}