diff --git a/build/image-recipe/build.sh b/build/image-recipe/build.sh index 5a2fe0293..2aa9ccf03 100755 --- a/build/image-recipe/build.sh +++ b/build/image-recipe/build.sh @@ -181,7 +181,7 @@ if [ "$NON_FREE" = 1 ]; then > config/archives/nvidia-container-toolkit.list fi -cat > config/archives/backports.pref <<- EOF +cat > config/archives/backports.pref <<-EOF Package: linux-image-* Pin: release n=${IB_SUITE}-backports Pin-Priority: 500 @@ -232,7 +232,7 @@ if [ "${NON_FREE}" = "1" ]; then # Ensure kernel headers are present if [ ! -e "/lib/modules/\${KVER}/build" ]; then - apt-get install linux-headers-\${KVER}-${IB_TARGET_ARCH} + apt-get install linux-headers-\${KVER} echo "[nvidia-hook] ERROR: /lib/modules/\${KVER}/build missing; install headers for \${KVER} before this hook." >&2 exit 1 fi diff --git a/core/src/net/gateway.rs b/core/src/net/gateway.rs index fe90e15df..7c7685ff8 100644 --- a/core/src/net/gateway.rs +++ b/core/src/net/gateway.rs @@ -703,22 +703,22 @@ async fn watch_ip( .into_iter() .map(IpNet::try_from) .try_collect()?; - let tables = ip4_proxy.route_data().await?.into_iter().filter_map(|d|d.table).collect::>(); - if !tables.is_empty() { - let rules = String::from_utf8(Command::new("ip").arg("rule").arg("list").invoke(ErrorKind::Network).await?)?; - for table in tables { - for subnet in subnets.iter().filter(|s| s.addr().is_ipv4()) { - let subnet_string = subnet.trunc().to_string(); - let rule = ["from", &subnet_string, "lookup", &table.to_string()]; - if !rules.contains(&rule.join(" ")) { - if rules.contains(&rule[..2].join(" ")) { - Command::new("ip").arg("rule").arg("del").args(&rule[..2]).invoke(ErrorKind::Network).await?; - } - Command::new("ip").arg("rule").arg("add").args(rule).invoke(ErrorKind::Network).await?; - } - } - } - } + // let tables = ip4_proxy.route_data().await?.into_iter().filter_map(|d|d.table).collect::>(); + // if !tables.is_empty() { + // let rules = String::from_utf8(Command::new("ip").arg("rule").arg("list").invoke(ErrorKind::Network).await?)?; + // for table in tables { + // for subnet in subnets.iter().filter(|s| s.addr().is_ipv4()) { + // let subnet_string = subnet.trunc().to_string(); + // let rule = ["from", &subnet_string, "lookup", &table.to_string()]; + // if !rules.contains(&rule.join(" ")) { + // if rules.contains(&rule[..2].join(" ")) { + // Command::new("ip").arg("rule").arg("del").args(&rule[..2]).invoke(ErrorKind::Network).await?; + // } + // Command::new("ip").arg("rule").arg("add").args(rule).invoke(ErrorKind::Network).await?; + // } + // } + // } + // } let wan_ip = if !subnets.is_empty() && !matches!( device_type, diff --git a/core/src/registry/migrations/m_01_package_s9pk_array.rs b/core/src/registry/migrations/m_01_package_s9pk_array.rs new file mode 100644 index 000000000..42a3d3e1c --- /dev/null +++ b/core/src/registry/migrations/m_01_package_s9pk_array.rs @@ -0,0 +1,28 @@ +use imbl::vector; +use imbl_value::json; + +use super::RegistryMigration; +use crate::prelude::*; + +pub struct PackageS9pkArray; +impl RegistryMigration for PackageS9pkArray { + fn name(&self) -> &'static str { + "PackageS9pkArray" + } + fn action(&self, db: &mut Value) -> Result<(), Error> { + for (_, info) in db["index"]["package"]["packages"] + .as_object_mut() + .unwrap() + .iter_mut() + { + for (_, info) in info["versions"].as_object_mut().unwrap().iter_mut() { + let hw_req = info["hardwareRequirements"].take(); + let mut s9pk = info["s9pk"].take(); + s9pk["urls"] = Value::Array(vector![s9pk["url"].take()]); + info["s9pks"] = Value::Array(vector![Value::Array(vector![hw_req, s9pk])]); + } + } + + Ok(()) + } +} diff --git a/core/src/registry/migrations/mod.rs b/core/src/registry/migrations/mod.rs index 3cb86b783..4620baa3e 100644 --- a/core/src/registry/migrations/mod.rs +++ b/core/src/registry/migrations/mod.rs @@ -4,14 +4,17 @@ use crate::prelude::*; use crate::registry::RegistryDatabase; mod m_00_package_signer_scope; +mod m_01_package_s9pk_array; pub trait RegistryMigration { fn name(&self) -> &'static str; fn action(&self, db: &mut Value) -> Result<(), Error>; } -pub const MIGRATIONS: &[&dyn RegistryMigration] = - &[&m_00_package_signer_scope::PackageSignerScopeMigration]; +pub const MIGRATIONS: &[&dyn RegistryMigration] = &[ + &m_00_package_signer_scope::PackageSignerScopeMigration, + &m_01_package_s9pk_array::PackageS9pkArray, +]; #[instrument(skip_all)] pub fn run_migrations(db: &mut Model) -> Result<(), Error> { diff --git a/core/src/registry/package/add.rs b/core/src/registry/package/add.rs index 44ba1b60b..62b66d67f 100644 --- a/core/src/registry/package/add.rs +++ b/core/src/registry/package/add.rs @@ -24,13 +24,14 @@ use crate::sign::ed25519::Ed25519; use crate::sign::{AnySignature, AnyVerifyingKey, SignatureScheme}; use crate::util::VersionString; use crate::util::io::TrackingIO; +use crate::util::serde::Base64; #[derive(Debug, Deserialize, Serialize, TS)] #[serde(rename_all = "camelCase")] #[ts(export)] pub struct AddPackageParams { - #[ts(type = "string")] - pub url: Url, + #[ts(type = "string[]")] + pub urls: Vec, #[ts(skip)] #[serde(rename = "__Auth_signer")] pub uploader: AnyVerifyingKey, @@ -41,7 +42,7 @@ pub struct AddPackageParams { pub async fn add_package( ctx: RegistryContext, AddPackageParams { - url, + urls, uploader, commitment, signature, @@ -52,15 +53,31 @@ pub async fn add_package( .verify_commitment(&uploader, &commitment, SIG_CONTEXT, &signature)?; let peek = ctx.db.peek().await; let uploader_guid = peek.as_index().as_signers().get_signer(&uploader)?; + + let ([url], rest) = urls.split_at(1) else { + return Err(Error::new( + eyre!("must specify at least 1 url"), + ErrorKind::InvalidRequest, + )); + }; + let s9pk = S9pk::deserialize( &Arc::new(HttpSource::new(ctx.client.clone(), url.clone()).await?), Some(&commitment), ) .await?; + for url in rest { + S9pk::deserialize( + &Arc::new(HttpSource::new(ctx.client.clone(), url.clone()).await?), + Some(&commitment), + ) + .await?; + } + let manifest = s9pk.as_manifest(); - let mut info = PackageVersionInfo::from_s9pk(&s9pk, url).await?; + let mut info = PackageVersionInfo::from_s9pk(&s9pk, urls).await?; for (_, s9pk) in &mut info.s9pks { if !s9pk.signatures.contains_key(&uploader) && s9pk.commitment == commitment { s9pk.signatures.insert(uploader.clone(), signature.clone()); @@ -88,7 +105,7 @@ pub async fn add_package( .upsert(&manifest.id, || Ok(Default::default()))?; let v = package.as_versions_mut(); if let Some(prev) = v.as_idx_mut(&manifest.version) { - prev.mutate(|p| p.merge_with(info))?; + prev.mutate(|p| p.merge_with(info, true))?; } else { v.insert(&manifest.version, &info)?; } @@ -107,7 +124,10 @@ pub async fn add_package( #[serde(rename_all = "camelCase")] pub struct CliAddPackageParams { pub file: PathBuf, - pub url: Url, + #[arg(long)] + pub url: Vec, + #[arg(long)] + pub no_verify: bool, } pub async fn cli_add_package( @@ -115,7 +135,12 @@ pub async fn cli_add_package( context: ctx, parent_method, method, - params: CliAddPackageParams { file, url }, + params: + CliAddPackageParams { + file, + url, + no_verify, + }, .. }: HandlerArgs, ) -> Result<(), Error> { @@ -123,7 +148,19 @@ pub async fn cli_add_package( let progress = FullProgressTracker::new(); let mut sign_phase = progress.add_phase(InternedString::intern("Signing File"), Some(1)); - let mut verify_phase = progress.add_phase(InternedString::intern("Verifying URL"), Some(100)); + let verify = if !no_verify { + url.iter() + .map(|url| { + let phase = progress.add_phase( + InternedString::from_display(&lazy_format!("Verifying {url}")), + Some(100), + ); + (url.clone(), phase) + }) + .collect() + } else { + Vec::new() + }; let mut index_phase = progress.add_phase( InternedString::intern("Adding File to Registry Index"), Some(1), @@ -137,11 +174,240 @@ pub async fn cli_add_package( let signature = Ed25519.sign_commitment(ctx.developer_key()?, &commitment, SIG_CONTEXT)?; sign_phase.complete(); - verify_phase.start(); - let source = BufferedHttpSource::new(ctx.client.clone(), url.clone(), verify_phase).await?; - let mut src = S9pk::deserialize(&Arc::new(source), Some(&commitment)).await?; - src.serialize(&mut TrackingIO::new(0, &mut tokio::io::sink()), true) - .await?; + for (url, mut phase) in verify { + phase.start(); + let source = BufferedHttpSource::new(ctx.client.clone(), url, phase).await?; + let mut src = S9pk::deserialize(&Arc::new(source), Some(&commitment)).await?; + src.serialize(&mut TrackingIO::new(0, &mut tokio::io::sink()), true) + .await?; + } + + index_phase.start(); + ctx.call_remote::( + &parent_method.into_iter().chain(method).join("."), + imbl_value::json!({ + "urls": &url, + "signature": AnySignature::Ed25519(signature), + "commitment": commitment, + }), + ) + .await?; + index_phase.complete(); + + progress.complete(); + + progress_task.await.with_kind(ErrorKind::Unknown)?; + + Ok(()) +} + +#[derive(Debug, Deserialize, Serialize, Parser, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct RemovePackageParams { + pub id: PackageId, + pub version: VersionString, + #[arg(long)] + pub sighash: Option>, + #[ts(skip)] + #[arg(skip)] + #[serde(rename = "__Auth_signer")] + pub signer: Option, +} + +pub async fn remove_package( + ctx: RegistryContext, + RemovePackageParams { + id, + version, + sighash, + signer, + }: RemovePackageParams, +) -> Result { + let peek = ctx.db.peek().await; + let signer = + signer.ok_or_else(|| Error::new(eyre!("missing signer"), ErrorKind::InvalidRequest))?; + let signer_guid = peek.as_index().as_signers().get_signer(&signer)?; + + let rev = ctx + .db + .mutate(|db| { + if db.as_admins().de()?.contains(&signer_guid) + || db + .as_index() + .as_package() + .as_packages() + .as_idx(&id) + .or_not_found(&id)? + .as_authorized() + .de()? + .get(&signer_guid) + .map_or(false, |v| version.satisfies(v)) + { + if let Some(package) = db + .as_index_mut() + .as_package_mut() + .as_packages_mut() + .as_idx_mut(&id) + { + if let Some(sighash) = sighash { + if if let Some(package) = package.as_versions_mut().as_idx_mut(&version) { + package.as_s9pks_mut().mutate(|s| { + s.retain(|(_, asset)| asset.commitment.root_sighash != sighash); + Ok(s.is_empty()) + })? + } else { + false + } { + package.as_versions_mut().remove(&version)?; + } + } else { + package.as_versions_mut().remove(&version)?; + } + } + Ok(()) + } else { + Err(Error::new(eyre!("UNAUTHORIZED"), ErrorKind::Authorization)) + } + }) + .await; + rev.result.map(|_| rev.revision.is_some()) +} + +#[derive(Debug, Deserialize, Serialize, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export)] +pub struct AddMirrorParams { + #[ts(type = "string")] + pub url: Url, + #[ts(skip)] + #[serde(rename = "__Auth_signer")] + pub uploader: AnyVerifyingKey, + pub commitment: MerkleArchiveCommitment, + pub signature: AnySignature, +} + +pub async fn add_mirror( + ctx: RegistryContext, + AddMirrorParams { + url, + uploader, + commitment, + signature, + }: AddMirrorParams, +) -> Result<(), Error> { + uploader + .scheme() + .verify_commitment(&uploader, &commitment, SIG_CONTEXT, &signature)?; + let peek = ctx.db.peek().await; + let uploader_guid = peek.as_index().as_signers().get_signer(&uploader)?; + + let s9pk = S9pk::deserialize( + &Arc::new(HttpSource::new(ctx.client.clone(), url.clone()).await?), + Some(&commitment), + ) + .await?; + + let manifest = s9pk.as_manifest(); + + let mut info = PackageVersionInfo::from_s9pk(&s9pk, vec![url]).await?; + for (_, s9pk) in &mut info.s9pks { + if !s9pk.signatures.contains_key(&uploader) && s9pk.commitment == commitment { + s9pk.signatures.insert(uploader.clone(), signature.clone()); + } + } + + ctx.db + .mutate(|db| { + if db.as_admins().de()?.contains(&uploader_guid) + || db + .as_index() + .as_package() + .as_packages() + .as_idx(&manifest.id) + .or_not_found(&manifest.id)? + .as_authorized() + .de()? + .get(&uploader_guid) + .map_or(false, |v| manifest.version.satisfies(v)) + { + let package = db + .as_index_mut() + .as_package_mut() + .as_packages_mut() + .as_idx_mut(&manifest.id) + .and_then(|p| p.as_versions_mut().as_idx_mut(&manifest.version)) + .or_not_found(&lazy_format!("{}@{}", &manifest.id, &manifest.version))?; + package.mutate(|p| p.merge_with(info, false))?; + + Ok(()) + } else { + Err(Error::new(eyre!("UNAUTHORIZED"), ErrorKind::Authorization)) + } + }) + .await + .result +} + +#[derive(Debug, Deserialize, Serialize, Parser)] +#[command(rename_all = "kebab-case")] +#[serde(rename_all = "camelCase")] +pub struct CliAddMirrorParams { + pub file: PathBuf, + pub url: Url, + pub no_verify: bool, +} + +pub async fn cli_add_mirror( + HandlerArgs { + context: ctx, + parent_method, + method, + params: + CliAddMirrorParams { + file, + url, + no_verify, + }, + .. + }: HandlerArgs, +) -> Result<(), Error> { + let s9pk = S9pk::open(&file, None).await?; + + let progress = FullProgressTracker::new(); + let mut sign_phase = progress.add_phase(InternedString::intern("Signing File"), Some(1)); + let verify = if !no_verify { + let url = &url; + vec![( + url.clone(), + progress.add_phase( + InternedString::from_display(&lazy_format!("Verifying {url}")), + Some(100), + ), + )] + } else { + Vec::new() + }; + let mut index_phase = progress.add_phase( + InternedString::intern("Adding File to Registry Index"), + Some(1), + ); + + let progress_task = + progress.progress_bar_task(&format!("Adding {} to registry...", file.display())); + + sign_phase.start(); + let commitment = s9pk.as_archive().commitment().await?; + let signature = Ed25519.sign_commitment(ctx.developer_key()?, &commitment, SIG_CONTEXT)?; + sign_phase.complete(); + + for (url, mut phase) in verify { + phase.start(); + let source = BufferedHttpSource::new(ctx.client.clone(), url, phase).await?; + let mut src = S9pk::deserialize(&Arc::new(source), Some(&commitment)).await?; + src.serialize(&mut TrackingIO::new(0, &mut tokio::io::sink()), true) + .await?; + } index_phase.start(); ctx.call_remote::( @@ -165,22 +431,26 @@ pub async fn cli_add_package( #[derive(Debug, Deserialize, Serialize, Parser, TS)] #[serde(rename_all = "camelCase")] #[ts(export)] -pub struct RemovePackageParams { +pub struct RemoveMirrorParams { pub id: PackageId, pub version: VersionString, + #[arg(long)] + #[ts(type = "string")] + pub url: Url, #[ts(skip)] #[arg(skip)] #[serde(rename = "__Auth_signer")] pub signer: Option, } -pub async fn remove_package( +pub async fn remove_mirror( ctx: RegistryContext, - RemovePackageParams { + RemoveMirrorParams { id, version, + url, signer, - }: RemovePackageParams, + }: RemoveMirrorParams, ) -> Result<(), Error> { let peek = ctx.db.peek().await; let signer = @@ -206,8 +476,20 @@ pub async fn remove_package( .as_package_mut() .as_packages_mut() .as_idx_mut(&id) + .and_then(|p| p.as_versions_mut().as_idx_mut(&version)) { - package.as_versions_mut().remove(&version)?; + package.as_s9pks_mut().mutate(|s| { + s.iter_mut() + .for_each(|(_, asset)| asset.urls.retain(|u| u != &url)); + if s.iter().any(|(_, asset)| asset.urls.is_empty()) { + Err(Error::new( + eyre!("cannot remove last mirror from an s9pk"), + ErrorKind::InvalidRequest, + )) + } else { + Ok(()) + } + })?; } Ok(()) } else { diff --git a/core/src/registry/package/index.rs b/core/src/registry/package/index.rs index 4549815fb..ee7e2adae 100644 --- a/core/src/registry/package/index.rs +++ b/core/src/registry/package/index.rs @@ -145,7 +145,10 @@ pub struct PackageVersionInfo { pub s9pks: Vec<(HardwareRequirements, RegistryAsset)>, } impl PackageVersionInfo { - pub async fn from_s9pk(s9pk: &S9pk, url: Url) -> Result { + pub async fn from_s9pk( + s9pk: &S9pk, + urls: Vec, + ) -> Result { Ok(Self { metadata: PackageMetadata::load(s9pk).await?, source_version: None, // TODO @@ -153,7 +156,7 @@ impl PackageVersionInfo { s9pk.as_manifest().hardware_requirements.clone(), RegistryAsset { published_at: Utc::now(), - urls: vec![url], + urls, commitment: s9pk.as_archive().commitment().await?, signatures: [( AnyVerifyingKey::Ed25519(s9pk.as_archive().signer()), @@ -165,18 +168,22 @@ impl PackageVersionInfo { )], }) } - pub fn merge_with(&mut self, other: Self) -> Result<(), Error> { + pub fn merge_with(&mut self, other: Self, replace_urls: bool) -> Result<(), Error> { for (hw_req, asset) in other.s9pks { if let Some((_, matching)) = self .s9pks .iter_mut() .find(|(h, s)| s.commitment == asset.commitment && *h == hw_req) { - for url in asset.urls { - if matching.urls.contains(&url) { - continue; + if replace_urls { + matching.urls = asset.urls; + } else { + for url in asset.urls { + if matching.urls.contains(&url) { + continue; + } + matching.urls.push(url); } - matching.urls.push(url); } } else { if let Some((h, matching)) = self.s9pks.iter_mut().find(|(h, _)| *h == hw_req) { diff --git a/core/src/registry/package/mod.rs b/core/src/registry/package/mod.rs index d868c4364..e09dbbb9a 100644 --- a/core/src/registry/package/mod.rs +++ b/core/src/registry/package/mod.rs @@ -32,14 +32,46 @@ pub fn package_api() -> ParentHandler { .no_display() .with_about("Add package to registry index"), ) + .subcommand( + "add-mirror", + from_fn_async(add::add_mirror) + .with_metadata("get_signer", Value::Bool(true)) + .no_cli(), + ) + .subcommand( + "add-mirror", + from_fn_async(add::cli_add_mirror) + .no_display() + .with_about("Add a mirror for an s9pk"), + ) .subcommand( "remove", from_fn_async(add::remove_package) .with_metadata("get_signer", Value::Bool(true)) - .no_display() + .with_custom_display_fn(|args, changed| { + if !changed { + tracing::warn!( + "{}@{}{} does not exist, so not removed", + args.params.id, + args.params.version, + args.params + .sighash + .map_or(String::new(), |h| format!("#{h}")) + ); + } + Ok(()) + }) .with_about("Remove package from registry index") .with_call_remote::(), ) + .subcommand( + "remove-mirror", + from_fn_async(add::remove_mirror) + .with_metadata("get_signer", Value::Bool(true)) + .no_display() + .with_about("Remove a mirror from a package") + .with_call_remote::(), + ) .subcommand( "signer", signer::signer_api::().with_about("Add, remove, and list package signers"), diff --git a/debian/startos/postinst b/debian/startos/postinst index bf4276990..924a29031 100755 --- a/debian/startos/postinst +++ b/debian/startos/postinst @@ -3,39 +3,67 @@ set -e SYSTEMCTL=systemctl if [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ]; then - SYSTEMCTL=deb-systemd-helper + SYSTEMCTL=deb-systemd-helper fi if [ -f /usr/sbin/grub-probe ] && ! [ -L /usr/sbin/grub-probe ]; then - mv /usr/sbin/grub-probe /usr/sbin/grub-probe-default - ln -s /usr/lib/startos/scripts/grub-probe-eos /usr/sbin/grub-probe + mv /usr/sbin/grub-probe /usr/sbin/grub-probe-default + ln -s /usr/lib/startos/scripts/grub-probe-eos /usr/sbin/grub-probe fi cp /usr/lib/startos/scripts/startos-initramfs-module /etc/initramfs-tools/scripts/startos if ! grep overlay /etc/initramfs-tools/modules > /dev/null; then - echo overlay >> /etc/initramfs-tools/modules + echo overlay >> /etc/initramfs-tools/modules fi update-initramfs -u -k all if [ -f /etc/default/grub ]; then - sed -i '/\(^\|#\)GRUB_CMDLINE_LINUX=/c\GRUB_CMDLINE_LINUX="boot=startos console=ttyS0,115200n8 console=tty0"' /etc/default/grub - sed -i '/\(^\|#\)GRUB_CMDLINE_LINUX_DEFAULT=/c\GRUB_CMDLINE_LINUX_DEFAULT=""' /etc/default/grub - sed -i '/\(^\|#\)GRUB_DISTRIBUTOR=/c\GRUB_DISTRIBUTOR="StartOS v$(cat /usr/lib/startos/VERSION.txt)"' /etc/default/grub - sed -i '/\(^\|#\)GRUB_TERMINAL=/c\GRUB_TERMINAL="serial"\nGRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1"' /etc/default/grub - if grep '^GRUB_SERIAL_COMMAND=' /etc/default/grub > /dev/null; then - sed -i '/\(^\|#\)GRUB_SERIAL_COMMAND=/c\GRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1"' /etc/default/grub - else - echo 'GRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1"' >> /etc/default/grub - fi + sed -i '/\(^\|#\)GRUB_CMDLINE_LINUX=/c\GRUB_CMDLINE_LINUX="boot=startos console=ttyS0,115200n8 console=tty0"' /etc/default/grub + sed -i '/\(^\|#\)GRUB_CMDLINE_LINUX_DEFAULT=/c\GRUB_CMDLINE_LINUX_DEFAULT=""' /etc/default/grub + sed -i '/\(^\|#\)GRUB_DISTRIBUTOR=/c\GRUB_DISTRIBUTOR="StartOS v$(cat /usr/lib/startos/VERSION.txt)"' /etc/default/grub + sed -i '/\(^\|#\)GRUB_TERMINAL=/c\GRUB_TERMINAL="serial"\nGRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1"' /etc/default/grub + if grep '^GRUB_SERIAL_COMMAND=' /etc/default/grub > /dev/null; then + sed -i '/\(^\|#\)GRUB_SERIAL_COMMAND=/c\GRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1"' /etc/default/grub + else + echo 'GRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1"' >> /etc/default/grub + fi + + cat > /etc/grub.d/01_reboot_efi <<-EOF + #!/bin/sh + + set -e + + # Only affect EFI systems + if [ ! -d /sys/firmware/efi ]; then + exit 0 + fi + + # Import helpers (path is Debian/Ubuntu style) + . /usr/lib/grub/grub-mkconfig_lib + + # Append reboot=efi to GRUB_CMDLINE_LINUX* seen by later scripts + if [ -n "\${GRUB_CMDLINE_LINUX}" ]; then + GRUB_CMDLINE_LINUX="\${GRUB_CMDLINE_LINUX} reboot=efi" + else + GRUB_CMDLINE_LINUX="reboot=efi" + fi + + if [ -n "\${GRUB_CMDLINE_LINUX_DEFAULT}" ]; then + GRUB_CMDLINE_LINUX_DEFAULT="\${GRUB_CMDLINE_LINUX_DEFAULT} reboot=efi" + fi + + export GRUB_CMDLINE_LINUX GRUB_CMDLINE_LINUX_DEFAULT + EOF + chmod +x /etc/grub.d/01_reboot_efi fi VERSION="$(cat /usr/lib/startos/VERSION.txt)" ENVIRONMENT=$(cat /usr/lib/startos/ENVIRONMENT.txt) VERSION_ENV="${VERSION}" if [ -n "${ENVIRONMENT}" ]; then - VERSION_ENV="${VERSION} (${ENVIRONMENT})" + VERSION_ENV="${VERSION} (${ENVIRONMENT})" fi # set /etc/os-release @@ -95,8 +123,8 @@ $SYSTEMCTL mask hibernate.target $SYSTEMCTL mask hybrid-sleep.target if which gsettings > /dev/null; then - gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout '0' - gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-timeout '0' + gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout '0' + gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-timeout '0' fi sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config @@ -128,7 +156,7 @@ ln -sf /usr/lib/startos/scripts/wireguard-vps-proxy-setup /usr/bin/wireguard-vps echo "fs.inotify.max_user_watches=1048576" > /etc/sysctl.d/97-startos.conf if ! getent group | grep '^startos:'; then - groupadd startos + groupadd startos fi rm -f /etc/motd