1
0
Fork 0

init commit: 0.1.0

This commit is contained in:
Pratham Patel 2024-03-04 22:31:23 +05:30
commit 57e82f86a5
Signed by: thefossguy
SSH Key Fingerprint: SHA256:/B3wAg7jnMEBQ2JwkebbS/eXVZANDmqRfnd9QkIhxMI
9 changed files with 345 additions and 0 deletions

1
.envrc Normal file
View File

@ -0,0 +1 @@
use flake

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.direnv/*
/target
result

77
Cargo.lock generated Normal file
View File

@ -0,0 +1,77 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "nixos-reedsreboot"
version = "0.1.0"
dependencies = [
"strum",
"strum_macros",
]
[[package]]
name = "proc-macro2"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "strum"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f"
[[package]]
name = "strum_macros"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "syn"
version = "2.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"

14
Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "nixos-reedsreboot"
version = "0.1.0"
edition = "2021"
description = "Determine if you need to reboot your NixOS machine"
license = "GPL-2.0"
repository = "https://github.com/thefossguy/nixos-reedsreboot"
readme = "README.md"
keywords = [ "nixos" ]
categories = [ "command-line-utilities" ]
[dependencies]
strum = "0.26"
strum_macros = "0.26"

4
README.md Normal file
View File

@ -0,0 +1,4 @@
# nixos-needsreboot
Checks if you should reboot your NixOS machine in case an upgrade brought in
some new goodies. :)

25
flake.lock Normal file
View File

@ -0,0 +1,25 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1709309926,
"narHash": "sha256-VZFBtXGVD9LWTecGi6eXrE0hJ/mVB3zGUlHImUs2Qak=",
"rev": "79baff8812a0d68e24a836df0a364c678089e2c7",
"revCount": 556338,
"type": "tarball",
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2311.556338%2Brev-79baff8812a0d68e24a836df0a364c678089e2c7/018dfea4-6d6e-74d3-b5df-3d859de1988e/source.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://flakehub.com/f/NixOS/nixpkgs/%2A.tar.gz"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

44
flake.nix Normal file
View File

@ -0,0 +1,44 @@
{
inputs = {
# a better way of using the latest stable version of nixpkgs
# without specifying specific release
nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/*.tar.gz";
};
outputs = { self, nixpkgs, ... }:
let
# helpers for producing system-specific outputs
supportedSystems = [
"aarch64-linux"
"riscv64-linux"
"x86_64-linux"
];
forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f {
pkgs = import nixpkgs { inherit system; };
});
in
{
devShells = forEachSupportedSystem ({ pkgs, ... }: {
default = pkgs.mkShell {
packages = with pkgs; [
rustup
gdb
pkg-config
# formatting this flake
nixpkgs-fmt
];
};
});
packages = forEachSupportedSystem ({ pkgs, ... }: {
default = pkgs.rustPlatform.buildRustPackage {
pname = "nixos-needsreboot";
version = "0.1.0";
src = ./.;
cargoHash = "sha256-5b8db/Jy17u+olpJy4aeR7BO7m01yxzg++ar2u5gYk0=";
};
});
};
}

View File

@ -0,0 +1,151 @@
use std::{error::Error, fmt, fs};
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
use crate::{NEW_SYSTEM_PATH, OLD_SYSTEM_PATH};
#[derive(EnumIter)]
enum ModuleType {
LinuxKernel,
Systemd,
}
// for printing messages
impl fmt::Display for ModuleType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::LinuxKernel => write!(f, "Linux Kernel"),
Self::Systemd => write!(f, "Systemd"),
}
}
}
// for getting the "suffix"
impl fmt::Debug for ModuleType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::LinuxKernel => write!(f, "/kernel"),
Self::Systemd => write!(f, "/system"),
}
}
}
impl ModuleType {
fn get_nix_store_path(&self, use_old_path: bool) -> Result<String, Box<dyn Error>> {
let suffix = match self {
Self::LinuxKernel => "/kernel",
Self::Systemd => "/systemd",
};
let strip_suffix = match self {
Self::Systemd => false,
Self::LinuxKernel => true,
};
let system_path = if use_old_path {
OLD_SYSTEM_PATH.to_string()
} else {
NEW_SYSTEM_PATH.to_string()
};
let tmp_module_path = fs::read_link(system_path + suffix)?
.into_os_string()
.into_string()
.expect("Cannot convert PathBuf to String");
let nix_module_path = if strip_suffix {
let split_module_path = tmp_module_path.split('/').collect::<Vec<&str>>();
let mut module_dir = split_module_path
.get(1..4)
.ok_or("Cannot find the module's directory in /nix/store")?
.join("/");
module_dir.insert(0, '/');
module_dir
} else {
tmp_module_path
};
Ok(nix_module_path)
}
fn get_linux_version(linux_path: &str) -> Result<String, Box<dyn Error>> {
let lib_modules_path = fs::read_dir(linux_path)?
.nth(0)
.ok_or("Expected one directory in ".to_string() + linux_path)??
.path()
.into_os_string()
.into_string()
.expect("Cannot convert PathBuf to String");
let linux_version = lib_modules_path.split('/').nth(6).ok_or(
"Could not determine Linux kernel version from path: ".to_string() + &lib_modules_path,
)?;
Ok(linux_version.to_string())
}
fn get_systemd_version(systemd_path: &str) -> Result<String, Box<dyn Error>> {
let split_systemd_path = systemd_path.split('-').collect::<Vec<&str>>();
let systemd_version = split_systemd_path
.get(2..)
.ok_or("Could not determine Systemd version from path: ".to_string() + systemd_path)?
.join("-");
Ok(systemd_version)
}
fn get_version(&self) -> Result<(String, String), Box<dyn Error>> {
let old_module_root_path = self.get_nix_store_path(true)?;
let new_module_root_path = self.get_nix_store_path(false)?;
let old_module_version: String;
let new_module_version: String;
match self {
Self::LinuxKernel => {
let linux_path = old_module_root_path + "/lib/modules";
old_module_version = Self::get_linux_version(&linux_path)?;
new_module_version = Self::get_linux_version(&linux_path)?;
}
Self::Systemd => {
old_module_version = Self::get_systemd_version(&old_module_root_path)?;
new_module_version = Self::get_systemd_version(&new_module_root_path)?;
}
}
Ok((old_module_version, new_module_version))
}
}
pub fn upgrades_available() -> Result<bool, Box<dyn Error>> {
let mut needs_reboot = false;
'x: for module in ModuleType::iter() {
let (mut old_module_version, mut new_module_version) = module.get_version()?;
if old_module_version != new_module_version {
if old_module_version.len() != new_module_version.len() {
if old_module_version.contains("-rc") && !new_module_version.contains("-rc") {
old_module_version = old_module_version.replace("-rc", ".");
new_module_version.push_str(".0");
} else if new_module_version.contains("-rc") && !old_module_version.contains("-rc")
{
new_module_version = new_module_version.replace("-rc", ".");
old_module_version.push_str(".0");
} else if new_module_version.contains("-rc") && old_module_version.contains("-rc") {
new_module_version = new_module_version.replace("-rc", ".");
old_module_version = old_module_version.replace("-rc", ".");
}
}
let old_version = &old_module_version.split('.').collect::<Vec<&str>>();
let new_version = &new_module_version.split('.').collect::<Vec<&str>>();
for (old, new) in old_version.iter().zip(new_version.iter()) {
if new > old {
eprintln!("DEBUG: needs upgrading for module '{module}'");
needs_reboot = true;
break 'x;
}
}
}
}
Ok(needs_reboot)
}

26
src/main.rs Normal file
View File

@ -0,0 +1,26 @@
use std::error::Error;
use std::fs;
mod compare_nixos_modules;
pub static OLD_SYSTEM_PATH: &str = "/run/booted-system";
pub static NEW_SYSTEM_PATH: &str = "/nix/var/nix/profiles/system";
fn main() -> Result<(), Box<dyn Error>> {
if std::path::Path::new("/nix/var/nix/profiles/system").exists() {
let old_system_id = fs::read_to_string(OLD_SYSTEM_PATH.to_string() + "/nixos-version")?;
let new_system_id = fs::read_to_string(NEW_SYSTEM_PATH.to_string() + "/nixos-version")?;
if old_system_id == new_system_id {
eprintln!("DEBUG: you are using the latest NixOS generation, no need to reboot");
} else if compare_nixos_modules::upgrades_available()? {
fs::File::create("/var/run/reboot-required")?;
} else {
eprintln!("DEBUG: no updates available, moar uptime!!!");
}
} else {
eprintln!("This binary is intedned to run only on NixOS.");
}
Ok(())
}