kernel: expose umount list to ioctl interface (#2950)

This idea is borrowed from simonpunk's susfs4ksu.
What we see here is that, yeah well, lets just have userspace send us
what it
wants unmounted, this is better than hardcoding everything.

This also solves that issue where MNT_DETACH fails, as long as we send
unmountables in proper order.

A small anti-duplicate mechanism is also added.

While in-kernel umount is a bit worse than zygisk-provider-based ones,
this can still
serve as a healthy alternative.

---------

- Remove duplicate checks

Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
Co-authored-by: weishu <twsxtd@gmail.com>
Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
This commit is contained in:
backslashxx
2025-11-18 11:10:44 +08:00
committed by ShirkNeko
parent 58c8289890
commit 029ae8d389
48 changed files with 252 additions and 260 deletions

View File

@@ -37,7 +37,6 @@ private val SPACING_LARGE = 16.dp
data class UmountPathEntry(
val path: String,
val checkMnt: Boolean,
val flags: Int,
val isDefault: Boolean
)
@@ -243,11 +242,11 @@ fun UmountManagerScreen(navigator: DestinationsNavigator) {
if (showAddDialog) {
AddUmountPathDialog(
onDismiss = { showAddDialog = false },
onConfirm = { path, checkMnt, flags ->
onConfirm = { path, flags ->
showAddDialog = false
scope.launch(Dispatchers.IO) {
val success = addUmountPath(path, checkMnt, flags)
val success = addUmountPath(path, flags)
withContext(Dispatchers.Main) {
if (success) {
saveUmountConfig()
@@ -308,10 +307,6 @@ fun UmountPathCard(
Spacer(modifier = Modifier.height(SPACING_SMALL))
Text(
text = buildString {
append(context.getString(R.string.check_mount_type))
append(": ")
append(if (entry.checkMnt) context.getString(R.string.yes) else context.getString(R.string.no))
append(" | ")
append(context.getString(R.string.flags))
append(": ")
append(entry.flags.toUmountFlagName(context))
@@ -352,10 +347,9 @@ fun UmountPathCard(
@Composable
fun AddUmountPathDialog(
onDismiss: () -> Unit,
onConfirm: (String, Boolean, Int) -> Unit
onConfirm: (String, Int) -> Unit
) {
var path by rememberSaveable { mutableStateOf("") }
var checkMnt by rememberSaveable { mutableStateOf(false) }
var flags by rememberSaveable { mutableStateOf("-1") }
AlertDialog(
@@ -373,20 +367,6 @@ fun AddUmountPathDialog(
Spacer(modifier = Modifier.height(SPACING_MEDIUM))
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = checkMnt,
onCheckedChange = { checkMnt = it }
)
Spacer(modifier = Modifier.width(SPACING_SMALL))
Text(stringResource(R.string.check_mount_type_overlay))
}
Spacer(modifier = Modifier.height(SPACING_MEDIUM))
OutlinedTextField(
value = flags,
onValueChange = { flags = it },
@@ -402,7 +382,7 @@ fun AddUmountPathDialog(
TextButton(
onClick = {
val flagsInt = flags.toIntOrNull() ?: -1
onConfirm(path, checkMnt, flagsInt)
onConfirm(path, flagsInt)
},
enabled = path.isNotBlank()
) {
@@ -426,7 +406,6 @@ private fun parseUmountPaths(output: String): List<UmountPathEntry> {
if (parts.size >= 4) {
UmountPathEntry(
path = parts[0],
checkMnt = parts[1].equals("true", ignoreCase = true),
flags = parts[2].toIntOrNull() ?: -1,
isDefault = parts[3].equals("Yes", ignoreCase = true)
)

View File

@@ -13,7 +13,6 @@ import android.util.Log
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.io.SuFile
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
@@ -22,7 +21,6 @@ import com.sukisu.ultra.Natives
import com.sukisu.ultra.ksuApp
import org.json.JSONArray
import java.io.File
import java.util.concurrent.CountDownLatch
/**
@@ -669,15 +667,14 @@ fun readUidScannerFile(): Boolean {
return try {
ShellUtils.fastCmd(shell, "cat /data/adb/ksu/.uid_scanner").trim() == "1"
} catch (_: Exception) {
false
false
}
}
fun addUmountPath(path: String, checkMnt: Boolean, flags: Int): Boolean {
fun addUmountPath(path: String, flags: Int): Boolean {
val shell = getRootShell()
val checkMntFlag = if (checkMnt) "--check-mnt" else ""
val flagsArg = if (flags >= 0) "--flags $flags" else ""
val cmd = "${getKsuDaemonPath()} umount add $path $checkMntFlag $flagsArg"
val cmd = "${getKsuDaemonPath()} umount add $path $flagsArg"
val result = ShellUtils.fastCmdResult(shell, cmd)
Log.i(TAG, "add umount path $path result: $result")
return result