Skip to content

Commit 33fb34e

Browse files
feat(oma-pm): not allow delete current kernel in AOSC OS (#535)
* feat(oma-pm)!: not allow delete current kernel in AOSC OS * chore(i18n): improve UI prompts for current kernel removal --------- Co-authored-by: Mingcong Bai <[email protected]>
1 parent e47de98 commit 33fb34e

File tree

10 files changed

+189
-73
lines changed

10 files changed

+189
-73
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

i18n/en-US/oma.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,3 +296,4 @@ successfully-refresh-without-status = Successfully refreshed the package databas
296296
not-allow-delete-using-kernel = Not allow deletion of the Linux kernel version in use: { $ver }.
297297
yes-mode-conflict-ui = `--yes` mode will not be applied in UI mode.
298298
oma-refresh-no-metadata-to-download = No suitable package metadata available based on your repository configuration.
299+
delete-current-kernel-tips = { $kernel } is currently in use, removing it may render the system inoperable.

i18n/zh-CN/oma.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,4 @@ update-available-2 = oma 已检测到您的系统有以下可用更新:
289289
not-allow-delete-using-kernel = 不允许删除正在使用的 Linux 内核版本:{ $ver }
290290
yes-mode-conflict-ui = UI 模式下将不会应用 `--yes` 模式。
291291
oma-refresh-no-metadata-to-download = 源配置中没有适用的软件包元数据。
292+
delete-current-kernel-tips = { $kernel } 为正在使用的内核,移除后可能导致系统无法工作。

oma-pm/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ memchr = "2"
3636
serde = { version = "1", features = ["derive"] }
3737
apt-auth-config = { version = "0.4.0", path = "../apt-auth-config" }
3838
once_cell = "1.20"
39+
sysinfo = { version = "0.37", optional = true }
3940

4041
[dev-dependencies]
4142
flume = "0.11"
4243

4344
[features]
44-
aosc = []
45+
aosc = ["dep:sysinfo"]

oma-pm/src/apt.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,28 @@ impl OmaApt {
531531
let sort = PackageSort::default().installed();
532532
let pkgs = self.cache.packages(&sort);
533533

534+
#[cfg(feature = "aosc")]
535+
let image_name = OnceCell::new();
536+
537+
#[cfg(feature = "aosc")]
538+
let current_kernel_ver = OnceCell::new();
539+
534540
for pkg in pkgs {
541+
#[cfg(feature = "aosc")]
542+
if pkg.name().starts_with("linux-kernel-") {
543+
let current_kernel_ver = current_kernel_ver
544+
.get_or_init(|| sysinfo::System::kernel_version().unwrap_or_default());
545+
546+
if crate::utils::pkg_is_current_kernel(
547+
Path::new(&self.sysroot()),
548+
&image_name,
549+
pkg.name(),
550+
current_kernel_ver,
551+
) {
552+
continue;
553+
}
554+
}
555+
535556
if pkg.is_auto_removable() && !pkg.marked_delete() {
536557
pkg.mark_delete(purge);
537558
pkg.protect();
@@ -557,7 +578,7 @@ impl OmaApt {
557578
custom_download_message: Option<CustomDownloadMessage>,
558579
callback: impl AsyncFn(Event),
559580
) -> OmaAptResult<()> {
560-
let sysroot = self.config.get("Dir").unwrap_or("/".to_string());
581+
let sysroot = self.sysroot();
561582

562583
if self.dry_run {
563584
debug!("op: {op:?}");
@@ -577,6 +598,10 @@ impl OmaApt {
577598
Ok(())
578599
}
579600

601+
fn sysroot(&self) -> String {
602+
self.config.get("Dir").unwrap_or_else(|| "/".to_string())
603+
}
604+
580605
pub fn fix_resolver_broken(&self) {
581606
self.cache.fix_broken();
582607
}

oma-pm/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub use search::PackageStatus;
4040
mod commit;
4141
mod dbus;
4242
mod download;
43+
pub mod utils;
4344
pub use commit::CommitNetworkConfig;
4445
pub mod sort;
4546
pub use oma_apt::records::RecordField;

oma-pm/src/utils.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use std::{fs, io, path::Path};
2+
3+
#[cfg(feature = "aosc")]
4+
pub fn pkg_is_current_kernel(
5+
sysroot: &Path,
6+
image_name: &once_cell::sync::OnceCell<Option<String>>,
7+
pkg_name: &str,
8+
current_kernel_ver: &str,
9+
) -> bool {
10+
fn is_installed_pkg_contains_file_impl(
11+
pkg_name: &str,
12+
image_names: &[impl AsRef<str>],
13+
sysroot: &Path,
14+
) -> bool {
15+
is_installed_pkg_contains_file(pkg_name, image_names, sysroot).unwrap_or_else(|e| {
16+
tracing::warn!("Failed to get package {pkg_name} file list: {e}");
17+
false
18+
})
19+
}
20+
21+
let image_name = image_name.get_or_init(get_kernel_image_filename);
22+
tracing::debug!("image name = {image_name:?}");
23+
24+
if let Some(image_name) = image_name {
25+
is_installed_pkg_contains_file_impl(pkg_name, &[image_name], sysroot)
26+
} else {
27+
is_installed_pkg_contains_file_impl(
28+
pkg_name,
29+
&[
30+
format!("vmlinux-{current_kernel_ver}"),
31+
format!("vmlinuz-{current_kernel_ver}"),
32+
],
33+
sysroot,
34+
)
35+
}
36+
}
37+
38+
#[cfg(feature = "aosc")]
39+
fn get_kernel_image_filename() -> Option<String> {
40+
let cmdline = fs::read_to_string("/proc/cmdline").ok()?;
41+
42+
for i in cmdline.split_ascii_whitespace() {
43+
if let Some(image_path) = i.strip_prefix("BOOT_IMAGE=") {
44+
return Some(
45+
Path::new(image_path)
46+
.file_name()
47+
.map(|x| x.to_string_lossy().to_string())
48+
.unwrap_or_else(|| image_path.to_string()),
49+
);
50+
}
51+
}
52+
53+
None
54+
}
55+
56+
pub fn is_installed_pkg_contains_file(
57+
pkg_name: &str,
58+
file_names: &[impl AsRef<str>],
59+
sysroot: &Path,
60+
) -> io::Result<bool> {
61+
let p = sysroot.join(format!("var/lib/dpkg/info/{pkg_name}.list"));
62+
let file = fs::read_to_string(&p)?;
63+
64+
for line in file.lines() {
65+
if Path::new(line).file_name().is_some_and(|n| {
66+
file_names
67+
.iter()
68+
.any(|name| name.as_ref() == n.to_string_lossy())
69+
}) {
70+
return Ok(true);
71+
}
72+
}
73+
74+
Ok(false)
75+
}

src/pb.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ impl OmaProgressBar {
7979
}
8080
}
8181

82+
impl Drop for OmaProgressBar {
83+
fn drop(&mut self) {
84+
self.inner.finish_and_clear();
85+
}
86+
}
87+
8288
impl Writeln for OmaProgressBar {
8389
fn writeln(&self, prefix: &str, msg: &str) -> std::io::Result<()> {
8490
let max_len = WRITER.get_max_len();

src/subcommand/remove.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ impl CliExecuter for Remove {
243243

244244
let pb = create_progress_spinner(no_progress, fl!("resolving-dependencies"));
245245

246+
#[cfg(feature = "aosc")]
247+
check_is_current_kernel_deleting(config, &sysroot, &pkgs, &pb)?;
248+
246249
let context = apt.remove(pkgs, remove_config, no_autoremove)?;
247250

248251
if let Some(pb) = pb {
@@ -278,6 +281,50 @@ impl CliExecuter for Remove {
278281
}
279282
}
280283

284+
#[cfg(feature = "aosc")]
285+
fn check_is_current_kernel_deleting(
286+
config: &Config,
287+
sysroot: &std::path::Path,
288+
pkgs: &[oma_pm::pkginfo::OmaPackageWithoutVersion],
289+
pb: &Option<crate::pb::OmaProgressBar>,
290+
) -> Result<(), OutputError> {
291+
use anyhow::Context;
292+
use once_cell::sync::OnceCell;
293+
294+
if let Some(pb) = pb {
295+
pb.inner.finish_and_clear();
296+
}
297+
298+
let image_name = OnceCell::new();
299+
let current_kernel_ver = OnceCell::new();
300+
301+
for pkg in pkgs
302+
.iter()
303+
.filter(|pkg| pkg.raw_pkg.name().starts_with("linux-kernel-"))
304+
{
305+
let current_kernel_ver =
306+
current_kernel_ver.get_or_try_init(|| -> anyhow::Result<String> {
307+
sysinfo::System::kernel_version().context("Failed to get kernel version")
308+
})?;
309+
310+
if oma_pm::utils::pkg_is_current_kernel(
311+
sysroot,
312+
&image_name,
313+
pkg.raw_pkg.name(),
314+
current_kernel_ver,
315+
) && (config.protect_essentials()
316+
|| !ask_user_delete_current_kernel(pkg.raw_pkg.name()).unwrap_or(false))
317+
{
318+
return Err(OutputError {
319+
description: fl!("not-allow-delete-using-kernel", ver = current_kernel_ver),
320+
source: None,
321+
});
322+
}
323+
}
324+
325+
Ok(())
326+
}
327+
281328
/// "Yes Do as I say" steps
282329
pub fn ask_user_do_as_i_say(pkg: &str) -> anyhow::Result<bool> {
283330
let theme = ColorfulTheme::default();
@@ -313,3 +360,22 @@ pub fn ask_user_do_as_i_say(pkg: &str) -> anyhow::Result<bool> {
313360

314361
Ok(true)
315362
}
363+
364+
#[cfg(feature = "aosc")]
365+
fn ask_user_delete_current_kernel(pkg: &str) -> anyhow::Result<bool> {
366+
let theme = ColorfulTheme::default();
367+
368+
warn!("{}", fl!("delete-current-kernel-tips", kernel = pkg));
369+
370+
let delete = Confirm::with_theme(&theme)
371+
.with_prompt(fl!("essential-continue"))
372+
.default(false)
373+
.interact()
374+
.map_err(|_| anyhow!(""))?;
375+
376+
if !delete {
377+
return Ok(false);
378+
}
379+
380+
Ok(true)
381+
}

src/subcommand/topics.rs

Lines changed: 10 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::{
22
fmt::Display,
3-
fs,
43
path::{Path, PathBuf},
54
sync::atomic::Ordering,
65
};
@@ -16,6 +15,7 @@ use oma_pm::{
1615
apt::{AptConfig, FilterMode, OmaApt, OmaAptArgs},
1716
matches::{GetArchMethod, PackagesMatcher},
1817
pkginfo::OmaPackageWithoutVersion,
18+
utils::pkg_is_current_kernel,
1919
};
2020
use oma_utils::dpkg::dpkg_arch;
2121
use once_cell::sync::OnceCell;
@@ -276,47 +276,24 @@ impl CliExecuter for Topics {
276276

277277
// linux-kernel-VER 包在关闭 topic 的时候应该直接删除
278278
if pkg_name.starts_with("linux-kernel-") {
279-
let kernel_ver = kernel_ver.get_or_try_init(|| {
279+
let current_kernel_ver = kernel_ver.get_or_try_init(|| {
280280
System::kernel_version().context("Failed to get kernel version")
281281
})?;
282282

283-
debug!("kernel version = {kernel_ver}");
284-
285-
let image_name = image_name.get_or_init(get_kernel_image_filename);
286-
debug!("image name = {image_name:?}");
287-
288-
let mut is_current_kernel = false;
289-
290-
if let Some(image_name) = image_name {
291-
is_current_kernel =
292-
is_installed_pkg_contains_file(pkg_name, image_name, &sysroot)
293-
.unwrap_or_else(|e| {
294-
warn!("{e}");
295-
false
296-
});
297-
} else {
298-
for i in ["vmlinuz", "vmlinux"] {
299-
if is_installed_pkg_contains_file(
300-
pkg_name,
301-
&format!("{i}-{kernel_ver}"),
302-
&sysroot,
303-
)
304-
.unwrap_or_else(|e| {
305-
warn!("{e}");
306-
false
307-
}) {
308-
is_current_kernel = true;
309-
break;
310-
}
311-
}
312-
}
283+
debug!("kernel version = {current_kernel_ver}");
284+
285+
let is_current_kernel =
286+
pkg_is_current_kernel(&sysroot, &image_name, pkg_name, current_kernel_ver);
313287

314288
debug!("Deleting kernel package name = {pkg_name}");
315289

316290
// 如果现在删除的版本是正在使用的内核版本,将拒绝操作
317291
if is_current_kernel {
318292
return Err(OutputError {
319-
description: fl!("not-allow-delete-using-kernel", ver = kernel_ver),
293+
description: fl!(
294+
"not-allow-delete-using-kernel",
295+
ver = current_kernel_ver
296+
),
320297
source: None,
321298
});
322299
}
@@ -418,44 +395,6 @@ impl CliExecuter for Topics {
418395
}
419396
}
420397

421-
fn is_installed_pkg_contains_file(
422-
pkg_name: &str,
423-
file_name: &str,
424-
sysroot: &Path,
425-
) -> anyhow::Result<bool> {
426-
let p = sysroot.join(format!("var/lib/dpkg/info/{pkg_name}.list"));
427-
let file = fs::read_to_string(&p)
428-
.with_context(|| format!("Failed to read dpkg list file: {}", p.display()))?;
429-
430-
for line in file.lines() {
431-
if Path::new(line)
432-
.file_name()
433-
.is_some_and(|n| n.to_string_lossy() == file_name)
434-
{
435-
return Ok(true);
436-
}
437-
}
438-
439-
Ok(false)
440-
}
441-
442-
fn get_kernel_image_filename() -> Option<String> {
443-
let cmdline = fs::read_to_string("/proc/cmdline").ok()?;
444-
445-
for i in cmdline.split_ascii_whitespace() {
446-
if let Some(image_path) = i.strip_prefix("BOOT_IMAGE=") {
447-
return Some(
448-
Path::new(image_path)
449-
.file_name()
450-
.map(|x| x.to_string_lossy().to_string())
451-
.unwrap_or_else(|| image_path.to_string()),
452-
);
453-
}
454-
}
455-
456-
None
457-
}
458-
459398
fn refresh<'a>(
460399
network_threads: usize,
461400
no_progress: bool,

0 commit comments

Comments
 (0)