{
- error("CompositionLocal LocalSnackbarController not present")
-}
\ No newline at end of file
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/Downloader.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/Downloader.kt
deleted file mode 100644
index 954cac50..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/Downloader.kt
+++ /dev/null
@@ -1,149 +0,0 @@
-package me.weishu.kernelsu.ui.util
-
-import android.annotation.SuppressLint
-import android.app.DownloadManager
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
-import android.net.Uri
-import android.os.Build
-import android.os.Environment
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
-import me.weishu.kernelsu.ui.util.module.LatestVersionInfo
-
-/**
- * @author weishu
- * @date 2023/6/22.
- */
-@SuppressLint("Range")
-fun download(
- context: Context,
- url: String,
- fileName: String,
- description: String,
- onDownloaded: (Uri) -> Unit = {},
- onDownloading: () -> Unit = {}
-) {
- val downloadManager =
- context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
-
- val query = DownloadManager.Query()
- query.setFilterByStatus(DownloadManager.STATUS_RUNNING or DownloadManager.STATUS_PAUSED or DownloadManager.STATUS_PENDING)
- downloadManager.query(query).use { cursor ->
- while (cursor.moveToNext()) {
- val uri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_URI))
- val localUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))
- val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
- val columnTitle = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE))
- if (url == uri || fileName == columnTitle) {
- if (status == DownloadManager.STATUS_RUNNING || status == DownloadManager.STATUS_PENDING) {
- onDownloading()
- return
- } else if (status == DownloadManager.STATUS_SUCCESSFUL) {
- onDownloaded(Uri.parse(localUri))
- return
- }
- }
- }
- }
-
- val request = DownloadManager.Request(Uri.parse(url))
- .setDestinationInExternalPublicDir(
- Environment.DIRECTORY_DOWNLOADS,
- fileName
- )
- .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
- .setMimeType("application/zip")
- .setTitle(fileName)
- .setDescription(description)
-
- downloadManager.enqueue(request)
-}
-
-fun checkNewVersion(): LatestVersionInfo {
- val url = "https://api.github.com/repos/tiann/KernelSU/releases/latest"
- // default null value if failed
- val defaultValue = LatestVersionInfo()
- runCatching {
- okhttp3.OkHttpClient().newCall(okhttp3.Request.Builder().url(url).build()).execute()
- .use { response ->
- if (!response.isSuccessful) {
- return defaultValue
- }
- val body = response.body?.string() ?: return defaultValue
- val json = org.json.JSONObject(body)
- val changelog = json.optString("body")
-
- val assets = json.getJSONArray("assets")
- for (i in 0 until assets.length()) {
- val asset = assets.getJSONObject(i)
- val name = asset.getString("name")
- if (!name.endsWith(".apk")) {
- continue
- }
-
- val regex = Regex("v(.+?)_(\\d+)-")
- val matchResult = regex.find(name) ?: continue
- val versionName = matchResult.groupValues[1]
- val versionCode = matchResult.groupValues[2].toInt()
- val downloadUrl = asset.getString("browser_download_url")
-
- return LatestVersionInfo(
- versionCode,
- downloadUrl,
- changelog
- )
- }
-
- }
- }
- return defaultValue
-}
-
-@Composable
-fun DownloadListener(context: Context, onDownloaded: (Uri) -> Unit) {
- DisposableEffect(context) {
- val receiver = object : BroadcastReceiver() {
- @SuppressLint("Range")
- override fun onReceive(context: Context?, intent: Intent?) {
- if (intent?.action == DownloadManager.ACTION_DOWNLOAD_COMPLETE) {
- val id = intent.getLongExtra(
- DownloadManager.EXTRA_DOWNLOAD_ID, -1
- )
- val query = DownloadManager.Query().setFilterById(id)
- val downloadManager =
- context?.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
- val cursor = downloadManager.query(query)
- if (cursor.moveToFirst()) {
- val status = cursor.getInt(
- cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
- )
- if (status == DownloadManager.STATUS_SUCCESSFUL) {
- val uri = cursor.getString(
- cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)
- )
- onDownloaded(Uri.parse(uri))
- }
- }
- }
- }
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- context.registerReceiver(
- receiver,
- IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE),
- Context.RECEIVER_EXPORTED
- )
- } else {
- context.registerReceiver(
- receiver,
- IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
- )
- }
- onDispose {
- context.unregisterReceiver(receiver)
- }
- }
-}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/HanziToPinyin.java b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/HanziToPinyin.java
deleted file mode 100644
index d3d57cef..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/HanziToPinyin.java
+++ /dev/null
@@ -1,576 +0,0 @@
-package me.weishu.kernelsu.ui.util;
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Locale;
-
-/**
- * An object to convert Chinese character to its corresponding pinyin string. For characters with
- * multiple possible pinyin string, only one is selected according to collator. Polyphone is not
- * supported in this implementation. This class is implemented to achieve the best runtime
- * performance and minimum runtime resources with tolerable sacrifice of accuracy. This
- * implementation highly depends on zh_CN ICU collation data and must be always synchronized with
- * ICU.
- *
- * Currently this file is aligned to zh.txt in ICU 4.6
- */
-public class HanziToPinyin {
- private static final String TAG = "HanziToPinyin";
-
- // Turn on this flag when we want to check internal data structure.
- private static final boolean DEBUG = false;
-
- /**
- * Unihans array.
- *
- * Each unihans is the first one within same pinyin when collator is zh_CN.
- */
- public static final char[] UNIHANS = {
- '\u963f', '\u54ce', '\u5b89', '\u80ae', '\u51f9', '\u516b',
- '\u6300', '\u6273', '\u90a6', '\u52f9', '\u9642', '\u5954',
- '\u4f3b', '\u5c44', '\u8fb9', '\u706c', '\u618b', '\u6c43',
- '\u51ab', '\u7676', '\u5cec', '\u5693', '\u5072', '\u53c2',
- '\u4ed3', '\u64a1', '\u518a', '\u5d7e', '\u66fd', '\u66fe',
- '\u5c64', '\u53c9', '\u8286', '\u8fbf', '\u4f25', '\u6284',
- '\u8f66', '\u62bb', '\u6c88', '\u6c89', '\u9637', '\u5403',
- '\u5145', '\u62bd', '\u51fa', '\u6b3b', '\u63e3', '\u5ddb',
- '\u5205', '\u5439', '\u65fe', '\u9034', '\u5472', '\u5306',
- '\u51d1', '\u7c97', '\u6c46', '\u5d14', '\u90a8', '\u6413',
- '\u5491', '\u5446', '\u4e39', '\u5f53', '\u5200', '\u561a',
- '\u6265', '\u706f', '\u6c10', '\u55f2', '\u7538', '\u5201',
- '\u7239', '\u4e01', '\u4e1f', '\u4e1c', '\u543a', '\u53be',
- '\u8011', '\u8968', '\u5428', '\u591a', '\u59b8', '\u8bf6',
- '\u5940', '\u97a5', '\u513f', '\u53d1', '\u5e06', '\u531a',
- '\u98de', '\u5206', '\u4e30', '\u8985', '\u4ecf', '\u7d11',
- '\u4f15', '\u65ee', '\u4f85', '\u7518', '\u5188', '\u768b',
- '\u6208', '\u7ed9', '\u6839', '\u522f', '\u5de5', '\u52fe',
- '\u4f30', '\u74dc', '\u4e56', '\u5173', '\u5149', '\u5f52',
- '\u4e28', '\u5459', '\u54c8', '\u548d', '\u4f44', '\u592f',
- '\u8320', '\u8bc3', '\u9ed2', '\u62eb', '\u4ea8', '\u5677',
- '\u53ff', '\u9f41', '\u4e6f', '\u82b1', '\u6000', '\u72bf',
- '\u5ddf', '\u7070', '\u660f', '\u5419', '\u4e0c', '\u52a0',
- '\u620b', '\u6c5f', '\u827d', '\u9636', '\u5dfe', '\u5755',
- '\u5182', '\u4e29', '\u51e5', '\u59e2', '\u5658', '\u519b',
- '\u5494', '\u5f00', '\u520a', '\u5ffc', '\u5c3b', '\u533c',
- '\u808e', '\u52a5', '\u7a7a', '\u62a0', '\u625d', '\u5938',
- '\u84af', '\u5bbd', '\u5321', '\u4e8f', '\u5764', '\u6269',
- '\u5783', '\u6765', '\u5170', '\u5577', '\u635e', '\u808b',
- '\u52d2', '\u5d1a', '\u5215', '\u4fe9', '\u5941', '\u826f',
- '\u64a9', '\u5217', '\u62ce', '\u5222', '\u6e9c', '\u56d6',
- '\u9f99', '\u779c', '\u565c', '\u5a08', '\u7567', '\u62a1',
- '\u7f57', '\u5463', '\u5988', '\u57cb', '\u5ada', '\u7264',
- '\u732b', '\u4e48', '\u5445', '\u95e8', '\u753f', '\u54aa',
- '\u5b80', '\u55b5', '\u4e5c', '\u6c11', '\u540d', '\u8c2c',
- '\u6478', '\u54de', '\u6bea', '\u55ef', '\u62cf', '\u8149',
- '\u56e1', '\u56d4', '\u5b6c', '\u7592', '\u5a1e', '\u6041',
- '\u80fd', '\u59ae', '\u62c8', '\u5b22', '\u9e1f', '\u634f',
- '\u56dc', '\u5b81', '\u599e', '\u519c', '\u7fba', '\u5974',
- '\u597b', '\u759f', '\u9ec1', '\u90cd', '\u5594', '\u8bb4',
- '\u5991', '\u62cd', '\u7705', '\u4e53', '\u629b', '\u5478',
- '\u55b7', '\u5309', '\u4e15', '\u56e8', '\u527d', '\u6c15',
- '\u59d8', '\u4e52', '\u948b', '\u5256', '\u4ec6', '\u4e03',
- '\u6390', '\u5343', '\u545b', '\u6084', '\u767f', '\u4eb2',
- '\u72c5', '\u828e', '\u4e18', '\u533a', '\u5cd1', '\u7f3a',
- '\u590b', '\u5465', '\u7a63', '\u5a06', '\u60f9', '\u4eba',
- '\u6254', '\u65e5', '\u8338', '\u53b9', '\u909a', '\u633c',
- '\u5827', '\u5a51', '\u77a4', '\u637c', '\u4ee8', '\u6be2',
- '\u4e09', '\u6852', '\u63bb', '\u95aa', '\u68ee', '\u50e7',
- '\u6740', '\u7b5b', '\u5c71', '\u4f24', '\u5f30', '\u5962',
- '\u7533', '\u8398', '\u6552', '\u5347', '\u5c38', '\u53ce',
- '\u4e66', '\u5237', '\u8870', '\u95e9', '\u53cc', '\u8c01',
- '\u542e', '\u8bf4', '\u53b6', '\u5fea', '\u635c', '\u82cf',
- '\u72fb', '\u590a', '\u5b59', '\u5506', '\u4ed6', '\u56fc',
- '\u574d', '\u6c64', '\u5932', '\u5fd1', '\u71a5', '\u5254',
- '\u5929', '\u65eb', '\u5e16', '\u5385', '\u56f2', '\u5077',
- '\u51f8', '\u6e4d', '\u63a8', '\u541e', '\u4e47', '\u7a75',
- '\u6b6a', '\u5f2f', '\u5c23', '\u5371', '\u6637', '\u7fc1',
- '\u631d', '\u4e4c', '\u5915', '\u8672', '\u4eda', '\u4e61',
- '\u7071', '\u4e9b', '\u5fc3', '\u661f', '\u51f6', '\u4f11',
- '\u5401', '\u5405', '\u524a', '\u5743', '\u4e2b', '\u6079',
- '\u592e', '\u5e7a', '\u503b', '\u4e00', '\u56d9', '\u5e94',
- '\u54df', '\u4f63', '\u4f18', '\u625c', '\u56e6', '\u66f0',
- '\u6655', '\u7b60', '\u7b7c', '\u5e00', '\u707d', '\u5142',
- '\u5328', '\u50ae', '\u5219', '\u8d3c', '\u600e', '\u5897',
- '\u624e', '\u635a', '\u6cbe', '\u5f20', '\u957f', '\u9577',
- '\u4f4b', '\u8707', '\u8d1e', '\u4e89', '\u4e4b', '\u5cd9',
- '\u5ea2', '\u4e2d', '\u5dde', '\u6731', '\u6293', '\u62fd',
- '\u4e13', '\u5986', '\u96b9', '\u5b92', '\u5353', '\u4e72',
- '\u5b97', '\u90b9', '\u79df', '\u94bb', '\u539c', '\u5c0a',
- '\u6628', '\u5159', '\u9fc3', '\u9fc4',};
-
- /**
- * Pinyin array.
- *
- * Each pinyin is corresponding to unihans of same
- * offset in the unihans array.
- */
- public static final byte[][] PINYINS = {
- {65, 0, 0, 0, 0, 0}, {65, 73, 0, 0, 0, 0},
- {65, 78, 0, 0, 0, 0}, {65, 78, 71, 0, 0, 0},
- {65, 79, 0, 0, 0, 0}, {66, 65, 0, 0, 0, 0},
- {66, 65, 73, 0, 0, 0}, {66, 65, 78, 0, 0, 0},
- {66, 65, 78, 71, 0, 0}, {66, 65, 79, 0, 0, 0},
- {66, 69, 73, 0, 0, 0}, {66, 69, 78, 0, 0, 0},
- {66, 69, 78, 71, 0, 0}, {66, 73, 0, 0, 0, 0},
- {66, 73, 65, 78, 0, 0}, {66, 73, 65, 79, 0, 0},
- {66, 73, 69, 0, 0, 0}, {66, 73, 78, 0, 0, 0},
- {66, 73, 78, 71, 0, 0}, {66, 79, 0, 0, 0, 0},
- {66, 85, 0, 0, 0, 0}, {67, 65, 0, 0, 0, 0},
- {67, 65, 73, 0, 0, 0}, {67, 65, 78, 0, 0, 0},
- {67, 65, 78, 71, 0, 0}, {67, 65, 79, 0, 0, 0},
- {67, 69, 0, 0, 0, 0}, {67, 69, 78, 0, 0, 0},
- {67, 69, 78, 71, 0, 0}, {90, 69, 78, 71, 0, 0},
- {67, 69, 78, 71, 0, 0}, {67, 72, 65, 0, 0, 0},
- {67, 72, 65, 73, 0, 0}, {67, 72, 65, 78, 0, 0},
- {67, 72, 65, 78, 71, 0}, {67, 72, 65, 79, 0, 0},
- {67, 72, 69, 0, 0, 0}, {67, 72, 69, 78, 0, 0},
- {83, 72, 69, 78, 0, 0}, {67, 72, 69, 78, 0, 0},
- {67, 72, 69, 78, 71, 0}, {67, 72, 73, 0, 0, 0},
- {67, 72, 79, 78, 71, 0}, {67, 72, 79, 85, 0, 0},
- {67, 72, 85, 0, 0, 0}, {67, 72, 85, 65, 0, 0},
- {67, 72, 85, 65, 73, 0}, {67, 72, 85, 65, 78, 0},
- {67, 72, 85, 65, 78, 71}, {67, 72, 85, 73, 0, 0},
- {67, 72, 85, 78, 0, 0}, {67, 72, 85, 79, 0, 0},
- {67, 73, 0, 0, 0, 0}, {67, 79, 78, 71, 0, 0},
- {67, 79, 85, 0, 0, 0}, {67, 85, 0, 0, 0, 0},
- {67, 85, 65, 78, 0, 0}, {67, 85, 73, 0, 0, 0},
- {67, 85, 78, 0, 0, 0}, {67, 85, 79, 0, 0, 0},
- {68, 65, 0, 0, 0, 0}, {68, 65, 73, 0, 0, 0},
- {68, 65, 78, 0, 0, 0}, {68, 65, 78, 71, 0, 0},
- {68, 65, 79, 0, 0, 0}, {68, 69, 0, 0, 0, 0},
- {68, 69, 78, 0, 0, 0}, {68, 69, 78, 71, 0, 0},
- {68, 73, 0, 0, 0, 0}, {68, 73, 65, 0, 0, 0},
- {68, 73, 65, 78, 0, 0}, {68, 73, 65, 79, 0, 0},
- {68, 73, 69, 0, 0, 0}, {68, 73, 78, 71, 0, 0},
- {68, 73, 85, 0, 0, 0}, {68, 79, 78, 71, 0, 0},
- {68, 79, 85, 0, 0, 0}, {68, 85, 0, 0, 0, 0},
- {68, 85, 65, 78, 0, 0}, {68, 85, 73, 0, 0, 0},
- {68, 85, 78, 0, 0, 0}, {68, 85, 79, 0, 0, 0},
- {69, 0, 0, 0, 0, 0}, {69, 73, 0, 0, 0, 0},
- {69, 78, 0, 0, 0, 0}, {69, 78, 71, 0, 0, 0},
- {69, 82, 0, 0, 0, 0}, {70, 65, 0, 0, 0, 0},
- {70, 65, 78, 0, 0, 0}, {70, 65, 78, 71, 0, 0},
- {70, 69, 73, 0, 0, 0}, {70, 69, 78, 0, 0, 0},
- {70, 69, 78, 71, 0, 0}, {70, 73, 65, 79, 0, 0},
- {70, 79, 0, 0, 0, 0}, {70, 79, 85, 0, 0, 0},
- {70, 85, 0, 0, 0, 0}, {71, 65, 0, 0, 0, 0},
- {71, 65, 73, 0, 0, 0}, {71, 65, 78, 0, 0, 0},
- {71, 65, 78, 71, 0, 0}, {71, 65, 79, 0, 0, 0},
- {71, 69, 0, 0, 0, 0}, {71, 69, 73, 0, 0, 0},
- {71, 69, 78, 0, 0, 0}, {71, 69, 78, 71, 0, 0},
- {71, 79, 78, 71, 0, 0}, {71, 79, 85, 0, 0, 0},
- {71, 85, 0, 0, 0, 0}, {71, 85, 65, 0, 0, 0},
- {71, 85, 65, 73, 0, 0}, {71, 85, 65, 78, 0, 0},
- {71, 85, 65, 78, 71, 0}, {71, 85, 73, 0, 0, 0},
- {71, 85, 78, 0, 0, 0}, {71, 85, 79, 0, 0, 0},
- {72, 65, 0, 0, 0, 0}, {72, 65, 73, 0, 0, 0},
- {72, 65, 78, 0, 0, 0}, {72, 65, 78, 71, 0, 0},
- {72, 65, 79, 0, 0, 0}, {72, 69, 0, 0, 0, 0},
- {72, 69, 73, 0, 0, 0}, {72, 69, 78, 0, 0, 0},
- {72, 69, 78, 71, 0, 0}, {72, 77, 0, 0, 0, 0},
- {72, 79, 78, 71, 0, 0}, {72, 79, 85, 0, 0, 0},
- {72, 85, 0, 0, 0, 0}, {72, 85, 65, 0, 0, 0},
- {72, 85, 65, 73, 0, 0}, {72, 85, 65, 78, 0, 0},
- {72, 85, 65, 78, 71, 0}, {72, 85, 73, 0, 0, 0},
- {72, 85, 78, 0, 0, 0}, {72, 85, 79, 0, 0, 0},
- {74, 73, 0, 0, 0, 0}, {74, 73, 65, 0, 0, 0},
- {74, 73, 65, 78, 0, 0}, {74, 73, 65, 78, 71, 0},
- {74, 73, 65, 79, 0, 0}, {74, 73, 69, 0, 0, 0},
- {74, 73, 78, 0, 0, 0}, {74, 73, 78, 71, 0, 0},
- {74, 73, 79, 78, 71, 0}, {74, 73, 85, 0, 0, 0},
- {74, 85, 0, 0, 0, 0}, {74, 85, 65, 78, 0, 0},
- {74, 85, 69, 0, 0, 0}, {74, 85, 78, 0, 0, 0},
- {75, 65, 0, 0, 0, 0}, {75, 65, 73, 0, 0, 0},
- {75, 65, 78, 0, 0, 0}, {75, 65, 78, 71, 0, 0},
- {75, 65, 79, 0, 0, 0}, {75, 69, 0, 0, 0, 0},
- {75, 69, 78, 0, 0, 0}, {75, 69, 78, 71, 0, 0},
- {75, 79, 78, 71, 0, 0}, {75, 79, 85, 0, 0, 0},
- {75, 85, 0, 0, 0, 0}, {75, 85, 65, 0, 0, 0},
- {75, 85, 65, 73, 0, 0}, {75, 85, 65, 78, 0, 0},
- {75, 85, 65, 78, 71, 0}, {75, 85, 73, 0, 0, 0},
- {75, 85, 78, 0, 0, 0}, {75, 85, 79, 0, 0, 0},
- {76, 65, 0, 0, 0, 0}, {76, 65, 73, 0, 0, 0},
- {76, 65, 78, 0, 0, 0}, {76, 65, 78, 71, 0, 0},
- {76, 65, 79, 0, 0, 0}, {76, 69, 0, 0, 0, 0},
- {76, 69, 73, 0, 0, 0}, {76, 69, 78, 71, 0, 0},
- {76, 73, 0, 0, 0, 0}, {76, 73, 65, 0, 0, 0},
- {76, 73, 65, 78, 0, 0}, {76, 73, 65, 78, 71, 0},
- {76, 73, 65, 79, 0, 0}, {76, 73, 69, 0, 0, 0},
- {76, 73, 78, 0, 0, 0}, {76, 73, 78, 71, 0, 0},
- {76, 73, 85, 0, 0, 0}, {76, 79, 0, 0, 0, 0},
- {76, 79, 78, 71, 0, 0}, {76, 79, 85, 0, 0, 0},
- {76, 85, 0, 0, 0, 0}, {76, 85, 65, 78, 0, 0},
- {76, 85, 69, 0, 0, 0}, {76, 85, 78, 0, 0, 0},
- {76, 85, 79, 0, 0, 0}, {77, 0, 0, 0, 0, 0},
- {77, 65, 0, 0, 0, 0}, {77, 65, 73, 0, 0, 0},
- {77, 65, 78, 0, 0, 0}, {77, 65, 78, 71, 0, 0},
- {77, 65, 79, 0, 0, 0}, {77, 69, 0, 0, 0, 0},
- {77, 69, 73, 0, 0, 0}, {77, 69, 78, 0, 0, 0},
- {77, 69, 78, 71, 0, 0}, {77, 73, 0, 0, 0, 0},
- {77, 73, 65, 78, 0, 0}, {77, 73, 65, 79, 0, 0},
- {77, 73, 69, 0, 0, 0}, {77, 73, 78, 0, 0, 0},
- {77, 73, 78, 71, 0, 0}, {77, 73, 85, 0, 0, 0},
- {77, 79, 0, 0, 0, 0}, {77, 79, 85, 0, 0, 0},
- {77, 85, 0, 0, 0, 0}, {78, 0, 0, 0, 0, 0},
- {78, 65, 0, 0, 0, 0}, {78, 65, 73, 0, 0, 0},
- {78, 65, 78, 0, 0, 0}, {78, 65, 78, 71, 0, 0},
- {78, 65, 79, 0, 0, 0}, {78, 69, 0, 0, 0, 0},
- {78, 69, 73, 0, 0, 0}, {78, 69, 78, 0, 0, 0},
- {78, 69, 78, 71, 0, 0}, {78, 73, 0, 0, 0, 0},
- {78, 73, 65, 78, 0, 0}, {78, 73, 65, 78, 71, 0},
- {78, 73, 65, 79, 0, 0}, {78, 73, 69, 0, 0, 0},
- {78, 73, 78, 0, 0, 0}, {78, 73, 78, 71, 0, 0},
- {78, 73, 85, 0, 0, 0}, {78, 79, 78, 71, 0, 0},
- {78, 79, 85, 0, 0, 0}, {78, 85, 0, 0, 0, 0},
- {78, 85, 65, 78, 0, 0}, {78, 85, 69, 0, 0, 0},
- {78, 85, 78, 0, 0, 0}, {78, 85, 79, 0, 0, 0},
- {79, 0, 0, 0, 0, 0}, {79, 85, 0, 0, 0, 0},
- {80, 65, 0, 0, 0, 0}, {80, 65, 73, 0, 0, 0},
- {80, 65, 78, 0, 0, 0}, {80, 65, 78, 71, 0, 0},
- {80, 65, 79, 0, 0, 0}, {80, 69, 73, 0, 0, 0},
- {80, 69, 78, 0, 0, 0}, {80, 69, 78, 71, 0, 0},
- {80, 73, 0, 0, 0, 0}, {80, 73, 65, 78, 0, 0},
- {80, 73, 65, 79, 0, 0}, {80, 73, 69, 0, 0, 0},
- {80, 73, 78, 0, 0, 0}, {80, 73, 78, 71, 0, 0},
- {80, 79, 0, 0, 0, 0}, {80, 79, 85, 0, 0, 0},
- {80, 85, 0, 0, 0, 0}, {81, 73, 0, 0, 0, 0},
- {81, 73, 65, 0, 0, 0}, {81, 73, 65, 78, 0, 0},
- {81, 73, 65, 78, 71, 0}, {81, 73, 65, 79, 0, 0},
- {81, 73, 69, 0, 0, 0}, {81, 73, 78, 0, 0, 0},
- {81, 73, 78, 71, 0, 0}, {81, 73, 79, 78, 71, 0},
- {81, 73, 85, 0, 0, 0}, {81, 85, 0, 0, 0, 0},
- {81, 85, 65, 78, 0, 0}, {81, 85, 69, 0, 0, 0},
- {81, 85, 78, 0, 0, 0}, {82, 65, 78, 0, 0, 0},
- {82, 65, 78, 71, 0, 0}, {82, 65, 79, 0, 0, 0},
- {82, 69, 0, 0, 0, 0}, {82, 69, 78, 0, 0, 0},
- {82, 69, 78, 71, 0, 0}, {82, 73, 0, 0, 0, 0},
- {82, 79, 78, 71, 0, 0}, {82, 79, 85, 0, 0, 0},
- {82, 85, 0, 0, 0, 0}, {82, 85, 65, 0, 0, 0},
- {82, 85, 65, 78, 0, 0}, {82, 85, 73, 0, 0, 0},
- {82, 85, 78, 0, 0, 0}, {82, 85, 79, 0, 0, 0},
- {83, 65, 0, 0, 0, 0}, {83, 65, 73, 0, 0, 0},
- {83, 65, 78, 0, 0, 0}, {83, 65, 78, 71, 0, 0},
- {83, 65, 79, 0, 0, 0}, {83, 69, 0, 0, 0, 0},
- {83, 69, 78, 0, 0, 0}, {83, 69, 78, 71, 0, 0},
- {83, 72, 65, 0, 0, 0}, {83, 72, 65, 73, 0, 0},
- {83, 72, 65, 78, 0, 0}, {83, 72, 65, 78, 71, 0},
- {83, 72, 65, 79, 0, 0}, {83, 72, 69, 0, 0, 0},
- {83, 72, 69, 78, 0, 0}, {88, 73, 78, 0, 0, 0},
- {83, 72, 69, 78, 0, 0}, {83, 72, 69, 78, 71, 0},
- {83, 72, 73, 0, 0, 0}, {83, 72, 79, 85, 0, 0},
- {83, 72, 85, 0, 0, 0}, {83, 72, 85, 65, 0, 0},
- {83, 72, 85, 65, 73, 0}, {83, 72, 85, 65, 78, 0},
- {83, 72, 85, 65, 78, 71}, {83, 72, 85, 73, 0, 0},
- {83, 72, 85, 78, 0, 0}, {83, 72, 85, 79, 0, 0},
- {83, 73, 0, 0, 0, 0}, {83, 79, 78, 71, 0, 0},
- {83, 79, 85, 0, 0, 0}, {83, 85, 0, 0, 0, 0},
- {83, 85, 65, 78, 0, 0}, {83, 85, 73, 0, 0, 0},
- {83, 85, 78, 0, 0, 0}, {83, 85, 79, 0, 0, 0},
- {84, 65, 0, 0, 0, 0}, {84, 65, 73, 0, 0, 0},
- {84, 65, 78, 0, 0, 0}, {84, 65, 78, 71, 0, 0},
- {84, 65, 79, 0, 0, 0}, {84, 69, 0, 0, 0, 0},
- {84, 69, 78, 71, 0, 0}, {84, 73, 0, 0, 0, 0},
- {84, 73, 65, 78, 0, 0}, {84, 73, 65, 79, 0, 0},
- {84, 73, 69, 0, 0, 0}, {84, 73, 78, 71, 0, 0},
- {84, 79, 78, 71, 0, 0}, {84, 79, 85, 0, 0, 0},
- {84, 85, 0, 0, 0, 0}, {84, 85, 65, 78, 0, 0},
- {84, 85, 73, 0, 0, 0}, {84, 85, 78, 0, 0, 0},
- {84, 85, 79, 0, 0, 0}, {87, 65, 0, 0, 0, 0},
- {87, 65, 73, 0, 0, 0}, {87, 65, 78, 0, 0, 0},
- {87, 65, 78, 71, 0, 0}, {87, 69, 73, 0, 0, 0},
- {87, 69, 78, 0, 0, 0}, {87, 69, 78, 71, 0, 0},
- {87, 79, 0, 0, 0, 0}, {87, 85, 0, 0, 0, 0},
- {88, 73, 0, 0, 0, 0}, {88, 73, 65, 0, 0, 0},
- {88, 73, 65, 78, 0, 0}, {88, 73, 65, 78, 71, 0},
- {88, 73, 65, 79, 0, 0}, {88, 73, 69, 0, 0, 0},
- {88, 73, 78, 0, 0, 0}, {88, 73, 78, 71, 0, 0},
- {88, 73, 79, 78, 71, 0}, {88, 73, 85, 0, 0, 0},
- {88, 85, 0, 0, 0, 0}, {88, 85, 65, 78, 0, 0},
- {88, 85, 69, 0, 0, 0}, {88, 85, 78, 0, 0, 0},
- {89, 65, 0, 0, 0, 0}, {89, 65, 78, 0, 0, 0},
- {89, 65, 78, 71, 0, 0}, {89, 65, 79, 0, 0, 0},
- {89, 69, 0, 0, 0, 0}, {89, 73, 0, 0, 0, 0},
- {89, 73, 78, 0, 0, 0}, {89, 73, 78, 71, 0, 0},
- {89, 79, 0, 0, 0, 0}, {89, 79, 78, 71, 0, 0},
- {89, 79, 85, 0, 0, 0}, {89, 85, 0, 0, 0, 0},
- {89, 85, 65, 78, 0, 0}, {89, 85, 69, 0, 0, 0},
- {89, 85, 78, 0, 0, 0}, {74, 85, 78, 0, 0, 0},
- {89, 85, 78, 0, 0, 0}, {90, 65, 0, 0, 0, 0},
- {90, 65, 73, 0, 0, 0}, {90, 65, 78, 0, 0, 0},
- {90, 65, 78, 71, 0, 0}, {90, 65, 79, 0, 0, 0},
- {90, 69, 0, 0, 0, 0}, {90, 69, 73, 0, 0, 0},
- {90, 69, 78, 0, 0, 0}, {90, 69, 78, 71, 0, 0},
- {90, 72, 65, 0, 0, 0}, {90, 72, 65, 73, 0, 0},
- {90, 72, 65, 78, 0, 0}, {90, 72, 65, 78, 71, 0},
- {67, 72, 65, 78, 71, 0}, {90, 72, 65, 78, 71, 0},
- {90, 72, 65, 79, 0, 0}, {90, 72, 69, 0, 0, 0},
- {90, 72, 69, 78, 0, 0}, {90, 72, 69, 78, 71, 0},
- {90, 72, 73, 0, 0, 0}, {83, 72, 73, 0, 0, 0},
- {90, 72, 73, 0, 0, 0}, {90, 72, 79, 78, 71, 0},
- {90, 72, 79, 85, 0, 0}, {90, 72, 85, 0, 0, 0},
- {90, 72, 85, 65, 0, 0}, {90, 72, 85, 65, 73, 0},
- {90, 72, 85, 65, 78, 0}, {90, 72, 85, 65, 78, 71},
- {90, 72, 85, 73, 0, 0}, {90, 72, 85, 78, 0, 0},
- {90, 72, 85, 79, 0, 0}, {90, 73, 0, 0, 0, 0},
- {90, 79, 78, 71, 0, 0}, {90, 79, 85, 0, 0, 0},
- {90, 85, 0, 0, 0, 0}, {90, 85, 65, 78, 0, 0},
- {90, 85, 73, 0, 0, 0}, {90, 85, 78, 0, 0, 0},
- {90, 85, 79, 0, 0, 0}, {0, 0, 0, 0, 0, 0},
- {83, 72, 65, 78, 0, 0}, {0, 0, 0, 0, 0, 0},};
-
- /**
- * First and last Chinese character with known Pinyin according to zh collation
- */
- private static final String FIRST_PINYIN_UNIHAN = "\u963F";
- private static final String LAST_PINYIN_UNIHAN = "\u9FFF";
-
- private static final Collator COLLATOR = Collator.getInstance(Locale.CHINA);
-
- private static HanziToPinyin sInstance;
- private final boolean mHasChinaCollator;
-
- public static class Token {
- /**
- * Separator between target string for each source char
- */
- public static final String SEPARATOR = " ";
-
- public static final int LATIN = 1;
- public static final int PINYIN = 2;
- public static final int UNKNOWN = 3;
-
- public Token() {
- }
-
- public Token(int type, String source, String target) {
- this.type = type;
- this.source = source;
- this.target = target;
- }
-
- /**
- * Type of this token, ASCII, PINYIN or UNKNOWN.
- */
- public int type;
- /**
- * Original string before translation.
- */
- public String source;
- /**
- * Translated string of source. For Han, target is corresponding Pinyin. Otherwise target is
- * original string in source.
- */
- public String target;
- }
-
- protected HanziToPinyin(boolean hasChinaCollator) {
- mHasChinaCollator = hasChinaCollator;
- }
-
- public static HanziToPinyin getInstance() {
- synchronized (HanziToPinyin.class) {
- if (sInstance != null) {
- return sInstance;
- }
- // Check if zh_CN collation data is available
- final Locale[] locale = Collator.getAvailableLocales();
- for (Locale value : locale) {
- if (value.equals(Locale.CHINA) || value.getLanguage().contains("zh")) {
- // Do self validation just once.
- if (DEBUG) {
- Log.d(TAG, "Self validation. Result: " + doSelfValidation());
- }
- sInstance = new HanziToPinyin(true);
- return sInstance;
- }
- }
- if (sInstance == null){//这个判断是用于处理国产ROM的兼容性问题
- if (Locale.CHINA.equals(Locale.getDefault())){
- sInstance = new HanziToPinyin(true);
- return sInstance;
- }
- }
- Log.w(TAG, "There is no Chinese collator, HanziToPinyin is disabled");
- sInstance = new HanziToPinyin(false);
- return sInstance;
- }
- }
-
- /**
- * Validate if our internal table has some wrong value.
- *
- * @return true when the table looks correct.
- */
- private static boolean doSelfValidation() {
- char lastChar = UNIHANS[0];
- String lastString = Character.toString(lastChar);
- for (char c : UNIHANS) {
- if (lastChar == c) {
- continue;
- }
- final String curString = Character.toString(c);
- int cmp = COLLATOR.compare(lastString, curString);
- if (cmp >= 0) {
- Log.e(TAG, "Internal error in Unihan table. " + "The last string \"" + lastString
- + "\" is greater than current string \"" + curString + "\".");
- return false;
- }
- lastString = curString;
- }
- return true;
- }
-
- private Token getToken(char character) {
- Token token = new Token();
- final String letter = Character.toString(character);
- token.source = letter;
- int offset = -1;
- int cmp;
- if (character < 256) {
- token.type = Token.LATIN;
- token.target = letter;
- return token;
- } else {
- cmp = COLLATOR.compare(letter, FIRST_PINYIN_UNIHAN);
- if (cmp < 0) {
- token.type = Token.UNKNOWN;
- token.target = letter;
- return token;
- } else if (cmp == 0) {
- token.type = Token.PINYIN;
- offset = 0;
- } else {
- cmp = COLLATOR.compare(letter, LAST_PINYIN_UNIHAN);
- if (cmp > 0) {
- token.type = Token.UNKNOWN;
- token.target = letter;
- return token;
- } else if (cmp == 0) {
- token.type = Token.PINYIN;
- offset = UNIHANS.length - 1;
- }
- }
- }
-
- token.type = Token.PINYIN;
- if (offset < 0) {
- int begin = 0;
- int end = UNIHANS.length - 1;
- while (begin <= end) {
- offset = (begin + end) / 2;
- final String unihan = Character.toString(UNIHANS[offset]);
- cmp = COLLATOR.compare(letter, unihan);
- if (cmp == 0) {
- break;
- } else if (cmp > 0) {
- begin = offset + 1;
- } else {
- end = offset - 1;
- }
- }
- }
- if (cmp < 0) {
- offset--;
- }
- StringBuilder pinyin = new StringBuilder();
- for (int j = 0; j < PINYINS[offset].length && PINYINS[offset][j] != 0; j++) {
- pinyin.append((char) PINYINS[offset][j]);
- }
- token.target = pinyin.toString();
- if (TextUtils.isEmpty(token.target)) {
- token.type = Token.UNKNOWN;
- token.target = token.source;
- }
- return token;
- }
-
- /**
- * Convert the input to a array of tokens. The sequence of ASCII or Unknown characters without
- * space will be put into a Token, One Hanzi character which has pinyin will be treated as a
- * Token. If these is no China collator, the empty token array is returned.
- */
- public ArrayList get(final String input) {
- ArrayList tokens = new ArrayList<>();
- if (!mHasChinaCollator || TextUtils.isEmpty(input)) {
- // return empty tokens.
- return tokens;
- }
- final int inputLength = input.length();
- final StringBuilder sb = new StringBuilder();
- int tokenType = Token.LATIN;
- // Go through the input, create a new token when
- // a. Token type changed
- // b. Get the Pinyin of current charater.
- // c. current character is space.
- for (int i = 0; i < inputLength; i++) {
- final char character = input.charAt(i);
- if (character == ' ') {
- if (sb.length() > 0) {
- addToken(sb, tokens, tokenType);
- }
- } else if (character < 256) {
- if (tokenType != Token.LATIN && sb.length() > 0) {
- addToken(sb, tokens, tokenType);
- }
- tokenType = Token.LATIN;
- sb.append(character);
- } else {
- Token t = getToken(character);
- if (t.type == Token.PINYIN) {
- if (sb.length() > 0) {
- addToken(sb, tokens, tokenType);
- }
- tokens.add(t);
- tokenType = Token.PINYIN;
- } else {
- if (tokenType != t.type && sb.length() > 0) {
- addToken(sb, tokens, tokenType);
- }
- tokenType = t.type;
- sb.append(character);
- }
- }
- }
- if (sb.length() > 0) {
- addToken(sb, tokens, tokenType);
- }
- return tokens;
- }
-
- private void addToken(
- final StringBuilder sb, final ArrayList tokens, final int tokenType) {
- String str = sb.toString();
- tokens.add(new Token(tokenType, str, str));
- sb.setLength(0);
- }
-
- public String toPinyinString(String string) {
- if (string == null) {
- return null;
- }
- StringBuilder sb = new StringBuilder();
- ArrayList tokens = get(string);
- for (Token token : tokens) {
- sb.append(token.target);
- }
- return sb.toString().toLowerCase();
- }
-}
\ No newline at end of file
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/HyperlinkText.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/HyperlinkText.kt
deleted file mode 100644
index 4473b828..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/HyperlinkText.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-package me.weishu.kernelsu.ui.util
-
-import androidx.compose.foundation.gestures.detectTapGestures
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.input.pointer.pointerInput
-import androidx.compose.ui.platform.LocalUriHandler
-import androidx.compose.ui.text.SpanStyle
-import androidx.compose.ui.text.TextLayoutResult
-import androidx.compose.ui.text.buildAnnotatedString
-import androidx.compose.ui.text.style.TextDecoration
-import java.util.regex.Pattern
-
-@Composable
-fun LinkifyText(
- text: String,
- modifier: Modifier = Modifier
-) {
- val uriHandler = LocalUriHandler.current
- val layoutResult = remember {
- mutableStateOf(null)
- }
- val linksList = extractUrls(text)
- val annotatedString = buildAnnotatedString {
- append(text)
- linksList.forEach {
- addStyle(
- style = SpanStyle(
- color = MaterialTheme.colorScheme.primary,
- textDecoration = TextDecoration.Underline
- ),
- start = it.start,
- end = it.end
- )
- addStringAnnotation(
- tag = "URL",
- annotation = it.url,
- start = it.start,
- end = it.end
- )
- }
- }
- Text(
- text = annotatedString,
- modifier = modifier.pointerInput(Unit) {
- detectTapGestures { offsetPosition ->
- layoutResult.value?.let {
- val position = it.getOffsetForPosition(offsetPosition)
- annotatedString.getStringAnnotations(position, position).firstOrNull()
- ?.let { result ->
- if (result.tag == "URL") {
- uriHandler.openUri(result.item)
- }
- }
- }
- }
- },
- onTextLayout = { layoutResult.value = it }
- )
-}
-
-private val urlPattern: Pattern = Pattern.compile(
- "(?:^|[\\W])((ht|f)tp(s?):\\/\\/|www\\.)"
- + "(([\\w\\-]+\\.){1,}?([\\w\\-.~]+\\/?)*"
- + "[\\p{Alnum}.,%_=?\\-+()\\[\\]\\*$~@!:/{};']*)",
- Pattern.CASE_INSENSITIVE or Pattern.MULTILINE or Pattern.DOTALL
-)
-
-private data class LinkInfo(
- val url: String,
- val start: Int,
- val end: Int
-)
-
-private fun extractUrls(text: String): List = buildList {
- val matcher = urlPattern.matcher(text)
- while (matcher.find()) {
- val matchStart = matcher.start(1)
- val matchEnd = matcher.end()
- val url = text.substring(matchStart, matchEnd).replaceFirst("http://", "https://")
- add(LinkInfo(url, matchStart, matchEnd))
- }
-}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt
deleted file mode 100644
index 108e08f2..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt
+++ /dev/null
@@ -1,428 +0,0 @@
-package me.weishu.kernelsu.ui.util
-
-import android.content.ContentResolver
-import android.content.Context
-import android.database.Cursor
-import android.net.Uri
-import android.os.Build
-import android.os.Environment
-import android.os.Parcelable
-import android.os.SystemClock
-import android.provider.OpenableColumns
-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
-import me.weishu.kernelsu.BuildConfig
-import me.weishu.kernelsu.Natives
-import me.weishu.kernelsu.ksuApp
-import org.json.JSONArray
-import java.io.File
-
-
-/**
- * @author weishu
- * @date 2023/1/1.
- */
-private const val TAG = "KsuCli"
-
-private fun getKsuDaemonPath(): String {
- return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libksud.so"
-}
-
-object KsuCli {
- val SHELL: Shell = createRootShell()
- val GLOBAL_MNT_SHELL: Shell = createRootShell(true)
-}
-
-fun getRootShell(globalMnt: Boolean = false): Shell {
- return if (globalMnt) KsuCli.GLOBAL_MNT_SHELL else {
- KsuCli.SHELL
- }
-}
-
-inline fun withNewRootShell(
- globalMnt: Boolean = false,
- block: Shell.() -> T
-): T {
- return createRootShell(globalMnt).use(block)
-}
-
-fun getFileNameFromUri(context: Context, uri: Uri): String? {
- var fileName: String? = null
- val contentResolver: ContentResolver = context.contentResolver
- val cursor: Cursor? = contentResolver.query(uri, null, null, null, null)
- cursor?.use {
- if (it.moveToFirst()) {
- fileName = it.getString(it.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME))
- }
- }
- return fileName
-}
-
-fun createRootShell(globalMnt: Boolean = false): Shell {
- Shell.enableVerboseLogging = BuildConfig.DEBUG
- val builder = Shell.Builder.create()
- return try {
- if (globalMnt) {
- builder.build(getKsuDaemonPath(), "debug", "su", "-g")
- } else {
- builder.build(getKsuDaemonPath(), "debug", "su")
- }
- } catch (e: Throwable) {
- Log.w(TAG, "ksu failed: ", e)
- try {
- if (globalMnt) {
- builder.build("su")
- } else {
- builder.build("su", "-mm")
- }
- } catch (e: Throwable) {
- Log.e(TAG, "su failed: ", e)
- builder.build("sh")
- }
- }
-}
-
-fun execKsud(args: String, newShell: Boolean = false): Boolean {
- return if (newShell) {
- withNewRootShell {
- ShellUtils.fastCmdResult(this, "${getKsuDaemonPath()} $args")
- }
- } else {
- ShellUtils.fastCmdResult(getRootShell(), "${getKsuDaemonPath()} $args")
- }
-}
-
-fun install() {
- val start = SystemClock.elapsedRealtime()
- val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so").absolutePath
- val result = execKsud("install --magiskboot $magiskboot", true)
- Log.w(TAG, "install result: $result, cost: ${SystemClock.elapsedRealtime() - start}ms")
-}
-
-fun listModules(): String {
- val shell = getRootShell()
-
- val out =
- shell.newJob().add("${getKsuDaemonPath()} module list").to(ArrayList(), null).exec().out
- return out.joinToString("\n").ifBlank { "[]" }
-}
-
-fun getModuleCount(): Int {
- val result = listModules()
- runCatching {
- val array = JSONArray(result)
- return array.length()
- }.getOrElse { return 0 }
-}
-
-fun getSuperuserCount(): Int {
- return Natives.allowList.size
-}
-
-fun toggleModule(id: String, enable: Boolean): Boolean {
- val cmd = if (enable) {
- "module enable $id"
- } else {
- "module disable $id"
- }
- val result = execKsud(cmd, true)
- Log.i(TAG, "$cmd result: $result")
- return result
-}
-
-fun uninstallModule(id: String): Boolean {
- val cmd = "module uninstall $id"
- val result = execKsud(cmd, true)
- Log.i(TAG, "uninstall module $id result: $result")
- return result
-}
-
-private fun flashWithIO(
- cmd: String,
- onStdout: (String) -> Unit,
- onStderr: (String) -> Unit
-): Shell.Result {
-
- val stdoutCallback: CallbackList = object : CallbackList() {
- override fun onAddElement(s: String?) {
- onStdout(s ?: "")
- }
- }
-
- val stderrCallback: CallbackList = object : CallbackList() {
- override fun onAddElement(s: String?) {
- onStderr(s ?: "")
- }
- }
-
- return withNewRootShell {
- newJob().add(cmd).to(stdoutCallback, stderrCallback).exec()
- }
-}
-
-fun flashModule(
- uri: Uri,
- onFinish: (Boolean, Int) -> Unit,
- onStdout: (String) -> Unit,
- onStderr: (String) -> Unit
-): Boolean {
- val resolver = ksuApp.contentResolver
- with(resolver.openInputStream(uri)) {
- val file = File(ksuApp.cacheDir, "module.zip")
- file.outputStream().use { output ->
- this?.copyTo(output)
- }
- val cmd = "module install ${file.absolutePath}"
- val result = flashWithIO("${getKsuDaemonPath()} $cmd", onStdout, onStderr)
- Log.i("KernelSU", "install module $uri result: $result")
-
- file.delete()
-
- onFinish(result.isSuccess, result.code)
- return result.isSuccess
- }
-}
-
-fun restoreBoot(
- onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit
-): Boolean {
- val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so")
- val result = flashWithIO("${getKsuDaemonPath()} boot-restore -f --magiskboot $magiskboot", onStdout, onStderr)
- onFinish(result.isSuccess, result.code)
- return result.isSuccess
-}
-
-fun uninstallPermanently(
- onFinish: (Boolean, Int) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit
-): Boolean {
- val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so")
- val result = flashWithIO("${getKsuDaemonPath()} uninstall --magiskboot $magiskboot", onStdout, onStderr)
- onFinish(result.isSuccess, result.code)
- return result.isSuccess
-}
-
-suspend fun shrinkModules(): Boolean = withContext(Dispatchers.IO) {
- execKsud("module shrink", true)
-}
-
-@Parcelize
-sealed class LkmSelection : Parcelable {
- data class LkmUri(val uri: Uri) : LkmSelection()
- data class KmiString(val value: String) : LkmSelection()
- data object KmiNone : LkmSelection()
-}
-
-fun installBoot(
- bootUri: Uri?,
- lkm: LkmSelection,
- ota: Boolean,
- onFinish: (Boolean, Int) -> Unit,
- onStdout: (String) -> Unit,
- onStderr: (String) -> Unit,
-): Boolean {
- val resolver = ksuApp.contentResolver
-
- val bootFile = bootUri?.let { uri ->
- with(resolver.openInputStream(uri)) {
- val bootFile = File(ksuApp.cacheDir, "boot.img")
- bootFile.outputStream().use { output ->
- this?.copyTo(output)
- }
-
- bootFile
- }
- }
-
- val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so")
- var cmd = "boot-patch --magiskboot ${magiskboot.absolutePath}"
-
- cmd += if (bootFile == null) {
- // no boot.img, use -f to force install
- " -f"
- } else {
- " -b ${bootFile.absolutePath}"
- }
-
- if (ota) {
- cmd += " -u"
- }
-
- var lkmFile: File? = null
- when (lkm) {
- is LkmSelection.LkmUri -> {
- lkmFile = with(resolver.openInputStream(lkm.uri)) {
- val file = File(ksuApp.cacheDir, "kernelsu-tmp-lkm.ko")
- file.outputStream().use { output ->
- this?.copyTo(output)
- }
-
- file
- }
- cmd += " -m ${lkmFile.absolutePath}"
- }
-
- is LkmSelection.KmiString -> {
- cmd += " --kmi ${lkm.value}"
- }
-
- LkmSelection.KmiNone -> {
- // do nothing
- }
- }
-
- // output dir
- val downloadsDir =
- Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
- cmd += " -o $downloadsDir"
-
- val result = flashWithIO("${getKsuDaemonPath()} $cmd", onStdout, onStderr)
- Log.i("KernelSU", "install boot result: ${result.isSuccess}")
-
- bootFile?.delete()
- lkmFile?.delete()
-
- // if boot uri is empty, it is direct install, when success, we should show reboot button
- onFinish(bootUri == null && result.isSuccess, result.code)
- return result.isSuccess
-}
-
-fun reboot(reason: String = "") {
- val shell = getRootShell()
- if (reason == "recovery") {
- // KEYCODE_POWER = 26, hide incorrect "Factory data reset" message
- ShellUtils.fastCmd(shell, "/system/bin/input keyevent 26")
- }
- ShellUtils.fastCmd(shell, "/system/bin/svc power reboot $reason || /system/bin/reboot $reason")
-}
-
-fun rootAvailable(): Boolean {
- val shell = getRootShell()
- return shell.isRoot
-}
-
-fun isAbDevice(): Boolean {
- val shell = getRootShell()
- return ShellUtils.fastCmd(shell, "getprop ro.build.ab_update").trim().toBoolean()
-}
-
-fun isInitBoot(): Boolean {
- val shell = getRootShell()
- if (shell.isRoot) {
- // if we have root, use /dev/block/by-name/init_boot to check
- val abDevice = isAbDevice()
- val initBootBlock = "/dev/block/by-name/init_boot${if (abDevice) "_a" else ""}"
- val file = SuFile(initBootBlock)
- file.shell = shell
- return file.exists()
- }
- // https://source.android.com/docs/core/architecture/partitions/generic-boot
- return ShellUtils.fastCmd(shell, "getprop ro.product.first_api_level").trim()
- .toInt() >= Build.VERSION_CODES.TIRAMISU
-}
-
-suspend fun getCurrentKmi(): String = withContext(Dispatchers.IO) {
- val shell = getRootShell()
- val cmd = "boot-info current-kmi"
- ShellUtils.fastCmd(shell, "${getKsuDaemonPath()} $cmd")
-}
-
-suspend fun getSupportedKmis(): List = withContext(Dispatchers.IO) {
- val shell = getRootShell()
- val cmd = "boot-info supported-kmi"
- val out = shell.newJob().add("${getKsuDaemonPath()} $cmd").to(ArrayList(), null).exec().out
- out.filter { it.isNotBlank() }.map { it.trim() }
-}
-
-fun overlayFsAvailable(): Boolean {
- val shell = getRootShell()
- // check /proc/filesystems
- return ShellUtils.fastCmdResult(shell, "cat /proc/filesystems | grep overlay")
-}
-
-fun hasMagisk(): Boolean {
- val shell = getRootShell(true)
- val result = shell.newJob().add("which magisk").exec()
- Log.i(TAG, "has magisk: ${result.isSuccess}")
- return result.isSuccess
-}
-
-fun isSepolicyValid(rules: String?): Boolean {
- if (rules == null) {
- return true
- }
- val shell = getRootShell()
- val result =
- shell.newJob().add("${getKsuDaemonPath()} sepolicy check '$rules'").to(ArrayList(), null)
- .exec()
- return result.isSuccess
-}
-
-fun getSepolicy(pkg: String): String {
- val shell = getRootShell()
- val result =
- shell.newJob().add("${getKsuDaemonPath()} profile get-sepolicy $pkg").to(ArrayList(), null)
- .exec()
- Log.i(TAG, "code: ${result.code}, out: ${result.out}, err: ${result.err}")
- return result.out.joinToString("\n")
-}
-
-fun setSepolicy(pkg: String, rules: String): Boolean {
- val shell = getRootShell()
- val result = shell.newJob().add("${getKsuDaemonPath()} profile set-sepolicy $pkg '$rules'")
- .to(ArrayList(), null).exec()
- Log.i(TAG, "set sepolicy result: ${result.code}")
- return result.isSuccess
-}
-
-fun listAppProfileTemplates(): List {
- val shell = getRootShell()
- return shell.newJob().add("${getKsuDaemonPath()} profile list-templates").to(ArrayList(), null)
- .exec().out
-}
-
-fun getAppProfileTemplate(id: String): String {
- val shell = getRootShell()
- return shell.newJob().add("${getKsuDaemonPath()} profile get-template '${id}'")
- .to(ArrayList(), null).exec().out.joinToString("\n")
-}
-
-fun setAppProfileTemplate(id: String, template: String): Boolean {
- val shell = getRootShell()
- val escapedTemplate = template.replace("\"", "\\\"")
- val cmd = """${getKsuDaemonPath()} profile set-template "$id" "$escapedTemplate'""""
- return shell.newJob().add(cmd)
- .to(ArrayList(), null).exec().isSuccess
-}
-
-fun deleteAppProfileTemplate(id: String): Boolean {
- val shell = getRootShell()
- return shell.newJob().add("${getKsuDaemonPath()} profile delete-template '${id}'")
- .to(ArrayList(), null).exec().isSuccess
-}
-
-fun forceStopApp(packageName: String) {
- val shell = getRootShell()
- val result = shell.newJob().add("am force-stop $packageName").exec()
- Log.i(TAG, "force stop $packageName result: $result")
-}
-
-fun launchApp(packageName: String) {
-
- val shell = getRootShell()
- val result =
- shell.newJob()
- .add("cmd package resolve-activity --brief $packageName | tail -n 1 | xargs cmd activity start-activity -n")
- .exec()
- Log.i(TAG, "launch $packageName result: $result")
-}
-
-fun restartApp(packageName: String) {
- forceStopApp(packageName)
- launchApp(packageName)
-}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/LogEvent.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/LogEvent.kt
deleted file mode 100644
index 19eb1df1..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/LogEvent.kt
+++ /dev/null
@@ -1,115 +0,0 @@
-package me.weishu.kernelsu.ui.util
-
-import android.content.ContentResolver
-import android.content.Context
-import android.net.Uri
-import android.os.Build
-import android.os.ParcelFileDescriptor
-import android.system.Os
-import com.topjohnwu.superuser.ShellUtils
-import me.weishu.kernelsu.Natives
-import me.weishu.kernelsu.ui.screen.getManagerVersion
-import java.io.File
-import java.io.FileOutputStream
-import java.io.FileWriter
-import java.io.PrintWriter
-import java.time.LocalDateTime
-import java.time.format.DateTimeFormatter
-
-fun getBugreportFile(context: Context): File {
-
- val bugreportDir = File(context.cacheDir, "bugreport")
- bugreportDir.mkdirs()
-
- val dmesgFile = File(bugreportDir, "dmesg.txt")
- val logcatFile = File(bugreportDir, "logcat.txt")
- val tombstonesFile = File(bugreportDir, "tombstones.tar.gz")
- val dropboxFile = File(bugreportDir, "dropbox.tar.gz")
- val pstoreFile = File(bugreportDir, "pstore.tar.gz")
- // Xiaomi/Readmi devices have diag in /data/vendor/diag
- val diagFile = File(bugreportDir, "diag.tar.gz")
- val opulsFile = File(bugreportDir, "opuls.tar.gz")
- val bootlogFile = File(bugreportDir, "bootlog.tar.gz")
- val mountsFile = File(bugreportDir, "mounts.txt")
- val fileSystemsFile = File(bugreportDir, "filesystems.txt")
- val adbFileTree = File(bugreportDir, "adb_tree.txt")
- val adbFileDetails = File(bugreportDir, "adb_details.txt")
- val ksuFileSize = File(bugreportDir, "ksu_size.txt")
- val appListFile = File(bugreportDir, "packages.txt")
- val propFile = File(bugreportDir, "props.txt")
- val allowListFile = File(bugreportDir, "allowlist.bin")
- val procModules = File(bugreportDir, "proc_modules.txt")
- val bootConfig = File(bugreportDir, "boot_config.txt")
- val kernelConfig = File(bugreportDir, "defconfig.gz")
-
- val shell = getRootShell(true)
-
- shell.newJob().add("dmesg > ${dmesgFile.absolutePath}").exec()
- shell.newJob().add("logcat -d > ${logcatFile.absolutePath}").exec()
- shell.newJob().add("tar -czf ${tombstonesFile.absolutePath} -C /data/tombstones .").exec()
- shell.newJob().add("tar -czf ${dropboxFile.absolutePath} -C /data/system/dropbox .").exec()
- shell.newJob().add("tar -czf ${pstoreFile.absolutePath} -C /sys/fs/pstore .").exec()
- shell.newJob().add("tar -czf ${diagFile.absolutePath} -C /data/vendor/diag . --exclude=./minidump.gz").exec()
- shell.newJob().add("tar -czf ${opulsFile.absolutePath} -C /mnt/oplus/op2/media/log/boot_log/ .").exec()
- shell.newJob().add("tar -czf ${bootlogFile.absolutePath} -C /data/adb/ksu/log .").exec()
-
- shell.newJob().add("cat /proc/1/mountinfo > ${mountsFile.absolutePath}").exec()
- shell.newJob().add("cat /proc/filesystems > ${fileSystemsFile.absolutePath}").exec()
- shell.newJob().add("busybox tree /data/adb > ${adbFileTree.absolutePath}").exec()
- shell.newJob().add("ls -alRZ /data/adb > ${adbFileDetails.absolutePath}").exec()
- shell.newJob().add("du -sh /data/adb/ksu/* > ${ksuFileSize.absolutePath}").exec()
- shell.newJob().add("cp /data/system/packages.list ${appListFile.absolutePath}").exec()
- shell.newJob().add("getprop > ${propFile.absolutePath}").exec()
- shell.newJob().add("cp /data/adb/ksu/.allowlist ${allowListFile.absolutePath}").exec()
- shell.newJob().add("cp /proc/modules ${procModules.absolutePath}").exec()
- shell.newJob().add("cp /proc/bootconfig ${bootConfig.absolutePath}").exec()
- shell.newJob().add("cp /proc/config.gz ${kernelConfig.absolutePath}").exec()
-
- val selinux = ShellUtils.fastCmd(shell, "getenforce")
-
- // basic information
- val buildInfo = File(bugreportDir, "basic.txt")
- PrintWriter(FileWriter(buildInfo)).use { pw ->
- pw.println("Kernel: ${System.getProperty("os.version")}")
- pw.println("BRAND: " + Build.BRAND)
- pw.println("MODEL: " + Build.MODEL)
- pw.println("PRODUCT: " + Build.PRODUCT)
- pw.println("MANUFACTURER: " + Build.MANUFACTURER)
- pw.println("SDK: " + Build.VERSION.SDK_INT)
- pw.println("PREVIEW_SDK: " + Build.VERSION.PREVIEW_SDK_INT)
- pw.println("FINGERPRINT: " + Build.FINGERPRINT)
- pw.println("DEVICE: " + Build.DEVICE)
- pw.println("Manager: " + getManagerVersion(context))
- pw.println("SELinux: $selinux")
-
- val uname = Os.uname()
- pw.println("KernelRelease: ${uname.release}")
- pw.println("KernelVersion: ${uname.version}")
- pw.println("Machine: ${uname.machine}")
- pw.println("Nodename: ${uname.nodename}")
- pw.println("Sysname: ${uname.sysname}")
-
- val ksuKernel = Natives.version
- pw.println("KernelSU: $ksuKernel")
- val safeMode = Natives.isSafeMode
- pw.println("SafeMode: $safeMode")
- val lkmMode = Natives.isLkmMode
- pw.println("LKM: $lkmMode")
- }
-
- // modules
- val modulesFile = File(bugreportDir, "modules.json")
- modulesFile.writeText(listModules())
-
- val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH_mm")
- val current = LocalDateTime.now().format(formatter)
-
- val targetFile = File(context.cacheDir, "KernelSU_bugreport_${current}.tar.gz")
-
- shell.newJob().add("tar czf ${targetFile.absolutePath} -C ${bugreportDir.absolutePath} .").exec()
- shell.newJob().add("rm -rf ${bugreportDir.absolutePath}").exec()
- shell.newJob().add("chmod 0644 ${targetFile.absolutePath}").exec()
-
- return targetFile
-}
-
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/SELinuxChecker.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/SELinuxChecker.kt
deleted file mode 100644
index 78346dd9..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/SELinuxChecker.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package me.weishu.kernelsu.ui.util
-
-import androidx.compose.ui.res.stringResource
-import androidx.compose.runtime.Composable
-import com.topjohnwu.superuser.Shell
-import me.weishu.kernelsu.R
-
-@Composable
-fun getSELinuxStatus(): String {
- val shell = Shell.Builder.create()
- .setFlags(Shell.FLAG_REDIRECT_STDERR)
- .build("sh")
-
- val list = ArrayList()
- val result = shell.use {
- it.newJob().add("getenforce").to(list, list).exec()
- }
- val output = result.out.joinToString("\n").trim()
-
- if (result.isSuccess) {
- return when (output) {
- "Enforcing" -> stringResource(R.string.selinux_status_enforcing)
- "Permissive" -> stringResource(R.string.selinux_status_permissive)
- "Disabled" -> stringResource(R.string.selinux_status_disabled)
- else -> stringResource(R.string.selinux_status_unknown)
- }
- }
-
- return if (output.endsWith("Permission denied")) {
- stringResource(R.string.selinux_status_enforcing)
- } else {
- stringResource(R.string.selinux_status_unknown)
- }
-}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/module/LatestVersionInfo.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/module/LatestVersionInfo.kt
deleted file mode 100644
index 374b3853..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/module/LatestVersionInfo.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package me.weishu.kernelsu.ui.util.module
-
-data class LatestVersionInfo(
- val versionCode : Int = 0,
- val downloadUrl : String = "",
- val changelog : String = ""
-)
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt
deleted file mode 100644
index 013453fb..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt
+++ /dev/null
@@ -1,161 +0,0 @@
-package me.weishu.kernelsu.ui.viewmodel
-
-import android.os.SystemClock
-import android.util.Log
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import me.weishu.kernelsu.ui.util.listModules
-import me.weishu.kernelsu.ui.util.overlayFsAvailable
-import org.json.JSONArray
-import org.json.JSONObject
-import java.text.Collator
-import java.util.Locale
-
-class ModuleViewModel : ViewModel() {
-
- companion object {
- private const val TAG = "ModuleViewModel"
- private var modules by mutableStateOf>(emptyList())
- }
-
- class ModuleInfo(
- val id: String,
- val name: String,
- val author: String,
- val version: String,
- val versionCode: Int,
- val description: String,
- val enabled: Boolean,
- val update: Boolean,
- val remove: Boolean,
- val updateJson: String,
- val hasWebUi: Boolean,
- )
-
- data class ModuleUpdateInfo(
- val version: String,
- val versionCode: Int,
- val zipUrl: String,
- val changelog: String,
- )
-
- var isRefreshing by mutableStateOf(false)
- private set
-
- var isOverlayAvailable by mutableStateOf(overlayFsAvailable())
- private set
-
- val moduleList by derivedStateOf {
- val comparator = compareBy(Collator.getInstance(Locale.getDefault()), ModuleInfo::id)
- modules.sortedWith(comparator).also {
- isRefreshing = false
- }
- }
-
- var isNeedRefresh by mutableStateOf(false)
- private set
-
- fun markNeedRefresh() {
- isNeedRefresh = true
- }
-
- fun fetchModuleList() {
- viewModelScope.launch(Dispatchers.IO) {
- isRefreshing = true
-
- val oldModuleList = modules
-
- val start = SystemClock.elapsedRealtime()
-
- kotlin.runCatching {
- isOverlayAvailable = overlayFsAvailable()
-
- val result = listModules()
-
- Log.i(TAG, "result: $result")
-
- val array = JSONArray(result)
- modules = (0 until array.length())
- .asSequence()
- .map { array.getJSONObject(it) }
- .map { obj ->
- ModuleInfo(
- obj.getString("id"),
-
- obj.optString("name"),
- obj.optString("author", "Unknown"),
- obj.optString("version", "Unknown"),
- obj.optInt("versionCode", 0),
- obj.optString("description"),
- obj.getBoolean("enabled"),
- obj.getBoolean("update"),
- obj.getBoolean("remove"),
- obj.optString("updateJson"),
- obj.optBoolean("web")
- )
- }.toList()
- isNeedRefresh = false
- }.onFailure { e ->
- Log.e(TAG, "fetchModuleList: ", e)
- isRefreshing = false
- }
-
- // when both old and new is kotlin.collections.EmptyList
- // moduleList update will don't trigger
- if (oldModuleList === modules) {
- isRefreshing = false
- }
-
- Log.i(TAG, "load cost: ${SystemClock.elapsedRealtime() - start}, modules: $modules")
- }
- }
-
- fun checkUpdate(m: ModuleInfo): Triple {
- val empty = Triple("", "", "")
- if (m.updateJson.isEmpty() || m.remove || m.update || !m.enabled) {
- return empty
- }
- // download updateJson
- val result = kotlin.runCatching {
- val url = m.updateJson
- Log.i(TAG, "checkUpdate url: $url")
- val response = okhttp3.OkHttpClient()
- .newCall(
- okhttp3.Request.Builder()
- .url(url)
- .build()
- ).execute()
- Log.d(TAG, "checkUpdate code: ${response.code}")
- if (response.isSuccessful) {
- response.body?.string() ?: ""
- } else {
- ""
- }
- }.getOrDefault("")
- Log.i(TAG, "checkUpdate result: $result")
-
- if (result.isEmpty()) {
- return empty
- }
-
- val updateJson = kotlin.runCatching {
- JSONObject(result)
- }.getOrNull() ?: return empty
-
- val version = updateJson.optString("version", "")
- val versionCode = updateJson.optInt("versionCode", 0)
- val zipUrl = updateJson.optString("zipUrl", "")
- val changelog = updateJson.optString("changelog", "")
- if (versionCode <= m.versionCode || zipUrl.isEmpty()) {
- return empty
- }
-
- return Triple(zipUrl, version, changelog)
- }
-}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SuperUserViewModel.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SuperUserViewModel.kt
deleted file mode 100644
index 37e05aa8..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SuperUserViewModel.kt
+++ /dev/null
@@ -1,160 +0,0 @@
-package me.weishu.kernelsu.ui.viewmodel
-
-import android.content.ComponentName
-import android.content.Intent
-import android.content.ServiceConnection
-import android.content.pm.ApplicationInfo
-import android.content.pm.PackageInfo
-import android.os.IBinder
-import android.os.Parcelable
-import android.os.SystemClock
-import android.util.Log
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
-import androidx.lifecycle.ViewModel
-import com.topjohnwu.superuser.Shell
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-import kotlinx.parcelize.Parcelize
-import me.weishu.kernelsu.IKsuInterface
-import me.weishu.kernelsu.Natives
-import me.weishu.kernelsu.ksuApp
-import me.weishu.kernelsu.ui.KsuService
-import me.weishu.kernelsu.ui.util.HanziToPinyin
-import me.weishu.kernelsu.ui.util.KsuCli
-import java.text.Collator
-import java.util.*
-import kotlin.coroutines.resume
-import kotlin.coroutines.suspendCoroutine
-
-class SuperUserViewModel : ViewModel() {
-
- companion object {
- private const val TAG = "SuperUserViewModel"
- private var apps by mutableStateOf>(emptyList())
- }
-
- @Parcelize
- data class AppInfo(
- val label: String,
- val packageInfo: PackageInfo,
- val profile: Natives.Profile?,
- ) : Parcelable {
- val packageName: String
- get() = packageInfo.packageName
- val uid: Int
- get() = packageInfo.applicationInfo.uid
-
- val allowSu: Boolean
- get() = profile != null && profile.allowSu
- val hasCustomProfile: Boolean
- get() {
- if (profile == null) {
- return false
- }
-
- return if (profile.allowSu) {
- !profile.rootUseDefault
- } else {
- !profile.nonRootUseDefault
- }
- }
- }
-
- var search by mutableStateOf("")
- var showSystemApps by mutableStateOf(false)
- var isRefreshing by mutableStateOf(false)
- private set
-
- private val sortedList by derivedStateOf {
- val comparator = compareBy {
- when {
- it.allowSu -> 0
- it.hasCustomProfile -> 1
- else -> 2
- }
- }.then(compareBy(Collator.getInstance(Locale.getDefault()), AppInfo::label))
- apps.sortedWith(comparator).also {
- isRefreshing = false
- }
- }
-
- val appList by derivedStateOf {
- sortedList.filter {
- it.label.contains(search, true) || it.packageName.contains(
- search,
- true
- ) || HanziToPinyin.getInstance()
- .toPinyinString(it.label).contains(search, true)
- }.filter {
- it.uid == 2000 // Always show shell
- || showSystemApps || it.packageInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) == 0
- }
- }
-
- private suspend inline fun connectKsuService(
- crossinline onDisconnect: () -> Unit = {}
- ): Pair = suspendCoroutine {
- val connection = object : ServiceConnection {
- override fun onServiceDisconnected(name: ComponentName?) {
- onDisconnect()
- }
-
- override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
- it.resume(binder as IBinder to this)
- }
- }
-
- val intent = Intent(ksuApp, KsuService::class.java)
-
- val task = KsuService.bindOrTask(
- intent,
- Shell.EXECUTOR,
- connection,
- )
- val shell = KsuCli.SHELL
- task?.let { it1 -> shell.execTask(it1) }
- }
-
- private fun stopKsuService() {
- val intent = Intent(ksuApp, KsuService::class.java)
- KsuService.stop(intent)
- }
-
- suspend fun fetchAppList() {
-
- isRefreshing = true
-
- val result = connectKsuService {
- Log.w(TAG, "KsuService disconnected")
- }
-
- withContext(Dispatchers.IO) {
- val pm = ksuApp.packageManager
- val start = SystemClock.elapsedRealtime()
-
- val binder = result.first
- val allPackages = IKsuInterface.Stub.asInterface(binder).getPackages(0)
-
- withContext(Dispatchers.Main) {
- stopKsuService()
- }
-
- val packages = allPackages.list
-
- apps = packages.map {
- val appInfo = it.applicationInfo
- val uid = appInfo.uid
- val profile = Natives.getAppProfile(it.packageName, uid)
- AppInfo(
- label = appInfo.loadLabel(pm).toString(),
- packageInfo = it,
- profile = profile,
- )
- }.filter { it.packageName != ksuApp.packageName }
- Log.i(TAG, "load cost: ${SystemClock.elapsedRealtime() - start}")
- }
- }
-}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/TemplateViewModel.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/TemplateViewModel.kt
deleted file mode 100644
index cbed82f2..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/TemplateViewModel.kt
+++ /dev/null
@@ -1,328 +0,0 @@
-package me.weishu.kernelsu.ui.viewmodel
-
-import android.os.Parcelable
-import android.util.Log
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
-import androidx.lifecycle.ViewModel
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-import kotlinx.parcelize.Parcelize
-import me.weishu.kernelsu.Natives
-import me.weishu.kernelsu.profile.Capabilities
-import me.weishu.kernelsu.profile.Groups
-import me.weishu.kernelsu.ui.util.getAppProfileTemplate
-import me.weishu.kernelsu.ui.util.listAppProfileTemplates
-import me.weishu.kernelsu.ui.util.setAppProfileTemplate
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import org.json.JSONArray
-import org.json.JSONObject
-import java.text.Collator
-import java.util.Locale
-import java.util.concurrent.TimeUnit
-
-
-/**
- * @author weishu
- * @date 2023/10/20.
- */
-const val TEMPLATE_INDEX_URL = "https://kernelsu.org/templates/index.json"
-const val TEMPLATE_URL = "https://kernelsu.org/templates/%s"
-
-const val TAG = "TemplateViewModel"
-
-class TemplateViewModel : ViewModel() {
- companion object {
-
- private var templates by mutableStateOf>(emptyList())
- }
-
- @Parcelize
- data class TemplateInfo(
- val id: String = "",
- val name: String = "",
- val description: String = "",
- val author: String = "",
- val local: Boolean = true,
-
- val namespace: Int = Natives.Profile.Namespace.INHERITED.ordinal,
- val uid: Int = Natives.ROOT_UID,
- val gid: Int = Natives.ROOT_GID,
- val groups: List = mutableListOf(),
- val capabilities: List = mutableListOf(),
- val context: String = Natives.KERNEL_SU_DOMAIN,
- val rules: List = mutableListOf(),
- ) : Parcelable
-
- var isRefreshing by mutableStateOf(false)
- private set
-
- val templateList by derivedStateOf {
- val comparator = compareBy(TemplateInfo::local).reversed().then(
- compareBy(
- Collator.getInstance(Locale.getDefault()), TemplateInfo::id
- )
- )
- templates.sortedWith(comparator).apply {
- isRefreshing = false
- }
- }
-
- suspend fun fetchTemplates(sync: Boolean = false) {
- isRefreshing = true
- withContext(Dispatchers.IO) {
- val localTemplateIds = listAppProfileTemplates()
- Log.i(TAG, "localTemplateIds: $localTemplateIds")
- if (localTemplateIds.isEmpty() || sync) {
- // if no templates, fetch remote templates
- fetchRemoteTemplates()
- }
-
- // fetch templates again
- templates = listAppProfileTemplates().mapNotNull(::getTemplateInfoById)
-
- isRefreshing = false
- }
- }
-
- suspend fun importTemplates(
- templates: String,
- onSuccess: suspend () -> Unit,
- onFailure: suspend (String) -> Unit
- ) {
- withContext(Dispatchers.IO) {
- runCatching {
- JSONArray(templates)
- }.getOrElse {
- runCatching {
- val json = JSONObject(templates)
- JSONArray().apply { put(json) }
- }.getOrElse {
- onFailure("invalid templates: $templates")
- return@withContext
- }
- }.let {
- 0.until(it.length()).forEach { i ->
- runCatching {
- val template = it.getJSONObject(i)
- val id = template.getString("id")
- template.put("local", true)
- setAppProfileTemplate(id, template.toString())
- }.onFailure { e ->
- Log.e(TAG, "ignore invalid template: $it", e)
- }
- }
- onSuccess()
- }
- }
- }
-
- suspend fun exportTemplates(onTemplateEmpty: () -> Unit, callback: (String) -> Unit) {
- withContext(Dispatchers.IO) {
- val templates = listAppProfileTemplates().mapNotNull(::getTemplateInfoById).filter {
- it.local
- }
- templates.ifEmpty {
- onTemplateEmpty()
- return@withContext
- }
- JSONArray(templates.map {
- it.toJSON()
- }).toString().let(callback)
- }
- }
-}
-
-private fun fetchRemoteTemplates() {
- runCatching {
- val client: OkHttpClient = OkHttpClient.Builder()
- .connectTimeout(5, TimeUnit.SECONDS)
- .writeTimeout(5, TimeUnit.SECONDS)
- .readTimeout(10, TimeUnit.SECONDS)
- .build()
-
- client.newCall(
- Request.Builder().url(TEMPLATE_INDEX_URL).build()
- ).execute().use { response ->
- if (!response.isSuccessful) {
- return
- }
- val remoteTemplateIds = JSONArray(response.body!!.string())
- Log.i(TAG, "fetchRemoteTemplates: $remoteTemplateIds")
- 0.until(remoteTemplateIds.length()).forEach { i ->
- val id = remoteTemplateIds.getString(i)
- Log.i(TAG, "fetch template: $id")
- val templateJson = client.newCall(
- Request.Builder().url(TEMPLATE_URL.format(id)).build()
- ).runCatching {
- execute().use { response ->
- if (!response.isSuccessful) {
- return@forEach
- }
- response.body!!.string()
- }
- }.getOrNull() ?: return@forEach
- Log.i(TAG, "template: $templateJson")
-
- // validate remote template
- runCatching {
- val json = JSONObject(templateJson)
- fromJSON(json)?.let {
- // force local template
- json.put("local", false)
- setAppProfileTemplate(id, json.toString())
- }
- }.onFailure {
- Log.e(TAG, "ignore invalid template: $it", it)
- return@forEach
- }
- }
- }
- }.onFailure { Log.e(TAG, "fetchRemoteTemplates: $it", it) }
-}
-
-@Suppress("UNCHECKED_CAST")
-private fun JSONArray.mapCatching(
- transform: (T) -> R, onFail: (Throwable) -> Unit
-): List {
- return List(length()) { i -> get(i) as T }.mapNotNull { element ->
- runCatching {
- transform(element)
- }.onFailure(onFail).getOrNull()
- }
-}
-
-private inline fun > getEnumOrdinals(
- jsonArray: JSONArray?, enumClass: Class
-): List {
- return jsonArray?.mapCatching({ name ->
- enumValueOf(name.uppercase())
- }, {
- Log.e(TAG, "ignore invalid enum ${enumClass.simpleName}: $it", it)
- }).orEmpty()
-}
-
-fun getTemplateInfoById(id: String): TemplateViewModel.TemplateInfo? {
- return runCatching {
- fromJSON(JSONObject(getAppProfileTemplate(id)))
- }.onFailure {
- Log.e(TAG, "ignore invalid template: $it", it)
- }.getOrNull()
-}
-
-private fun getLocaleString(json: JSONObject, key: String): String {
- val fallback = json.getString(key)
- val locale = Locale.getDefault()
- val localeKey = "${locale.language}_${locale.country}"
- json.optJSONObject("locales")?.let {
- // check locale first
- it.optJSONObject(localeKey)?.let { json->
- return json.optString(key, fallback)
- }
- // fallback to language
- it.optJSONObject(locale.language)?.let { json->
- return json.optString(key, fallback)
- }
- }
- return fallback
-}
-
-private fun fromJSON(templateJson: JSONObject): TemplateViewModel.TemplateInfo? {
- return runCatching {
- val groupsJsonArray = templateJson.optJSONArray("groups")
- val capabilitiesJsonArray = templateJson.optJSONArray("capabilities")
- val context = templateJson.optString("context").takeIf { it.isNotEmpty() }
- ?: Natives.KERNEL_SU_DOMAIN
- val namespace = templateJson.optString("namespace").takeIf { it.isNotEmpty() }
- ?: Natives.Profile.Namespace.INHERITED.name
-
- val rulesJsonArray = templateJson.optJSONArray("rules")
- val templateInfo = TemplateViewModel.TemplateInfo(
- id = templateJson.getString("id"),
- name = getLocaleString(templateJson, "name"),
- description = getLocaleString(templateJson, "description"),
- author = templateJson.optString("author"),
- local = templateJson.optBoolean("local"),
- namespace = Natives.Profile.Namespace.valueOf(
- namespace.uppercase()
- ).ordinal,
- uid = templateJson.optInt("uid", Natives.ROOT_UID),
- gid = templateJson.optInt("gid", Natives.ROOT_GID),
- groups = getEnumOrdinals(groupsJsonArray, Groups::class.java).map { it.gid },
- capabilities = getEnumOrdinals(
- capabilitiesJsonArray, Capabilities::class.java
- ).map { it.cap },
- context = context,
- rules = rulesJsonArray?.mapCatching({ it }, {
- Log.e(TAG, "ignore invalid rule: $it", it)
- }).orEmpty()
- )
- templateInfo
- }.onFailure {
- Log.e(TAG, "ignore invalid template: $it", it)
- }.getOrNull()
-}
-
-fun TemplateViewModel.TemplateInfo.toJSON(): JSONObject {
- val template = this
- return JSONObject().apply {
-
- put("id", template.id)
- put("name", template.name.ifBlank { template.id })
- put("description", template.description.ifBlank { template.id })
- if (template.author.isNotEmpty()) {
- put("author", template.author)
- }
- put("namespace", Natives.Profile.Namespace.entries[template.namespace].name)
- put("uid", template.uid)
- put("gid", template.gid)
-
- if (template.groups.isNotEmpty()) {
- put("groups", JSONArray(
- Groups.entries.filter {
- template.groups.contains(it.gid)
- }.map {
- it.name
- }
- ))
- }
-
- if (template.capabilities.isNotEmpty()) {
- put("capabilities", JSONArray(
- Capabilities.entries.filter {
- template.capabilities.contains(it.cap)
- }.map {
- it.name
- }
- ))
- }
-
- if (template.context.isNotEmpty()) {
- put("context", template.context)
- }
-
- if (template.rules.isNotEmpty()) {
- put("rules", JSONArray(template.rules))
- }
- }
-}
-
-@Suppress("unused")
-fun generateTemplates() {
- val templateJson = JSONObject()
- templateJson.put("id", "com.example")
- templateJson.put("name", "Example")
- templateJson.put("description", "This is an example template")
- templateJson.put("local", true)
- templateJson.put("namespace", Natives.Profile.Namespace.INHERITED.name)
- templateJson.put("uid", 0)
- templateJson.put("gid", 0)
-
- templateJson.put("groups", JSONArray().apply { put(Groups.INET.name) })
- templateJson.put("capabilities", JSONArray().apply { put(Capabilities.CAP_NET_RAW.name) })
- templateJson.put("context", "u:r:su:s0")
- Log.i(TAG, "$templateJson")
-}
\ No newline at end of file
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/MimeUtil.java b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/MimeUtil.java
deleted file mode 100644
index 1fc2f4a4..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/MimeUtil.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package me.weishu.kernelsu.ui.webui;
-
-import java.net.URLConnection;
-
-class MimeUtil {
-
- public static String getMimeFromFileName(String fileName) {
- if (fileName == null) {
- return null;
- }
-
- // Copying the logic and mapping that Chromium follows.
- // First we check against the OS (this is a limited list by default)
- // but app developers can extend this.
- // We then check against a list of hardcoded mime types above if the
- // OS didn't provide a result.
- String mimeType = URLConnection.guessContentTypeFromName(fileName);
-
- if (mimeType != null) {
- return mimeType;
- }
-
- return guessHardcodedMime(fileName);
- }
-
- // We should keep this map in sync with the lists under
- // //net/base/mime_util.cc in Chromium.
- // A bunch of the mime types don't really apply to Android land
- // like word docs so feel free to filter out where necessary.
- private static String guessHardcodedMime(String fileName) {
- int finalFullStop = fileName.lastIndexOf('.');
- if (finalFullStop == -1) {
- return null;
- }
-
- final String extension = fileName.substring(finalFullStop + 1).toLowerCase();
-
- return switch (extension) {
- case "webm" -> "video/webm";
- case "mpeg", "mpg" -> "video/mpeg";
- case "mp3" -> "audio/mpeg";
- case "wasm" -> "application/wasm";
- case "xhtml", "xht", "xhtm" -> "application/xhtml+xml";
- case "flac" -> "audio/flac";
- case "ogg", "oga", "opus" -> "audio/ogg";
- case "wav" -> "audio/wav";
- case "m4a" -> "audio/x-m4a";
- case "gif" -> "image/gif";
- case "jpeg", "jpg", "jfif", "pjpeg", "pjp" -> "image/jpeg";
- case "png" -> "image/png";
- case "apng" -> "image/apng";
- case "svg", "svgz" -> "image/svg+xml";
- case "webp" -> "image/webp";
- case "mht", "mhtml" -> "multipart/related";
- case "css" -> "text/css";
- case "html", "htm", "shtml", "shtm", "ehtml" -> "text/html";
- case "js", "mjs" -> "application/javascript";
- case "xml" -> "text/xml";
- case "mp4", "m4v" -> "video/mp4";
- case "ogv", "ogm" -> "video/ogg";
- case "ico" -> "image/x-icon";
- case "woff" -> "application/font-woff";
- case "gz", "tgz" -> "application/gzip";
- case "json" -> "application/json";
- case "pdf" -> "application/pdf";
- case "zip" -> "application/zip";
- case "bmp" -> "image/bmp";
- case "tiff", "tif" -> "image/tiff";
- default -> null;
- };
- }
-}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/SuFilePathHandler.java b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/SuFilePathHandler.java
deleted file mode 100644
index ff450e8e..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/SuFilePathHandler.java
+++ /dev/null
@@ -1,191 +0,0 @@
-package me.weishu.kernelsu.ui.webui;
-
-import android.content.Context;
-import android.util.Log;
-import android.webkit.WebResourceResponse;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.WorkerThread;
-import androidx.webkit.WebViewAssetLoader;
-
-import com.topjohnwu.superuser.Shell;
-import com.topjohnwu.superuser.io.SuFile;
-import com.topjohnwu.superuser.io.SuFileInputStream;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.zip.GZIPInputStream;
-
-/**
- * Handler class to open files from file system by root access
- * For more information about android storage please refer to
- * Android Developers
- * Docs: Data and file storage overview.
- *
- * To avoid leaking user or app data to the web, make sure to choose {@code directory}
- * carefully, and assume any file under this directory could be accessed by any web page subject
- * to same-origin rules.
- *
- * A typical usage would be like:
- *
- * File publicDir = new File(context.getFilesDir(), "public");
- * // Host "files/public/" in app's data directory under:
- * // http://appassets.androidplatform.net/public/...
- * WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
- * .addPathHandler("/public/", new InternalStoragePathHandler(context, publicDir))
- * .build();
- *
- */
-public final class SuFilePathHandler implements WebViewAssetLoader.PathHandler {
- private static final String TAG = "SuFilePathHandler";
-
- /**
- * Default value to be used as MIME type if guessing MIME type failed.
- */
- public static final String DEFAULT_MIME_TYPE = "text/plain";
-
- /**
- * Forbidden subdirectories of {@link Context#getDataDir} that cannot be exposed by this
- * handler. They are forbidden as they often contain sensitive information.
- *
- * Note: Any future addition to this list will be considered breaking changes to the API.
- */
- private static final String[] FORBIDDEN_DATA_DIRS =
- new String[] {"/data/data", "/data/system"};
-
- @NonNull
- private final File mDirectory;
-
- private final Shell mShell;
-
- /**
- * Creates PathHandler for app's internal storage.
- * The directory to be exposed must be inside either the application's internal data
- * directory {@link Context#getDataDir} or cache directory {@link Context#getCacheDir}.
- * External storage is not supported for security reasons, as other apps with
- * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} may be able to modify the
- * files.
- *
- * Exposing the entire data or cache directory is not permitted, to avoid accidentally
- * exposing sensitive application files to the web. Certain existing subdirectories of
- * {@link Context#getDataDir} are also not permitted as they are often sensitive.
- * These files are ({@code "app_webview/"}, {@code "databases/"}, {@code "lib/"},
- * {@code "shared_prefs/"} and {@code "code_cache/"}).
- *
- * The application should typically use a dedicated subdirectory for the files it intends to
- * expose and keep them separate from other files.
- *
- * @param context {@link Context} that is used to access app's internal storage.
- * @param directory the absolute path of the exposed app internal storage directory from
- * which files can be loaded.
- * @throws IllegalArgumentException if the directory is not allowed.
- */
- public SuFilePathHandler(@NonNull Context context, @NonNull File directory, Shell rootShell) {
- try {
- mDirectory = new File(getCanonicalDirPath(directory));
- if (!isAllowedInternalStorageDir(context)) {
- throw new IllegalArgumentException("The given directory \"" + directory
- + "\" doesn't exist under an allowed app internal storage directory");
- }
- mShell = rootShell;
- } catch (IOException e) {
- throw new IllegalArgumentException(
- "Failed to resolve the canonical path for the given directory: "
- + directory.getPath(), e);
- }
- }
-
- private boolean isAllowedInternalStorageDir(@NonNull Context context) throws IOException {
- String dir = getCanonicalDirPath(mDirectory);
-
- for (String forbiddenPath : FORBIDDEN_DATA_DIRS) {
- if (dir.startsWith(forbiddenPath)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Opens the requested file from the exposed data directory.
- *
- * The matched prefix path used shouldn't be a prefix of a real web path. Thus, if the
- * requested file cannot be found or is outside the mounted directory a
- * {@link WebResourceResponse} object with a {@code null} {@link InputStream} will be
- * returned instead of {@code null}. This saves the time of falling back to network and
- * trying to resolve a path that doesn't exist. A {@link WebResourceResponse} with
- * {@code null} {@link InputStream} will be received as an HTTP response with status code
- * {@code 404} and no body.
- *
- * The MIME type for the file will be determined from the file's extension using
- * {@link java.net.URLConnection#guessContentTypeFromName}. Developers should ensure that
- * files are named using standard file extensions. If the file does not have a
- * recognised extension, {@code "text/plain"} will be used by default.
- *
- * @param path the suffix path to be handled.
- * @return {@link WebResourceResponse} for the requested file.
- */
- @Override
- @WorkerThread
- @NonNull
- public WebResourceResponse handle(@NonNull String path) {
- try {
- File file = getCanonicalFileIfChild(mDirectory, path);
- if (file != null) {
- InputStream is = openFile(file, mShell);
- String mimeType = guessMimeType(path);
- return new WebResourceResponse(mimeType, null, is);
- } else {
- Log.e(TAG, String.format(
- "The requested file: %s is outside the mounted directory: %s", path,
- mDirectory));
- }
- } catch (IOException e) {
- Log.e(TAG, "Error opening the requested path: " + path, e);
- }
- return new WebResourceResponse(null, null, null);
- }
-
- public static String getCanonicalDirPath(@NonNull File file) throws IOException {
- String canonicalPath = file.getCanonicalPath();
- if (!canonicalPath.endsWith("/")) canonicalPath += "/";
- return canonicalPath;
- }
-
- public static File getCanonicalFileIfChild(@NonNull File parent, @NonNull String child)
- throws IOException {
- String parentCanonicalPath = getCanonicalDirPath(parent);
- String childCanonicalPath = new File(parent, child).getCanonicalPath();
- if (childCanonicalPath.startsWith(parentCanonicalPath)) {
- return new File(childCanonicalPath);
- }
- return null;
- }
-
- @NonNull
- private static InputStream handleSvgzStream(@NonNull String path,
- @NonNull InputStream stream) throws IOException {
- return path.endsWith(".svgz") ? new GZIPInputStream(stream) : stream;
- }
-
- public static InputStream openFile(@NonNull File file, @NonNull Shell shell) throws IOException {
- SuFile suFile = new SuFile(file.getAbsolutePath());
- suFile.setShell(shell);
- InputStream fis = SuFileInputStream.open(suFile);
- return handleSvgzStream(file.getPath(), fis);
- }
-
- /**
- * Use {@link MimeUtil#getMimeFromFileName} to guess MIME type or return the
- * {@link #DEFAULT_MIME_TYPE} if it can't guess.
- *
- * @param filePath path of the file to guess its MIME type.
- * @return MIME type guessed from file extension or {@link #DEFAULT_MIME_TYPE}.
- */
- @NonNull
- public static String guessMimeType(@NonNull String filePath) {
- String mimeType = MimeUtil.getMimeFromFileName(filePath);
- return mimeType == null ? DEFAULT_MIME_TYPE : mimeType;
- }
-}
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIActivity.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIActivity.kt
deleted file mode 100644
index eccb002a..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIActivity.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-package me.weishu.kernelsu.ui.webui
-
-import android.annotation.SuppressLint
-import android.app.ActivityManager
-import android.content.Context
-import android.os.Bundle
-import android.webkit.WebResourceRequest
-import android.webkit.WebResourceResponse
-import android.webkit.WebView
-import android.webkit.WebViewClient
-import androidx.activity.ComponentActivity
-import androidx.webkit.WebViewAssetLoader
-import com.topjohnwu.superuser.Shell
-import me.weishu.kernelsu.ui.util.createRootShell
-import java.io.File
-
-@SuppressLint("SetJavaScriptEnabled")
-class WebUIActivity : ComponentActivity() {
- private lateinit var webviewInterface: WebViewInterface
-
- private var rootShell: Shell? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- val moduleId = intent.getStringExtra("id")!!
- val name = intent.getStringExtra("name")!!
- setTaskDescription(ActivityManager.TaskDescription("KernelSU - $name"))
-
- val prefs = getSharedPreferences("settings", Context.MODE_PRIVATE)
- WebView.setWebContentsDebuggingEnabled(prefs.getBoolean("enable_web_debugging", false))
-
- val webRoot = File("/data/adb/modules/${moduleId}/webroot")
- val rootShell = createRootShell(true).also { this.rootShell = it }
- val webViewAssetLoader = WebViewAssetLoader.Builder()
- .setDomain("mui.kernelsu.org")
- .addPathHandler(
- "/",
- SuFilePathHandler(this, webRoot, rootShell)
- )
- .build()
-
- val webViewClient = object : WebViewClient() {
- override fun shouldInterceptRequest(
- view: WebView,
- request: WebResourceRequest
- ): WebResourceResponse? {
- return webViewAssetLoader.shouldInterceptRequest(request.url)
- }
- }
-
- val webView = WebView(this).apply {
- settings.javaScriptEnabled = true
- settings.domStorageEnabled = true
- settings.allowFileAccess = false
- webviewInterface = WebViewInterface(this@WebUIActivity, this)
- addJavascriptInterface(webviewInterface, "ksu")
- setWebViewClient(webViewClient)
- loadUrl("https://mui.kernelsu.org/index.html")
- }
-
- setContentView(webView)
- }
-
- override fun onDestroy() {
- super.onDestroy()
- runCatching { rootShell?.close() }
- }
-}
\ No newline at end of file
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt
deleted file mode 100644
index 4b6a3c8f..00000000
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt
+++ /dev/null
@@ -1,190 +0,0 @@
-package me.weishu.kernelsu.ui.webui
-
-import android.app.Activity
-import android.content.Context
-import android.os.Handler
-import android.os.Looper
-import android.text.TextUtils
-import android.view.Window
-import android.webkit.JavascriptInterface
-import android.webkit.WebView
-import android.widget.Toast
-import androidx.core.view.WindowCompat
-import androidx.core.view.WindowInsetsCompat
-import androidx.core.view.WindowInsetsControllerCompat
-import com.topjohnwu.superuser.CallbackList
-import com.topjohnwu.superuser.ShellUtils
-import me.weishu.kernelsu.ui.util.createRootShell
-import me.weishu.kernelsu.ui.util.withNewRootShell
-import org.json.JSONArray
-import org.json.JSONObject
-import java.util.concurrent.CompletableFuture
-
-class WebViewInterface(val context: Context, private val webView: WebView) {
-
- @JavascriptInterface
- fun exec(cmd: String): String {
- return withNewRootShell(true) { ShellUtils.fastCmd(this, cmd) }
- }
-
- @JavascriptInterface
- fun exec(cmd: String, callbackFunc: String) {
- exec(cmd, null, callbackFunc)
- }
-
- private fun processOptions(sb: StringBuilder, options: String?) {
- val opts = if (options == null) JSONObject() else {
- JSONObject(options)
- }
-
- val cwd = opts.optString("cwd")
- if (!TextUtils.isEmpty(cwd)) {
- sb.append("cd ${cwd};")
- }
-
- opts.optJSONObject("env")?.let { env ->
- env.keys().forEach { key ->
- sb.append("export ${key}=${env.getString(key)};")
- }
- }
- }
-
- @JavascriptInterface
- fun exec(
- cmd: String,
- options: String?,
- callbackFunc: String
- ) {
- val finalCommand = StringBuilder()
- processOptions(finalCommand, options)
- finalCommand.append(cmd)
-
- val result = withNewRootShell(true) {
- newJob().add(finalCommand.toString()).to(ArrayList(), ArrayList()).exec()
- }
- val stdout = result.out.joinToString(separator = "\n")
- val stderr = result.err.joinToString(separator = "\n")
-
- val jsCode =
- "javascript: (function() { try { ${callbackFunc}(${result.code}, ${
- JSONObject.quote(
- stdout
- )
- }, ${JSONObject.quote(stderr)}); } catch(e) { console.error(e); } })();"
- webView.post {
- webView.loadUrl(jsCode)
- }
- }
-
- @JavascriptInterface
- fun spawn(command: String, args: String, options: String?, callbackFunc: String) {
- val finalCommand = StringBuilder()
-
- processOptions(finalCommand, options)
-
- if (!TextUtils.isEmpty(args)) {
- finalCommand.append(command).append(" ")
- JSONArray(args).let { argsArray ->
- for (i in 0 until argsArray.length()) {
- finalCommand.append(argsArray.getString(i))
- finalCommand.append(" ")
- }
- }
- } else {
- finalCommand.append(command)
- }
-
- val shell = createRootShell(true)
-
- val emitData = fun(name: String, data: String) {
- val jsCode =
- "javascript: (function() { try { ${callbackFunc}.${name}.emit('data', ${
- JSONObject.quote(
- data
- )
- }); } catch(e) { console.error('emitData', e); } })();"
- webView.post {
- webView.loadUrl(jsCode)
- }
- }
-
- val stdout = object : CallbackList() {
- override fun onAddElement(s: String) {
- emitData("stdout", s)
- }
- }
-
- val stderr = object : CallbackList() {
- override fun onAddElement(s: String) {
- emitData("stderr", s)
- }
- }
-
- val future = shell.newJob().add(finalCommand.toString()).to(stdout, stderr).enqueue()
- val completableFuture = CompletableFuture.supplyAsync {
- future.get()
- }
-
- completableFuture.thenAccept { result ->
- val emitExitCode =
- "javascript: (function() { try { ${callbackFunc}.emit('exit', ${result.code}); } catch(e) { console.error(`emitExit error: \${e}`); } })();"
- webView.post {
- webView.loadUrl(emitExitCode)
- }
-
- if (result.code != 0) {
- val emitErrCode =
- "javascript: (function() { try { var err = new Error(); err.exitCode = ${result.code}; err.message = ${
- JSONObject.quote(
- result.err.joinToString(
- "\n"
- )
- )
- };${callbackFunc}.emit('error', err); } catch(e) { console.error('emitErr', e); } })();"
- webView.post {
- webView.loadUrl(emitErrCode)
- }
- }
- }.whenComplete { _, _ ->
- runCatching { shell.close() }
- }
- }
-
- @JavascriptInterface
- fun toast(msg: String) {
- webView.post {
- Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
- }
- }
-
- @JavascriptInterface
- fun fullScreen(enable: Boolean) {
- if (context is Activity) {
- Handler(Looper.getMainLooper()).post {
- if (enable) {
- hideSystemUI(context.window)
- } else {
- showSystemUI(context.window)
- }
- }
- }
- }
-
-}
-
-fun hideSystemUI(window: Window) {
- WindowCompat.setDecorFitsSystemWindows(window, false)
- WindowInsetsControllerCompat(window, window.decorView).let { controller ->
- controller.hide(WindowInsetsCompat.Type.systemBars())
- controller.systemBarsBehavior =
- WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
- }
-}
-
-fun showSystemUI(window: Window) {
- WindowCompat.setDecorFitsSystemWindows(window, true)
- WindowInsetsControllerCompat(
- window,
- window.decorView
- ).show(WindowInsetsCompat.Type.systemBars())
-}
\ No newline at end of file
diff --git a/manager/app/src/main/jniLibs/.gitignore b/manager/app/src/main/jniLibs/.gitignore
deleted file mode 100644
index 311f7299..00000000
--- a/manager/app/src/main/jniLibs/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-libksud.so
\ No newline at end of file
diff --git a/manager/app/src/main/jniLibs/arm64-v8a/libmagiskboot.so b/manager/app/src/main/jniLibs/arm64-v8a/libmagiskboot.so
deleted file mode 100644
index 451ca81c..00000000
Binary files a/manager/app/src/main/jniLibs/arm64-v8a/libmagiskboot.so and /dev/null differ
diff --git a/manager/app/src/main/res/drawable/ic_launcher_background.xml b/manager/app/src/main/res/drawable/ic_launcher_background.xml
deleted file mode 100644
index 900e2d8c..00000000
--- a/manager/app/src/main/res/drawable/ic_launcher_background.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/drawable/ic_launcher_foreground.xml b/manager/app/src/main/res/drawable/ic_launcher_foreground.xml
deleted file mode 100644
index c9ad0ad4..00000000
--- a/manager/app/src/main/res/drawable/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/drawable/ic_launcher_monochrome.xml b/manager/app/src/main/res/drawable/ic_launcher_monochrome.xml
deleted file mode 100644
index e4dc522e..00000000
--- a/manager/app/src/main/res/drawable/ic_launcher_monochrome.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/manager/app/src/main/res/mipmap-anydpi/ic_launcher.xml
deleted file mode 100644
index b070c763..00000000
--- a/manager/app/src/main/res/mipmap-anydpi/ic_launcher.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/mipmap-hdpi/ic_launcher.png b/manager/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 485b815d..00000000
Binary files a/manager/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/manager/app/src/main/res/mipmap-ldpi/ic_launcher.png b/manager/app/src/main/res/mipmap-ldpi/ic_launcher.png
deleted file mode 100644
index 5c18cc79..00000000
Binary files a/manager/app/src/main/res/mipmap-ldpi/ic_launcher.png and /dev/null differ
diff --git a/manager/app/src/main/res/mipmap-mdpi/ic_launcher.png b/manager/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 9df35253..00000000
Binary files a/manager/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/manager/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/manager/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index f8dc01c5..00000000
Binary files a/manager/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/manager/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/manager/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index ba22bf82..00000000
Binary files a/manager/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/manager/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/manager/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index cddff920..00000000
Binary files a/manager/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/manager/app/src/main/res/values-ar/strings.xml b/manager/app/src/main/res/values-ar/strings.xml
deleted file mode 100644
index c38c4fc8..00000000
--- a/manager/app/src/main/res/values-ar/strings.xml
+++ /dev/null
@@ -1,134 +0,0 @@
-
-
- الرئيسية
- غير مثبت
- إضغط للتثبيت
- يعمل
- الإصدار: %d
- مستخدمين الجذر: %d
- الإضافات: %d
- غير مدعوم
- KernelSU يدعم GKI kernels فقط
- إصدار النواة
- إصدار المدير
- البصمة
- وضع SELinux
- معطل
- مفروض
- متساهل
- مجهول
- مستخدم خارق
- فشل في تمكين الإضافة: %s
- فشل تعطيل الإضافة : %s
- لا توجد إضافات مثبتة
- الإضافات
- إلغاء التثبيت
- تثبيت الوحدة
- تثبيت
- إعادة تشغيل
- الإعدادات
- إعادة تشغيل سريعة
- إعادة تشغيل إلى وضع Recovery
- إعادة تشغيل إلى وضع Bootloader
- إعادة تشغيل إلى وضع Download
- إعادة تشغيل إلى وضع EDL
- من نحن
- هل أنت متأكد أنك تريد إلغاء تثبيت الإضافة %s ?
- تم إلغاء تثبيتها %s
- فشل إلغاء التثبيت: %s
- الإصدار
- المطور
- التراكبات غير متوفرة ، لا يمكن للإضافة أن تعمل!
- إنعاش
- إظهار تطبيقات النظام
- إخفاء تطبيقات النظام
- إرسال السجلات
- الوضع الآمن
- إعادة التشغيل لتطبيق التغييرات
- تم تعطيل الإضافات لأنها تتعارض مع Magisk!
- تعلم KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- تعرف على كيفية تثبيت KernelSU واستخدام الإضافات
- إدعمنا
- KernelSU سيظل دائماً مجانياً ومفتوح المصدر. مع ذلك، يمكنك أن تظهر لنا أنك تهتم بالتبرع.
- إنضم إلى قناتنا في %2$s ]]>
- القدرات
- تحديث
- تحميل الإضافة: %s
- ابدأ التنزيل: %s
- الإصدار الجديد: %s متاح ، انقر للتحديث
- تشغيل
- الإفتراضي
- نموذج
- موروث
- عالمي
- فردي
- مجموعات
- مُخصّص
- تركيب مساحة الاسم
- الغاء تحميل الإضافات
- فشل تحديث ملف تعريف التطبيق لـ %s
- سياق SELinux
- ايقاف إجباري
- الغاء تحميل الإضافات بشكل افتراضي
- القيمة الافتراضية العامة لـ\"إلغاء تحميل الإضافات\" في ملفات تعريف التطبيقات. إذا تم تمكينه، إزالة جميع تعديلات الإضافات على النظام للتطبيقات التي لا تحتوي على مجموعة ملف تعريف.
- سيسمح تمكين هذا الخيار لـKernelSU باستعادة أي ملفات معدلة بواسطة الإضافات لهذا التطبيق.
- المجال
- القواعد
- إعادة تشغيل التطبيق
- فشل تحديث قواعد SELinux لما يلي: %s
- اسم الملف الشخصي
- إصدار KernelSU الحالي %d منخفض جدًا بحيث لا يعمل المدير بشكل صحيح. الرجاء الترقية إلى الإصدار %d أو أعلى!
- سجل التغييرات
- تم الاستيراد بنجاح
- تصدير إلى الحافظة
- لا يمكن العثور على القالب المحلي للتصدير!
- معرف القالب موجود بالفعل!
- استيراد من الحافظة
- فشل في جلب سجل التغيير: %s
- الاسم
- معرف القالب غير صالح
- مزامنة القوالب عبر الإنترنت
- إنشاء قالب
- للقراءة فقط
- استيراد / تصدير
- فشل في حفظ القالب
- تحرير القالب
- المعرف
- قالب ملف تعريف التطبيق
- الوصف
- حفظ
- إدارة القالب المحلي وعبر الإنترنت لملف تعريف التطبيق
- حذف
- الحافظة فارغة!
- عرض القالب
- فشل في منح صلاحية الجذر!
- فتح
- التحقق تلقائيًا من وجود تحديثات عند فتح التطبيق
- التحقق من التحديث
- تمكين تصحيح أخطاء WebView
- يمكن استخدامه لتصحيح أخطاء WebUI، يرجى تمكينه فقط عند الحاجة.
- التالي
- اختيار ملف
- تثبيت مباشر (موصى به)
- التثبيت على فتحة غير نشطة (بعد OTA)
- سيتم **إجبار** جهازك على التمهيد إلى الفتحة غير النشطة الحالية بعد إعادة التشغيل!
-\nاستخدم هذا الخيار فقط بعد انتهاء التحديث.
-\nأستمرار؟
- اختر KMI
- يوصى باستخدام صورة القسم %1$s
- تصغير الصورة المتفرقة
- قم بتغيير حجم الصورة المتفرقة حيث توجد الإضافة إلى حجمها الفعلي. لاحظ أن هذا قد يتسبب في عمل الإضافة بشكل غير طبيعي، لذا يرجى استخدامها فقط عند الضرورة (مثل النسخ الاحتياطي)
- إلغاء التثبيت
- إلغاء التثبيت مؤقتًا
- إلغاء التثبيت بشكل دائم
- استعادة الصورة الاصلية
- إلغاء تثبيت KernelSU (الجذر وجميع الوحدات) بشكل كامل ودائم.
- تركيب
- نجح التركيب
- فشل التركيب
- صورة lkm المحددة: %s
- استعادة صورة المصنع المخزنة (في حالة وجود نسخة احتياطية)، والتي تُستخدم عادة قبل OTA؛ إذا كنت بحاجة إلى إلغاء تثبيت KernelSU، فيرجى استخدام \"إلغاء التثبيت الدائم\".
- قم بإلغاء تثبيت KernelSU مؤقتًا، واستعد إلى حالته الأصلية بعد إعادة التشغيل التالية.
- حفظ السجلات
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-az/strings.xml b/manager/app/src/main/res/values-az/strings.xml
deleted file mode 100644
index 21ec189f..00000000
--- a/manager/app/src/main/res/values-az/strings.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
- Ana səhifə
- Super istifadəçilər: %d
- Nüvə
- Yüklənmədi
- Yükləmək üçün toxunun
- İşləyir
- Versiya: %d
- Modullar: %d
- Hal-hazırda KernelSU yalnız GKI nüvələrini dəstəkləyir
- Dəstəklənmir
- Yüklə
- Yüklə
- Naməlum
- Barmaq izi
- Menecer versiyası
- Qeyri-aktiv
- SELinux vəziyyəti
- Sərbəst
- Məcburi
- Super istifadəçi
- Sil
- Modulu aktiv etmək mümkün olmadı: %s
- Modulu deaktiv etmək mümkün olmadı: %s
- Heç bir modul quraşdırılmayıb
- Modul
- Yenidən başlat
- Parametrlər
- Bərpa rejimində yenidən başlat
- Yüngül vəziyyətdə yenodən başlat
- Bootloader rejimində yenidən başlat
- Yükləmə rejimində yenidən başlat
- Versiya
- Sahib
- Modulu silmək istədiyinizdən əminsiniz %s\?
- Sistem proqramlarını göstər
- Haqqında
- EDL rejimində yenidən başlat
- Silmək mümkün olmadı: %s
- %s silindi
- Sistem proqramlarını gizlət
- overlayfs mövcud deyil,modul işləyə bilməyəcək!
- Log-u göndər
- Yenilə
- Təhlükəsiz rejimi
- Qüvvəyə minməsi üçün yenidən başlat
- Modular deaktiv edilir,çünki o Magisk-in modulları ilə toqquşur!
- KernelSU-yu öyrən
- https://kernelsu.org/guide/what-is-kernelsu.html
- Bizi dəstəkləyin
- KernelSU-yu necə quraşdırılacağını və modulların necə istifadə ediləcəyini öyrən
- Şablon
- Defolt
- Özəl
- KernelSU pulsuz və açıq mənbəlidir,həmişə belə olacaqdır. Bununla belə, ianə etməklə bizə qayğı göstərdiyinizi göstərə bilərsiniz.
- Mənbə kodlarımıza baxın %1$s
Kanalımıza %2$s qoşulun
- Profil adı
- Bacarıqlar
- Modulları umount et
- Miras qalmış
- Qlobal
- Bölmənin ad sahəsi
- Fərdi
- Qruplar
- Defolt olaraq modulları umount et
- SELinux konteksi
- %s görə tətbiq profillərini güncəlləmək mümkün olmadı
- Tətbiq Profillərində \"Umount modulları\" üçün qlobal standart dəyər. Aktivləşdirilərsə, o, Profil dəsti olmayan proqramlar üçün sistemdəki bütün modul dəyişikliklərini siləcək.
- Domen
- Qaydalar
- Güncəllə
- Endirməni başlat: %s
- Yeni versiya: %s əlçatandır, endirmək üçün toxunun
- Modul yüklənir: %s
- Bu seçimi aktivləşdirmək KernelSU-ya bu proqram üçün modullar tərəfindən hər hansı dəyişdirilmiş faylları bərpa etməyə imkan verəcək.
- Aç
- Məcburi dayandır
- Yenidən başlat
- %s görə SELinux qaydalarını güncəlləmək mümkün olmadı
- Girişləri Saxla
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-bn-rBD/strings.xml b/manager/app/src/main/res/values-bn-rBD/strings.xml
deleted file mode 100644
index 078d88fe..00000000
--- a/manager/app/src/main/res/values-bn-rBD/strings.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
- কর্নেল এস ইউ কেবল মাত্র জিকআই কর্নেল সাপোর্ট করে
- এসইলিনাক্স স্টেটাস
- আননোন
- মোডিউল ইনেবল করা যায়নি: %s
- ইন্সটল করটে চাপুন
- কাজ করছে
- মোডিউল: %d
- অমূলক
- কর্নেল
- ম্যানেজার ভারসন
- ফিঙ্গারপ্রিন্ট
- ডিসেবল
- এনফোর্সিং
- সুপার ইউজার
- মোডিউল
- আনইন্সটল
- ইন্সটল
- ইন্সটল
- রিবুট
- সেটিংস
- সফট রিবুট
- গ্লোবাল
- গ্রুপস
- এসইলিনাক্স কন্টেক্সট
- %s এর জন্য অ্যাপ প্রফাইল আপডেট করা যায়নি
- বাইডিফল্ট মোডিউল আনমাউন্ট
- হোম
- ইন্সটল হয়নী
- পারমিসিভ
- মোডিউল ডিসেবল করা যায়নি: %s
- কোনো মোডিউল ইন্সটল করা নেই
- সংস্করণ: %d
- সুপার ইউজার: %d
- নেইম স্পেস মাউন্ট
- ইনহেরিটেড
- ইন্ডিভিজুয়াল
- ক্যাপাবিলিটিস
- আনমাউন্ট মোডিউলস
- রিকভারিতে বুট
- বুটলোডারে বুট
- ডাউনলোড মডে বুট
- ইমারজেন্সি ডাউনলোড মডে বুট
- অ্যাবাউট
- %s মোডিউল আনইনস্টলের বেপারে নিশ্চিৎ\?
- %s আনইনস্টলড
- %s আনইনস্টল করা যায়নি
- ভার্সন
- অথার
- লগ সংরক্ষণ করুন
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-bn/strings.xml b/manager/app/src/main/res/values-bn/strings.xml
deleted file mode 100644
index 312672c8..00000000
--- a/manager/app/src/main/res/values-bn/strings.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
- হোম
- ইনস্টল করা হয়নি
- ইনস্টল করার জন্য ক্লিক করুন
- ওয়ার্কিং
- ওয়ার্কিং সংস্করণ: %d
- সুপার ইউজার: %d
- মডিউল: %d
- অসমর্থিত
- KernelSU শুধুমাত্র GKI কার্নেল সমর্থন করে
- কার্নেল
- ম্যানেজার সংস্করণ
- ফিঙ্গারপ্রিন্ট
- SELinux স্টেটাস
- ডিজেবল
- কার্যকর
- অনুমতিমূলক
- অজানা
- সুপার ইউজার
- মডিউল সক্ষম করতে ব্যর্থ হয়েছে: %s
- মডিউল নিষ্ক্রিয় করতে ব্যর্থ হয়েছে: %s
- কোন মডিউল ইনস্টল করা নেই
- মডিউল
- আনইন্সটল
- মডিউল ইনস্টল
- ইনস্টল
- রিবুট
- সেটিংস
- সফট রিবুট
- রিবুট রিকোভারি
- রিবুট বুটলোডার
- রিবুট ডাউনলোড
- রিবুট ইডিএল
- এবাউট
- মডিউল আনইনস্টল নিশ্চিত করুন %s?
- %s আনইনস্টল সফল
- আনইন্সটল ব্যর্থ: %s
- ভার্সন
- লেখক
- ওভারলেএফএস উপলব্ধ নয়, মডিউল কাজ করতে পারে না!
- রিফ্রেশ
- শো সিস্টেম অ্যাপস
- হাইড সিস্টেম অ্যাপস
- সেন্ড লগ
- সেইফ মোড
- রিবুট এপ্লাই
- মডিউলগুলি অক্ষম কারণ তারা ম্যাজিস্কের সাথে বিরোধিতা করে!
- লার্ন কার্নেলএসইউ
- https://kernelsu.org/guide/what-is-kernelsu.html
- কিভাবে কার্নেলএসইউ ইনস্টল করতে হয় এবং মডিউল ব্যবহার করতে হয় তা শিখুন
- সাপোর্ট টাইটেল
- কার্নেলএসইউ বিনামূল্যে এবং ওপেন সোর্স, এবং সবসময় থাকবে। আপনি সবসময় একটি অনুদান দিয়ে আপনার কৃতজ্ঞতা প্রদর্শন করতে পারেন.
- আমাদের %2$s চ্যানেল মার্জ করুন]]>
- প্রফাইলের নাম
- নেমস্পেস মাউন্ট
- গ্রুপস
- যোগ্যতা
- এসই লিনাক্স কনটেক্সট
- ডিফল্ট
- টেমপ্লেট
- কাস্টম
- গ্লোবাল
- আলাদাভাবে
- আনমাউন্ট মোডিউল
- ম্যানেজার সঠিকভাবে কাজ করার জন্য বর্তমান KernelSU সংস্করণ %d খুবই কম। অনুগ্রহ করে %d বা উচ্চতর সংস্করণে আপগ্রেড করুন!
- লগ সংরক্ষণ করুন
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-bs/strings.xml b/manager/app/src/main/res/values-bs/strings.xml
deleted file mode 100644
index da078631..00000000
--- a/manager/app/src/main/res/values-bs/strings.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
- Imenski prostor nosača
- Naslijeđen
- Globalan
- Pojedinačan
- Grupe
- Sposobnosti
- SELinux kontekst
- Umount module
- Ažuriranje Profila Aplikacije za %s nije uspjelo
- Trenutna KernelSU verzija %d je preniska da bi upravitelj ispravno radio. Molimo vas da nadogradite na verziju %d ili noviju!
- Umount module po zadanom
- Globalna zadana vrijednost za \"Umount module\" u Profilima Aplikacije. Ako je omogućeno, uklonit će sve izmjene modula na sistemu za aplikacije koje nemaju postavljen Profil.
- Uključivanjem ove opcije omogućit će KernelSU-u da vrati sve izmjenute datoteke od strane modula za ovu aplikaciju.
- Ažuriranje
- Skidanje module: %s
- Započnite sa skidanjem: %s
- Nova verzija: %s je dostupna, kliknite da skinete
- Pokrenite
- Prisilno Zaustavite
- Resetujte
- U Provođenju
- Početna
- Nije instalirano
- Kliknite da instalirate
- Superkorisnici: %d
- Module: %d
- Nepodržano
- KernelSU samo podržava GKI kernele sad
- Verzija Upravitelja
- Otisak prsta
- SELinux stanje
- Instalirajte
- Instalirajte
- Ponovo pokrenite
- Podešavanja
- Verzija
- Autor
- Osvježi
- Prikažite sistemske aplikacije
- Sakrijte sistemske aplikacije
- Sigurnosni mod
- Ponovo pokrenite da bi proradilo
- Module su isključene jer je u sukobu sa Magisk-om!
- https://kernelsu.org/guide/what-is-kernelsu.html
- Naučite kako da instalirate KernelSU i da koristite module
- Podržite Nas
- Pošaljite Izvještaj
- Naučite KernelSU
- Pogledajte izvornu kodu na %1$s
Pridružite nam se na %2$s kanalu
- Domena
- Pravila
- Neuspješno ažuriranje SELinux pravila za: %s
- Radi
- Verzija: %d
- Kernel
- Permisivno
- Deinstalirajte
- Nepoznato
- Nema instaliranih modula
- Superkorisnik
- Modula
- Ponovo pokrenite u Pogonski Učitavatelj
- Ponovo pokrenite u Oporavu
- %s deinstalirana
- Lagano Ponovo pokretanje
- Neuspješno uključivanje module: %s
- Ponovo pokrenite u Preuzimanje
- Neuspješno isključivanje module: %s
- Ponovo pokrenite u EDL
- Neuspješna deinstalacija: %s
- Isključeno
- O
- Jeste li sigurni da želite deinstalirati modulu %s\?
- overlayfs nije dostupan, modula ne može raditi!
- KernelSU je, i uvijek če biti, besplatan, i otvorenog izvora. Možete nam međutim pokazati da vas je briga s time da napravite donaciju.
- Zadano
- Šablon
- Prilagođeno
- Naziv profila
- Sačuvaj Dnevnike
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-da/strings.xml b/manager/app/src/main/res/values-da/strings.xml
deleted file mode 100644
index 6ab02256..00000000
--- a/manager/app/src/main/res/values-da/strings.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
- Arbejder
- Moduler: %d
- Ikke understøttet
- Kernel
- KernelSU understøtter kun GKI kernels
- Manager Version
- SELinux-status
- Deaktiveret
- Tilladende
- Superbruger
- Håndhævende
- Deaktivering af modul fejlede: %s
- Intet modul installeret
- Afinstaller
- Installer
- Installer
- Genstart
- Indstillinger
- Blød Genstart
- Genstart til Download
- Genstart til EDL
- Om
- Er du sikker på, at du vil afinstallere modulet %s\?
- %s afinstalleret
- Afinstallation af: %s fejlede
- overlayfs er ikke tilgængeligt, modulet kan ikke fungere!
- Opdater
- Send Log
- Sikker tilstand
- Genstart for at tage effekt
- Lær KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- Lær hvordan man installerer KernelSU og moduler
- Se source koden ved %1$s
Deltage i vores %2$s kanal
- Standard
- Skabelon
- Monter navnerum
- Arvet
- Global
- Grupper
- Evner
- SELinux-kontext
- Afmonteret moduler
- Afmontere moduler som standard
- Aktivering af denne indstilling vil tillade KernelSU at gendanne hvilken som helst modificeret filer af modulet for denne applikation.
- Opdatering
- Downloader modulet: %s
- Ny version: %s er tilgængelig, kilk for at downloade
- Start
- Tving Stop
- Opdatering af SELinux-regler for: %s fejlede
- Start download: %s
- Klik for at installere
- Version: %d
- Hjem
- Ikke installeret
- Superbrugere: %d
- Fingeraftryk
- Ukendt
- Aktivering af modul fejlede: %s
- Genstart til Recovery
- Modul
- Forfatter
- Genstart til Bootloader
- Version
- Gem system-apps
- Vis system-apps
- Moduler er deaktiveret, fordi der er konflikt med Magiskes!
- Støt Os
- KernelSU er, og vil altid være gratis og open source. Du kan stadig vise os din støtte ved at donere.
- Brugerdefineret
- Profilnavn
- Individuel
- Opdatering af App Profil for %s fejlede
- Den globale standard værdi for \"Afmonter moduler\" i App Profiler. Hvis aktiveret vil den fjerne alle modulers modifikationer til system applikationerne der ikke har en sat Profil.
- Domæne
- Regler
- Genstart
- Den nuværende KernelSU version %d er for lav til manageren for at fungere ordentligt. Opgrader til version %d eller højere!
- Gem Logfiler
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-de/strings.xml b/manager/app/src/main/res/values-de/strings.xml
deleted file mode 100644
index 04712346..00000000
--- a/manager/app/src/main/res/values-de/strings.xml
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
- Startseite
- Nicht installiert
- Permissiv
- Funktioniert
- Version: %d
- SuperUser
- Tippen zum Installieren
- Superuser: %d
- Unbekannt
- Erzwingen
- Neustart in Bootloader
- Neustart in Download-Modus
- Neustart mit EDL-Modus
- Autor
- overlayfs nicht verfügbar, Modul kann nicht funktionieren!
- Über
- Module sind deaktiviert, weil es einen Konflikt mit Magisk gibt!
- https://kernelsu.org/guide/what-is-kernelsu.html
- Erfahren, wie KernelSU installiert und Module verwendet werden
- Unterstütze uns
- KernelSU ist und wird immer frei und quelloffen sein. Du kannst uns jedoch deine Unterstützung zeigen, indem du eine Spende tätigst.
- SELinux-Kontext
- Module standardmäßig aushängen
- Globaler Standardwert für \'Module aushängen\' in App-Profilen. Falls aktiviert, werden alle Moduländerungen im System für alle Apps entfernt, für die kein Profil festgelegt ist.
- Standard
- Vorlage
- Benutzerdefiniert
- App-Profilaktualisierung für %s fehlgeschlagen
- Vererbt
- Global
- Individuell
- Domäne
- Aktualisieren
- Wenn du diese Option aktivierst, kann KernelSU alle von den Modulen für diese App geänderten Dateien wiederherstellen.
- Regeln
- Herunterladen startet: %s
- Fehler beim Aktualisieren der SELinux-Regeln für: %s
- Starten
- Neue Version: %s verfügbar, tippen zum Aktualisieren
- Stopp erzwingen
- Neustart
- Module: %d
- Manager-Version
- SELinux-Status
- Deaktiviert
- Modulaktivierung fehlgeschlagen: %s
- Moduldeaktivierung fehlgeschlagen: %s
- Keine Module installiert
- Modul
- Deinstallieren
- Installieren
- Neustarten
- Einstellungen
- Neustart in Recovery
- %s deinstalliert
- Version
- Neu laden
- System-Apps anzeigen
- System-Apps ausblenden
- Protokoll senden
- KernelSU verstehen
- Sicherer Modus
- Neustarten, damit Änderungen wirksam werden
- Quellcode unter %1$s ansehen
Unserem %2$s-Kanal beitreten
- Profilname
- Namespace einhängen
- Gruppen
- Fähigkeiten
- Module aushängen
- Modul herunterladen: %s
- Nicht unterstützt
- KernelSU unterstützt derzeit nur GKI-Kernel
- Kernel
- Fingerabdruck
- Installieren
- Soft-Reboot
- Sicher, dass du das Modul %s deinstallieren möchtest\?
- Deinstallation fehlgeschlagen: %s
- Die aktuelle Kernel-Version %d ist zu alt für diese Manager-Version. Bitte auf Version %d oder höher upgraden!
- Änderungsprotokoll
- Erfolgreich importiert
- In Zwischenablage exportieren
- Kann lokale Vorlage nicht finden!
- Vorlagen-ID existiert bereits!
- Aus Zwischenablage importieren
- Konnte Changelog nicht laden: %s
- Name
- Ungültige Vorlagen-ID
- Online-Vorlagen synchronisieren
- Vorlage erstellen
- Schreibgeschützt
- Import/Export
- Fehler beim Speichern
- Vorlage bearbeiten
- ID
- App-Profil-Template
- Beschreibung
- Speichern
- verwalte lokale und online Profil Vorlagen
- Löschen
- Zwischenablage ist leer!
- Vorlage ansehen
- WebView-Debugging aktivieren
- Kann verwendet werden zum Debugging von WebUI, bitte nur falls nötig aktivieren.
- %1$s Partitionsabbild empfohlen
- KMI auswählen
- Weiter
- Direkte Installation (empfohlen)
- Datei auswählen
- In inaktiven Slot installieren (nach OTA)
- Nach einem Neustart wird dein Gerät **GEZWUNGEN** in den derzeit inaktiven Slot zu booten.
-\nBenutze dies nur nach Fertigstellung des OTA.
-\nFortfahren?
- Root-Zugriff konnte nicht gewährt werden!
- Öffnen
- Updates suchen
- Automatisch nach Updates suchen beim Öffnen der App
- Protokolle Speichern
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-es/strings.xml b/manager/app/src/main/res/values-es/strings.xml
deleted file mode 100644
index 5623b47a..00000000
--- a/manager/app/src/main/res/values-es/strings.xml
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
- Inicio
- No instalado
- Toca para instalar
- Funcionando
- Versión: %d
- Superusuarios: %d
- Módulos: %d
- No soportado
- Por el momento, KernelSU solo es compatible con kernels genéricos (GKIs)
- Versión del kernel
- Versión del gestor
- Huella del dispositivo
- Estado de SELinux
-
- Desactivado
- Enforcing de SELinux
- Permisivo
- Desconocido
- Superusuario
- No se pudo habilitar el módulo \"%s\"
- No se pudo deshabilitar el módulo \"%s\"
- No hay ningún módulo instalado
- Módulo
- Desinstalar
- Instalar módulo
- Instalar
- Reiniciar
- Ajustes
- Reinicio minimo
- Reiniciar en modo de recuperación
- Reiniciar en modo de arranque
- Reiniciar en modo Download
- Reiniciar en modo EDL
- Acerca de
- ¿Estás seguro de que quieres desinstalar el módulo \"%s\"?
- \"%s\" esta desinstalado
- No se pudo desinstalar \"%s\"
- Versión
- Autor
- El módulo no puede funcionar ya que OverlayFS no está disponible!
- Recargar
- Mostrar applicaciones del sistema
- Ocultar applicaciones del sistema
- Enviar registro de informe
- Modo seguro
- Reinicia para aplicar cambios
- Se deshabilitaron los módulos ya que entran en conflicto con los de Magisk!
- Aprende KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- Descubre cómo instalar KernelSU y utilizar módulos
- Apóyanos
- KernelSU es y siempre será, libre y de código abierto. De todas formas, puedes mostrarnos tu apoyo mediante una donación.
- Mirar el código en %1$s
Únete a nuestro canal de %2$s
- Predeterminado
- Plantilla
- Personalizado
- Nombre de perfil
- Montaje del espacio de nombres
- Heredado
- Global
- Individual
- Grupos
- Capacidades
- Contexto de SELinux
- Desmontar módulos
- No se pudo actualizar el perfil de la applicación para %s
- Desmontar módulos por defecto
- El valor global predeterminado para \"Desmontar módulos\" en los perfiles de las aplicaciones. Si la habilitas, se desharán todas las modificaciones al sistema hechas por el módulo para las applicaciones que no tengan un perfil establecido.
- Si habilitas esta opción, KernelSU podrá restaurar cualquier archivo modificado por los módulos para esta app.
- Dominio
- Reglas
- Actualizar
- Descargando módulo: \"%s\"
- Iniciar descarga: %s
- Nueva versión: %s está disponible, toque para actualizar
- Abrir Aplicacion
- Forzar cierre de la aplicacion
- Reiniciar aplicacion
- Falló al actualizar reglas de SEpolicy por: %s
- La versión actual de KernelSU %d es demasiado baja para que el gestor funcione correctamente. ¡Por favor actualiza a la versión %d o superior!
- Registro de cambios
- Importado con exíto
- Exportar a portapapeles
- No se puede encontrar plantilla local para exportar!
- Ya existe un ID de la plantilla!
- Importar desde portapapeles
- Error en obtener los registros de cambios: %s
- Nombre
- ID de la plantilla es invalido
- Sincronizar plantillas en linea
- Crear plantilla
- sololectura
- Importar/Exportar
- Fallo en guardar plantilla
- Editar plantilla
- id
- Plantilla del perfil de la aplicacion
- Descripción
- Guardar
- Administrar las plantillas locales y de en linea del perfil de la aplicacion
- Eliminar
- El portapapeles esta vacio!
- Ver plantilla
- Guardar Registros
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-et/strings.xml b/manager/app/src/main/res/values-et/strings.xml
deleted file mode 100644
index d514fc6a..00000000
--- a/manager/app/src/main/res/values-et/strings.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-
-
- Töötamine
- Versioon: %d
- Mooduleid: %d
- Tuum
- Manageri versioon
- Sõrmejälg
- Lubav
- Mooduli lubamine ebaõnnestus: %s
- Mooduleid pole paigaldatud
- Taaskäivita
- Taaskäivita taastusesse
- Kas soovid kindlasti eemaldada mooduli %s?
- %s on eemaldatud
- Raporteeri logi
- Turvarežiim
- Muudatuste rakendamiseks taaskäivita
- Õpi KernelSUd
- https://kernelsu.org/guide/what-is-kernelsu.html
- Vaikimisi
- Haagi nimeruum
- Lahtihaagitud moodulid
- Rakenduseprofiili uuendamine %s jaoks ebaõnnestus
- Haagi moodulid vaikimisi lahti
- Allalaadimise alustamine: %s
- SELinux reeglite uuendamine ebaõnnestus: %s
- Muuda malli
- Rakenduseprofiili mall
- ID
- vaid lugemiseks
- malli ID juba eksisteerib!
- Ekspordi lõikelauale
- Sünkrooni võrgumallid
- Muudatuste logi hankimine ebaõnnestus: %s
- Kodu
- Klõpsa paigaldamiseks
- Pole paigaldatud
- Mittetoetatud
- Superkasutajaid: %d
- KernelSU toetab hetkel vaid GSI tuumasid
- SELinuxi olek
- Keelatud
- Jõustav
- Teadmata
- Superkasutaja
- Mooduli keelamine ebaõnnestus: %s
- Moodul
- Taaskäivita käivituslaadurisse
- Eemalda
- Paigalda
- Teave
- Paigalda
- Seaded
- Pehme taaskäivitus
- Taaskäivita allalaadimisrežiimi
- Taaskäivita EDL-i
- Värskenda
- Autor
- Eemaldamine ebaõnnestus: %s
- Versioon
- overlayfs pole saadaval, moodul ei saa töötada!
- Kuva süsteemirakendused
- Peida süsteemirakendused
- Moodulid on keelatud, kuna need lähevad konflikti Magiski omadega!
- Õpi KernelSUd paigaldama ja mooduleid kasutama
- Toeta meid
- Grupid
- KernelSU on, ja alati jääb, tasuta ning avatud lähtekoodiga kättesaadavaks. Sellegipoolest võid sa näidata, et hoolid, ning teha annetuse.
- Mall
- Vaata lähtekoodi %1$sis
Liitu meie %2$si kanaliga
- Profiili nimi
- Kohandatud
- Päritud
- Globaalne
- Individuaalne
- Võimekused
- Sobimatu malli ID
- SELinux kontekst
- Praegune KernelSU versioon %d on liiga madal, haldur ei saa konkreetselt toimida. Palun täienda versioonile %d või kõrgem!
- Domeen
- Käivita
- Sundpeata
- Reeglid
- Uuenda
- Mooduli allalaadimine: %s
- Uus versioon: %s on saadaval, klõpsa täiendamiseks
- Taaskäivita
- Muudatuste logi
- Nimi
- Kirjeldus
- Edukalt imporditud
- Salvesta
- Lõikelaud on tühi!
- Kustuta
- Vaata malli
- Impordi/ekspordi
- Impordi lõikelaualt
- Malli salvestamine ebaõnnestus
- Loo mall
- Halda kohalikke ja võrgusolevaid rakenduseprofiili malle
- Selle valiku lubamine lubab KernelSU-l taastada selle rakenduse moodulite poolt mistahes muudetud faile.
- Eksportimiseks kohalikku malli ei leitud!
- Globaalne vaikeväärtus \"Lahtihaagitud moodulitele\" rakenduseprofiilides. Lubamisel eemaldab see kõik moodulite süsteemimuudatused rakendustele, millel ei ole profiili määratud.
- Saab kasutada WebUI silumiseks, palun luba ainult vajadusel.
- Juurkasutaja andmine ebaõnnestus!
- Kontrolli uuendusi
- Rakenduse avamisel kontrolli automaatselt uuendusi
- Ava
- Luba WebView silumine
- Salvesta Logid
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-fa/strings.xml b/manager/app/src/main/res/values-fa/strings.xml
deleted file mode 100644
index a5cdb2f7..00000000
--- a/manager/app/src/main/res/values-fa/strings.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-
-خانه
-نصب نشده است
-برای نصب ضربه بزنید
-به درستی کار میکند
-نسخه: %d
-برنامه های با دسترسی روت: %d
-ماژولها: %d
-پشتیبانی نشده
-کرنل اس یو فقط هسته های gki را پشتیبانی میکند
- هسته
- نسخه برنامه
- اثرانگشت
- وضعیت SELinux
-غیرفعال
-قانونمند
-آزاد
-ناشناخته
-دسترسی روت
- فعال کردن ماژول ناموفق بود: %s
-غیرفعال کردن ماژول ناموفق بود: %s
-هیچ ماژولی نصب نشده است
-ماژول
-لغو نصب
-نصب
-نصب
-راه اندازی دوباره
-تنظیمات
-راه اندازی نرم
-راه اندازی به ریکاوری
-راه اندازی به بوتلودر
-راه اندازی به حالت دانلود
-راه اندازی به EDL
-درباره
- آیا مطمئنید که میخواهید ماژول %s را پاک کنید؟
-%s پاک شد
-پاک کردن ناموفق بود: %s
-نسخه
-سازنده
-overlayfs موجود نیست. مازول کار نمیکند!!
-تازهسازی
-نمایش برنامه های سیستمی
-مخفی کردن برنامه های سیستمی
-ارسال وقایع
-حالت امن
-راهاندازی مجدد برای تاثیرگذاری
-مازول به دلیل تعارض با مجیسک غیرفعال شده اند\'s!
-یادگیری کرنل اس یو
-https://kernelsu.org/guide/what-is-kernelsu.html
-یاد بگیرید چگونه از کرنل اس یو و ماژول ها استفاده کنید
-از ما حمایت کنید
-KernelSU رایگان است و همیشه خواهد بود و منبع باز است. با این حال، می توانید با اهدای کمک مالی به ما نشان دهید که برایتان مهم است.
-
-Join our %2$s channel ]]>
-
-پروفایل برنامه
-پیشفرض
-قالب
-شخصی سازی شده
-اسم پروفایل
-Mount namespace
-اثر گرفته
-گلوبال
-تکی
-جداکردن ماژول ها
- ذخیره گزارشها
-
diff --git a/manager/app/src/main/res/values-fil/strings.xml b/manager/app/src/main/res/values-fil/strings.xml
deleted file mode 100644
index fc527bf3..00000000
--- a/manager/app/src/main/res/values-fil/strings.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
- Katayuan ng SELinux
- Hindi pinagana
- Enforcing
- Permissive
- Hindi naka-install
- Home
- Pindutin para mag-install
- Gumagana
- Bersyon: %d
- Hindi matukoy
- Mga Modyul: %d
- Hindi Suportado
- Sinusuportahan lang ng KernelSU ang mga kernel ng GKI ngayon
- Nabigong paganahin ang modyul: %s
- Nabigong i-disable ang modyul: %s
- Walang naka-install na modyul
- Modyul
- I-install
- I-install
- I-reboot
- I-soft Reboot
- I-reboot sa Download
- I-reboot sa EDL
- Tungkol
- Sigurado ka bang gusto mong i-uninstall ang modyul %s\?
- Na-uninstall ang %s
- Nabigong i-uninstall: %s
- May-akda
- Ang overlayfs ay hindi magagamit, ang modyul ay hindi gagana!
- I-refresh
- Ipakita ang mga application ng system
- Magpadala ng Log
- I-reboot para umepekto
- Hindi pinagana ang mga modyul dahil salungat ito sa Magisk!
- Alamin ang KernelSU
- Matutunan kung paano mag-install ng KernelSU at gumamit ng mga modyul
- Suportahan Kami
- Ang KernelSU ay, at palaging magiging, libre, at open source. Gayunpaman, maaari mong ipakita sa amin na nagmamalasakit ka sa pamamagitan ng pagbibigay ng donasyon.
- Tingnan ang source code sa %1$s
Sumali sa aming %2$s channel
- I-mount ang namespace
- Indibidwal
- Mga Grupo
- Mga Kakayanan
- Konteksto ng SELinux
- I-unmount ang mga modyul
- Nabigong i-update ang App Profile para sa %s
- Ang kasalukuyang bersyon ng KernelSU %d ay masyadong mababa para gumana nang maayos ang manager. Mangyaring mag-upgrade sa bersyon %d o mas mataas!
- Ang pagpapagana sa opsyong ito ay magbibigay-daan sa KernelSU na ibalik ang anumang binagong file ng mga modyul para sa aplikasyon na ito.
- Mga Tuntunin
- Nagda-download ng modyul: %s
- Simulan ang pag-download: %s
- Bagong bersyon: Available ang %s, i-click upang i-download
- Ilunsad
- Pilit na I-hinto
- I-restart
- Nabigong i-update ang mga panuntunan ng SELinux para sa: %s
- Bersyon ng Manager
- Mga setting
- I-reboot sa Recovery
- I-reboot sa Bootloader
- Bersyon
- I-uninstall
- Itago ang mga application ng system
- Pangalan ng profile
- Minana
- Ang pangkalahatang default na halaga para sa \"Umount modules\" sa Mga Profile ng App. Kung pinagana, aalisin nito ang lahat ng mga pagbabago sa modyul sa system para sa mga aplikasyon na walang hanay ng Profile.
- I-save ang mga Log
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-fr/strings.xml b/manager/app/src/main/res/values-fr/strings.xml
deleted file mode 100644
index 01c0672b..00000000
--- a/manager/app/src/main/res/values-fr/strings.xml
+++ /dev/null
@@ -1,135 +0,0 @@
-
-
- Non installé
- Fonctionnel
- Version : %d
- Super-utilisateurs : %d
- Modules : %d
- Actuellement, KernelSU ne supporte que les noyaux GKI
- Noyau
- Empreinte digitale
- Mode SELinux
- Désactivé
- Permissive
- Inconnu
- Super-utilisateur
- Aucun module installé
- Accueil
- Appuyez ici pour installer
- Non supporté
- Échec de la désinstallation : %s
- Version
- Version du gestionnaire
- Enforcing
- Échec de l\'activation du module : %s
- Modules
- Désinstaller
- Installer
- Échec de la désactivation du module : %s
- Redémarrer
- Installer
- Paramètres
- Redémarrer en mode bootloader
- Redémarrage progressif
- Redémarrer en mode de récupération
- Redémarrer en mode EDL
- À propos
- %s a été désinstallé
- Redémarrer en mode de téléchargement
- Auteur
- Êtes-vous sûr(e) de vouloir désinstaller le module %s \?
- Découvrir KernelSU
- OverlayFS est indisponible, impossible de faire fonctionner les modules !
- Rafraîchir
- Afficher les applications système
- Masquer les applications système
- Mode sans échec
- Rapport de journal
- Redémarrez pour appliquer les modifications
- Les modules sont désactivés car ils sont en conflit avec ceux de Magisk !
- https://kernelsu.org/guide/what-is-kernelsu.html
- Soutenez-nous
- Découvrez comment installer KernelSU et utiliser les modules
- KernelSU est, et restera toujours, gratuit et open source. Vous pouvez cependant nous témoigner de votre soutien en nous faisant un don.
- Voir le code source sur %1$s
-\nRejoindre notre canal %2$s
- Modèle
- Par défaut
- Personnalisé
- Nom du profil
- Espace de noms de montage
- Hérité
- Individuel
- Contexte SELinux
- Global
- Groupes
- Capacités
- Démonter les modules
- Échec de la modification du profil d\'application de %s
- L\'activation de cette option permettra à KernelSU de restaurer tous les fichiers modifiés par les modules de cette application.
- Démonter les modules par défaut
- Valeur globale par défaut pour l\'option « Démonter les modules » dans les profils d\'application. Lorsqu\'elle est activée, les modifications apportées au système par les modules seront supprimées pour les applications qui n\'ont pas de profil défini.
- Domaine
- Règles
- Mettre à jour
- Téléchargement du module : %s
- Lancer
- La version %s est disponible, appuyez ici pour mettre à jour
- Début du téléchargement de : %s
- Forcer l\'arrêt
- Relancer l\'application
- Échec de la mise à jour des règles SELinux pour : %s
- La version actuelle de KernelSU (%d) est trop ancienne pour que le gestionnaire fonctionne correctement. Veuillez passer à la version %d ou à une version supérieure !
- Importation réussie
- Exporter vers le presse-papiers
- Impossible de trouver un modèle local à exporter !
- L\'id du modèle existe déjà !
- Journal des modifications
- Importer à partir du presse-papiers
- Échec de récupération du journal des modifications : %s
- Nom
- id de modèle invalide
- Synchroniser les modèles en ligne
- Créer un modèle
- lecture seule
- Importer/exporter
- Échec de l\'enregistrement du modèle
- Modifier le modèle
- id
- Modèles de profils d\'application
- Description
- Enregistrer
- Gérer les modèles de profils d\'application locaux et en ligne
- Supprimer
- Le presse-papiers est vide !
- Voir le modèle
- Vérifier automatiquement les mises à jour à l\'ouverture de l\'application
- Vérifier les mises à jour
- Activer le débogage de WebView
- Peut être utilisé pour déboguer WebUI, n\'activez cette option que si nécessaire.
- Échec de l\'octroi des privilèges root !
- Ouvrir
- Installation directe (recommandé)
- Sélectionner un fichier
- Installer dans l\'emplacement inactif (après OTA)
- Votre appareil sera **FORCÉ** à démarrer sur l\'emplacement inactif actuel après un redémarrage !
-\nN\'utilisez cette option qu\'une fois la mise à jour OTA terminée.
-\nContinuer ?
- Suivant
- L\'image de la partition %1$s est recommandée
- Sélectionner une KMI
- Minimiser l\'image clairsemée
- Redimensionne l\'image clairsemée où se trouve le module à sa taille réelle. Notez que cela peut entraîner un dysfonctionnement du module, alors utilisez cette fonctionnalité uniquement lorsque nécessaire (pour la sauvegarde, par exemple)
- Désinstaller
- Désinstaller temporairement
- Désinstaller définitivement
- Restaurer l\'image stock
- Restaurer l\'image stock d\'usine (s\'il en existe une sauvegarde), option généralement utilisée avant une mise à jour OTA ; si vous avez besoin de désinstaller KernelSU, utilisez plutôt l\'option « Désinstaller définitivement ».
- Flash en cours
- Flash réussi
- Échec du flash
- lkm sélectionné : %s
- Désinstallation complète et permanente de KernelSU (root et tous les modules).
- Désinstaller KernelSU temporairement et rétablir l\'état original au redémarrage suivant.
- Enregistrer les Journaux
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-hi/strings.xml b/manager/app/src/main/res/values-hi/strings.xml
deleted file mode 100644
index f9304469..00000000
--- a/manager/app/src/main/res/values-hi/strings.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
- प्रभाव में होने के लिए रीबूट करें
- जानें कि KernelSU कैसे स्थापित करें और मॉड्यूल का उपयोग कैसे करें
- अज्ञात
- सिस्टम एप्प दिखाए
- %s अनइंस्टॉल सफल हुआ
- मॉड्यूल्स अनमाउंट करें
- लॉग भेजे
- डिसेबल्ड (बंद)
- हमें प्रोत्साहन दें
- Inherited
- मॉड्यूल बंद कर दिए गए हैं क्योंकि यह मैजिक के साथ टकरा रहे है!
- क्या बदलाव हुए है
- पर्मिसिव
- डाउनलोड में रिबूट करें
- डिफ़ॉल्ट रूप से मॉड्यूल अनमाउन्ट करें
- इस विकल्प को चालू करने से KernelSU को इस एप्लिकेशन के लिए मॉड्यूल द्वारा किसी भी मोडिफाइड फ़ाइल को रिस्टोर करें।
- Individual
- %s मॉड्यूल चालू करने में विफल
- जबर्दस्ती बंद करें
- EDL मोड में रिबूट करें
- फिर से चालू करें
- क्षमताएं
- सुपरयूजर : %d
- %s की डाउनलोडिंग स्टार्ट करें
- Global
- ऐप प्रोफाइल में \"अनमाउंट मॉड्यूल\" के लिए ग्लोबल डिफ़ॉल्ट वैल्यू। यदि चालू किया गया है, तो यह एप्लीकेशंस के लिऐ सिस्टम के सभी मॉड्यूल मोडिफिकेशन को हटा देगा जिनकी प्रोफ़ाइल सेट नहीं है।
- मॉड्यूल्स : %d
- एनफोर्सिंग
- SELinux context
- फिंगरप्रिंट
- डिफॉल्ट
- लॉन्च करें
- सेफ मोड
- मैनेजर के ठीक से काम करने के लिए वर्तमान KernelSU वर्जन %d बहुत कम है। कृपया वर्जन %d या उच्चतर में अपग्रेड करें!
- रिकवरी में रिबूट करें
- सॉफ्ट रिबूट
- प्रोफाइल का नाम
- KernelSU मुफ़्त और ओपन सोर्स और हमेशा रहेगा। हालाँकि आप दान देकर हमें दिखा सकते हैं कि आप संरक्षण करते हैं।
- अनइंस्टॉल करें
- Namspace माउंट करें
- इंस्टाल करें
- इंस्टाल करने के लिए क्लिक करें
- नियम
- समूह
- Overlayfs उपलब्ध नहीं है, मॉड्यूल काम नहीं कर सकता !
- मॉड्यूल
- निर्माता
- हमारे बारे में
- वर्जन: %d
- रीबूट करें
- KernelSU अभी केवल GKI कर्नल्स को सपोर्ट करता है
- SELinux स्थिति
- सिस्टम एप्प छिपाए
- वर्जन
- सपोर्ट नहीं करता है
- डोमेन
- होम
- कस्टम
- टेम्पलेट
- रिफ्रेश
- %s मॉड्यूल डाउनलोड हो रहा है
- अपडेट
- KernelSU सीखें
- क्या आप सच में मॉड्यूल %s को अनइंस्टॉल करना चाहते हैं\?
- %s अनइंस्टल करने में असफल
- सुपरयूजर
- सेटिंग
- काम कर रहा है
- %s मॉड्यूल बंद करने में विफल
- कोई मॉड्यूल इंस्टाल नहीं हुआ
- इंस्टाल करें
- कर्नल
- इंस्टाल नहीं हुआ
- %s के लिए ऐप प्रोफ़ाइल अपडेट करने में विफल
- https://kernelsu.org/guide/what-is-kernelsu.html
- %s के लिए SELinux नियमों को अपटेड करने में विफल
- बुटलोडर में रिबूट करें
- %1$s पर स्रोत कोड देखें
हमारे %2$s चैनल से जुड़ें
- मैनेजर वर्जन
- नया वर्जन: %s उपलब्ध है,अपग्रेड के लिए क्लिक करें
- लॉग सहेजें
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-hr/strings.xml b/manager/app/src/main/res/values-hr/strings.xml
deleted file mode 100644
index 9fb1e4c6..00000000
--- a/manager/app/src/main/res/values-hr/strings.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
- Prikažite sistemske aplikacije
- Sakrijte sistemske aplikacije
- Pošaljite Izvještaj
- Sigurnosni mod
- Ponovno pokrenite da bi proradilo
- Neuspješno ažuriranje SELinux pravila za: %s
- Početna
- Nije instalirano
- Verzija: %d
- Kliknite da instalirate
- Radi
- Superkorisnici: %d
- Module: %d
- Nepodržano
- KernelSU samo podržava GKI kernele sad
- Kernel
- Verzija Voditelja
- Otisak prsta
- Isključeno
- U Provođenju
- Permisivno
- SELinux stanje
- Nepoznato
- Superkorisnik
- Neuspješno uključivanje module: %s
- Neuspješno isključivanje module: %s
- Nema instaliranih modula
- Modula
- Deinstalirajte
- Instalirajte
- Instalirajte
- Ponovno pokrenite
- Postavke
- Lagano Ponovno pokretanje
- Ponovno pokrenite u Oporavu
- Ponovno pokrenite u Pogonski Učitavalac
- Ponovno pokrenite u Preuzimanje
- Ponovo pokrenite u EDL
- O
- Jeste li sigurni da želite deinstalirati modulu %s\?
- %s deinstalirana
- Neuspješna deinstalacija: %s
- Verzija
- Autor
- Osvježi
- overlayfs nije dostupan, modula ne može raditi!
- Module su isključene jer je u sukobu sa Magisk-om!
- Naučite KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- Naučite kako da instalirate KernelSU i da koristite module
- Podržite Nas
- KernelSU je, i uvijek če biti, besplatan, i otvorenog izvora. Možete nam međutim pokazati da vas je briga s time da napravite donaciju.
- Pogledajte izvornu kodu na %1$s
Pridružite nam se na %2$s kanalu
- Zadano
- Šablon
- Prilagođeno
- Naziv profila
- Naslijeđen
- Imenski prostor nosača
- Ažuriranje Profila Aplikacije za %s nije uspjelo
- Globalan
- Pojedinačan
- Umount module
- Grupe
- Sposobnosti
- SELinux kontekst
- Trenutna KernelSU verzija %d je preniska da bi voditelj ispravno radio. Molimo vas da nadogradite na verziju %d ili noviju!
- Umount module po zadanom
- Globalna zadana vrijednost za \"Umount module\" u Profilima Aplikacije. Ako je omogućeno, uklonit će sve izmjene modula na sistemu za aplikacije koje nemaju postavljen Profil.
- Domena
- Uključivanjem ove opcije omogućit će KernelSU-u da vrati sve izmjenute datoteke od strane modula za ovu aplikaciju.
- Pravila
- Ažuriranje
- Preuzimanje module: %s
- Započnite sa preuzimanjem: %s
- Nova verzija: %s je dostupna, kliknite da preuzmete
- Pokrenite
- Prisilno Zaustavite
- Resetujte
- Spremi Zapise
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-hu/strings.xml b/manager/app/src/main/res/values-hu/strings.xml
deleted file mode 100644
index 2b52317c..00000000
--- a/manager/app/src/main/res/values-hu/strings.xml
+++ /dev/null
@@ -1,106 +0,0 @@
-
-
- Működik
- Verzió: %d
- Modulok: %d
- KernelSU csak GKI kerneleket támogat jelenleg
- Kernel
- App verziója
- Build Fingerprint
- Kikapcsolt
- Újraindítás letöltő módba
- Újraindítás EDL-be
- Névjegy
- Biztos vagy benne hogy eltávolítod a következő modult: %s\?
- Nem sikerült eltávolítani: %s
- Készítő
- Overlayfs nem elérhető, a modul nem tud enélkül működni!
- Újratöltés
- Mutasd a rendszer alkalmazásokat
- Rejtsd el a rendszer alkalmazásokat
- Biztonságos mód
- A modul letiltva mert ütközik a Magisk verziójával!
- Tudj meg többet a KernelSU-ról
- Tudd meg hogyan telepítsd a KernelSU-t és használd moduljait
- Támogass minket
- Tekintsd meg a forráskódot a %1$s-n
Csatlakozz a %2$s csatornánkhoz
- Alapértelmezett
- Sablon
- Egyedi
- Profil neve
- Mountold a névteret
- Örökölt
- https://kernelsu.org/guide/what-is-kernelsu.html
- Különálló
- Csoportok
- Jogosultságok
- SElinux kontextus
- Umountold a modulokat alpértelmezés szerint
- Ennek az opciónak az engedélyezése lehetővé teszi, hogy a KernelSU visszaállítsa az alkalmazás moduljai által módosított fájlokat.
- Tartomány
- Szabályok
- Frissítés
- A %s modul letöltése folyamatban
- Indítsd el a letöltést: %s
- Indítás
- Kényszerített leállítás
- újraindítás
- Kezdőlap
- Nincs telepítve
- Kattints a telepítéshez
- Engedélyezett alkalmazások: %d
- Nem támogatott
- SELinux státusz
- Érvényesítés
- Megengedő
- Ismeretlen
- Super user
- Nem sikerült engedélyezni a következő modult: %s
- Nem sikerült letiltani a következő modulokat: %s
- Nincs modul telepítve
- Modulok
- Eltávolítás
- Telepítés
- Telepítés
- Újraindítás
- Beállítások
- Android felület újraindítása
- Újraindítás recovery-módba
- Újraindítás bootloader-módba
- %s törölve
- Verzió
- Napló küldése
- Indítsd újra a készüléket hogy érvényesítsd a változást
- A KernelSU ingyenes és nyílt forráskódú és mindig is az lesz. Te viszont meg tudod mutatni azt, hogy törődsz ennek a projektnek a sorsával egy adomány formájában.
- Globális
- Unmountold a modulokat
- Nem sikerült frissíteni az App Profilt ehhez %s
- A „Modulok csatlakoztatása” globális alapértelmezett értéke az alkalmazásprofilokban. Ha engedélyezve van, eltávolítja a rendszer összes modul-módosítását azoknál az alkalmazásoknál, amelyeknek nincs beállított profilja.
- Új verzió: %s elérhető, kattints a frissítéshez
- Nem sikerült frissíteni a SELinux szabályait a következőhöz: %s
- A jelenlegi KernelSU verzió %d túlságosan elavult. Kérlek frissíts a %d verzióra vagy újabbra!
- Sikeresen importálva
- Exportálás a vágólapból
- A helyi sablon nem található az exportáláshoz!
- A sablon ID már létezik!
- Változások
- Importálás a vágólapból
- A változásnapló lekérése nem sikerült: %s
- Név
- Hibás sablon ID
- Online sablonok szinkronizálása
- Sablon készítése
- csak olvasható
- Import/Export
- A sablon mentése sikertelen
- Sablon szerkesztése
- id
- Alkalmazásprofil sablon
- Leírás
- Mentés
- Az alkalmazásprofil helyi és online sablon kezelése
- Törlés
- A vágólap üres!
- Sablon megnézése
- Naplók Mentése
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-in/strings.xml b/manager/app/src/main/res/values-in/strings.xml
deleted file mode 100644
index 98698f52..00000000
--- a/manager/app/src/main/res/values-in/strings.xml
+++ /dev/null
@@ -1,135 +0,0 @@
-
-
- Beranda
- Tidak terinstal
- Klik untuk menginstal
- Berfungsi
- Versi: %d
- SuperUser: %d
- Modul: %d
- Tidak didukung
- KernelSU saat ini hanya mendukung kernel GKI
- Kernel
- Versi Manager
- Identitas
- Status SELinux
- Nonaktif
- Enforcing
- Permissive
- Unknown
- SuperUser
- Gagal mengaktifkan modul: %s
- Gagal menonaktifkan modul: %s
- Tidak ada modul
- Modul
- Hapus
- Instal
- Instal
- Reboot
- Pengaturan
- SoftReboot
- But ke Recovery
- But ke Bootloader
- But ke Download
- But ke EDL
- Tentang
- Yakin menghapus modul %s?
- %s berhasil dihapus
- Gagal menghapus: %s
- Versi
- Oleh
- OverlayFS tidak tersedia, modul tidak berfungsi!
- Muat ulang
- Tampilkan aplikasi sistem
- Sembunyikan aplikasi sistem
- Laporkan Log
- Mode aman
- Reboot agar berfungsi
- Konflik dengan Magisk, fungsi modul ditiadakan!
- Pelajari KernelSU
- https://kernelsu.org/id_ID/guide/what-is-kernelsu.html
- Pelajari cara instal KernelSU dan menggunakan modul
- Dukung Kami
- KernelSU akan selalu menjadi aplikasi gratis dan terbuka. Anda dapat memberikan donasi sebagai bentuk dukungan.
- Lihat kode sumber di %1$s
Gabung kanal %2$s kami
- Profil Apl
- Bawaan
- Templat
- Khusus
- Nama profil
- Mount Namespace
- Diwariskan
- Universal
- Individual
- Kelompok
- Kemampuan
- Konteks SELinux
- Umount Modul
- Gagal membarui Profil pada %s
- Melepas Modul secara bawaan
- Menggunakan \"Umount Modul\" secara universal pada Profil aplikasi. Jika diaktifkan, akan menghapus semua modifikasi sistem untuk aplikasi yang tidak memiliki set Profil.
- Aktifkan opsi ini agar KernelSU dapat memulihkan kembali berkas termodifikasi oleh modul pada aplikasi ini.
- Domain
- Aturan
- Membarui
- Mengunduh modul: %s
- Mulai mengunduh: %s
- Tersedia versi terbaru: %s, Klik untuk membarui
- Jalankan
- Paksa Berhenti
- Mulai ulang
- Gagal membarui aturan SELinux pada: %s
- Versi KernelSU %d terlalu rendah agar manajer berfungsi normal. Harap membarui ke versi %d atau di atasnya!
- Catatan Perubahan
- Berhasil diimpor
- Ekspor ke papan klip
- Tidak ditemukan templat lokal untuk diekspor!
- Id templat sudah ada!
- Impor dari papan klip
- Gagal mengambil Changelog: %s
- Nama
- Id templat tidak valid
- Sinkronkan templat daring
- Buat Templat
- Impor/Ekspor
- Gagal menyimpan templat
- Edit Templat
- id
- Templat Profil Aplikasi
- Deskripsi
- Simpan
- Atur templat Profil yang lokal dan daring
- Hapus
- Papan klip kosong!
- Lihat Templat
- ReadOnly
- Pengawakutuan WebView
- Dapat mengawakutu WebView, hanya aktifkan jika butuh.
- %1$s image partisi terekomendasi
- Pilih KMI
- Selanjutnya
- Gawai akan **DIPAKSA** untuk but ke slot nonaktif!
-\nHANYA gunakan setelah proses OTA selesai.
-\nLanjutkan?
- Instal Langsung (rekomendasi)
- Pilih berkas
- Instal ke slot nonaktif (setelah OTA)
- Gagal memberikan akses root!
- Buka
- Cek terbaru
- Cek terbaru setiap membuka aplikasi
- Meminimalkan sparse image
- Mengembalikan sparse image, lokasi modul disimpan, ke ukuran sebenarnya. Dapat menyebabkan modul bekerja abnormal, maka gunakan saat dibutuhkan saja (mis. untuk pencadangan)
- Hapus permanen KernelSU (root dan modul).
- Hapus Temporer
- Pulihkan Image Asal
- Hapus
- Hapus Temporer KernelSU, pulihkan ke kondisi asali setelah but berikutnya.
- Hapus Permanen
- Pulihkan image bawaan ROM (jika cadangan tersedia), umumnya dilakukan sebelum OTA; jika ingin menghapus KernelSU, gunakan fungsi \"Hapus Permanen\".
- Pemasangan Berhasil
- LKM dipilih: %s
- Pasang
- Pemasangan Gagal
- Simpan Log
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-it/strings.xml b/manager/app/src/main/res/values-it/strings.xml
deleted file mode 100644
index 7bd3f924..00000000
--- a/manager/app/src/main/res/values-it/strings.xml
+++ /dev/null
@@ -1,134 +0,0 @@
-
-
- Home
- Non installato
- Clicca per installare
- In esecuzione
- Versione: %d
- Applicazioni con accesso root: %d
- Moduli installati: %d
- Non supportato
- KernelSU ora supporta solo i kernel GKI
- Kernel
- Versione del manager
- Impronta della build di Android
- Stato di SELinux
- Disabilitato
- Enforcing
- Permissive
- Sconosciuto
- Accesso root
- Impossibile abilitare il modulo: %s
- Impossibile disabilitare il modulo: %s
- Nessun modulo installato
- Modulo
- Disinstalla
- Installa
- Installa
- Riavvia
- Impostazioni
- Riavvio rapido
- Riavvia in modalità Recovery
- Riavvia in modalità Bootloader
- Riavvia in modalità Download
- Riavvia in modalità EDL
- Informazioni
- Sei sicuro di voler disinstallare il modulo %s?
- %s disinstallato
- Impossibile disinstallare: %s
- Versione
- Autore
- overlayfs non è disponibile, i moduli non possono funzionare!
- Ricarica
- Mostra app di sistema
- Nascondi app di sistema
- Invia log
- Modalità provvisoria
- Riavvia per applicare la modifica
- I moduli sono disabilitati perché in conflitto con quelli di Magisk!
- Scopri KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- Scopri come installare KernelSU e utilizzare i moduli
- Supportaci
- KernelSU è, e sempre sarà, gratuito e open source. Puoi comunque mostrarci il tuo apprezzamento facendo una donazione.
- Unisciti al nostro canale %2$s]]>
- Nome profilo
- Spazio dei nomi del mount
- Globale
- Gruppi
- Ereditato
- Individuale
- Predefinito
- Personalizzato
- Modello
- Scollega moduli
- Contesto SELinux
- Aggiornamento App Profile per %s fallito
- Aggiorna
- Apri
- Capacità
- Scollega moduli da default
- Regole
- Sto scaricando il modulo: %s
- Inizia a scaricare:%s
- Nuova versione: %s disponibile, tocca per aggiornare
- Arresto forzato
- Riavvia
- Aggiornamento regole SELinux per %s fallito
- Attivando questa opzione permetterai a KernelSU di ripristinare ogni file modificato dai moduli per questa app.
- Dominio
- Il valore predefinito per \"Scollega moduli\" in App Profile. Se attivato, rimuoverà tutte le modifiche al sistema da parte dei moduli per le applicazioni che non hanno un profilo impostato.
- La versione attualmente installata di KernelSU (%d) è troppo vecchia ed il gestore non può funzionare correttamente. Si prega di aggiornare alla versione %d o successiva!
- Registro aggiornamenti
- Crea modello
- Modifica modello
- identificativo
- Identificativo modello non valido
- Nome
- Visualizza modello
- Sola lettura
- L\'identificativo del modello esiste già!
- Importa/Esporta
- Importa dagli appunti
- Esporta negli appunti
- Impossibile trovare modello locale da esportare!
- Importato con successo
- Sincronizza i modelli remoti
- Gli appunti sono vuoti!
- Impossibile ottenere l\'accesso root!
- Modelli App Profile
- Gestisci i modelli locali e remoti di App Profile
- Elimina
- Descrizione
- Salva
- Impossibile salvare il modello
- Apri
- Impossibile reperire il changelog: %s
- Controlla aggiornamenti
- Controlla automaticamente la disponibilità di aggiornamenti all\'apertura dell\'applicazione
- Abilita il Debug di WebView
- Può essere usato per svolgere il debug di WebUI, è consigliato attivarlo solo quando necessario.
- È consigliato usare immagine della partizione %1$s
- Scegli il KMI
- Avanti
- Installazione diretta (Raccomandata)
- Scegli un File
- Installa nello Slot Inattivo (Dopo OTA)
- Il tuo dispositivo sarà **FORZATO** ad avviarsi nello slot inattivo dopo il riavvio!
-\nUsa questa opzione solo quando l\'applicazione dell\'aggiornamento OTA è terminata.
-\nProcedere?
- Riduci la dimensione dell\'immagine moduli sparse al minimo
- Riduci la dimensione dell\'immagine sparse dei moduli alla sua reale dimenzione. Nota che questo potrebbe causare malfunzionamenti dei moduli quindi utilizzala solo quando necessario (ad esempio in caso di backup)
- Disinstalla
- Disinstalla Temporaneamente
- Disinstalla Permanentemente
- Ripristina immagine originale del produttore
- Disinstalla temporaneamente KernelSU, ripristina lo stato originale dopo il prossimo riavvio.
- Disinstalla KernelSU (Root e tutti i moduli) completamente e permanentemente.
- Installazione
- Installazione completata
- Installazione fallita
- LKM selezionato: %s
- Ripristina l\'immagine di fabbrica del produttore (se il backup è presente), solitamente usato prima di applicare l\'OTA; se devi disinstallare KernelSU, utilizza invece \"Disinstalla Permanentemente\".
- Salva Registri
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-iw/strings.xml b/manager/app/src/main/res/values-iw/strings.xml
deleted file mode 100644
index 18cfc638..00000000
--- a/manager/app/src/main/res/values-iw/strings.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
- הפעל מחדש כדי להכניס לתוקף
- למד כיצד להתקין את KernelSU ולהשתמש במודולים
- לא ידוע
- הצג אפליקציות מערכת
- %s הוסר
- הסרת טעינת מודולים
- שלח לוג
- מושבת
- תמכו בנו
- ירושה
- מודולים מושבתים מכיוון שהם מתנגשים עם זה של Magisk!
- יומן שינויים
- התרים
- הפעלה מחדש למצב הורדה
- טעינת מודולים כברירת מחדל
- הפעלת אפשרות זו תאפשר ל-KernelSU לשחזר קבצים שהשתנו על ידי המודולים עבור יישום זה.
- אישי
- הפעלת המודל נכשלה: %s
- עצירה בכח
- הפעלה מחדש למצב EDL
- איתחול
- יכולת
- משתמשי על: %d
- מפעיל מודל: %s
- גלובלי
- ערך ברירת המחדל הגלובלי עבור \"טעינת מודולים\" בפרופילי אפליקציה. אם מופעל, זה יסיר את כל שינויי המודול למערכת עבור יישומים שאין להם ערכת פרופיל.
- מודלים:%d
- אכיפה
- הקשר SELinux
- טביעת אצבע
- ברירת מחדל
- להשיק
- מצב בטוח
- גרסת KernelSU הנוכחית %d נמוכה מדי כדי שהמנהל יפעל כראוי. אנא שדרג לגרסה %d ומעלה!
- הפעלה מחדש לריקברי
- רך Reboot
- שם פרופיל
- KernelSU הוא, ותמיד יהיה, חינמי וקוד פתוח. עם זאת, תוכל להראות לנו שאכפת לך על ידי תרומה.
- הסרה
- טעינת מרחב שמות
- התקנה
- לחץ להתקנה
- כללים
- קבוצה
- שכבות-על לא זמינות, המודול לא יכול לעבוד!
- מודולים
- יוצר
- אודות
- גרסה: %d
- הפעלה מחדש
- KernelSU תומך רק בליבת GKI כעת
- סטטוס SELinux
- הסתר אפליקציות מערכת
- גרסה
- אינו נתמך
- תחום
- בית
- מותאם אישית
- תבנית
- רענון
- מוריד מודל: %s
- עדכון
- למד אודות KernelSU
- האם אתה בטוח שברצונך להסיר את התקנת המודל %s\?
- הסרת התקנת %s נכשלה:
- משתמש על
- הגדרות
- עובד
- השבתת מודל %s נכשלה:
- אין מודלים מותקנים
- להתקין
- Kernel
- לא מותקן
- נכשל עדכון פרופיל האפליקציה עבור %s
- https://kernelsu.org/guide/what-is-kernelsu.html
- נכשל עדכון כללי SELinux עבור: %s
- הפעלה מחדש לבוטלאודר
- ראה את קוד המקור ב%1$s
הצטרף אלינו %2$s בערוץ
- גרסת מנהל
- גרסה חדשה עבור: %s זמינה, לחץ כדי לשדרג
- שמור יומנים
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-ja/strings.xml b/manager/app/src/main/res/values-ja/strings.xml
deleted file mode 100644
index 4ecf7420..00000000
--- a/manager/app/src/main/res/values-ja/strings.xml
+++ /dev/null
@@ -1,135 +0,0 @@
-
-
- ホーム
- 未インストール
- タップでインストール
- 動作中
- バージョン: %d
- スーパーユーザー: %d
- モジュール: %d
- 非対応
- 現在、 KernelSU は GKI カーネルにのみ対応しています
- カーネル
- アプリのバージョン
- Fingerprint
- SELinux の状態
- Disabled
- Enforcing
- Permissive
- 不明
- スーパーユーザー
- モジュールの有効化に失敗: %s
- モジュールの無効化に失敗: %s
- モジュールをインストールしていません
- モジュール
- アンインストール
- インストール
- インストール
- 再起動
- 設定
- 通常の再起動
- リカバリーへ再起動
- ブートローダー へ再起動
- ダウンロードモードへ再起動
- EDL へ再起動
- アプリについて
- モジュール %s をアンインストールしますか?
- %s はアンインストールされました
- アンインストールに失敗: %s
- バージョン
- 制作者
- OverlayFS が有効でないためモジュールは動作しません!
- 更新
- システムアプリを表示
- システムアプリを非表示
- ログを送信
- セーフモード
- 再起動すると有効化されます
- Magisk と競合しているためモジュールは無効になっています!
- KernelSU について
- https://kernelsu.org/ja_JP/guide/what-is-kernelsu.html
- KernelSU のインストール方法やモジュールの使い方はこちら
- 支援する
- KernelSU はこれからもずっとフリーでオープンソースです。寄付をすることで私たちを気にかけていることを示せます。
- %2$s チャンネルに参加]]>
- アプリのプロファイル
- 既定
- テンプレート
- カスタム
- プロファイル名
- 名前空間のマウント
- 継承
- 共通
- 分離
- モジュールのアンマウント
- グループ
- SELinux コンテキスト
- %s のアプリのプロファイルの更新をできませでした
- ドメイン
- ルール
- 新しいバージョン: %s が利用可能です。タップしてダウンロード
- アップデート
- ダウンロードを開始: %s
- 起動
- 強制停止
- 再起動
- SELinux ルールの更新に失敗しました: %s
- ケーパビリティ
- モジュールをダウンロード中: %s
- このオプションを有効にすると、KernelSU はこのアプリのモジュールによって変更されたファイルを復元できるようになります。
- 既定でモジュールのマウントを解除
- アプリプロファイルの「モジュールのアンマウント」の共通のデフォルト値です。 有効にすると、プロファイルセットを持たないアプリのシステムに対するすべてのモジュールの変更が削除されます。
- 現在の KernelSU バージョン %d はマネージャーが適切に機能するには低すぎます。 バージョン %d 以降にアップグレードしてください!
- 変更履歴
- インポート成功
- クリップボードからエクスポート
- エクスポートするローカル テンプレートが見つかりません!
- テンプレート id はすでに存在します!
- クリップボードからインポート
- 変更ログの取得に失敗しました: %s
- 名前
- 無効なテンプレート id
- オンラインテンプレートの同期
- テンプレートの作成
- 読み取り専用
- インポート/エクスポート
- テンプレートの保存に失敗しました
- テンプレートの編集
- id
- アプリプロファイルのテンプレート
- 説明
- 保存
- アプリプロファイルのローカルおよびオンラインテンプレートを管理する
- 消去
- クリップボードが空です!
- テンプレートを表示
- アップデートを確認
- アプリを開いたときにアップデートを自動的に確認する
- root の付与に失敗しました!
- 開く
- WebView デバッグを有効にする
- WebUI のデバッグに使用できます。必要な場合にのみ有効にしてください。
- %1$s パーティション イメージが推奨されます
- KMI を選択してください
- 次に
- 非アクティブなスロットにインストール (OTA 後)
- 再起動後、デバイスは**強制的に**、現在非アクティブなスロットから起動します。
-\nこのオプションは、OTA が完了した後にのみ使用してください。
-\n続く?
- 直接インストール (推奨)
- ファイルを選択してください
- スパースイメージを最小化
- モジュールが配置されているスパースイメージのサイズを実際のサイズに変更します。 モジュールが正常に動作しなくなる可能性がありますので、必要な場合にのみご使用ください
- 完全にアンインストールする
- ストックイメージを復元
- 一時的にアンインストールする
- アンインストール
- KernelSU を一時的にアンインストールし、次回の再起動後に元の状態に戻します。
- KernelSU (ルートおよびすべてのモジュール) を完全かつ永久にアンインストールします。
- バックアップが存在する場合、工場出荷時のイメージを復元できます (OTA の前に使用してください)。KernelSU をアンインストールする必要がある場合は、「完全にアンインストールする」を使用してください。
- フラッシュ
- フラッシュ成功
- フラッシュ失敗
- 選択された lkm: %s
- ログを保存
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-kn/strings.xml b/manager/app/src/main/res/values-kn/strings.xml
deleted file mode 100644
index 3c4e79fe..00000000
--- a/manager/app/src/main/res/values-kn/strings.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
- ಪರಿಣಾಮ ಬೀರಲು ರೀಬೂಟ್ ಮಾಡಿ
- KernelSU ಅನ್ನು ಹೇಗೆ ಸ್ಥಾಪಿಸಬೇಕು ಮತ್ತು ಮಾಡ್ಯೂಲ್ಗಳನ್ನು ಬಳಸುವುದು ಹೇಗೆ ಎಂದು ತಿಳಿಯಿರಿ
- ತಿಳಿಯದ
- ಸಿಸ್ಟಮ್ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ತೋರಿಸಿ
- %s ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲಾಗಿದೆ
- Umount ಮಾಡ್ಯೂಲ್ಗಳು
- ಲಾಗ್ ಕಳುಹಿಸಿ
- ನಮ್ಮನ್ನು ಬೆಂಬಲಿಸಿ
- ಪಿತ್ರಾರ್ಜಿತ
- ಮಾಡ್ಯೂಲ್ಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ ಏಕೆಂದರೆ ಇದು ಮ್ಯಾಜಿಸ್ಕ್ನೊಂದಿಗೆ ಸಂಘರ್ಷವಾಗಿದೆ!
- ಚೇಂಜ್ಲಾಗ್
- Permissive
- ಡೀಫಾಲ್ಟ್ ಆಗಿ Umount ಮಾಡ್ಯೂಲ್
- ಈ ಆಯ್ಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುವುದರಿಂದ ಈ ಅಪ್ಲಿಕೇಶನ್ಗಾಗಿ ಮಾಡ್ಯೂಲ್ಗಳ ಮೂಲಕ ಯಾವುದೇ ಮಾರ್ಪಡಿಸಿದ ಫೈಲ್ಗಳನ್ನು ಮರುಸ್ಥಾಪಿಸಲು KernelSU ಗೆ ಅನುಮತಿಸುತ್ತದೆ.
- ವೈಯಕ್ತಿಕ
- ಮಾಡ್ಯೂಲ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ವಿಫಲವಾಗಿದೆ: %s
- ಫೋರ್ಸ್ ಸ್ಟಾಪ್
- EDL ಗೆ ರೀಬೂಟ್
- ಸಾಮರ್ಥ್ಯಗಳು
- ಸೂಪರ್ಯೂಸರ್ಗಳು: %d
- ಡೌನ್ಲೋಡ್ ಮಾಡುವುದನ್ನು ಪ್ರಾರಂಭಿಸಿ: %s
- ಜಾಗತಿಕ
- ಅಪ್ಲಿಕೇಶನ್ ಪ್ರೊಫೈಲ್ಗಳಲ್ಲಿ \"Umount ಮಾಡ್ಯೂಲ್\" ಗಾಗಿ ಜಾಗತಿಕ ಡೀಫಾಲ್ಟ್ ಮೌಲ್ಯ. ಸಕ್ರಿಯಗೊಳಿಸಿದರೆ, ಪ್ರೊಫೈಲ್ ಸೆಟ್ ಅನ್ನು ಹೊಂದಿರದ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗಾಗಿ ಸಿಸ್ಟಮ್ಗೆ ಎಲ್ಲಾ ಮಾಡ್ಯೂಲ್ ಮಾರ್ಪಾಡುಗಳನ್ನು ಇದು ತೆಗೆದುಹಾಕುತ್ತದೆ.
- ಮಾಡ್ಯೂಲ್ಗಳು: %d
- SELinux ಸಂದರ್ಭ
- ಡೀಫಾಲ್ಟ್
- ಲಾಂಚ್
- ಸುರಕ್ಷಿತ ಮೋಡ್
- ಪ್ರಸ್ತುತ KernelSU ಆವೃತ್ತಿ %d ಮ್ಯಾನೇಜರ್ ಸರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ತುಂಬಾ ಕಡಿಮೆಯಾಗಿದೆ. ದಯವಿಟ್ಟು ಆವೃತ್ತಿ %d ಅಥವಾ ಹೆಚ್ಚಿನದಕ್ಕೆ ಅಪ್ಗ್ರೇಡ್ ಮಾಡಿ!
- ಸಾಫ್ಟ್ ರೀಬೂಟ್
- ಪ್ರೊಫೈಲ್ ಹೆಸರು
- KernelSU ಉಚಿತ ಮತ್ತು ಮುಕ್ತ ಮೂಲವಾಗಿದೆ ಮತ್ತು ಯಾವಾಗಲೂ ಇರುತ್ತದೆ. ಆದಾಗ್ಯೂ ನೀವು ದೇಣಿಗೆ ನೀಡುವ ಮೂಲಕ ನೀವು ಕಾಳಜಿ ವಹಿಸುತ್ತೀರಿ ಎಂದು ನಮಗೆ ತೋರಿಸಬಹುದು.
- ಅನ್ಇನ್ಸ್ಟಾಲ್
- ಮೌಂಟ್ ನೇಮ್ಸ್ಪೇಸ್
- ನಿಯಮಗಳು
- ಗುಂಪುಗಳು
- ಓವರ್ಲೇಫ್ಗಳು ಲಭ್ಯವಿಲ್ಲ, ಮಾಡ್ಯೂಲ್ ಕಾರ್ಯನಿರ್ವಹಿಸುವುದಿಲ್ಲ!
- ಮಾಡ್ಯೂಲ್
- ಲೇಖಕ
- ಬಗ್ಗೆ
- ವರ್ಷನ್: %d
- ರೀಬೂಟ್
- KernelSU ಈಗ GKI ಕರ್ನಲ್ಗಳನ್ನು ಮಾತ್ರ ಬೆಂಬಲಿಸುತ್ತದೆ
- SELinux ಸ್ಥಿತಿ
- ಸಿಸ್ಟಮ್ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಮರೆಮಾಡಿ
- ವರ್ಷನ್
- ಬೆಂಬಲಿತವಾಗಿಲ್ಲ
- ಡೊಮೇನ್
- ಮನೆ
- ಕಸ್ಟಮ್
- ಟೆಂಪ್ಲೇಟ್
- ರಿಫ್ರೆಶ್
- ಮಾಡ್ಯೂಲ್ ಅನ್ನು ಡೌನ್ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ: %s
- KernelSU ಕಲಿಯಿರಿ
- %s ಮಾಡ್ಯೂಲ್ ಅನ್ನು ಅಸ್ಥಾಪಿಸಲು ನೀವು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ\?
- ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ: %s
- ಸೂಪರ್ಯೂಸರ್
- ಕೆಲಸ ಮಾಡುತ್ತಿದೆ
- ಮಾಡ್ಯೂಲ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ವಿಫಲವಾಗಿದೆ: %s
- ಮಾಡ್ಯೂಲ್ ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ
- ಕರ್ನಲ್
- %s ಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್ ಪ್ರೊಫೈಲ್ ಅನ್ನು ನವೀಕರಿಸಲು ವಿಫಲವಾಗಿದೆ
- https://kernelsu.org/guide/what-is-kernelsu.html
- %1$s ನಲ್ಲಿ ಮೂಲ ಕೋಡ್ ಅನ್ನು ವೀಕ್ಷಿಸಿ
ನಮ್ಮ %2$s ಚಾನಲ್ಗೆ ಸೇರಿ
- ಮ್ಯಾನೇಜರ್ ವರ್ಷನ್
- ಹೊಸ ಆವೃತ್ತಿ: %s ಲಭ್ಯವಿದೆ, ಅಪ್ಗ್ರೇಡ್ ಮಾಡಲು ಕ್ಲಿಕ್ ಮಾಡಿ
- ಲಾಗ್ಗಳನ್ನು ಉಳಿಸಿ
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-ko/strings.xml b/manager/app/src/main/res/values-ko/strings.xml
deleted file mode 100644
index 7c29cc02..00000000
--- a/manager/app/src/main/res/values-ko/strings.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
- 홈
- 설치되지 않음
- 이 곳을 눌러 설치하기
- 정상 작동 중
- 버전: %d
- 루트 권한: %d개
- 설치된 모듈: %d개
- 지원되지 않음
- KernelSU는 현재 GKI 커널만 지원합니다
- 커널
- 매니저 버전
- 빌드 정보
- SELinux 상태
- 비활성화됨
- 적용
- 허용
- 알 수 없음
- 슈퍼유저
- 모듈 활성화 실패: %s
- 모듈 비활성화 실패: %s
- 설치된 모듈 없음
- 모듈
- 삭제
- 설치
- 설치
- 다시 시작
- 설정
- 빠른 다시 시작
- 복구 모드로 다시 시작
- 부트로더로 다시 시작
- 다운로드 모드로 다시 시작
- EDL 모드로 다시 시작
- 정보
- %s 모듈을 삭제할까요?
- %s 모듈 삭제됨
- 모듈 삭제 실패: %s
- 버전
- 제작자
- overlayfs 사용 불가, 모듈을 사용할 수 없습니다!
- 새로고침
- 시스템 앱 보이기
- 시스템 앱 숨기기
- 로그 보내기
- 안전 모드
- 다시 시작하여 변경 사항 적용
- Magisk와의 충돌로 인해 모듈을 사용할 수 없습니다!
- KernelSU 알아보기
- KernelSU 설치 방법과 모듈 사용 방법을 확인합니다
- 지원이 필요합니다
- KernelSU는 지금도, 앞으로도 항상 무료이며 오픈 소스로 유지됩니다. 기부를 통해 여러분의 관심을 보여주세요.
- %2$s 채널 참가하기]]>
- https://kernelsu.org/guide/what-is-kernelsu.html
- 앱 프로필 메뉴의 \"모듈 사용 해제\" 설정에 대한 전역 기본값을 설정합니다. 활성화 시, 개별 프로필이 설정되지 않은 앱은 시스템에 대한 모듈의 모든 수정사항이 적용되지 않습니다.
- 다시 시작
- 규칙
- 새 버전: %s 사용 가능, 여기를 눌러서 받기
- 다운로드 시작: %s
- 강제 중지
- 기본값
- 사용자 지정
- 템플릿
- 프로필 이름
- 이름 공간 마운트
- 상속
- 전역
- 개별
- 사용자 그룹
- 모듈 사용 해제
- SELinux 컨텍스트
- 권한
- %s에 대한 앱 프로필 업데이트 실패
- 기본값으로 모듈 사용 해제
- 이 옵션이 활성화되면, KernelSU는 이 애플리케이션에 대한 모듈의 모든 수정사항을 복구합니다.
- 업데이트
- 모듈 받는 중: %s
- 도메인
- 실행
- 다음 앱에 대한 SELinux 규칙 업데이트 실패: %s
- 로그 저장
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-lt/strings.xml b/manager/app/src/main/res/values-lt/strings.xml
deleted file mode 100644
index cba5f5b1..00000000
--- a/manager/app/src/main/res/values-lt/strings.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
- Pirštų atspaudas
- Išjungta
- Priverstinas
- Nežinomas
- Supernaudotojai
- Nepavyko įjungti modulio: %s
- Nepavyko išjungti modulio: %s
- Leistinas
- Nėra įdiegtų modulių
- Moduliai
- Perkrovimas neišjungus
- Perkrauti į atkūrimo rėžimą
- Perkrauti į įkrovos tvarkyklę
- Perkrauti į atsisiuntimo rėžimą
- Apie
- Nepavyko išdiegti: %s
- %s išdiegtas
- Versija
- Autorius
- overlayfs nepasiekiamas, modulis negali veikti!
- Rodyti sistemos programas
- Slėpti sistemos programas
- Siųsti žurnalą
- Paleisti iš naujo
- Atšviežinti
- Saugus rėžimas
- Paleiskite iš naujo, kad įsigaliotų
- Moduliai yra išjungti, nes jie konfliktuoja su Magisk\'s!
- https://kernelsu.org/guide/what-is-kernelsu.html
- Sužinokite apie KernelSU
- Sužinokite, kaip įdiegti KernelSU ir naudoti modulius
- Peržiūrėkite šaltinio kodą %1$s
Prisijunkite prie mūsų %2$s kanalo
- Numatytas
- Šablonas
- Pasirinktinis
- Profilio pavadinimas
- Prijungti vardų erdvę
- Paveldėtas
- Globalus
- Individualus
- Grupės
- Galimybės
- SELinux kontekstas
- Atjungti modulius
- Atjungti modulius pagal numatytuosius parametrus
- Įjungus šią parinktį, KernelSU galės atkurti visus modulių modifikuotus failus šiai programai.
- Domenas
- Taisyklės
- Atnaujinti
- Atsisiunčiamas modulis: %s
- Pradedamas atsisiuntimas: %s
- Nauja versija: %s pasiekiama, spustelėkite norėdami atsinaujinti
- Paleisti
- Priversti sustoti
- Perkrauti
- Nepavyko atnaujinti SELinux taisyklių: %s
- Namai
- Neįdiegta
- KernelSU dabar palaiko tik GKI branduolius
- Spustelėkite norėdami įdiegti
- Veikia
- Supernaudotojai: %d
- Versija: %d
- Nepalaikoma
- Moduliai: %d
- Tvarkyklės versija
- Branduolys
- SELinux statusas
- Išdiegti
- Įdiegti
- Įdiegti
- Parametrai
- Perkrauti į EDL
- Ar tikrai norite išdiegti modulį %s\?
- Paremkite mus
- KernelSU yra ir visada bus nemokamas ir atvirojo kodo. Tačiau galite parodyti, kad jums rūpi, paaukodami mums.
- Nepavyko atnaujinti programos profilio %s
- Visuotinė numatytoji „Modulių atjungimo“ reikšmė programų profiliuose. Jei įjungta, ji pašalins visus sistemos modulio pakeitimus programoms, kurios neturi profilio.
- Keitimų žurnalas
- Ši KernelSU versija %d yra per žema, kad šis vadybininkas galėtų tinkamai funkcionuoti. Prašome atsinaujinti į versiją %d ar aukščiau!
- Saglabāt Žurnālus
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-lv/strings.xml b/manager/app/src/main/res/values-lv/strings.xml
deleted file mode 100644
index c264b76a..00000000
--- a/manager/app/src/main/res/values-lv/strings.xml
+++ /dev/null
@@ -1,134 +0,0 @@
-
-
- Iespējojot šo opciju, KernelSU varēs atjaunot visus moduļos šīs lietojumprogrammas modificētos failus.
- Neizdevās atjaunināt SELinux noteikumus: %s
- Pārvaldiet vietējo un tiešsaistes lietotņu profila veidni
- Nederīgs veidnes id
- veidnes id jau pastāv!
- Eksportēt starpliktuvē
- Importēt no starpliktuves
- Importēts veiksmīgi
- Sinhronizēt tiešsaistes veidnes
- Sākums
- Nav ieinstalēts
- Noklikšķiniet, lai instalētu
- Darbojas
- Versija: %d
- Superlietotāji: %d
- Moduļi: %d
- Neatbalstīts
- KernelSU atbalsta tikai GKI kodolus
- Kodols
- Pārvaldnieka versija
- Pirkstu nospiedums
- SELinux statuss
- Izpildīšana
- Atspējots
- Nezināms
- SuperLietotājs
- Neizdevās atspējot moduli: %s
- Nav instalētu moduļu
- Moduļi
- Atinstalēt
- Instalēt
- Restartēt
- Iestatījumi
- Ātri restartēt
- Restartēt uz Bootloaderu
- Restartēt uz Recovery
- Restartēt uz Download
- Restartēt uz EDL
- Par
- %s ir atinstalēts
- Neizdevās atinstalēt: %s
- Autors
- Atjaunot
- Rādīt sistēmas lietotnes
- Slēpt sistēmas lietotnes
- Ziņot žurnālu
- Restartējiet, lai stātos spēkā
- Uzzināt par KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- Uzzināt, kā instalēt KernelSU un izmantot moduļus
- Atbalsti mūs
- Skatiet avota kodu vietnē %1$s
Pievienojies mūsu %2$s kanālam
- Noklusējums
- Veidne
- Pielāgots
- Profila vārds
- Mount nosaukumvieta
- Individuāls
- Iespējas
- SELinux konteksts
- Atvienot moduļus
- Neizdevās atjaunināt lietotnes profilu %s
- Pēc noklusējuma atvienot moduļus
- Globālā noklusējuma vērtība vienumam “Atvienot moduļus” lietotņu profilos. Ja tas ir iespējots, lietojumprogrammām, kurām nav iestatīts profils, tiks noņemtas visas sistēmas moduļu modifikācijas.
- Domēns
- Noteikumi
- Atjaunināt
- Lejupielādē moduli: %s
- Sākt lejupielādi: %s
- Jaunā versija: %s ir pieejama, noklikšķiniet, lai atjauninātu
- Palaist
- Piespiedu apstāšana
- Restartēt aplikāciju
- Izmaiņu žurnāls
- Lietotnes profila veidne
- Izveidot veidni
- Rediģēt veidni
- id
- Vārds
- Apraksts
- Saglabāt
- Dzēst
- Skatīt veidni
- tikai lasīt
- Importēt/Eksportēt
- Nevar atrast vietējo eksportējamo veidni!
- Neizdevās saglabāt veidni
- Starpliktuve ir tukša!
- Izmaiņu žurnāla iegūšana neizdevās: %s
- Visatļautība
- Neizdevās iespējot moduli: %s
- Instalēt
- Vai tiešām vēlaties atinstalēt moduli %s?
- Versija
- overlayfs nav pieejams, modulis nevar darboties!
- Drošais režīms
- Moduļi ir atspējoti, jo tie konfliktē ar Magisk!
- KernelSU ir un vienmēr būs bezmaksas un atvērtā koda. Tomēr jūs varat parādīt mums, ka jums rūp, veicot ziedojumu.
- Grupas
- Globāli
- Pašreizējā KernelSU versija %d ir pārāk zema, lai pārvaldnieks darbotos pareizi. Lūdzu, atjauniniet uz versiju %d vai jaunāku!
- Iespējot WebView atkļūdošanu
- Ieteicams %1$s nodalījuma attēls
- Nākamais
- Mantots
- Izvēlieties failu
- Instalēt neaktīvajā slotā (pēc OTA)
- Pēc restartēšanas jūsu ierīce tiks **PIESPIESTI** palaista pašreizējā neaktīvajā slotā!
-\nIzmantojiet šo opciju tikai pēc OTA pabeigšanas
-\nTurpināt?
- Tiešā instalēšana (Ieteicams)
- Atinstalēt
- Pagaidu atinstalēšana
- Atjaunot oriģinālo attēlu
- Īslaicīgi atinstalēt KernelSU, pēc nākamās restartēšanas atjaunot sākotnējo stāvokli.
- KernelSU (saknes un visu moduļu) pilnīga atinstalēšana.
- Atjaunojot rūpnīcas attēlu (ja ir dublējums), ko parasti izmanto pirms OTA; ja nepieciešams atinstalēt KernelSU, lūdzu, izmantojiet \"Neatgriezeniski atinstalēt\".
- Izvēlētais lkm: %s
- Neizdevās piešķirt sakni!
- Atvērt
- Pārbaudīt atjauninājumus
- Automātiski pārbaudīt atjauninājumus atverot aplikāciju
- Var izmantot WebUI atkļūdošanai, lūdzu, izmantot tikai tad, kad tas ir nepieciešams.
- Izvēlieties KMI
- Neatgriezeniski atinstalēt
- Instalē
- Instalēts veiksmīgi
- Instalēšana neizdevās
- Samazināt reto attēlu
- Mainīt retā attēla izmēru, kurā atrodas modulis, līdz tā faktiskajam izmēram. Ņemiet vērā, ka tas var izraisīt moduļa neparastu darbību, tāpēc, lūdzu, izmantojiet tikai nepieciešamības gadījumā (piemēram, dublēšanai)
- Išsaugoti Žurnalus
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-mr/strings.xml b/manager/app/src/main/res/values-mr/strings.xml
deleted file mode 100644
index eaaf2a25..00000000
--- a/manager/app/src/main/res/values-mr/strings.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
- इंस्टॉल केले नाही
- होम
- इंस्टॉल साठी क्लिक करा
- कार्यरत
- आवृत्ती: %d
- मॉड्यूल्स: %d
- सुपरयूझर: %d
- असमर्थित
- KernelSU आता फक्त GKI कर्नलचे समर्थन करते
- कर्नल
- फिंगरप्रिंट
- व्यवस्थापक आवृत्ती
- SELinux स्थिती
- अक्षम
- एनफोर्सिंग
- परमिसिव
- अज्ञात
- स्थापित करा
- कोणतेही मॉड्यूल स्थापित केलेले नाही
- रीबूट करा
- सुपरयुझर
- मॉड्यूल सक्षम करण्यात अयशस्वी: %s
- विस्थापित करा
- मॉड्यूल अक्षम करण्यात अयशस्वी: %s
- मॉड्यूल
- स्थापित करा
- सेटिंग्ज
- सॉफ्ट रीबूट
- बद्दल
- EDL वर रीबूट करा
- तुमची खात्री आहे की तुम्ही मॉड्यूल %s विस्थापित करू इच्छिता\?
- विस्थापित करण्यात अयशस्वी: %s
- overlayfs उपलब्ध नाही, मॉड्यूल काम करू शकत नाही!
- सिस्टम अॅप्स दाखवा
- बूटलोडरवर रीबूट करा
- %s विस्थापित
- आवृत्ती
- लेखक
- रिफ्रेश करा
- रिकवरी मध्ये रिबुट करा
- डाउनलोड करण्यासाठी रीबूट करा
- लॉग पाठवा
- सुरक्षित मोड
- सिस्टम अॅप्स लपवा
- प्रभावी होण्यासाठी रीबूट करा
- KernelSU शिका
- https://kernelsu.org/guide/what-is-kernelsu.html
- मॉड्यूल अक्षम केले आहेत कारण ते Magisk च्या विरोधाभास आहे!
- KernelSU कसे स्थापित करायचे आणि मॉड्यूल कसे वापरायचे ते शिका
- KernelSU विनामूल्य आणि मुक्त स्रोत आहे, आणि नेहमीच असेल. तथापि, देणगी देऊन तुम्ही आम्हाला दाखवू शकता की तुमची काळजी आहे.
- आम्हाला पाठिंबा द्या
- कस्टम
- माउंट नेमस्पेस
- डीफॉल्ट
- साचा
- वैयक्तिक
- क्षमता
- %1$s वर स्रोत कोड पहा
आमच्या %2$s चॅनेलमध्ये सामील व्हा
- प्रोफाइल नाव
- इनहेरीटेड
- जागतिक
- गट
- SELinux संदर्भ
- उमाउंट मॉड्यूल्स
- %s साठी अॅप प्रोफाइल अपडेट करण्यात अयशस्वी
- डीफॉल्टनुसार मॉड्यूल्स उमाउंट करा
- अॅप प्रोफाइलमधील \"उमाउंट मॉड्यूल्स\" साठी जागतिक डीफॉल्ट मूल्य. सक्षम असल्यास, ते प्रोफाइल सेट नसलेल्या ॲप्लिकेशनचे सिस्टममधील सर्व मॉड्यूल बदल काढून टाकेल.
- हा पर्याय सक्षम केल्याने KernelSU ला या ऍप्लिकेशनसाठी मॉड्यूल्सद्वारे कोणत्याही सुधारित फाइल्स पुनर्संचयित करण्यास अनुमती मिळेल.
- यासाठी SELinux नियम अपडेट करण्यात अयशस्वी: %s
- नियम
- अपडेट करा
- डोमेन
- मॉड्यूल डाउनलोड करत आहे: %s
- डाउनलोड करणे सुरू करा: %s
- नवीन आवृत्ती: %s उपलब्ध आहे, डाउनलोड करण्यासाठी क्लिक करा
- सक्तीने थांबा
- लाँच करा
- पुन्हा सुरू करा
- लॉग जतन करा
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-ms/strings.xml b/manager/app/src/main/res/values-ms/strings.xml
deleted file mode 100644
index 46c1539c..00000000
--- a/manager/app/src/main/res/values-ms/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
- Tidak Diketahui
- Lumpuhkan
- Permisif
- Mulakan semula ke Download
- Modul tidak berjaya Diaktifkan:%s
- Mulakan semula ke EDL
- Superusers%d
- Modul%d
- Enforcing
- Cap Jari
- Mulakan semula ke Recovery
- Soft reboot
- Padam
- Pasang
- Tekan untuk memasang
- Modul
- Tentang
- Versi%d
- Mulakan semula
- KernelSU ketika ini hanya menyokong kernel GKI
- Status SELinux
- Tidak Disokong
- Layar Utama
- Apakah anda pasti ingin membuang modul %s\?
- SuperUser
- Tetapan
- Berjalan
- Gagal mematikan modul:%s
- Tiada modul dipasang
- Pasang
- Kernel
- Tidak terpasang
- Mulakan semula ke bootloader
- Versi Manager
- Simpan Log
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-night-v27/themes.xml b/manager/app/src/main/res/values-night-v27/themes.xml
deleted file mode 100644
index 10a773b1..00000000
--- a/manager/app/src/main/res/values-night-v27/themes.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-night/themes.xml b/manager/app/src/main/res/values-night/themes.xml
deleted file mode 100644
index 91abf657..00000000
--- a/manager/app/src/main/res/values-night/themes.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-nl/strings.xml b/manager/app/src/main/res/values-nl/strings.xml
deleted file mode 100644
index bebf3789..00000000
--- a/manager/app/src/main/res/values-nl/strings.xml
+++ /dev/null
@@ -1,129 +0,0 @@
-
-
- Home
- Niet geïnstalleerd
- Klik om te installeren
- Werkend
- Versie: %d
- Supergebruikers: %d
- Modules: %d
- Niet ondersteund
- KernelSU ondersteunt alleen GKI kernels
- Kernel
- Manager Versie
- Fingerprint
- SELinux status
- Uitgeschakeld
- Afgedwongen
- Permissief
- Niet gekend
- SupergeBruiker
- Mislukt om module in te schakelen: %s
- Mislukt om module uit te schakelen: %s
- Geen geïnstalleerde modules
- Module
- Verwijderen
- Installeren
- Installeren
- Herstart
- Instellingen
- Soft herstart
- Herstart naar Recovery
- Herstart naar Bootloader
- Herstart om te downloaden
- Herstart naar EDL
- Over
- Zeker van het verwijderen van module %s?
- %s is verwijderd
- Mislukt om te verwijderen: %s
- Versie
- Auteur
- overlayfs is niet beschikbaar, module kan niet werken!
- Vernieuwen
- Toon systeem apps
- Verberg systeem apps
- Rapport Log
- Safe mode
- Herstart om effect te hebben
- Modules zijn uitgeschakeld omdat ze in conflict zijn met magisk!
- Leer KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- Leer hoe KernelSU te installeren en modules te gebruiken
- Ondersteun ons
- KernelSU is, en zal altijd, vrij en open source zijn. Je kan altijd je appreciatie tonen met een donatie.
- Vervoeg ons %2$s kanaal]]>
- App profiel
- Standaard
- Sjabloon
- Aangepast
- Profiel naam
- Koppel naamruimte
- Overgenomen
- Globaal
- Individuëel
- Groepen
- Mogelijkheden
- SELinux context
- Ontkoppel modules
- Mislukt om App Profiel te updaten voor %s
- Ontkoppel standaard de modules
- De globale standaard waarde voor \"Ontkoppel modules\" in App Profielen. Indien geactiveerd, zal het alle module wijzigingen tot het systeem verwijderen voor applicaties die geen Profiel ingesteld hebben.
- Met deze optie ingeschakeld zal KernelSU toelaten om alle gewijzigde bestanden door de modules voor deze applicatie te herstellen.
- Domein
- Regels
- Update
- Downloaden van module: %s
- Nieuwe versie: %s is beschikbaar,klik om te upgraden
- Start
- Forceer Stop
- Herstart
- Begin met downloaden: %s
- Kan SELinux-regels niet bijwerken voor: %s
- De huidige KernelSU-versie %d is te laag om de manager correct te laten functioneren. Upgrade naar versie %d of hoger!
- wijzigings logboek
- App-profiel Sjabloon
- Maken Sjabloon
- Bewerkin Sjabloon
- id
- Ongeldige sjabloon id
- Naam
- Redde
- Bekijken Sjabloon
- Beschrijving
- Beheer lokale en online sjabloon van app-profiel
- Verwijderen
- alleen lezen
- sjabloon id bestaat al!
- Synchroniseer online-sjablonen
- Mislukt naar opslaan sjabloon
- Klembord is leeg!
- Importeren/Exporteren
- Importeren vanaf klembord
- Ophalen van wijzigingslogboek mislukt: %s
- Exporteren naar klembord
- Controleer update
- Schakel WebView-foutopsporing
- Kan worden gebruikt om WebUI te debuggen. Schakel dit alleen in als dat nodig is.
- Kan geen lokale sjabloon vinden om te exporteren!
- Succesvol geïmporteerd
- Open
- Controleer automatisch op updates bij het openen van de app
- Directe installatie (aanbevolen)
- Selecteer een bestand
- Kan geen root verlenen!
- Minimaliseer schaarse afbeeldingen
- Wijzig het formaat van de beperkte afbeelding waar de module zich bevindt naar de werkelijke grootte. Houd er rekening mee dat dit ervoor kan zorgen dat de module abnormaal werkt, dus gebruik deze alleen wanneer dit nodig is (zoals voor back-up)
- %1$s partitie-image wordt aanbevolen
- Naast
- Uw apparaat wordt **GEFORCEERD** om na een herstart op te starten naar het huidige inactieve slot!
-\nGebruik deze optie alleen nadat OTA is voltooid.
-\nDoorgaan?
- Installeren in inactief slot (na OTA)
- KMI selecteren
- Desinstalleren
- Tijdelijk verwijderen
- Permanent verwijderen
- Herstel stockafbeelding
- Verwijder KernelSU tijdelijk en herstel het naar de oorspronkelijke staat na de volgende herstart.
- Logboeken Opslaan
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-pl/strings.xml b/manager/app/src/main/res/values-pl/strings.xml
deleted file mode 100644
index b4fe83f3..00000000
--- a/manager/app/src/main/res/values-pl/strings.xml
+++ /dev/null
@@ -1,136 +0,0 @@
-
-
- KernelSU
- Strona główna
- Nie zainstalowano
- Kliknij, aby zainstalować
- Działa
- Wersja: %d
- Superużytkownicy: %d
- Moduły: %d
- Nieobsługiwany
- KernelSU obsługuje obecnie tylko jądra GKI
- Jądro
- Wersja menedżera
- Odcisk
- Status SELinux
- Wyłączony
- Enforcing
- Dozwolony
- Nieznany
- Superużytkownik
- Nie udało się włączyć modułu: %s
- Nie udało się wyłączyć modułu: %s
- Brak zainstalowanych modułów
- Moduły
- Odinstaluj
- Instaluj
- Instaluj
- Uruchom ponownie
- Ustawienia
- Miękki restart
- Restart do trybu Recovery
- Restart do trybu Bootloader
- Restart do trybu Download
- Restart do trybu EDL
- Informacje
- Czy na pewno chcesz odinstalować moduł %s?
- Odinstalowano %s
- Nie udało się odinstalować:: %s
- Wersja
- Autor
- overlayfs jest niedostępny, moduł nie zadziała!
- Odśwież
- Pokaż aplikacje systemowe
- Ukryj aplikacje systemowe
- Raportuj log
- Tryb bezpieczny
- Uruchom ponownie, aby zastosować zmiany
- Moduły są wyłączone, ponieważ są w konflikcie z modułami Magiska!
- Poznaj KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- Dowiedz się jak zainstalować KernelSU i jak korzystać z modułów
- Wesprzyj nas
- KernelSU jest i zawsze będzie darmowy oraz otwarty. Niemniej jednak możesz nam pokazać, że Ci zależy, wysyłając darowiznę.
- Dołącz do kanału %2$s]]>
- Profil aplikacji
- Domyślny
- Szablon
- Własny
- Nazwa profilu
- Przestrzeń nazw montowania
- Odziedziczona
- Globalna
- Indywidualna
- Grupy
- Uprawnienia
- Kontekst SELinux
- Odmontuj moduły
- Nie udało się zaktualizować profilu aplikacji dla %s
- Domyślnie odmontuj moduły
- Globalna wartość domyślna opcji \"Odmontuj moduły\" w profilach aplikacji. Jeśli jest włączona, wycofuje wszystkie modyfikacje dokonane przez moduły dla aplikacji, które nie mają ustawionego profilu.
- Włączenie tej opcji umożliwi KernelSU przywrócenie wszelkich zmodyfikowanych plików przez moduły dla tej aplikacji.
- Domena
- Reguły
- Zaktualizuj
- Pobieranie modułu: %s
- Rozpocznij pobieranie: %s
- Nowa wersja: %s jest dostępna. Kliknij, aby zaktualizować
- Uruchom
- Wymuś zatrzymanie
- Restartuj
- Nie udało się zaktualizować reguł SELinux dla: %s
- Obecna wersja KernelSU %d jest zbyt stara, aby menedżer działał poprawnie. Prosimy o aktualizację do wersji %d lub nowszej!
- Dziennik zmian
- Włącz debugowanie WebView
- Może być użyte do debugowania WebUI. Włącz tylko w razie potrzeby.
- Obraz partycji %1$s jest zalecany
- Wybierz KMI
- Dalej
- Instalacja bezpośrednia (zalecane)
- Wybierz plik
- Zainstaluj do nieaktywnego slotu (po aktualizcji OTA)
- Po ponownym uruchomieniu Twoje urządzenie zostanie **ZMUSZONE** do uruchomia się z obecnie nieaktywnego slotu!
-\nUżyj tej opcji dopiero po zakończeniu aktualizacji OTA.
-\nCzy chcesz kontynuować?
- Stwórz szablon
- Edytuj szablon
- Nazwa
- Opis
- Zapisz
- Usuń
- tylko do odczytu
- Importuj/Eksportuj
- Importuj ze schowka
- Eksportuj do schowka
- Nie można znaleźć lokalnego szablonu do eksportu!
- Zaimportowano pomyślnie
- Nie udało się zapisać szablonu
- Schowek jest pusty!
- Zarządzaj lokalnym i internetowym szablonem profilu aplikacji
- Synchronizuj internetowe szablony
- Zobacz szablon
- Błędny identyfikator szablonu
- Szablon profilu aplikacji
- Identyfikator
- Szablon o takim identyfikatorze już istnieje!
- Nie udało się przyznać roota!
- Otwórz
- Pobranie dziennika zmian nie powiodło się: %s
- Wyszukaj aktualizacje
- Wyszukuj aktualizacje automatycznie przy otwieraniu aplikacji
- Minimalizuj rozrzedzony (sparse) obraz
- Zmienia rozmiar obrazu rozrzedzonego(sparse), w którym znajduje się moduł, do jego rzeczywistego rozmiaru. Należy pamiętać, że może to spowodować nieprawidłowe działanie modułu, więc należy go używać tylko wtedy, gdy jest to konieczne (np. do tworzenia kopii zapasowych)
- Odinstaluj zupełnie
- Przywróć obraz fabryczny
- Odinstaluj tymczasowo
- Odinstaluj
- Tymczasowo odinstaluj KernelSU, przywróć do oryginalnego stanu po następnym ponownym uruchomieniu.
- Całkowite i trwałe odinstalowanie KernelSU(Root i wszystkich modułów).
- Przywróć obraz fabryczny (jeśli istnieje kopia zapasowa), zwykle używany przed OTA; jeśli chcesz odinstalować KernelSU, użyj opcji \"Odinstaluj zupełnie\".
- Flashowanie
- Flashowanie ukończone pomyślnie
- Flashowanie nieudane
- Wybrano lkm: %s
- Zapisz Dzienniki
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-pt-rBR/strings.xml b/manager/app/src/main/res/values-pt-rBR/strings.xml
deleted file mode 100644
index f092a451..00000000
--- a/manager/app/src/main/res/values-pt-rBR/strings.xml
+++ /dev/null
@@ -1,135 +0,0 @@
-
-
- Início
- Não instalado
- Clique para instalar
- Em execução
- Versão: %d
- SuperUsuários: %d
- Módulos: %d
- Sem suporte
- KernelSU suporta apenas kernels GKI agora
- Kernel
- Versão do gerenciador
- Impressão digital
- Status do SELinux
- Desativado
- Impondo
- Permissivo
- Desconhecido
- SuperUsuário
- Falha ao ativar o módulo %s
- Falha ao desativar o módulo %s
- Nenhum módulo instalado
- Módulo
- Desinstalar
- Instalar
- Instalar
- Reiniciar
- Configurações
- Reinicialização suave
- Reiniciar em modo Recovery
- Reiniciar em modo Bootloader
- Reiniciar em modo Download
- Reiniciar em modo EDL
- Sobre
- Tem certeza que deseja desinstalar o módulo %s?
- %s desinstalado
- Falha ao desinstalar %s
- Versão
- Autor
- Os módulos estão indisponíveis porque OverlayFS está desabilitado pelo kernel!
- Atualizar
- Mostrar apps do sistema
- Ocultar apps do sistema
- Reportar registro
- Modo de segurança
- Reinicie para entrar em vigor
- Os módulos estão indisponíveis devido a um conflito com Magisk!
- Saiba mais sobre o KernelSU
- https://kernelsu.org/pt_BR/guide/what-is-kernelsu.html
- Saiba como instalar o KernelSU e usar os módulos
- Apoie-nos
- KernelSU sempre foi e sempre será, gratuito e de código aberto. No entanto, você pode nos ajudar enviando uma pequena doação.
- Junte-se ao nosso canal do %2$s]]>
- Perfil do Aplicativo
- Padrão
- Modelo
- Personalizado
- Nome do perfil
- Montar namespace
- Herdado
- Global
- Individual
- Grupos
- Capacidades
- Contexto do SELinux
- Desmontar módulos
- Falha ao atualizar o Perfil do Aplicativo para %s
- Desmontar módulos por padrão
- O valor padrão global para \"Desmontar módulos\" em Perfil do Aplicativo. Se ativado, ele removerá todas as modificações do módulo no sistema para apps que não possuem um perfil definido.
- Ativar esta opção permitirá que o KernelSU restaure quaisquer arquivos modificados pelos módulos para este app.
- Domínio
- Regras
- Atualizar
- Baixando módulo %s
- Começando a baixar %s
- Nova versão %s está disponível, clique para atualizar.
- Iniciar
- Forçar parada
- Reiniciar
- Falha ao atualizar as regras do SELinux para: %s
- A versão atual do KernelSU %d é muito baixa para o gerenciador funcionar corretamente. Por favor, atualize para a versão %d ou superior!
- Registro de alterações
- Importado com sucesso
- Exportar para a área de transferência
- Não foi possível encontrar o modelo local para exportar!
- O ID do modelo já existe!
- Importar da área de transferência
- Falha ao buscar o registro de alterações: %s
- Nome
- ID do modelo inválido
- Sincronizar modelos online
- Criar modelo
- Somente leitura
- Importar/Exportar
- Falha ao salvar o modelo
- Editar modelo
- ID
- Modelo do Perfil do Aplicativo
- Descrição
- Salvar
- Gerencie o modelo local e online do Perfil do Aplicativo
- Excluir
- A área de transferência está vazia!
- Ver modelo
- Verificar por atualização
- Verifique automaticamente se há atualizações ao abrir o app
- Falha ao conceder acesso root!
- Abrir
- Ativar depuração do WebView
- Pode ser usado para depurar o WebUI. Por favor, ative somente quando necessário.
- Selecione um arquivo
- Instalação direta (recomendada)
- Instalar no slot inativo (após o OTA)
- Seu dispositivo será **FORÇADO** a inicializar no slot inativo atual após uma reinicialização!
-\nSó use esta opção após a conclusão do OTA.
-\nDeseja continuar?
- Próximo
- A imagem da partição %1$s é recomendada
- Selecionar KMI
- Minimizar imagem esparsa
- Redimensione a imagem esparsa onde o módulo está localizado para seu tamanho real. Observe que isso pode fazer com que o módulo funcione de forma anormal, portanto, use-o somente quando necessário (como um backup).
- Desinstalar
- Desinstalar temporariamente
- Desinstalar permanentemente
- Restaurar imagem de fábrica
- Restaure a imagem de fábrica (se existir um backup), geralmente usada antes do OTA. Se você precisar desinstalar o KernelSU, use \"Desinstalar permanentemente\".
- Desinstale temporariamente o KernelSU e restaure ao estado original após a próxima reinicialização
- Desinstale o KernelSU (Root e todos os módulos) completamente e permanentemente
- LKM selecionado: %s
- Flash falhou
- Flashando
- Flash bem-sucedido
- Salvar Logs
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-pt/strings.xml b/manager/app/src/main/res/values-pt/strings.xml
deleted file mode 100644
index ea1547db..00000000
--- a/manager/app/src/main/res/values-pt/strings.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
- Não instalado
- Início
- Clique para instalar
- Funcionando
- Super Usuário: %d
- Módulos: %d
- Versão: %d
- Kernel
- Instalar
- Sem suporte
- KernelSU suporta apenas kernels GKI agora
- Status do SELinux
- Versão do aplicativo
- Falha ao desativar o módulo: %s
- Impressão digital
- Desabilitado
- Impondo
- Permissivo
- Desconhecido
- Super Usuário
- Falha ao ativar o módulo: %s
- Nenhum módulo instalado
- Desinstalar
- Modulos
- Reiniciar
- Instalar
- Reinicialização Suave
- Configurações
- Reinicializar modo Bootloader
- Reiniciar modo recuperação
- Falha ao desinstalar: %s
- Versão
- Autor
- Atualizar
- Esconder apps do sistema
- Reiniciar para baixar
- Reiniciar em EDL
- Tem certeza de que deseja desinstalar o módulo %s\?
- Sobre
- overlayfs não está disponível, o módulo não pode funcionar!
- Enviar log
- %s desinstalado
- Mostrar aplicativos do sistema
- Aprenda a instalar o KernelSU e usar os módulos
- O KernelSU é, e sempre será, gratuito e de código aberto. No entanto, você pode nos mostrar que se importa fazendo uma doação.
- Veja o código-fonte em %1$s
Junte-se ao nosso canal %2$s
- Individual
- Global
- Herdado
- Padrão
- Modelo
- Personalizado
- Nome do perfil
- Montar namespace
- Modo de segurança
- Reinicie para entrar em vigor
- Aprender KernelSU
- Os módulos estão desativados porque estão em conflito com os do Magisk!
- Apoie-nos
- Grupos
- Capacidades
- contexto SELinux
- Domínio
- Atualização
- Desativar modulos
- Falha ao atualizar o perfil do aplicativo para %s
- Módulos desativados por padrão
- O valor padrão global para \"Módulos Umount\" em Perfis de Aplicativos. Se ativado, removerá todas as modificações de módulo do sistema para aplicativos que não possuem um Perfil definido.
- Regras
- Ativar esta opção permitirá que o KernelSU restaure quaisquer arquivos modificados pelos módulos para este aplicativo.
- Iniciar o download: %s
- Baixando módulo: %s
- Falha ao atualizar as regras do SELinux para: %s
- https://kernelsu.org/guide/what-is-kernelsu.html
- Reiniciar
- Lançar
- Forçar parada
- Nova versão: %s está disponível, clique para baixar
- A versão atual do KernelSU %d é muito baixa para o gerenciador funcionar corretamente. Atualize para a versão %d ou superior!
- Salvar Registros
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-ro/strings.xml b/manager/app/src/main/res/values-ro/strings.xml
deleted file mode 100644
index fea3ffb6..00000000
--- a/manager/app/src/main/res/values-ro/strings.xml
+++ /dev/null
@@ -1,132 +0,0 @@
-
-
- Acasă
- Nu este instalat
- Click pentru a instala
- Funcționează
- Versiune: %d
- Super-utilizatori: %d
- Module: %d
- Necompatibil
- KernelSU suportă doar nuclee GKI acum
- Nucleu
- Versiune Manager
- Amprentă
- Stare SELinux
- Dezactivat
- Obligatoriu
- Permisiv
- Necunoscut
- Super-Utilizator
- Activarea modulului %s a eșuat
- Dezactivarea modulului %s a eșuat
- Niciun modul instalat
- Module
- Dezinstalează
- Instalează
- Instalează
- Repornește
- Setări
- Repornire rapidă
- Repornire în Recuperare
- Repornire în Bootloader
- Repornire în Download
- Repornire în EDL
- Despre
- Sigur dorești să dezinstalezi modulul %s?
- %s dezinstalat
- Dezinstalare eșuată: %s
- Versiune
- Autor
- overlayfs nu este disponibil, modulul nu poate funcționa!
- Reîmprospătează
- Arată aplicațiile de sistem
- Ascunde aplicațiile de sistem
- Raportează jurnal
- Mod sigur
- Repornește pentru ca modificările să intre în vigoare
- Modulele sunt dezactivate deoarece sunt în conflict cu cele ale Magisk-ului!
- Află mai multe despre KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- Află cum să instalezi KernelSU și să utilizezi module
- Suport
- KernelSU este, și va fi întotdeauna, gratuit și cu codul sursă deschis. Cu toate acestea, ne poți arăta că îți pasă făcând o donație.
- Alătură-te canalului nostru %2$s]]>
- Implicit
- Șablon
- Personalizat
- Nume profil
- Montare spațiu de nume
- Moștenit
- Global
- Individual
- Grupuri
- Capabilități
- Context SELinux
- Module u-montate
- Nu s-a putut actualiza profilul aplicației pentru %s
- U-montează modulele în mod implicit
- Valoarea implicită globală pentru „Module u-montate” în Profilurile aplicațiilor. Dacă este activat, va elimina toate modificările modulelor aduse sistemului pentru aplicațiile care nu au un profil setat.
- Activarea acestei opțiuni va permite KernelSU să restaureze orice fișiere modificate de către modulele pentru această aplicație.
- Domeniu
- Reguli
- Actualizează
- Se descarcă modulul: %s
- Începe descărcarea: %s
- Versiune nouă: %s este disponibilă, clic pentru a actualiza
- Nu s-au reușit actualizările regulilor SELinux pentru: %s
- Lansare
- Oprire forțată
- Repornește
- Versiunea actuală a KernelSU %d este prea mică pentru ca managerul să funcționeze corect. Actualizează la versiunea %d sau o versiune superioară!
- Jurnalul modificărilor
- Importat cu succes
- Export în clipboard
- Nu există șabloane locale de exportat!
- ID-ul șablonului există deja!
- Import din clipboard
- Preluarea jurnalului de modificări a eșuat: %s
- Nume
- ID șablon nevalid
- Sincronizează șabloanele online
- Creează un șablon
- doar citire
- Import/Export
- Nu s-a salvat șablonul
- Editează șablonul
- ID
- Șablon de profil al aplicației
- Descriere
- Salvează
- Gestionează șablonul local și online al Profilului aplicației
- Șterge
- Clipboard-ul este gol!
- Vizualizare șablon
- Verifică actualizarea
- Se verifică automat actualizările când deschizi aplicația
- Activează depanarea WebView
- Poate fi folosit pentru a depana WebUI, activează numai când este necesar.
- Nu s-a acordat acces root!
- Deschide
- Se recomandă imaginea partiției %1$s
- Înainte
- Dispozitivul va fi **FORȚAT** să pornească în slot-ul inactiv curent după o repornire!
-\nFolosește această opțiune numai după finisarea OTA.
-\nContinui?
- Selectează KMI
- Instalare directă (recomandat)
- Selectează un fișier
- Instalează într-un slot inactiv (după OTA)
- Dezinstalează
- Restaurare imagine stoc
- Dezinstalează temporar KernelSU, se revine la starea inițială după următoarea repornire.
- Lkm selectat: %s
- Dezinstalează temporar
- Dezinstalează definitiv
- Dezinstalare KernelSU (Root și toate modulele) complet și permanent.
- Restaurează imaginea stoc din fabrică (dacă există o copie de rezervă), utilizată de obicei înainte de OTA; dacă trebuie să dezinstalezi KernelSU, utilizează „Dezinstalare permanentă”.
- Instalare
- Instalare reușită
- Instalarea a eșuat
- Salvează Jurnale
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-ru/strings.xml b/manager/app/src/main/res/values-ru/strings.xml
deleted file mode 100644
index 91dd276f..00000000
--- a/manager/app/src/main/res/values-ru/strings.xml
+++ /dev/null
@@ -1,138 +0,0 @@
-
-
- Главная
- Не установлен
- Нажмите, чтобы установить
- Работает
- Версия: %d
- Суперпользователи: %d
-
- Модули: %d
- Не поддерживается
- KernelSU поддерживает только GKI ядра
- Ядро
- Версия менеджера
- Подпись
- Состояние SELinux
- Выключен
- Принудительный
- Разрешающий
- Неизвестно
- SU пользователь
-
- Не удалось включить модуль: %s
- Не удалось отключить модуль: %s
- Нет установленных модулей
- Модули
- Удалить
- Установить
- Установка
- Перезагрузить
- Настройки
- Мягкая перезагрузка
- Перезагрузить в Recovery
- Перезагрузить в Bootloader
- Перезагрузить в Download
- Перезагрузить в EDL
- О приложении
- Вы уверены, что хотите удалить модуль %s?
- %s удален
- Не удалось удалить: %s
- Версия
- Автор
- overlayfs недоступен, модуль не может работать!
- Обновить страницу
- Показать системные приложения
- Скрыть системные приложения
- Отправить лог
- Безопасный режим
- Перезагрузите, чтобы изменения вступили в силу
- Модули отключены, потому что они конфликтуют с Magisk!
- Узнайте о KernelSU
- https://kernelsu.org/ru_RU/guide/what-is-kernelsu.html
- Узнайте, как установить KernelSU и использовать модули
- Поддержите нас
- KernelSU был и всегда будет бесплатным и открытым проектом. Однако Вы всегда можете поддержать нас, отправив небольшое пожертвование.
- Присоединяйтесь к нашему %2$s каналу]]>
- App Profile
-
- По умолчанию
- Шаблон
- Пользовательский
- Название профиля
- Монтировать пространство имен
- Унаследованный
- Глобальный
- Индивидуальный
- Группы
- Возможности
- Контекст SELinux
- Размонтировать модули
- Не удалось обновить App Profile для %s
- Размонтировать модули по умолчанию
- Глобальное значение по умолчанию для \"Размонтировать модули\" в App Profile. При включении будут удалены все модификации модулей в системе для приложений, у которых не задан Profile.
- Включение этой опции позволит KernelSU восстанавливать любые измененные модулями файлы для данного приложения.
- Домен
- Правила
- Обновить
- Скачивание модуля: %s
- Начало скачивания: %s
- Новая версия: %s доступна, нажмите, чтобы скачать
- Принудительно остановить
- Не удалось обновить правила SELinux для %s
- Запустить
- Перезапустить
- Текущая версия KernelSU %d слишком низкая для правильной работы менеджера. Пожалуйста, обновите до версии %d или выше!
- Список изменений
- Успешный импорт
- Экспортировать в буфер обмена
- Нет локальных шаблонов для экспорта!
- Шаблон с таким id уже существует!
- Импортировать из буфера обмена
- Не удалось получить список изменений: %s
- Название
- Неверный id шаблона
- Синхронизировать онлайн-шаблоны
- Создать шаблон
- только чтение
- Импорт/Экспорт
- Не удалось сохранить шаблон
- Редактирование шаблона
- Идентификационный номер
- Шаблон профиля приложения
- Описание
- Сохранить
- Управление локальным и онлайн-шаблоном профиля приложения
- Удалить
- Буфер обмена пуст!
- Просмотр шаблона
- Проверка обновлений
- Автоматическая проверка обновлений при открытии приложения
- Не удалось выдать root!
- Открыть
- Включить отладку WebView
- Используется для отладки WebUI. Пожалуйста, включайте только при необходимости.
- Прямая установка (Рекомендуется)
- Установка в неактивный слот (После OTA)
- Далее
- Выбрать файл
- Ваше устройство будет **ПРИНУДИТЕЛЬНО** загружено в текущий неактивный слот после перезагрузки!
-\n Используйте эту опцию только после завершения OTA.
-\n Продолжить?
- Выбрать KMI
- %1$s образ раздела рекомендуется
- Минимизировать разреженный образ
- Изменить размер разреженного образа в котором находятся модули, до его фактического размера. Обратите внимание, что это может вызвать ненормальную работу модулей, поэтому используйте это только при необходимости (например, для резервного копирования)
- Удалить Временно
- Удалить KernelSU (Root и все модули) полностью и навсегда.
- Удалить Навсегда
- Временно удалить KernelSU, восстановить исходное состояние после следующей перезагрузки.
- Удалить
- Восстановить Сток образ
- Восстановить стоковый заводской образ (если существует резервная копия), обычно используется перед OTA; если вам нужно удалить KernelSU, используйте «Удалить Навсегда».
- Установка выполнена
- Установка
- Установка не выполнена
- Выбран lkm: %s
- Сохранить Журналы
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-sl/strings.xml b/manager/app/src/main/res/values-sl/strings.xml
deleted file mode 100644
index ae02e596..00000000
--- a/manager/app/src/main/res/values-sl/strings.xml
+++ /dev/null
@@ -1,106 +0,0 @@
-
-
- Klikni za namestitev
- V obdelavi
- Verzija: %d
- Superuporabniki: %d
- KernelSU podpira samo GKI kernele
- Kernel
- Verzija upravitelja
- Prstni odtis
- SELinux status
- Onemogočeno
- Neznano
- Napaka pri onemogočanju modula: %s
- Ni nameščenih modulov
- Modul
- Odmesti
- Namesti
- Namesti
- Mehki ponovni zagon
- Ponovni zagon v Recovery
- Ponovni zagon v Bootloader
- Ponovni zagon v EDL
- Ste prepričani, da želite odstraniti modul %s?
- %s je odmeščen
- Avtor
- overlayfs ni na voljo, modul ne more delovati!
- Skrij prikaz sistemskih aplikacij
- Prijavite dnevnik
- Naučite se KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- Naučite se, kako namestiti KernelSU in uporabiti module
- Glej odprto kodo na %1$s
Pridružite se našem %2$s kanalu
- Privzeto
- Predloga
- Imenski prostor vmestitve
- Podedovano
- Globalno
- Pozameznik
- Zmožnosti
- Izvrzi module
- Po privzetem izvrzi module
- Domena
- Posodobitev
- Nalaganje modula: %s
- Zaženi
- Ponovni zagon
- Dnevnik sprememb
- Predloga za aplikacijski profil
- Domov
- Moduli: %d
- Ne podpira
- SuperUporabnik
- Napaka pri omogočanju modula: %s
- Znova zaženi
- Nastavitve
- Ponovni zagon v Download
- O nas
- Verzija
- Napaka pri odmeščanju: %s
- Osveži
- Varni način
- Za uveljavitev je potreben ponovni zagon
- Prikaz sistemskih aplikacij
- Moduli so onemogočeni, ker so v konfliktu z Magiskovimi!
- Podprite nas
- Po meri
- Ime profila
- Skupine
- SELinux kontekst
- KernelSU je, in bo vedno brezplačen in odprtokoden. Kljub temu, nam lahko z donacijo pokažete, da vam je mar.
- Napaka pri posodobitvi aplikacijskega profila za %s
- Za pravilno funkionalnost upravitelja je trenutna KernelSU verzija %d prenizka. Potrebna je nadgradnja na verzijo %d ali več!
- Globalno privzeta vrednost za \"Izvrzi module\" v aplikacijskih profilih. Če je omogočena, bo to odstranilo vse sistemske modifikacije modulov za aplikacije, ki nimajo nastavljenega profila.
- Omogočanje te opcije bo dovolilo KernelSU, da obnovi vse zaradi modulov spremenjene datoteke za to aplikacijo.
- Prisilna ustavitev
- Pravila
- Začni z nalaganjem: %s
- Na voljo je nova verzija: %s, kliknite za nadgradnjo
- Napaka pri posodobitvi SELinux pravil za: %s
- Ni nameščeno
- Enforcing
- Permissive
- Ustvari predlogo
- Uredi predlogo
- Neveljaven id predloge
- Opis
- Shrani
- Odstrani
- le za branje
- id predloge že obstaja!
- Uvoz iz odložišča
- Izvoz v odložišče
- Lokalna predloga za izvoz ni bila najdena!
- Napaka pri shranjevanju predloge
- Odložišče je prazno!
- Upravljaj z lokalnimi in spletnimi predlogami za aplikacijski profil
- id
- Ime
- Ogled predloge
- Uvoz uspešen
- Sinhroniziraj predloge iz spleta
- Uvoz/Izvoz
- Napaka pri pridobivanju dnevnika sprememb: %s
- Shrani Dnevnike
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-sr/strings.xml b/manager/app/src/main/res/values-sr/strings.xml
deleted file mode 100644
index 73920b6f..00000000
--- a/manager/app/src/main/res/values-sr/strings.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
- Superkorisnici
- Moduli: %d
- Додирните да бисте инсталирали
- Почетна
- Није инсталирано
- Верзија: %d
- Ради
- Сачувај Дневнике
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-te/strings.xml b/manager/app/src/main/res/values-te/strings.xml
deleted file mode 100644
index f6095426..00000000
--- a/manager/app/src/main/res/values-te/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
- తెలియదు
- మాడ్యూల్ని ప్రారంభించడంలో విఫలమైంది: %s
- బలవంతంగా ఆపడం
- పునఃప్రారంభించండి
- మాడ్యూల్
- గురించి
- SELinux స్థితి
- హోమ్
- సూపర్యూజర్
- మాడ్యూల్ని నిలిపివేయడంలో విఫలమైంది: %s
- మాడ్యూల్ ఏదీ ఇన్స్టాల్ చేయబడలేదు
- ఇన్స్టాల్ చేయలేదు
- ఇన్స్టాల్ చేయడానికి క్లిక్ చేయండి
- పని చేస్తోంది
- వెర్షన్: %d
- సూపర్యూజర్లు: %d
- మాడ్యూల్స్: %d
- లాగ్లు సేవ్ చేయండి
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-th/strings.xml b/manager/app/src/main/res/values-th/strings.xml
deleted file mode 100644
index 50bb145e..00000000
--- a/manager/app/src/main/res/values-th/strings.xml
+++ /dev/null
@@ -1,134 +0,0 @@
-
-
- หน้าหลัก
- ยังไม่ได้ติดตั้ง
- กดเพื่อติดตั้ง
- กำลังทำงาน
- เวอร์ชั่น: %d
- เวอร์ชั่นตัวจัดการ
- สิทธิ์ผู้ใช้ขั้นสูง: %d
- โมดูล: %d
- ไม่รองรับ
- Enforcing
- รีบูตเข้าสู่โหมดกู้คืน
- ซอฟต์รีบูต
- ตอนนี้ KernelSU รองรับเคอร์เนลประเภท GKI เท่านั้น
- เคอร์เนล
- ปิดใช้งาน
- ลายนิ้วมือ
- สถานะ SELinux
- Permissive
- ไม่ทราบ
- สิทธิ์ผู้ใช้ขั้นสูง
- ล้มเหลวในการเปิดใช้งานโมดูล: %s
- ล้มเหลวในการปิดใช้งานโมดูล: %s
- ไม่มีโมดูลที่ติดตั้ง
- โมดูล
- ถอนการติดตั้ง
- ตั้งค่า
- ติดตั้ง
- ติดตั้ง
- รีบูต
- รีบูตเข้าสู่โหมด Bootloader
- เกี่ยวกับ
- รีบูตเข้าสู่โหมด Download
- รีบูตเข้าสู่โหมด EDL
- %s ถอนการติดตั้งสำเร็จ
- ล้มเหลวในการถอนการติดตั้ง: %s
- overlayfs ไม่สามารถใช้งานได้ โมดูลหยุดทำงาน!
- คุณแน่ใจว่าจะถอนการติดตั้งโมดูล %s หรือไม่\?
- ผู้สร้าง
- เวอร์ชั่น
- แสดงแอประบบ
- ซ่อนแอประบบ
- รีเฟรช
- ส่งรายงาน Log
- โหมดปลอดภัย
- รีบูตเพื่อให้มีผล
- โมดูลถูกปิดใช้งานเนื่องจากขัดแย้งกับ Magisk!
- เรียนรู้เกี่ยวกับ KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- เรียนรู้วิธีการติดตั้ง KernelSU และวิธีใช้งานโมดูลต่าง ๆ
- สนับสนุนพวกเรา
- KernelSU เป็นโอเพ่นซอร์สฟรีทั้งจากนี้และตลอดไป อย่างไรก็ตาม คุณสามารถแสดงความห่วงใยได้ด้วยการบริจาค
- ดูซอร์สโค้ดที่ %1$s
และเข้าร่วมช่อง %2$s ของเรา
- กำหนดเอง
- ค่าเริ่มต้น
- เทมเพลต
- ชื่อโปรไฟล์
- Mount เนมสเปซ
- ทั่วไป
- สืบทอด
- ส่วนบุคคล
- หมวดหมู่
- ความสามารถของแอป
- การเปิดใช้งานตัวเลือกนี้จะทำให้ KernelSU สามารถกู้คืนไฟล์ที่แก้ไขโดยโมดูลสำหรับแอปพลิเคชั่นนี้ได้
- บริบท SELinux
- Umount โมดูล
- ไม่สามารถอัปเดตโปรไฟล์แอปสำหรับ %s ได้
- Umount โมดูลตามค่าเริ่มต้น
- โดเมน
- อัปเดต
- กฎ
- กำลังดาวน์โหลดโมดูล: %s
- กำลังเริ่มดาวน์โหลด: %s
- เวอร์ชั่นใหม่: %s พร้อมใช้งาน โปรดคลิกเพื่ออัปเกรด
- บังคับหยุด
- รีสตาร์ท
- หากเปิดใช้งานค่าเริ่มต้นโดยทั่วไปสำหรับ \"Umount โมดูล\" ในโปรไฟล์แอป จะเป็นการลบการแก้ไขโมดูลทั้งหมดในระบบสำหรับแอปพลิเคชั่นที่ไม่มีการตั้งค่าโปรไฟล์
- เปิด
- ไม่สามารถอัปเดตกฎ SElinux สำหรับ: %s ได้
- KernelSU เวอร์ชั่น %d ต่ำเกินไป ทำให้ตัวจัดการไม่สามารถใช้งานได้อย่างถูกต้อง โปรดอัปเกรดเป็นเวอร์ชั่น %d หรือที่สูงกว่า!
- บันทึกการเปลี่ยนแปลง
- นำเข้าเสร็จสิ้น
- ส่งออกไปยังคลิปบอร์ด
- ไม่พบเทมเพลตในเครื่องที่จะส่งออก!
- มีไอดีเทมเพลตนี้อยู่แล้ว!
- นำเข้าจากคลิปบอร์ด
- ชื่อ
- ไอดีเทมเพลตไม่ถูกต้อง
- ซิงค์เทมเพลตออนไลน์
- สร้างเทมเพลต
- อ่านเท่านั้น
- นำเข้า/ส่งออก
- ไม่สามารถบันทึกเทมเพลต
- แก้ไขเทมเพลต
- ไอดี
- เทมเพลตโปรไฟล์แอป
- คำอธิบาย
- บันทึก
- จัดการเทมเพลตโปรไฟล์แอปในเครื่องและเทมเพลตออนไลน์
- ลบ
- คลิปบอร์ดว่างเปล่า!
- ดูเทมเพลต
- ดึงข้อมูลบันทึกการเปลี่ยนแปลงล้มเหลว: %s
- เปิด
- ไม่สามารถให้สิทธิ์รูทได้!
- ตรวจสอบการอัปเดต
- ตรวจสอบการอัปเดตโดยอัตโนมัติเมื่อเปิดแอป
- เปิดใช้งานการแก้ไขข้อบกพร่อง WebView
- เลือก KMI
- ต่อไป
- เลือกไฟล์
- ติดตั้งลงในสล็อตที่ไม่ใช้งาน (หลังจาก OTA)
- ติดตั้งโดยตรง (แนะนำ)
- แนะนำให้ใช้อิมเมจพาร์ติชั่น %1$s
- สามารถใช้เพื่อดีบัก WebUI โปรดเปิดใช้งานเมื่อจำเป็นเท่านั้น
- อุปกรณ์ของคุณจะถูก **บังคับ** ให้บูตไปยังสล็อตที่ไม่ได้ใช้งานหลังจากรีบูต!
-\nโปรดใช้ตัวเลือกนี้หลังจาก OTA เสร็จแล้วเท่านั้น
-\nดำเนินการต่อหรือไม่?
- ลดความกระจายของอิมเมจ
- ปรับขนาดความกระจายของอิมเมจในโมดูลให้เป็นขนาดจริง โปรดทราบว่านี่อาจทำให้โมดูลทำงานผิดปกติ โปรดใช้เมื่อจำเป็นเท่านั้น (เช่น การสำรองข้อมูล)
- ถอนการติดตั้งถาวร
- เรียกคืนอิมเมจดั้งเดิม
- ถอนการติดตั้ง KernelSU ชั่วคราว จะคืนค่าเป็นสถานะดั้งเดิมหลังจากรีบูตในครั้งถัดไป
- กำลังแฟลช
- แฟลชสำเร็จ
- แฟลชล้มเหลว
- เลือก lkm: %s
- ถอนการติดตั้ง
- ถอนการติดตั้งชั่วคราว
- การถอนการติดตั้ง KernelSU (การรูทและโมดูลทั้งหมด) อย่างสมบูรณ์โดยถาวร
- คืนค่าโรงงานอิมเมจดั้งเดิม (หากมีข้อมูลสำรอง) ส่วนใหญ่มักใช้ก่อนทำการ OTA ซึ่งหากคุณต้องการถอนการติดตั้ง KernelSU โปรดใช้ \"ถอนการติดตั้งถาวร\"
- บันทึกบันทึก
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-tr/strings.xml b/manager/app/src/main/res/values-tr/strings.xml
deleted file mode 100644
index ed0bcd0f..00000000
--- a/manager/app/src/main/res/values-tr/strings.xml
+++ /dev/null
@@ -1,136 +0,0 @@
-
-
- KernelSU
- Ana Sayfa
- Kurulmadı
- Kurmak için tıklayın
- Çalışıyor
- Sürüm: %d
- Süper kullanıcılar: %d
- Modüller: %d
- Desteklenmiyor
- KernelSU şimdilik sadece GKI çekirdeklerini destekliyor
- Çekirdek
- Yönetici sürümü
- Parmak izi
- SELinux durumu
- Devre dışı
- Etkin (Enforcing)
- Serbest (Permissive)
- Bilinmiyor
- Süper kullanıcı
- Modül etkinleştirilemedi: %s
- Modül devre dışı bırakılamadı: %s
- Kurulu modül yok
- Modül
- Kaldır
- Kur
- Kur
- Cihazı yeniden başlat
- Ayarlar
- Hızlı yeniden başlat
- Kurtarma modunda yeniden başlat
- Önyükleyici modunda yeniden başlat
- İndirme modunda yeniden başlat
- EDL modunda yeniden başlat
- Hakkında
- %s modülünü kaldırmak istediğinizden emin misiniz?
- %s kaldırıldı
- Kaldırma başarısız: %s
- Sürüm
- Geliştirici
- overlayfs mevcut değil, modül çalışamaz!
- Yenile
- Sistem uygulamalarını göster
- Sistem uygulamalarını gizle
- Günlük raporu gönder
- Güvenli mod
- Değişikliklerin uygulanması için cihazı yeniden başlat
- Modüller, Magisk\'tekiler ile çakıştığı için devre dışı bırakıldı!
- KernelSU\'yu öğrenin
- https://kernelsu.org/guide/what-is-kernelsu.html
- KernelSU\'nun nasıl kurulacağını ve modüllerin nasıl kullanılacağını öğrenin
- Bizi destekleyin
- KernelSU ücretsiz ve açık kaynaklı bir yazılımdır ve her zaman öyle kalacaktır. Ancak bağış yaparak bize destek olduğunuzu gösterebilirsiniz.
- %1$s adresinde kaynak kodunu görüntüleyin.
%2$s kanalımıza katılın.
- Uygulama profili
- Varsayılan
- Şablon
- Özel
- Profil adı
- Ad alanını bağla
- Kalıtsal
- Küresel
- Bireysel
- Gruplar
- Yetkinlikler
- SELinux içeriği
- Modüllerin bağlantısını kes
- %s için uygulama profili güncellenemedi.
- Mevcut KernelSU sürümü %d, yöneticinin düzgün çalışabilmesi için çok düşük. Lütfen %d sürümüne veya daha yüksek bir sürüme güncelleyin!
- Varsayılan olarak modüllerin bağlantısını kes
- Uygulama profilindeki \"Modüllerin bağlantısını kes\" seçeneği için varsayılan değer. Etkinleştirilirse, profil ayarı yapılmamış uygulamalar için modüllerin sistemde yaptığı tüm değişiklikler kaldırılacaktır.
- Bu seçeneği etkinleştirmek, KernelSU\'nun bu uygulama için modüller tarafından değiştirilen dosyaları geri yüklemesine izin verir.
- İsim alanı
- Kurallar
- Güncelle
- Modül indiriliyor: %s
- İndirme başladı: %s
- Yeni sürüm: %s mevcut, güncellemek için tıklayın
- Uygulamayı başlat
- Uygulamayı durmaya zorla
- Uygulamayı yeniden başlat
- %s için SELinux kuralları güncellenemedi.
- Değişiklik geçmişi
- Uygulama profili şablonu
- Yerel ve çevrimiçi uygulama profili şablonlarını yönetin
- Şablon oluştur
- Şablonu düzenle
- Kimlik
- Geçersiz şablon kimliği
- İsim
- Açıklama
- Kaydet
- Sil
- Şablonu görüntüle
- salt okunur
- Şablon kimliği zaten mevcut!
- İçe aktar/Dışa aktar
- Panodan içe aktar
- Panodan dışa aktar
- Dışa aktarmak için yerel şablon bulunamadı!
- Başarıyla içe aktarıldı
- Çevrimiçi şablonları senkronize et
- Şablon kaydedilemedi
- Pano boş!
- Değişiklik geçmişi alınamadı: %s
- Güncellemeleri denetle
- Uygulamayı açarken güncellemeleri otomatik denetle
- Root izni verilemedi!
- Aç
- Web Görünümü Hata Ayıklamasını Etkinleştir
- Web kullanıcı arayüzünde hata ayıklamak için kullanılabilir, lütfen yalnızca gerektiğinde etkinleştirin.
- Doğrudan Kur (Tavsiye Edilen)
- Bir Dosya Seçin
- Etkin Olmayan Yuvaya Kur (OTA\'dan Sonra)
- Cihazınız geçerli etkin olmayan yuvaya **ZORLA** yeniden başlatılacaktır!
-\nBu seçeneği yalnızca OTA tamamlandıktan sonra kullanın.
-\nDevam edilsin mi?
- Sonraki
- KMI seçin
- %1$s bölüm imajı önerilir
- Sparse imajını küçültün
- Modülün bulunduğu sparse imajını gerçek boyutuna yeniden boyutlandırın. Bunun modülün anormal çalışmasına neden olabileceğini unutmayın, bu nedenle lütfen yalnızca gerekli olduğunda kullanın (yedekleme gibi)
- Geçici Olarak Kaldır
- Kalıcı Olarak Kaldır
- Stok İmajı Geri Yükle
- KernelSU\'yu geçici olarak kaldır, bir sonraki yeniden başlatmadan sonra orijinal durumuna geri yükle.
- Kaldır
- KernelSU (Root ve tüm modüller) tamamen ve kalıcı olarak kaldırılıyor.
- Stok fabrika imajını geri yükler (eğer yedek varsa), genellikle OTA\'dan önce kullanılır; KernelSU\'yu kaldırmanız gerekiyorsa, lütfen \"Kalıcı Olarak Kaldır\" seçeneğini kullanın.
- Flaşlama başarılı
- Seçili lkm: %s
- Flaşlanıyor
- Flaşlama başarısız
- Günlükleri Kaydet
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-uk/strings.xml b/manager/app/src/main/res/values-uk/strings.xml
deleted file mode 100644
index 919ac133..00000000
--- a/manager/app/src/main/res/values-uk/strings.xml
+++ /dev/null
@@ -1,135 +0,0 @@
-
-
- Головна
- Не встановлено
- Натисніть щоб встановити
- Працює
- Версія: %d
- Суперкористувачі: %d
- Модулі: %d
- Не підтримується
- KernelSU підтримує лише GKI ядра на данний момент
- Ядро
- Версія менеджера
- Відбиток
- Статус SELinux
- Вимкнено
- Примусовий
- Дозвільний
- Невідомо
- Суперкористувач
- Не вдалося ввімкнути модуль: %s
- Не вдалося вимкнути модуль: %s
- Немає встановлених модулів
- Модулі
- Видалити
- Встановити
- Встановити
- Перезавантажити
- Налаштування
- М\'яке перезавантаження
- Перезавантажити до Recovery
- Перезавантажити до Bootloader
- Перезавантажити до Download
- Перезавантажити до EDL
- Про додаток
- Ви впевнені, що хочете видалити модуль %s?
- %s видалено
- Не вдалося видалити: %s
- Версія
- Автор
- overlayfs не доступний, модуль не може працювати!
- Освіжати(Оновити)
- Показати системні додатки
- Сховати системні додатки
- Надіслати логи
- Безпечний режим
- Перезавантажте, щоб застосувати
- Модулі вимкнено, оскільки вони конфліктують із модулями Magisk!
- Дізнайтеся про KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- Дізнайтеся, як інсталювати KernelSU і використовувати модулі
- Підтримати нас
- KernelSU є, і завжди буде безкоштовним та з відкритим кодом. Однак, якщо вам не байдуже, можете зробити невеличке пожертвування.
- Приєднуйтесь до нашого каналу %2$s]]>
- Профіль додатка
- Типовий
- Шаблон
- Власний
- Назва профілю
- Змонтувати простір імен
- Наслідуваний
- Глобальний
- Індивідуальний
- Групи
- Можливості
- Контекст SELinux
- Розмонтувати модулі
- Не вдалося оновити профіль додатка для %s
- Розмонтувати модулі за замовчуванням
- Загальне значення за замовчуванням для \"Розмонтувати модулі\" у профілях додатків. Якщо ввімкнено, буде видалено всі модифікації модулів у системі для додатків, які не мають встановленого профілю.
- Увімкнення даної опції дозволить KernelSU відновити для цього додатка будь-які файли, змінені модулями.
- Домен
- Правила
- Оновити
- Завантаження модуля: %s
- Початок завантаження: %s
- Запустити
- Примусово зупинити
- Перезапустити
- Нова версія: %s доступна, натисніть, щоб завантажити
- Не вдалося оновити правила SELinux для: %s
- Журнал змін
- Поточна версія KernelSU %d занадто низька, щоб менеджер міг працювати належним чином. Будь ласка, оновіть до версії %d або вище!
- Успішно імпортовано
- Експортувати в буфер обміну
- Неможливо знайти локальні шаблони для експорту!
- Шаблон з таким ідентифікатором вже існує!
- Імпортувати з буферу обміну
- Невдача при завантаженні списку змін: %s
- Ім\'я
- Невірний ідентифікатор шаблону
- Синхронізувати мережеві шаблони
- Створити шаблон
- Тільки читання
- Імпорт/Експорт
- Помилка при збереженні шаблону
- Редагувати шаблон
- Ідентифікатор
- Шаблон Профілю Додатку
- Опис
- Зберегти
- Керувати локальними та мережевими шаблонами профілів додатків
- Видалити
- Буфер обміну пустий!
- Переглянути шаблон
- Увімкнути налагодження WebView
- Виберіть KMI
- Далі
- Перевірка оновлень
- Автоматична перевірка оновлень під час відкриття програми
- Використовується для налагодження WebUI. Будь ласка, вмикайте тільки за потреби.
- Пряме встановлення (рекомендовано)
- Виберіть файл
- Встановлення в неактивний слот (Після OTA)
- Ваш пристрій буде **ПРИМУСОВО** завантажено в поточний неактивний слот після перезавантаження!
-\n Використовуйте цю опцію тільки після завершення OTA.
-\n Продовжити?
- %1$s образ розділу рекомендується
- Не вдалося отримати root!
- Відкрити
- Мінімізувати розріджений образ
- Змінити розмір розрідженого образу, в якому знаходяться модулі, до його фактичного розміру. Зверніть увагу, що це може спричинити ненормальну роботу модулів, тому використовуйте це лише за потреби (наприклад, для резервного копіювання)
- Тимчасово видалити
- Назавжди видалити
- Відновити Стоковий образ
- Тимчасово видалити KernelSU, відновити початковий стан після наступного перезавантаження.
- Видалити
- Прошивка
- Прошивку виконано
- Прошивка не виконана
- Обрано lkm: %s
- Видалити KernelSU (Root і всі модулі) повністю і назавжди.
- Відновити стоковий заводський образ (якщо є резервна копія), зазвичай використовується перед OTA; якщо вам потрібно видалити KernelSU, використовуйте \"Назавжди видалити\".
- Зберегти Журнали
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-v27/themes.xml b/manager/app/src/main/res/values-v27/themes.xml
deleted file mode 100644
index 325416c0..00000000
--- a/manager/app/src/main/res/values-v27/themes.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-vi/strings.xml b/manager/app/src/main/res/values-vi/strings.xml
deleted file mode 100644
index 04d87838..00000000
--- a/manager/app/src/main/res/values-vi/strings.xml
+++ /dev/null
@@ -1,135 +0,0 @@
-
-
- Hồ sơ ứng dụng
- Mặc định
- Mẫu
- Tuỳ chỉnh
- Tên hồ sơ
- Nhóm
- Không thể cập nhật Hồ sơ ứng dụng cho %s
- Ngắt mô-đun theo mặc định
- Giá trị mặc định của \"Ngắt mô-đun\" trong Cấu hình ứng dụng. Nếu bật, KernelSU sẽ khôi phục mọi tệp hệ thống đã sửa đổi bởi mô-đun cho các ứng dụng chưa thiết lập Cấu hình.
- Bật tùy chọn này sẽ khôi phục mọi tệp đã sửa đổi bởi các mô-đun cho ứng dụng này.
- Cập nhật
- Đang tải xuống mô-đun: %s
- Bắt đầu tải xuống: %s
- Phiên bản mới: %s đã có, bấm để nâng cấp
- Tìm hiểu KernelSU
- Tìm hiểu cách cài đặt KernelSU và sử dụng các mô-đun
- Hỗ trợ chúng tôi
- KernelSU sẽ luôn luôn miễn phí và mã nguồn mở. Tuy nhiên bạn có thể ủng hộ chúng tôi bằng một khoản đóng góp nhỏ.
- Tham gia kênh %2$s của chúng tôi]]>
- Các mô-đun bị vô hiệu hóa vì chúng xung đột với Magisk!
- Bạn có muốn gỡ cài đặt mô-đun %s không\?
- Nhật ký báo cáo
- Trang chủ
- Chưa cài đặt
- Nhấn để cài đặt
- Đang hoạt động
- Phiên bản: %d
- Không được hỗ trợ
- KernelSU hiện tại chỉ hỗ trợ kernel GKI
- Kernel
- Phiên bản Manager
- Fingerprint
- Trạng thái SELinux
- Vô hiệu hóa
- Thực thi
- Cho phép
- Không rõ
- SuperUser
- Không thể kích hoạt mô-đun: %s
- Không thể vô hiệu hóa mô-đun: %s
- Chưa cài đặt mô-đun nào
- Mô-đun
- Gỡ cài đặt
- Cài đặt
- Cài đặt
- Khởi động lại
- Thiết đặt
- Khởi động mềm
- Khởi động lại vào Recovery
- Khởi động lại vào Bootloader
- Khởi động lại vào Download Mode
- Khởi động lại vào EDL
- Giới thiệu
- %s được gỡ cài đặt
- Lỗi khi gỡ cài đặt: %s
- Phiên bản
- Tác giả
- overlayfs hiện không khả dụng, mô-đun không thể hoạt động!
- Làm mới
- Hiển thị ứng dụng hệ thống
- Ẩn ứng dụng hệ thống
- Chế độ an toàn
- Khởi động lại để có hiệu lực
- https://kernelsu.org/vi_VN/guide/what-is-kernelsu.html
- Số superuser: %d
- Số mô-đun: %d
- Phạm vi
- Quy định
- Khởi chạy
- Khởi động lại
- Gắn namespace
- Quyền
- Không thể cập nhật quy định SELinux cho: %s
- Buộc dừng
- Thừa hưởng
- Chung
- Riêng
- Bối cảnh SELinux
- Ngắt mô-đun
- KernelSU phiên bản %d quá thấp để trình quản lý hoạt động, hãy cập nhật lên %d hoặc mới hơn!
- Đã nhập thành công
- Xuất từ khay nhớ tạm
- Không thể tìm thấy mẫu cục bộ để xuất!
- id bản mẫu đã tồn tại!
- Nhật ký thay đổi
- Nhập từ khay nhớ tạm
- Không nạp được nhật ký thay đổi: %s
- Tên
- Id mẫu không hợp lệ
- Đồng bộ hóa các mẫu trực tuyến
- Tạo Bản Mẫu
- Nhập/Xuất
- Không lưu được mẫu
- Sửa Bản Mẫu
- Mẫu Hồ Sơ Ứng Dụng
- Mô tả
- Lưu
- Quản lý mẫu Hồ sơ Ứng dụng cục bộ và trực tuyến
- Xóa
- Clipboard trống!
- Xem Bản Mẫu
- chỉ đọc
- id
- Bật gỡ lỗi WebView
- Có thể được sử dụng để gỡ lỗi WebUI, vui lòng chỉ bật khi cần.
- Không cấp được quyền root!
- Kiểm tra cập nhật
- Tự động kiểm tra cập nhật khi mở ứng dụng
- Mở
- Cài đặt vào khe không hoạt động (Sau OTA)
- Thiết bị của bạn sẽ **BẮT BUỘC** khởi động vào khe không hoạt động hiện tại sau khi khởi động lại!
-\nChỉ sử dụng tùy chọn này sau khi OTA hoàn tất.
-\nTiếp tục?
- Tạm thời gỡ cài đặt KernelSU, khôi phục về trạng thái ban đầu sau lần khởi động lại tiếp theo.
- Chọn KMI
- Kế tiếp
- Cài đặt trực tiếp (Được khuyến nghị)
- Chọn một tệp
- Gỡ cài đặt
- Gỡ cài đặt tạm thời
- Gỡ cài đặt vĩnh viễn
- Khôi phục hình ảnh gốc
- Gỡ cài đặt KernelSU (Root và tất cả các mô-đun) hoàn toàn và vĩnh viễn.
- Khôi phục hình ảnh gốc của nhà máy (nếu có bản sao lưu), thường được sử dụng trước OTA; nếu bạn cần gỡ cài đặt KernelSU, vui lòng sử dụng \"Gỡ cài đặt vĩnh viễn\".
- Đang cài
- Cài thành công
- Cài thất bại
- Đã chọn lkm: %s
- Nên sử dụng hình ảnh phân vùng %1$s
- Giảm thiểu hình ảnh thưa thớt
- Thay đổi kích thước hình ảnh thưa nơi đặt mô-đun theo kích thước thực tế của nó. Lưu ý điều này có thể khiến module hoạt động không bình thường nên vui lòng chỉ sử dụng khi cần thiết (chẳng hạn như để sao lưu)
- Lưu Nhật Ký
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-zh-rCN/strings.xml b/manager/app/src/main/res/values-zh-rCN/strings.xml
deleted file mode 100644
index e854fb60..00000000
--- a/manager/app/src/main/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,132 +0,0 @@
-
-
- 主页
- 未安装
- 点击安装
- 工作中
- 版本: %d
- 超级用户数:%d
- 不支持
- KernelSU 现在只支持 GKI 内核
- 内核版本
- 管理器版本
- 系统指纹
- SELinux 状态
- 被禁用
- 强制执行
- 宽容模式
- 未知
- 超级用户
- 无法启用模块: %s
- 无法禁用模块: %s
- 没有安装模块
- 模块
- 卸载
- 安装
- 安装
- 重启
- 设置
- 软重启
- 重启到 Recovery
- 重启到 BootLoader
- 重启到 Download
- 重启到 EDL
- 关于
- 确定要卸载模块 %s 吗?
- %s 已卸载
- 卸载失败: %s
- 版本
- 作者
- 内核不支持 overlayfs,模块功能无法运作!
- 刷新
- 显示系统应用
- 隐藏系统应用
- 发送日志
- 安全模式
- 重启生效
- 所有模块已被禁用,因为它与 Magisk 的模块系统有冲突!
- 模块数:%d
- 了解 KernelSU
- https://kernelsu.org/zh_CN/guide/what-is-kernelsu.html
- 了解如何安装 KernelSU 以及如何开发模块
- 支持开发
- KernelSU 将保持免费开源,向开发者捐赠以表示支持。
- 加入我们的 %2$s 频道
加入我们的 QQ 频道]]>
- 默认
- 模版
- 自定义
- 名称
- 命名空间
- 继承
- 全局
- 私有
- 组
- 权能
- SELinux
- 卸载模块
- 为 %s 更新 App Profile 失败
- 当前 KernelSU 版本 %d 过低,管理器无法正常工作,请升级内核 KernelSU 版本至 %d 或以上!
- 默认卸载模块
- App Profile 中\"卸载模块\"的全局默认值,如果启用,将会为没有设置 Profile 的应用移除所有模块针对系统的修改。
- 启用后将允许 KernelSU 为本应用还原被模块修改过的文件。
- 域
- 规则
- 更新
- 正在下载模块:%s
- 开始下载:%s
- 发现新版本:%s,点击升级
- 启动
- 强制停止
- 重新启动
- 为:%s 更新翻译失败
- 更新日志
- App Profile 模版
- 管理本地和在线的 App Profile 模版
- 创建模版
- 编辑模版
- 模版 id
- 模版 id 不合法
- 名字
- 描述
- 保存
- 删除
- 查看模版
- 只读
- 模版 id 已存在!
- 导入/导出
- 从剪切板导入
- 导出到剪切板
- 没有本地模版可以导出!
- 导入成功!
- 同步在线规则
- 模版保存失败!
- 剪切板为空!
- 获取更新日志失败:%s
- 检查更新
- 在应用启动后自动检查是否有最新版
- 获取 root 失败!
- 打开
- 启用 WebView 调试
- 可用于调试 WebUI ,请仅在需要时启用。
- 直接安装(推荐)
- 选择一个文件
- 安装到未使用的槽位(OTA 后)
- 将在重启后强制切换到另一个槽位!\n注意只能在 OTA 更新完成后的重启之前使用。\n确认?
- 下一步
- 建议选择 %1$s 分区镜像
- 选择 KMI
- 最小化稀疏文件
- 将模块所在的稀疏文件镜像调整为其实际大小,注意这可能导致模块工作异常,请仅在必要时(如备份)使用
- 卸载
- 临时卸载
- 永久卸载
- 恢复原厂镜像
- 临时卸载 KernelSU,下次重启后恢复
- 完全并永久移除 KernelSU 和所有模块
- 恢复原厂镜像,一般在 OTA 前使用;如需卸载请使用“永久卸载”
- 刷写中
- 刷写完成
- 刷写失败
- 选择的 LKM :%s
- 保存日志
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-zh-rHK/strings.xml b/manager/app/src/main/res/values-zh-rHK/strings.xml
deleted file mode 100644
index 154ddac9..00000000
--- a/manager/app/src/main/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,124 +0,0 @@
-
-
- 首頁
- 未安裝
- 按一下以安裝
- 運作中
- KernelSU 版本:%d
- 超級使用者:%d 個
- 已安裝模組:%d 個
- 不支援
- KernelSU 現在僅支援 GKI 核心
- 核心
- 管理器版本
- 指紋
- SELinux 狀態
- 已停用
- 強制
- 寬鬆
- 未知
- 超級使用者
- 無法啟用模組:%s
- 無法停用模組:%s
- 尚未安裝模組
- 模組
- 解除安裝
- 安裝
- 安裝
- 重新啟動
- 設定
- 軟啟動
- 重新啟動至 Recovery
- 重新啟動至 Bootloader
- 重新啟動至 Download
- 重新啟動至 EDL
- 關於
- 您確定要解除安裝模組「%s」嗎?
- 「%s」已解除安裝
- 無法解除安裝:%s
- 版本
- 作者
- OverlayFS 無法使用,模組無法正常運作!
- 重新整理
- 顯示系統應用程式
- 隱藏系統應用程式
- 傳送記錄
- 安全模式
- 重新啟動以生效
- 模組已停用,因其與 Magisk 的模組存在衝突!
- 深入瞭解 KernelSU
- https://kernelsu.org/zh_TW/guide/what-is-kernelsu.html
- 瞭解如何安裝 KernelSU 以及如何開發模組
- 支援開發
- KernelSU 將保持免費和開源,您可以考慮向開發人員贊助以表示支持。
- 加入我們的 %2$s 頻道]]>
- 預設
- 設定檔名稱
- 範本
- 繼承
- 全域
- 功能
- 卸載模組
- 無法更新 %s 應用程式設定檔
- 規則
- 目前 KernelSU 版本 %d 過低,管理器無法正常運作。請升級至 %d 或更高版本!
- 應用程式設定檔中「解除安裝模組」的全域預設值,如果啟用,將會為沒有設定檔的應用程式移除所有模組針對系統的修改。
- 啟用此選項將允許 KernelSU 為這個應用程式還原任何被模組修改過的檔案。
- 網域
- 更新
- 自訂
- 掛載命名空間
- 個人
- 群組
- SELinux 環境
- 預設解除安裝模組
- 正在下載模組:%s
- 開始下載:%s
- 新版本:%s 已可供使用,按一下以升級
- 啟動
- 強制停止
- 重新啟動
- 無法為 %s 更新 SELinux 規則
- 變更記錄
- 成功匯出
- 導出到剪貼板
- 本地沒有模板可匯出!
- 模板 ID 已存在!
- 從剪貼簿匯入
- 獲取更新日誌失敗:%s
- 名字
- 模板 ID 無效
- 同步在線規則
- 創建模板
- 只讀
- 匯出 / 匯入
- 模板儲存失敗
- 編輯模板
- 模板 ID
- App Profile 模板
- 描述
- 儲存
- 管理本地和線上的 App Profile 模板
- 刪除
- 剪貼簿沒有內容!
- 查看模板
- 啟用 WebView 偵錯
- 可用於偵錯WebUI,請僅在需要時啟用。
- 直接安裝(建議)
- 選擇一個文件
- 安裝到非活動插槽(OTA 後)
- 重新啟動後,您的裝置將強制啟動到目前非活動插槽!
-\n僅在 OTA 完成後使用此選項。
-\n繼續?
- 下一個
- 選擇KMI
- 建議使用 %1$s 分割區映像
- 授予root權限失敗!
- 打開
- 檢查更新
- 開啟應用程式時自動檢查更新
- 最小化稀疏影像
- 將模組所在的稀疏影像調整為實際大小。 請注意,這可能會導致模組工作異常,因此請僅在必要時使用(例如備份)
- 解除安裝
- 保存日志
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values-zh-rTW/strings.xml b/manager/app/src/main/res/values-zh-rTW/strings.xml
deleted file mode 100644
index 7917ddef..00000000
--- a/manager/app/src/main/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,134 +0,0 @@
-
-
- 首頁
- 未安裝
- 按一下以安裝
- 運作中
- KernelSU 版本:%d
- 已授權 Root:%d 個
- 不支援
- KernelSU 現在僅支援 GKI 核心
- 核心
- 管理器版本
- 指紋
- SELinux 狀態
- 已停用
- 強制
- 寬鬆
- 未知
- Root 授權
- 無法啟用模組:%s
- 無法停用模組:%s
- 尚未安裝模組
- 模組
- 解除安裝
- 安裝
- 安裝
- 重新啟動
- 設定
- 軟重新啟動
- 重新啟動至 Recovery
- 重新啟動至 Bootloader
- 重新啟動至 Download
- 重新啟動至 EDL
- 關於
- 您確定要解除安裝模組「%s」嗎?
- 「%s」已解除安裝
- 無法解除安裝:%s
- 版本
- 作者
- OverlayFS 無法使用,模組無法正常運作!
- 重新整理
- 顯示系統應用程式
- 隱藏系統應用程式
- 傳送記錄
- 安全模式
- 重新啟動以生效
- 模組已停用,因其與 Magisk 的模組存在衝突!
- 已安裝模組:%d 個
- 深入瞭解 KernelSU
- https://kernelsu.org/zh_TW/guide/what-is-kernelsu.html
- 瞭解如何安裝 KernelSU 以及如何開發模組
- 支援開發
- KernelSU 將保持免費和開源,您可以考慮向開發人員贊助以表示支持。
- 加入我們的 %2$s 頻道]]>
- 卸載模組
- 無法更新 %s 應用程式設定檔
- 目前安裝的 KernelSU 版本 %d 過低,管理器無法正常工作,請升級核心 KernelSU 版本至 %d 或以上!
- 預設卸載模組
- 應用程式設定檔中「卸載模組」的全域預設值,如果啟用,將會為沒有設定檔的應用程式移除所有模組針對系統的修改。
- 啟用後將允許 KernelSU 為本應用程式還原被模組修改過的檔案。
- 預設
- 自訂
- 權限
- 規則
- 正在下載模組:%s
- 重新啟動
- 模板
- 設定檔名稱
- 掛載命名空間
- 繼承
- 全域
- 私人
- 群組
- SELinux context
- 域
- 更新
- 開始下載:%s
- 發現新版本:%s 已可供使用,按一下即可升級
- 啟動
- 強制停止
- 無法為 %s 更新 SELinux
- 變更記錄
- 模板 ID 無效
- 創建模板
- 編輯模板
- 模板 ID
- App Profile 模板
- 管理本地和線上的 App Profile 模板
- 成功匯入
- 匯出至剪貼簿
- 沒有本地模板可匯出!
- 模板 ID 已存在!
- 從剪貼簿匯入
- 獲取更新日誌失敗:%s
- 名稱
- 與線上規則同步
- 唯讀
- 匯出 / 匯入
- 模板儲存失敗
- 描述
- 儲存
- 刪除
- 剪貼簿沒有內容!
- 檢查模板
- 可用於偵錯 WebUI,請僅在需要時啟用。
- 啟用 WebView 偵錯
- 取得root失敗!
- 開啟
- 檢查更新
- 在打開App時自動檢查更新
- 選擇一個檔案
- 安裝到非使用中的槽位(在 OTA 更新後)
- 您的裝置將在下次重新啟動後強制切換到非使用中的槽位!
-\n這個選項僅在 OTA 更新完畢後使用。
-\n請問是否繼續?
- 直接安裝(建議)
- 下一步
- 選擇 KMI
- 建議使用 %1$s 分區
- 最小化模組稀疏映像
- 將模組的稀疏映像調整為其實際大小,請注意這可能導致模組工作異常,請僅在需要時(如備份)使用
- 解除安裝
- 暫時解除安裝
- 還原原廠映像
- 暫時卸載KernelSU,下次重啟後恢復原狀。
- 永久解除安裝
- 完全的(永久的)解除安裝 KernelSU(Root 和所有模組)。
- 寫入中
- 寫入完成
- 恢復原廠映像(如果有備份),通常在OTA之前使用;如果需要解除安裝KernelSU,請使用「永久解除安裝」。
- 寫入失敗
- 選擇的 LKM :%s
- 儲存日誌
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml
deleted file mode 100644
index d094969a..00000000
--- a/manager/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,134 +0,0 @@
-
-
- KernelSU
- Home
- Not installed
- Click to install
- Working
- Version: %d
- Superusers: %d
- Modules: %d
- Unsupported
- KernelSU only supports GKI kernels now
- Kernel
- Manager Version
- Fingerprint
- SELinux status
- Disabled
- Enforcing
- Permissive
- Unknown
- SuperUser
- Failed to enable module: %s
- Failed to disable module: %s
- No installed modules
- Module
- Uninstall
- Install
- Install
- Reboot
- Settings
- Soft Reboot
- Reboot to Recovery
- Reboot to Bootloader
- Reboot to Download
- Reboot to EDL
- About
- Are you sure you want to uninstall module %s?
- %s is uninstalled
- Failed to uninstall: %s
- Version
- Author
- overlayfs is not available, module cannot work!
- Refresh
- Show system apps
- Hide system apps
- Report Log
- Safe mode
- Reboot to take effect
- Modules are disabled because it is conflict with Magisk\'s!
- Learn KernelSU
- https://kernelsu.org/guide/what-is-kernelsu.html
- Learn how to install KernelSU and use modules
- Support Us
- KernelSU is, and always will be, free, and open source. You can however show us that you care by making a donation.
- Join our %2$s channel]]>
- App Profile
- Default
- Template
- Custom
- Profile name
- Mount namespace
- Inherited
- Global
- Individual
- Groups
- Capabilities
- SELinux context
- Umount modules
- Failed to update App Profile for %s
- The current KernelSU version %d is too low for the manager to function properly. Please upgrade to version %d or higher!
- Umount modules by default
- The global default value for \"Umount modules\" in App Profiles. If enabled, it will remove all module modifications to the system for applications that do not have a Profile set.
- Enabling this option will allow KernelSU to restore any modified files by the modules for this application.
- Domain
- Rules
- Update
- Downloading module: %s
- Start downloading: %s
- New version: %s is available, click to upgrade
- Launch
- Force Stop
- Restart
- Failed to update SELinux rules for: %s
- Changelog
- App Profile Template
- Manage local and online template of App Profile
- Create Template
- Edit Template
- id
- Invalid template id
- Name
- Description
- Save
- Delete
- View Template
- readonly
- template id already exists!
- Import/Export
- Import from clipboard
- Export to clipboard
- Can not find local template to export!
- Imported successfully
- Sync online templates
- Failed to save template
- Clipboard is empty!
- Fetch changelog failed: %s
- Check update
- Automatically check for updates when opening the app
- Failed to grant root!
- Open
- Enable WebView Debugging
- Can be used to debug WebUI, please enable only when needed.
- Direct Install (Recommended)
- Select a File
- Install to Inactive Slot (After OTA)
- Your device will be **FORCED** to boot to the current inactive slot after a reboot!\nOnly use this option after OTA is done.\nContinue?
- Next
- %1$s partition image is recommended
- Select KMI
- Minimize sparse image
- Resize the sparse image where the module is located to its actual size. Note that this may cause the module to work abnormally, so please only use when necessary (such as for backup)
- Uninstall
- Uninstall Temporarily
- Uninstall Permanently
- Restore Stock Image
- Temporarily uninstall KernelSU, restore to original state after next reboot.
- Uninstalling KernelSU(Root and all modules) completely and permanently.
- Restore the stock factory image (if a backup exists), usually used before OTA; if you need to uninstall KernelSU, please use \"Permanent Uninstall\".
- Flashing
- Flash success
- Flash failed
- Selected lkm: %s
- Save Logs
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/values/themes.xml b/manager/app/src/main/res/values/themes.xml
deleted file mode 100644
index 7d41d8ec..00000000
--- a/manager/app/src/main/res/values/themes.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/xml/backup_rules.xml b/manager/app/src/main/res/xml/backup_rules.xml
deleted file mode 100644
index fa0f996d..00000000
--- a/manager/app/src/main/res/xml/backup_rules.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/xml/data_extraction_rules.xml b/manager/app/src/main/res/xml/data_extraction_rules.xml
deleted file mode 100644
index 9ee9997b..00000000
--- a/manager/app/src/main/res/xml/data_extraction_rules.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/xml/filepaths.xml b/manager/app/src/main/res/xml/filepaths.xml
deleted file mode 100644
index f8a9a5c5..00000000
--- a/manager/app/src/main/res/xml/filepaths.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/manager/app/src/main/res/xml/network_security_config.xml b/manager/app/src/main/res/xml/network_security_config.xml
deleted file mode 100644
index 6dd26ccf..00000000
--- a/manager/app/src/main/res/xml/network_security_config.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
- 127.0.0.1
- 0.0.0.0
- ::1
-
-
diff --git a/manager/build.gradle.kts b/manager/build.gradle.kts
deleted file mode 100644
index 0e503df3..00000000
--- a/manager/build.gradle.kts
+++ /dev/null
@@ -1,101 +0,0 @@
-import com.android.build.api.dsl.ApplicationDefaultConfig
-import com.android.build.api.dsl.CommonExtension
-import com.android.build.gradle.api.AndroidBasePlugin
-import java.io.ByteArrayOutputStream
-
-plugins {
- alias(libs.plugins.agp.app) apply false
- alias(libs.plugins.agp.lib) apply false
- alias(libs.plugins.kotlin) apply false
- alias(libs.plugins.compose.compiler) apply false
- alias(libs.plugins.lsplugin.cmaker)
-}
-
-cmaker {
- default {
- arguments.addAll(
- arrayOf(
- "-DANDROID_STL=c++_static",
- )
- )
- val flags = arrayOf(
- "-Wno-gnu-string-literal-operator-template",
- "-Wno-c++2b-extensions",
- )
- cFlags.addAll(flags)
- cppFlags.addAll(flags)
- abiFilters("arm64-v8a", "x86_64")
- }
- buildTypes {
- if (it.name == "release") {
- arguments += "-DDEBUG_SYMBOLS_PATH=${buildDir.absolutePath}/symbols"
- }
- }
-}
-
-val androidMinSdkVersion = 26
-val androidTargetSdkVersion = 34
-val androidCompileSdkVersion = 34
-val androidBuildToolsVersion = "34.0.0"
-val androidCompileNdkVersion = "26.3.11579264"
-val androidSourceCompatibility = JavaVersion.VERSION_21
-val androidTargetCompatibility = JavaVersion.VERSION_21
-val managerVersionCode by extra(getVersionCode())
-val managerVersionName by extra(getVersionName())
-
-fun getGitCommitCount(): Int {
- val out = ByteArrayOutputStream()
- exec {
- commandLine("git", "rev-list", "--count", "HEAD")
- standardOutput = out
- }
- return out.toString().trim().toInt()
-}
-
-fun getGitDescribe(): String {
- val out = ByteArrayOutputStream()
- exec {
- commandLine("git", "describe", "--tags", "--always")
- standardOutput = out
- }
- return out.toString().trim()
-}
-
-fun getVersionCode(): Int {
- val commitCount = getGitCommitCount()
- val major = 1
- return major * 10000 + commitCount + 200
-}
-
-fun getVersionName(): String {
- return getGitDescribe()
-}
-
-subprojects {
- plugins.withType(AndroidBasePlugin::class.java) {
- extensions.configure(CommonExtension::class.java) {
- compileSdk = androidCompileSdkVersion
- ndkVersion = androidCompileNdkVersion
- buildToolsVersion = androidBuildToolsVersion
-
- defaultConfig {
- minSdk = androidMinSdkVersion
- if (this is ApplicationDefaultConfig) {
- targetSdk = androidTargetSdkVersion
- versionCode = managerVersionCode
- versionName = managerVersionName
- }
- }
-
- lint {
- abortOnError = true
- checkReleaseBuilds = false
- }
-
- compileOptions {
- sourceCompatibility = androidSourceCompatibility
- targetCompatibility = androidTargetCompatibility
- }
- }
- }
-}
\ No newline at end of file
diff --git a/manager/gradle.properties b/manager/gradle.properties
deleted file mode 100644
index 387da396..00000000
--- a/manager/gradle.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-android.experimental.enableNewResourceShrinker.preciseShrinking=true
-android.enableAppCompileTimeRClass=true
-android.useAndroidX=true
diff --git a/manager/gradle/libs.versions.toml b/manager/gradle/libs.versions.toml
deleted file mode 100644
index 039835ee..00000000
--- a/manager/gradle/libs.versions.toml
+++ /dev/null
@@ -1,78 +0,0 @@
-[versions]
-agp = "8.4.1"
-kotlin = "2.0.0"
-ksp = "2.0.0-1.0.21"
-compose-bom = "2024.05.00"
-lifecycle = "2.8.1"
-accompanist = "0.34.0"
-navigation = "2.7.7"
-activity-compose = "1.9.0"
-kotlinx-coroutines = "1.8.1"
-coil-compose = "2.6.0"
-compose-destination = "1.10.2"
-sheets-compose-dialogs = "1.3.0"
-markdown = "4.6.2"
-webkit = "1.11.0"
-appiconloader-coil = "1.5.0"
-parcelablelist = "2.0.1"
-libsu = "5.2.2"
-apksign = "1.4"
-cmaker = "1.2"
-
-[plugins]
-agp-app = { id = "com.android.application", version.ref = "agp" }
-agp-lib = { id = "com.android.library", version.ref = "agp" }
-
-kotlin = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
-
-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
-
-lsplugin-apksign = { id = "org.lsposed.lsplugin.apksign", version.ref = "apksign" }
-lsplugin-cmaker = { id = "org.lsposed.lsplugin.cmaker", version.ref = "cmaker" }
-
-[libraries]
-androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" }
-
-androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" }
-
-androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
-androidx-compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended" }
-androidx-compose-material = { group = "androidx.compose.material", name = "material" }
-androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" }
-androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" }
-androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
-androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
-androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
-
-androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" }
-androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle" }
-androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" }
-
-androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" }
-
-com-google-accompanist-drawablepainter = { group = "com.google.accompanist", name = "accompanist-drawablepainter", version.ref = "accompanist" }
-com-google-accompanist-navigation-animation = { group = "com.google.accompanist", name = "accompanist-navigation-animation", version.ref = "accompanist" }
-com-google-accompanist-systemuicontroller = { group = "com.google.accompanist", name = "accompanist-systemuicontroller", version.ref = "accompanist" }
-com-google-accompanist-webview = { group = "com.google.accompanist", name = "accompanist-webview", version.ref = "accompanist" }
-
-com-github-topjohnwu-libsu-core = { group = "com.github.topjohnwu.libsu", name = "core", version.ref = "libsu" }
-com-github-topjohnwu-libsu-service = { group = "com.github.topjohnwu.libsu", name = "service", version.ref = "libsu" }
-com-github-topjohnwu-libsu-io= { group = "com.github.topjohnwu.libsu", name = "io", version.ref = "libsu" }
-
-dev-rikka-rikkax-parcelablelist = { module = "dev.rikka.rikkax.parcelablelist:parcelablelist", version.ref = "parcelablelist" }
-
-io-coil-kt-coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil-compose" }
-
-kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
-
-me-zhanghai-android-appiconloader-coil = { group = "me.zhanghai.android.appiconloader", name = "appiconloader-coil", version.ref = "appiconloader-coil" }
-
-compose-destinations-animations-core = { group = "io.github.raamcosta.compose-destinations", name = "animations-core", version.ref = "compose-destination" }
-compose-destinations-ksp = { group = "io.github.raamcosta.compose-destinations", name = "ksp", version.ref = "compose-destination" }
-
-sheet-compose-dialogs-core = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "core", version.ref = "sheets-compose-dialogs" }
-sheet-compose-dialogs-list = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "list", version.ref = "sheets-compose-dialogs" }
-sheet-compose-dialogs-input = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "input", version.ref = "sheets-compose-dialogs" }
-
-markdown = { group = "io.noties.markwon", name = "core", version.ref = "markdown" }
\ No newline at end of file
diff --git a/manager/gradle/wrapper/gradle-wrapper.jar b/manager/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index e6441136..00000000
Binary files a/manager/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/manager/gradle/wrapper/gradle-wrapper.properties b/manager/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index b82aa23a..00000000
--- a/manager/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
-networkTimeout=10000
-validateDistributionUrl=true
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/manager/gradlew b/manager/gradlew
deleted file mode 100755
index 4b6a9cfc..00000000
--- a/manager/gradlew
+++ /dev/null
@@ -1,248 +0,0 @@
-#!/bin/sh
-#
-# Copyright © 2015-2021 the original authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-##############################################################################
-#
-# Gradle start up script for POSIX generated by Gradle.
-#
-# Important for running:
-#
-# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
-# noncompliant, but you have some other compliant shell such as ksh or
-# bash, then to run this script, type that shell name before the whole
-# command line, like:
-#
-# ksh Gradle
-#
-# Busybox and similar reduced shells will NOT work, because this script
-# requires all of these POSIX shell features:
-# * functions;
-# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
-# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
-# * compound commands having a testable exit status, especially «case»;
-# * various built-in commands including «command», «set», and «ulimit».
-#
-# Important for patching:
-#
-# (2) This script targets any POSIX shell, so it avoids extensions provided
-# by Bash, Ksh, etc; in particular arrays are avoided.
-#
-# The "traditional" practice of packing multiple parameters into a
-# space-separated string is a well documented source of bugs and security
-# problems, so this is (mostly) avoided, by progressively accumulating
-# options in "$@", and eventually passing that to Java.
-#
-# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
-# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
-# see the in-line comments for details.
-#
-# There are tweaks for specific operating systems such as AIX, CygWin,
-# Darwin, MinGW, and NonStop.
-#
-# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
-# within the Gradle project.
-#
-# You can find Gradle at https://github.com/gradle/gradle/.
-#
-##############################################################################
-
-# Attempt to set APP_HOME
-
-# Resolve links: $0 may be a link
-app_path=$0
-
-# Need this for daisy-chained symlinks.
-while
- APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
- [ -h "$app_path" ]
-do
- ls=$( ls -ld "$app_path" )
- link=${ls#*' -> '}
- case $link in #(
- /*) app_path=$link ;; #(
- *) app_path=$APP_HOME$link ;;
- esac
-done
-
-# This is normally unused
-# shellcheck disable=SC2034
-APP_BASE_NAME=${0##*/}
-# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD=maximum
-
-warn () {
- echo "$*"
-} >&2
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-} >&2
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "$( uname )" in #(
- CYGWIN* ) cygwin=true ;; #(
- Darwin* ) darwin=true ;; #(
- MSYS* | MINGW* ) msys=true ;; #(
- NONSTOP* ) nonstop=true ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD=$JAVA_HOME/jre/sh/java
- else
- JAVACMD=$JAVA_HOME/bin/java
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD=java
- if ! command -v java >/dev/null 2>&1
- then
- die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-fi
-
-# Increase the maximum file descriptors if we can.
-if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
- case $MAX_FD in #(
- max*)
- # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC2039,SC3045
- MAX_FD=$( ulimit -H -n ) ||
- warn "Could not query maximum file descriptor limit"
- esac
- case $MAX_FD in #(
- '' | soft) :;; #(
- *)
- # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC2039,SC3045
- ulimit -n "$MAX_FD" ||
- warn "Could not set maximum file descriptor limit to $MAX_FD"
- esac
-fi
-
-# Collect all arguments for the java command, stacking in reverse order:
-# * args from the command line
-# * the main class name
-# * -classpath
-# * -D...appname settings
-# * --module-path (only if needed)
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if "$cygwin" || "$msys" ; then
- APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
-
- JAVACMD=$( cygpath --unix "$JAVACMD" )
-
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- for arg do
- if
- case $arg in #(
- -*) false ;; # don't mess with options #(
- /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
- [ -e "$t" ] ;; #(
- *) false ;;
- esac
- then
- arg=$( cygpath --path --ignore --mixed "$arg" )
- fi
- # Roll the args list around exactly as many times as the number of
- # args, so each arg winds up back in the position where it started, but
- # possibly modified.
- #
- # NB: a `for` loop captures its iteration list before it begins, so
- # changing the positional parameters here affects neither the number of
- # iterations, nor the values presented in `arg`.
- shift # remove old arg
- set -- "$@" "$arg" # push replacement arg
- done
-fi
-
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
-# and any embedded shellness will be escaped.
-# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
-# treated as '${Hostname}' itself on the command line.
-
-set -- \
- "-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
- "$@"
-
-# Stop when "xargs" is not available.
-if ! command -v xargs >/dev/null 2>&1
-then
- die "xargs is not available"
-fi
-
-# Use "xargs" to parse quoted args.
-#
-# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
-#
-# In Bash we could simply go:
-#
-# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
-# set -- "${ARGS[@]}" "$@"
-#
-# but POSIX shell has neither arrays nor command substitution, so instead we
-# post-process each arg (as a line of input to sed) to backslash-escape any
-# character that might be a shell metacharacter, then use eval to reverse
-# that process (while maintaining the separation between arguments), and wrap
-# the whole thing up as a single "set" statement.
-#
-# This will of course break if any of these variables contains a newline or
-# an unmatched quote.
-#
-
-eval "set -- $(
- printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
- xargs -n1 |
- sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
- tr '\n' ' '
- )" '"$@"'
-
-exec "$JAVACMD" "$@"
diff --git a/manager/gradlew.bat b/manager/gradlew.bat
deleted file mode 100644
index 25da30db..00000000
--- a/manager/gradlew.bat
+++ /dev/null
@@ -1,92 +0,0 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%"=="" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%"=="" set DIRNAME=.
-@rem This is normally unused
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if %ERRORLEVEL% equ 0 goto execute
-
-echo. 1>&2
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
-echo. 1>&2
-echo Please set the JAVA_HOME variable in your environment to match the 1>&2
-echo location of your Java installation. 1>&2
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo. 1>&2
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
-echo. 1>&2
-echo Please set the JAVA_HOME variable in your environment to match the 1>&2
-echo location of your Java installation. 1>&2
-
-goto fail
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
-
-:end
-@rem End local scope for the variables with windows NT shell
-if %ERRORLEVEL% equ 0 goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-set EXIT_CODE=%ERRORLEVEL%
-if %EXIT_CODE% equ 0 set EXIT_CODE=1
-if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
-exit /b %EXIT_CODE%
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/manager/settings.gradle.kts b/manager/settings.gradle.kts
deleted file mode 100644
index 2230bf48..00000000
--- a/manager/settings.gradle.kts
+++ /dev/null
@@ -1,21 +0,0 @@
-@file:Suppress("UnstableApiUsage")
-
-enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
-
-pluginManagement {
- repositories {
- google()
- mavenCentral()
- }
-}
-
-dependencyResolutionManagement {
- repositories {
- google()
- mavenCentral()
- maven("https://jitpack.io")
- }
-}
-
-rootProject.name = "KernelSU"
-include(":app")
diff --git a/manager/sign.example.properties b/manager/sign.example.properties
deleted file mode 100644
index bc70a60c..00000000
--- a/manager/sign.example.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-KEYSTORE_FILE=
-KEYSTORE_PASSWORD=
-KEY_ALIAS=
-KEY_PASSWORD=
diff --git a/userspace/ksud/.gitignore b/userspace/ksud/.gitignore
deleted file mode 100644
index 3c71873d..00000000
--- a/userspace/ksud/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/target
-.cargo/
\ No newline at end of file
diff --git a/userspace/ksud/Cargo.lock b/userspace/ksud/Cargo.lock
deleted file mode 100644
index e39414ab..00000000
--- a/userspace/ksud/Cargo.lock
+++ /dev/null
@@ -1,1860 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "addr2line"
-version = "0.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
-dependencies = [
- "gimli",
-]
-
-[[package]]
-name = "adler"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-
-[[package]]
-name = "adler32"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
-
-[[package]]
-name = "aes"
-version = "0.8.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
-dependencies = [
- "cfg-if 1.0.0",
- "cipher",
- "cpufeatures",
-]
-
-[[package]]
-name = "aho-corasick"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "android-properties"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
-
-[[package]]
-name = "android-tzdata"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
-
-[[package]]
-name = "android_log-sys"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937"
-
-[[package]]
-name = "android_logger"
-version = "0.13.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f"
-dependencies = [
- "android_log-sys",
- "env_logger 0.10.2",
- "log",
- "once_cell",
-]
-
-[[package]]
-name = "android_system_properties"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "anstream"
-version = "0.6.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
-dependencies = [
- "anstyle",
- "anstyle-parse",
- "anstyle-query",
- "anstyle-wincon",
- "colorchoice",
- "is_terminal_polyfill",
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
-
-[[package]]
-name = "anstyle-parse"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
-dependencies = [
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle-query"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5"
-dependencies = [
- "windows-sys",
-]
-
-[[package]]
-name = "anstyle-wincon"
-version = "3.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
-dependencies = [
- "anstyle",
- "windows-sys",
-]
-
-[[package]]
-name = "anyhow"
-version = "1.0.86"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
-
-[[package]]
-name = "arbitrary"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
-dependencies = [
- "derive_arbitrary",
-]
-
-[[package]]
-name = "async-trait"
-version = "0.1.80"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.65",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
-
-[[package]]
-name = "backtrace"
-version = "0.3.71"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
-dependencies = [
- "addr2line",
- "cc",
- "cfg-if 1.0.0",
- "libc",
- "miniz_oxide",
- "object",
- "rustc-demangle",
-]
-
-[[package]]
-name = "base64ct"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
-
-[[package]]
-name = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "bitflags"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
-
-[[package]]
-name = "block-buffer"
-version = "0.10.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "bumpalo"
-version = "3.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
-
-[[package]]
-name = "byteorder"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
-
-[[package]]
-name = "bytes"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
-
-[[package]]
-name = "bzip2"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
-dependencies = [
- "bzip2-sys",
- "libc",
-]
-
-[[package]]
-name = "bzip2-sys"
-version = "0.1.11+1.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
-dependencies = [
- "cc",
- "libc",
- "pkg-config",
-]
-
-[[package]]
-name = "cc"
-version = "1.0.98"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f"
-dependencies = [
- "jobserver",
- "libc",
- "once_cell",
-]
-
-[[package]]
-name = "cfg-if"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "chrono"
-version = "0.4.38"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
-dependencies = [
- "android-tzdata",
- "iana-time-zone",
- "js-sys",
- "num-traits",
- "wasm-bindgen",
- "windows-targets",
-]
-
-[[package]]
-name = "cipher"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
-dependencies = [
- "crypto-common",
- "inout",
-]
-
-[[package]]
-name = "clap"
-version = "4.5.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
-dependencies = [
- "clap_builder",
- "clap_derive",
-]
-
-[[package]]
-name = "clap_builder"
-version = "4.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
-dependencies = [
- "anstream",
- "anstyle",
- "clap_lex",
- "strsim",
-]
-
-[[package]]
-name = "clap_derive"
-version = "4.5.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn 2.0.65",
-]
-
-[[package]]
-name = "clap_lex"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
-
-[[package]]
-name = "colorchoice"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
-
-[[package]]
-name = "const_format"
-version = "0.2.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673"
-dependencies = [
- "const_format_proc_macros",
-]
-
-[[package]]
-name = "const_format_proc_macros"
-version = "0.2.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-xid",
-]
-
-[[package]]
-name = "constant_time_eq"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
-
-[[package]]
-name = "core-foundation-sys"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
-
-[[package]]
-name = "cpufeatures"
-version = "0.2.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "crc32fast"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
-dependencies = [
- "cfg-if 1.0.0",
-]
-
-[[package]]
-name = "crossbeam"
-version = "0.8.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"
-dependencies = [
- "crossbeam-channel",
- "crossbeam-deque",
- "crossbeam-epoch",
- "crossbeam-queue",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-channel"
-version = "0.5.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
-dependencies = [
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-deque"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
-dependencies = [
- "crossbeam-epoch",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-epoch"
-version = "0.9.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
-dependencies = [
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-queue"
-version = "0.3.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
-dependencies = [
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
-
-[[package]]
-name = "crypto-common"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
-dependencies = [
- "generic-array",
- "typenum",
-]
-
-[[package]]
-name = "deflate64"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83ace6c86376be0b6cdcf3fb41882e81d94b31587573d1cfa9d01cd06bba210d"
-
-[[package]]
-name = "deranged"
-version = "0.3.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
-dependencies = [
- "powerfmt",
-]
-
-[[package]]
-name = "derive-new"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.65",
-]
-
-[[package]]
-name = "derive_arbitrary"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.65",
-]
-
-[[package]]
-name = "digest"
-version = "0.10.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
-dependencies = [
- "block-buffer",
- "crypto-common",
- "subtle",
-]
-
-[[package]]
-name = "displaydoc"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.65",
-]
-
-[[package]]
-name = "either"
-version = "1.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
-
-[[package]]
-name = "encoding_rs"
-version = "0.8.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
-dependencies = [
- "cfg-if 1.0.0",
-]
-
-[[package]]
-name = "env_filter"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
-dependencies = [
- "log",
-]
-
-[[package]]
-name = "env_logger"
-version = "0.10.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
-dependencies = [
- "log",
- "regex",
-]
-
-[[package]]
-name = "env_logger"
-version = "0.11.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
-dependencies = [
- "env_filter",
- "log",
-]
-
-[[package]]
-name = "equivalent"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
-
-[[package]]
-name = "errno"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "errno"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
-dependencies = [
- "libc",
- "windows-sys",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "extattr"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b59f8a77817ff1b795adafc535941bdf664184f5f95e0b6d1d77dd6d12815dc"
-dependencies = [
- "bitflags 1.3.2",
- "errno 0.2.8",
- "libc",
-]
-
-[[package]]
-name = "flate2"
-version = "1.0.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
-dependencies = [
- "crc32fast",
- "miniz_oxide",
-]
-
-[[package]]
-name = "fuchsia-cprng"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
-
-[[package]]
-name = "generic-array"
-version = "0.14.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
-dependencies = [
- "typenum",
- "version_check",
-]
-
-[[package]]
-name = "getopts"
-version = "0.2.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
-dependencies = [
- "unicode-width",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
-dependencies = [
- "cfg-if 1.0.0",
- "libc",
- "wasi",
-]
-
-[[package]]
-name = "gimli"
-version = "0.28.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
-
-[[package]]
-name = "hashbrown"
-version = "0.14.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
-
-[[package]]
-name = "heck"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
-[[package]]
-name = "hmac"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
-dependencies = [
- "digest",
-]
-
-[[package]]
-name = "hole-punch"
-version = "0.0.4-alpha.0"
-source = "git+https://github.com/tiann/hole-punch#11ab7a61bfb98682b72fd7f58a47d8e5d997328e"
-dependencies = [
- "cfg-if 0.1.10",
- "errno 0.2.8",
- "libc",
- "memmap",
- "thiserror",
- "winapi",
-]
-
-[[package]]
-name = "home"
-version = "0.5.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
-dependencies = [
- "windows-sys",
-]
-
-[[package]]
-name = "humansize"
-version = "2.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7"
-dependencies = [
- "libm",
-]
-
-[[package]]
-name = "iana-time-zone"
-version = "0.1.60"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
-dependencies = [
- "android_system_properties",
- "core-foundation-sys",
- "iana-time-zone-haiku",
- "js-sys",
- "wasm-bindgen",
- "windows-core",
-]
-
-[[package]]
-name = "iana-time-zone-haiku"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
-dependencies = [
- "cc",
-]
-
-[[package]]
-name = "include-flate"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2e11569346406931d20276cc460215ee2826e7cad43aa986999cb244dd7adb0"
-dependencies = [
- "include-flate-codegen-exports",
- "lazy_static",
- "libflate",
-]
-
-[[package]]
-name = "include-flate-codegen"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a7d6e1419fa3129eb0802b4c99603c0d425c79fb5d76191d5a20d0ab0d664e8"
-dependencies = [
- "libflate",
- "proc-macro-hack",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "include-flate-codegen-exports"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75657043ffe3d8280f1cb8aef0f505532b392ed7758e0baeac22edadcee31a03"
-dependencies = [
- "include-flate-codegen",
- "proc-macro-hack",
-]
-
-[[package]]
-name = "indexmap"
-version = "2.2.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
-dependencies = [
- "equivalent",
- "hashbrown",
-]
-
-[[package]]
-name = "inout"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "is_executable"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "is_terminal_polyfill"
-version = "1.70.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
-
-[[package]]
-name = "itoa"
-version = "1.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
-
-[[package]]
-name = "java-properties"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37bf6f484471c451f2b51eabd9e66b3fa7274550c5ec4b6c3d6070840945117f"
-dependencies = [
- "encoding_rs",
- "lazy_static",
- "regex",
-]
-
-[[package]]
-name = "jobserver"
-version = "0.1.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "js-sys"
-version = "0.3.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
-dependencies = [
- "wasm-bindgen",
-]
-
-[[package]]
-name = "jwalk"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2735847566356cd2179a2a38264839308f7079fa96e6bd5a42d740460e003c56"
-dependencies = [
- "crossbeam",
- "rayon",
-]
-
-[[package]]
-name = "ksud"
-version = "0.1.0"
-dependencies = [
- "android-properties",
- "android_logger",
- "anyhow",
- "chrono",
- "clap",
- "const_format",
- "derive-new",
- "encoding_rs",
- "env_logger 0.11.3",
- "extattr",
- "getopts",
- "hole-punch",
- "humansize",
- "is_executable",
- "java-properties",
- "jwalk",
- "libc",
- "log",
- "loopdev",
- "nom",
- "procfs",
- "regex",
- "retry",
- "rust-embed",
- "rustix 0.38.30",
- "serde",
- "serde_json",
- "sha1",
- "sha256",
- "tempdir",
- "which",
- "zip 2.1.2",
- "zip-extensions",
-]
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
-[[package]]
-name = "libc"
-version = "0.2.155"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
-
-[[package]]
-name = "libflate"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ff4ae71b685bbad2f2f391fe74f6b7659a34871c08b210fdc039e43bee07d18"
-dependencies = [
- "adler32",
- "crc32fast",
- "libflate_lz77",
-]
-
-[[package]]
-name = "libflate_lz77"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a52d3a8bfc85f250440e4424db7d857e241a3aebbbe301f3eb606ab15c39acbf"
-dependencies = [
- "rle-decode-fast",
-]
-
-[[package]]
-name = "libm"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.4.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
-
-[[package]]
-name = "lockfree-object-pool"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
-
-[[package]]
-name = "log"
-version = "0.4.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
-
-[[package]]
-name = "loopdev"
-version = "0.5.0"
-source = "git+https://github.com/Kernel-SU/loopdev#7a921f8d966477a645b1188732fac486c71a68ef"
-dependencies = [
- "errno 0.2.8",
- "libc",
-]
-
-[[package]]
-name = "memchr"
-version = "2.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
-
-[[package]]
-name = "memmap"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
-dependencies = [
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
-[[package]]
-name = "miniz_oxide"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae"
-dependencies = [
- "adler",
-]
-
-[[package]]
-name = "nom"
-version = "7.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
-[[package]]
-name = "num-conv"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
-
-[[package]]
-name = "num-traits"
-version = "0.2.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "object"
-version = "0.32.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
-
-[[package]]
-name = "password-hash"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
-dependencies = [
- "base64ct",
- "rand_core 0.6.4",
- "subtle",
-]
-
-[[package]]
-name = "pbkdf2"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
-dependencies = [
- "digest",
- "hmac",
- "password-hash",
- "sha2",
-]
-
-[[package]]
-name = "pin-project-lite"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
-
-[[package]]
-name = "pkg-config"
-version = "0.3.30"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
-
-[[package]]
-name = "powerfmt"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
-
-[[package]]
-name = "proc-macro-hack"
-version = "0.5.20+deprecated"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.83"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "procfs"
-version = "0.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4"
-dependencies = [
- "bitflags 2.5.0",
- "chrono",
- "flate2",
- "hex",
- "lazy_static",
- "procfs-core",
- "rustix 0.38.34",
-]
-
-[[package]]
-name = "procfs-core"
-version = "0.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29"
-dependencies = [
- "bitflags 2.5.0",
- "chrono",
- "hex",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "rand"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
-dependencies = [
- "fuchsia-cprng",
- "libc",
- "rand_core 0.3.1",
- "rdrand",
- "winapi",
-]
-
-[[package]]
-name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
-dependencies = [
- "rand_core 0.4.2",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom",
-]
-
-[[package]]
-name = "rayon"
-version = "1.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
-dependencies = [
- "either",
- "rayon-core",
-]
-
-[[package]]
-name = "rayon-core"
-version = "1.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
-dependencies = [
- "crossbeam-deque",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "rdrand"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
-dependencies = [
- "rand_core 0.3.1",
-]
-
-[[package]]
-name = "regex"
-version = "1.10.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-automata",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
-
-[[package]]
-name = "remove_dir_all"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "retry"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9166d72162de3575f950507683fac47e30f6f2c3836b71b7fbc61aa517c9c5f4"
-dependencies = [
- "rand 0.8.5",
-]
-
-[[package]]
-name = "rle-decode-fast"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
-
-[[package]]
-name = "rust-embed"
-version = "8.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19549741604902eb99a7ed0ee177a0663ee1eda51a29f71401f166e47e77806a"
-dependencies = [
- "include-flate",
- "rust-embed-impl",
- "rust-embed-utils",
- "walkdir",
-]
-
-[[package]]
-name = "rust-embed-impl"
-version = "8.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb9f96e283ec64401f30d3df8ee2aaeb2561f34c824381efa24a35f79bf40ee4"
-dependencies = [
- "proc-macro2",
- "quote",
- "rust-embed-utils",
- "syn 2.0.65",
- "walkdir",
-]
-
-[[package]]
-name = "rust-embed-utils"
-version = "8.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38c74a686185620830701348de757fd36bef4aa9680fd23c49fc539ddcc1af32"
-dependencies = [
- "sha2",
- "walkdir",
-]
-
-[[package]]
-name = "rustc-demangle"
-version = "0.1.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
-
-[[package]]
-name = "rustix"
-version = "0.38.30"
-source = "git+https://github.com/Kernel-SU/rustix.git?branch=main#0e270bce2d97466be6b987bb5f7ea5b1e8d84969"
-dependencies = [
- "bitflags 2.5.0",
- "errno 0.3.9",
- "itoa",
- "libc",
- "linux-raw-sys",
- "once_cell",
- "windows-sys",
-]
-
-[[package]]
-name = "rustix"
-version = "0.38.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
-dependencies = [
- "bitflags 2.5.0",
- "errno 0.3.9",
- "libc",
- "linux-raw-sys",
- "windows-sys",
-]
-
-[[package]]
-name = "ryu"
-version = "1.0.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
-
-[[package]]
-name = "same-file"
-version = "1.0.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
-dependencies = [
- "winapi-util",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.202"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.202"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.65",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.117"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
-dependencies = [
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "sha1"
-version = "0.10.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
-dependencies = [
- "cfg-if 1.0.0",
- "cpufeatures",
- "digest",
-]
-
-[[package]]
-name = "sha2"
-version = "0.10.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
-dependencies = [
- "cfg-if 1.0.0",
- "cpufeatures",
- "digest",
-]
-
-[[package]]
-name = "sha256"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18278f6a914fa3070aa316493f7d2ddfb9ac86ebc06fa3b83bffda487e9065b0"
-dependencies = [
- "async-trait",
- "bytes",
- "hex",
- "sha2",
- "tokio",
-]
-
-[[package]]
-name = "simd-adler32"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
-
-[[package]]
-name = "strsim"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
-
-[[package]]
-name = "subtle"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
-
-[[package]]
-name = "syn"
-version = "1.0.109"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.65"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "tempdir"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
-dependencies = [
- "rand 0.4.6",
- "remove_dir_all",
-]
-
-[[package]]
-name = "thiserror"
-version = "1.0.61"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "1.0.61"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.65",
-]
-
-[[package]]
-name = "time"
-version = "0.3.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
-dependencies = [
- "deranged",
- "num-conv",
- "powerfmt",
- "serde",
- "time-core",
-]
-
-[[package]]
-name = "time-core"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
-
-[[package]]
-name = "tokio"
-version = "1.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
-dependencies = [
- "backtrace",
- "bytes",
- "pin-project-lite",
-]
-
-[[package]]
-name = "typenum"
-version = "1.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
-
-[[package]]
-name = "unicode-width"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
-
-[[package]]
-name = "utf8parse"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
-
-[[package]]
-name = "version_check"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-
-[[package]]
-name = "walkdir"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
-dependencies = [
- "same-file",
- "winapi-util",
-]
-
-[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
-dependencies = [
- "cfg-if 1.0.0",
- "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
-dependencies = [
- "bumpalo",
- "log",
- "once_cell",
- "proc-macro2",
- "quote",
- "syn 2.0.65",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
-dependencies = [
- "quote",
- "wasm-bindgen-macro-support",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.65",
- "wasm-bindgen-backend",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.92"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
-
-[[package]]
-name = "which"
-version = "6.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7"
-dependencies = [
- "either",
- "home",
- "rustix 0.38.34",
- "winsafe",
-]
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-util"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
-dependencies = [
- "windows-sys",
-]
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "windows-core"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
-dependencies = [
- "windows-targets",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
-dependencies = [
- "windows-targets",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
-dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
-
-[[package]]
-name = "winsafe"
-version = "0.0.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
-
-[[package]]
-name = "zip"
-version = "0.6.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
-dependencies = [
- "aes",
- "byteorder",
- "bzip2",
- "constant_time_eq",
- "crc32fast",
- "crossbeam-utils",
- "flate2",
- "hmac",
- "pbkdf2",
- "sha1",
- "time",
- "zstd 0.11.2+zstd.1.5.2",
-]
-
-[[package]]
-name = "zip"
-version = "2.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "098d5d7737fb0b70814faa73c17df84f047d38dd31d13bbf2ec3fb354b5abf45"
-dependencies = [
- "arbitrary",
- "bzip2",
- "crc32fast",
- "crossbeam-utils",
- "deflate64",
- "displaydoc",
- "flate2",
- "indexmap",
- "memchr",
- "thiserror",
- "time",
- "zopfli",
- "zstd 0.13.1",
-]
-
-[[package]]
-name = "zip-extensions"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c865b4f0f43f22d1bd7ba05479b5c003e0e98e9090c3a2e4280b5eace59f62df"
-dependencies = [
- "zip 0.6.6",
-]
-
-[[package]]
-name = "zopfli"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
-dependencies = [
- "bumpalo",
- "crc32fast",
- "lockfree-object-pool",
- "log",
- "once_cell",
- "simd-adler32",
-]
-
-[[package]]
-name = "zstd"
-version = "0.11.2+zstd.1.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
-dependencies = [
- "zstd-safe 5.0.2+zstd.1.5.2",
-]
-
-[[package]]
-name = "zstd"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a"
-dependencies = [
- "zstd-safe 7.1.0",
-]
-
-[[package]]
-name = "zstd-safe"
-version = "5.0.2+zstd.1.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
-dependencies = [
- "libc",
- "zstd-sys",
-]
-
-[[package]]
-name = "zstd-safe"
-version = "7.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a"
-dependencies = [
- "zstd-sys",
-]
-
-[[package]]
-name = "zstd-sys"
-version = "2.0.10+zstd.1.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa"
-dependencies = [
- "cc",
- "pkg-config",
-]
diff --git a/userspace/ksud/Cargo.toml b/userspace/ksud/Cargo.toml
deleted file mode 100644
index b5486ada..00000000
--- a/userspace/ksud/Cargo.toml
+++ /dev/null
@@ -1,63 +0,0 @@
-[package]
-name = "ksud"
-version = "0.1.0"
-edition = "2021"
-rust-version = "1.77.2"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-anyhow = "1"
-clap = { version = "4", features = ["derive"] }
-const_format = "0.2"
-zip = { version = "2", features = [
- "deflate",
- "deflate64",
- "bzip2",
- "time",
- "zstd",
-], default-features = false }
-zip-extensions = "0.7"
-java-properties = "2"
-log = "0.4"
-env_logger = { version = "0.11", default-features = false }
-serde = { version = "1" }
-serde_json = "1"
-regex = "1"
-encoding_rs = "0.8"
-retry = "2"
-humansize = "2"
-libc = "0.2"
-extattr = "1"
-jwalk = "0.8"
-is_executable = "1"
-nom = "7"
-derive-new = "0.6"
-rust-embed = { version = "8", features = [
- "debug-embed",
- "compression", # must clean build after updating binaries
-] }
-which = "6"
-getopts = "0.2"
-sha256 = "1"
-sha1 = "0.10"
-tempdir = "0.3"
-chrono = "0.4"
-hole-punch = { git = "https://github.com/tiann/hole-punch" }
-
-[target.'cfg(any(target_os = "android", target_os = "linux"))'.dependencies]
-rustix = { git = "https://github.com/Kernel-SU/rustix.git", branch = "main", features = [
- "all-apis",
-] }
-# some android specific dependencies which compiles under unix are also listed here for convenience of coding
-android-properties = { version = "0.2", features = ["bionic-deprecated"] }
-procfs = "0.16"
-loopdev = { git = "https://github.com/Kernel-SU/loopdev" }
-
-[target.'cfg(target_os = "android")'.dependencies]
-android_logger = "0.13"
-
-[profile.release]
-strip = true
-opt-level = "z"
-lto = true
\ No newline at end of file
diff --git a/userspace/ksud/bin/.gitignore b/userspace/ksud/bin/.gitignore
deleted file mode 100644
index 1464b7ed..00000000
--- a/userspace/ksud/bin/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-**/*.ko
\ No newline at end of file
diff --git a/userspace/ksud/bin/aarch64/bootctl b/userspace/ksud/bin/aarch64/bootctl
deleted file mode 100644
index cf5c6136..00000000
Binary files a/userspace/ksud/bin/aarch64/bootctl and /dev/null differ
diff --git a/userspace/ksud/bin/aarch64/busybox b/userspace/ksud/bin/aarch64/busybox
deleted file mode 100755
index 1ddf3f73..00000000
Binary files a/userspace/ksud/bin/aarch64/busybox and /dev/null differ
diff --git a/userspace/ksud/bin/aarch64/ksuinit b/userspace/ksud/bin/aarch64/ksuinit
deleted file mode 100755
index 8d3ba057..00000000
Binary files a/userspace/ksud/bin/aarch64/ksuinit and /dev/null differ
diff --git a/userspace/ksud/bin/aarch64/resetprop b/userspace/ksud/bin/aarch64/resetprop
deleted file mode 100644
index 1155e5f4..00000000
Binary files a/userspace/ksud/bin/aarch64/resetprop and /dev/null differ
diff --git a/userspace/ksud/bin/x86_64/busybox b/userspace/ksud/bin/x86_64/busybox
deleted file mode 100755
index 2557c61d..00000000
Binary files a/userspace/ksud/bin/x86_64/busybox and /dev/null differ
diff --git a/userspace/ksud/bin/x86_64/ksuinit b/userspace/ksud/bin/x86_64/ksuinit
deleted file mode 100755
index 9517baf9..00000000
Binary files a/userspace/ksud/bin/x86_64/ksuinit and /dev/null differ
diff --git a/userspace/ksud/bin/x86_64/resetprop b/userspace/ksud/bin/x86_64/resetprop
deleted file mode 100644
index dc4d9910..00000000
Binary files a/userspace/ksud/bin/x86_64/resetprop and /dev/null differ
diff --git a/userspace/ksud/build.rs b/userspace/ksud/build.rs
deleted file mode 100644
index 021418ac..00000000
--- a/userspace/ksud/build.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-use std::env;
-use std::fs::File;
-use std::io::Write;
-use std::path::Path;
-use std::process::Command;
-
-fn get_git_version() -> Result<(u32, String), std::io::Error> {
- let output = Command::new("git")
- .args(["rev-list", "--count", "HEAD"])
- .output()?;
-
- let output = output.stdout;
- let version_code = String::from_utf8(output).expect("Failed to read git count stdout");
- let version_code: u32 = version_code
- .trim()
- .parse()
- .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Failed to parse git count"))?;
- let version_code = 10000 + 200 + version_code; // For historical reasons
-
- let version_name = String::from_utf8(
- Command::new("git")
- .args(["describe", "--tags", "--always"])
- .output()?
- .stdout,
- )
- .map_err(|_| {
- std::io::Error::new(
- std::io::ErrorKind::Other,
- "Failed to read git describe stdout",
- )
- })?;
- let version_name = version_name.trim_start_matches('v').to_string();
- Ok((version_code, version_name))
-}
-
-fn main() {
- let (code, name) = match get_git_version() {
- Ok((code, name)) => (code, name),
- Err(_) => {
- // show warning if git is not installed
- println!("cargo:warning=Failed to get git version, using 0.0.0");
- (0, "0.0.0".to_string())
- }
- };
- let out_dir = env::var("OUT_DIR").expect("Failed to get $OUT_DIR");
- let out_dir = Path::new(&out_dir);
- File::create(Path::new(out_dir).join("VERSION_CODE"))
- .expect("Failed to create VERSION_CODE")
- .write_all(code.to_string().as_bytes())
- .expect("Failed to write VERSION_CODE");
-
- File::create(Path::new(out_dir).join("VERSION_NAME"))
- .expect("Failed to create VERSION_NAME")
- .write_all(name.trim().as_bytes())
- .expect("Failed to write VERSION_NAME");
-}
diff --git a/userspace/ksud/src/apk_sign.rs b/userspace/ksud/src/apk_sign.rs
deleted file mode 100644
index 6d047cca..00000000
--- a/userspace/ksud/src/apk_sign.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-use anyhow::{ensure, Result};
-use std::io::{Read, Seek, SeekFrom};
-
-pub fn get_apk_signature(apk: &str) -> Result<(u32, String)> {
- let mut buffer = [0u8; 0x10];
- let mut size4 = [0u8; 4];
- let mut size8 = [0u8; 8];
- let mut size_of_block = [0u8; 8];
-
- let mut f = std::fs::File::open(apk)?;
-
- let mut i = 0;
- loop {
- let mut n = [0u8; 2];
- f.seek(SeekFrom::End(-i - 2))?;
- f.read_exact(&mut n)?;
-
- let n = u16::from_le_bytes(n);
- if i64::from(n) == i {
- f.seek(SeekFrom::Current(-22))?;
- f.read_exact(&mut size4)?;
-
- if u32::from_le_bytes(size4) ^ 0xcafe_babe_u32 == 0xccfb_f1ee_u32 {
- if i > 0 {
- println!("warning: comment length is {i}");
- }
- break;
- }
- }
-
- ensure!(n != 0xffff, "not a zip file");
-
- i += 1;
- }
-
- f.seek(SeekFrom::Current(12))?;
- // offset
- f.read_exact(&mut size4)?;
- f.seek(SeekFrom::Start(u64::from(u32::from_le_bytes(size4)) - 0x18))?;
-
- f.read_exact(&mut size8)?;
- f.read_exact(&mut buffer)?;
-
- ensure!(&buffer == b"APK Sig Block 42", "Can not found sig block");
-
- let pos = u64::from(u32::from_le_bytes(size4)) - (u64::from_le_bytes(size8) + 0x8);
- f.seek(SeekFrom::Start(pos))?;
- f.read_exact(&mut size_of_block)?;
-
- ensure!(size_of_block == size8, "not a signed apk");
-
- let mut v2_signing: Option<(u32, String)> = None;
- let mut v3_signing_exist = false;
- let mut v3_1_signing_exist = false;
-
- loop {
- let mut id = [0u8; 4];
- let mut offset = 4u32;
-
- f.read_exact(&mut size8)?; // sequence length
- if size8 == size_of_block {
- break;
- }
-
- f.read_exact(&mut id)?; // id
-
- let id = u32::from_le_bytes(id);
- if id == 0x7109_871a_u32 {
- v2_signing = Some(calc_cert_sha256(&mut f, &mut size4, &mut offset)?);
- } else if id == 0xf053_68c0_u32 {
- // v3 signature scheme
- v3_signing_exist = true;
- } else if id == 0x1b93_ad61_u32 {
- // v3.1 signature scheme: credits to vvb2060
- v3_1_signing_exist = true;
- }
-
- f.seek(SeekFrom::Current(
- i64::from_le_bytes(size8) - i64::from(offset),
- ))?;
- }
-
- if v3_signing_exist || v3_1_signing_exist {
- return Err(anyhow::anyhow!("Unexpected v3 signature found!",));
- }
-
- v2_signing.ok_or(anyhow::anyhow!("No signature found!"))
-}
-
-fn calc_cert_sha256(
- f: &mut std::fs::File,
- size4: &mut [u8; 4],
- offset: &mut u32,
-) -> Result<(u32, String)> {
- f.read_exact(size4)?; // signer-sequence length
- f.read_exact(size4)?; // signer length
- f.read_exact(size4)?; // signed data length
- *offset += 0x4 * 3;
-
- f.read_exact(size4)?; // digests-sequence length
- let pos = u32::from_le_bytes(*size4); // skip digests
- f.seek(SeekFrom::Current(i64::from(pos)))?;
- *offset += 0x4 + pos;
-
- f.read_exact(size4)?; // certificates length
- f.read_exact(size4)?; // certificate length
- *offset += 0x4 * 2;
-
- let cert_len = u32::from_le_bytes(*size4);
- let mut cert: Vec = vec![0; cert_len as usize];
- f.read_exact(&mut cert)?;
- *offset += cert_len;
-
- Ok((cert_len, sha256::digest(&cert)))
-}
diff --git a/userspace/ksud/src/assets.rs b/userspace/ksud/src/assets.rs
deleted file mode 100644
index e8255c82..00000000
--- a/userspace/ksud/src/assets.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use anyhow::Result;
-use const_format::concatcp;
-use rust_embed::RustEmbed;
-use std::path::Path;
-
-use crate::{defs::BINARY_DIR, utils};
-
-pub const RESETPROP_PATH: &str = concatcp!(BINARY_DIR, "resetprop");
-pub const BUSYBOX_PATH: &str = concatcp!(BINARY_DIR, "busybox");
-pub const BOOTCTL_PATH: &str = concatcp!(BINARY_DIR, "bootctl");
-
-#[cfg(all(target_arch = "x86_64", target_os = "android"))]
-#[derive(RustEmbed)]
-#[folder = "bin/x86_64"]
-struct Asset;
-
-// IF NOT x86_64 ANDROID, ie. macos, linux, windows, always use aarch64
-#[cfg(not(all(target_arch = "x86_64", target_os = "android")))]
-#[derive(RustEmbed)]
-#[folder = "bin/aarch64"]
-struct Asset;
-
-pub fn ensure_binaries(ignore_if_exist: bool) -> Result<()> {
- for file in Asset::iter() {
- if file == "ksuinit" || file.ends_with(".ko") {
- // don't extract ksuinit and kernel modules
- continue;
- }
- let asset = Asset::get(&file).ok_or(anyhow::anyhow!("asset not found: {}", file))?;
- utils::ensure_binary(format!("{BINARY_DIR}{file}"), &asset.data, ignore_if_exist)?
- }
- Ok(())
-}
-
-pub fn copy_assets_to_file(name: &str, dst: impl AsRef) -> Result<()> {
- let asset = Asset::get(name).ok_or(anyhow::anyhow!("asset not found: {}", name))?;
- std::fs::write(dst, asset.data)?;
- Ok(())
-}
-
-pub fn list_supported_kmi() -> Result> {
- let mut list = Vec::new();
- for file in Asset::iter() {
- // kmi_name = "xxx_kernelsu.ko"
- if let Some(kmi) = file.strip_suffix("_kernelsu.ko") {
- list.push(kmi.to_string());
- }
- }
- Ok(list)
-}
diff --git a/userspace/ksud/src/banner b/userspace/ksud/src/banner
deleted file mode 100644
index 6087569c..00000000
--- a/userspace/ksud/src/banner
+++ /dev/null
@@ -1,5 +0,0 @@
- _ __ _ ____ _ _
- | |/ /___ _ __ _ __ ___| / ___|| | | |
- | ' // _ \ '__| '_ \ / _ \ \___ \| | | |
- | . \ __/ | | | | | __/ |___) | |_| |
- |_|\_\___|_| |_| |_|\___|_|____/ \___/
diff --git a/userspace/ksud/src/boot_patch.rs b/userspace/ksud/src/boot_patch.rs
deleted file mode 100644
index c2661c68..00000000
--- a/userspace/ksud/src/boot_patch.rs
+++ /dev/null
@@ -1,632 +0,0 @@
-#[cfg(unix)]
-use std::os::unix::fs::PermissionsExt;
-use std::path::Path;
-use std::path::PathBuf;
-use std::process::Command;
-use std::process::Stdio;
-
-use anyhow::anyhow;
-use anyhow::bail;
-use anyhow::ensure;
-use anyhow::Context;
-use anyhow::Result;
-use which::which;
-
-use crate::defs;
-use crate::defs::BACKUP_FILENAME;
-use crate::defs::{KSU_BACKUP_DIR, KSU_BACKUP_FILE_PREFIX};
-use crate::{assets, utils};
-
-#[cfg(target_os = "android")]
-fn ensure_gki_kernel() -> Result<()> {
- let version = get_kernel_version()?;
- let is_gki = version.0 == 5 && version.1 >= 10 || version.2 > 5;
- ensure!(is_gki, "only support GKI kernel");
- Ok(())
-}
-
-#[cfg(target_os = "android")]
-pub fn get_kernel_version() -> Result<(i32, i32, i32)> {
- use regex::Regex;
- let uname = rustix::system::uname();
- let version = uname.release().to_string_lossy();
- let re = Regex::new(r"(\d+)\.(\d+)\.(\d+)")?;
- if let Some(captures) = re.captures(&version) {
- let major = captures
- .get(1)
- .and_then(|m| m.as_str().parse::().ok())
- .ok_or_else(|| anyhow!("Major version parse error"))?;
- let minor = captures
- .get(2)
- .and_then(|m| m.as_str().parse::().ok())
- .ok_or_else(|| anyhow!("Minor version parse error"))?;
- let patch = captures
- .get(3)
- .and_then(|m| m.as_str().parse::().ok())
- .ok_or_else(|| anyhow!("Patch version parse error"))?;
- Ok((major, minor, patch))
- } else {
- Err(anyhow!("Invalid kernel version string"))
- }
-}
-
-#[cfg(target_os = "android")]
-fn parse_kmi(version: &str) -> Result {
- use regex::Regex;
- let re = Regex::new(r"(.* )?(\d+\.\d+)(\S+)?(android\d+)(.*)")?;
- let cap = re
- .captures(version)
- .ok_or_else(|| anyhow::anyhow!("Failed to get KMI from boot/modules"))?;
- let android_version = cap.get(4).map_or("", |m| m.as_str());
- let kernel_version = cap.get(2).map_or("", |m| m.as_str());
- Ok(format!("{android_version}-{kernel_version}"))
-}
-
-#[cfg(target_os = "android")]
-fn parse_kmi_from_uname() -> Result {
- let uname = rustix::system::uname();
- let version = uname.release().to_string_lossy();
- parse_kmi(&version)
-}
-
-#[cfg(target_os = "android")]
-fn parse_kmi_from_modules() -> Result {
- use std::io::BufRead;
- // find a *.ko in /vendor/lib/modules
- let modfile = std::fs::read_dir("/vendor/lib/modules")?
- .filter_map(Result::ok)
- .find(|entry| entry.path().extension().map_or(false, |ext| ext == "ko"))
- .map(|entry| entry.path())
- .ok_or_else(|| anyhow!("No kernel module found"))?;
- let output = Command::new("modinfo").arg(modfile).output()?;
- for line in output.stdout.lines().map_while(Result::ok) {
- if line.starts_with("vermagic") {
- return parse_kmi(&line);
- }
- }
- anyhow::bail!("Parse KMI from modules failed")
-}
-
-#[cfg(target_os = "android")]
-pub fn get_current_kmi() -> Result {
- parse_kmi_from_uname().or_else(|_| parse_kmi_from_modules())
-}
-
-#[cfg(not(target_os = "android"))]
-pub fn get_current_kmi() -> Result {
- bail!("Unsupported platform")
-}
-
-fn do_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> {
- let status = Command::new(magiskboot)
- .current_dir(workdir)
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .arg("cpio")
- .arg("ramdisk.cpio")
- .arg(cmd)
- .status()?;
-
- ensure!(status.success(), "magiskboot cpio {} failed", cmd);
- Ok(())
-}
-
-fn is_magisk_patched(magiskboot: &Path, workdir: &Path) -> Result {
- let status = Command::new(magiskboot)
- .current_dir(workdir)
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .args(["cpio", "ramdisk.cpio", "test"])
- .status()?;
-
- // 0: stock, 1: magisk
- Ok(status.code() == Some(1))
-}
-
-fn is_kernelsu_patched(magiskboot: &Path, workdir: &Path) -> Result {
- let status = Command::new(magiskboot)
- .current_dir(workdir)
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .args(["cpio", "ramdisk.cpio", "exists kernelsu.ko"])
- .status()?;
-
- Ok(status.success())
-}
-
-fn dd, Q: AsRef>(ifile: P, ofile: Q) -> Result<()> {
- let status = Command::new("dd")
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .arg(format!("if={}", ifile.as_ref().display()))
- .arg(format!("of={}", ofile.as_ref().display()))
- .status()?;
- ensure!(
- status.success(),
- "dd if={:?} of={:?} failed",
- ifile.as_ref(),
- ofile.as_ref()
- );
- Ok(())
-}
-
-pub fn restore(
- image: Option,
- magiskboot_path: Option,
- flash: bool,
-) -> Result<()> {
- let tmpdir = tempdir::TempDir::new("KernelSU").context("create temp dir failed")?;
- let workdir = tmpdir.path();
- let magiskboot = find_magiskboot(magiskboot_path, workdir)?;
-
- let kmi = get_current_kmi().unwrap_or_else(|_| String::from(""));
-
- let skip_init = kmi.starts_with("android12-");
-
- let (bootimage, bootdevice) = find_boot_image(&image, skip_init, false, false, workdir)?;
-
- println!("- Unpacking boot image");
- let status = Command::new(&magiskboot)
- .current_dir(workdir)
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .arg("unpack")
- .arg(bootimage.display().to_string())
- .status()?;
- ensure!(status.success(), "magiskboot unpack failed");
-
- let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir)?;
- ensure!(is_kernelsu_patched, "boot image is not patched by KernelSU");
-
- let mut new_boot = None;
- let mut from_backup = false;
-
- #[cfg(target_os = "android")]
- if do_cpio_cmd(&magiskboot, workdir, &format!("exists {BACKUP_FILENAME}")).is_ok() {
- do_cpio_cmd(
- &magiskboot,
- workdir,
- &format!("extract {0} {0}", BACKUP_FILENAME),
- )?;
- let sha = std::fs::read(workdir.join(BACKUP_FILENAME))?;
- let sha = String::from_utf8(sha)?;
- let sha = sha.trim();
- let backup_path =
- PathBuf::from(KSU_BACKUP_DIR).join(format!("{KSU_BACKUP_FILE_PREFIX}{sha}"));
- if backup_path.is_file() {
- new_boot = Some(backup_path);
- from_backup = true;
- } else {
- println!("- Warning: no backup {backup_path:?} found!");
- }
-
- if let Err(e) = clean_backup(sha) {
- println!("- Warning: Cleanup backup image failed: {e}");
- }
- } else {
- println!("- Backup info is absent!");
- }
-
- if new_boot.is_none() {
- // remove kernelsu.ko
- do_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
-
- // if init.real exists, restore it
- let status = do_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok();
- if status {
- do_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
- } else {
- let ramdisk = workdir.join("ramdisk.cpio");
- std::fs::remove_file(ramdisk)?;
- }
-
- println!("- Repacking boot image");
- let status = Command::new(&magiskboot)
- .current_dir(workdir)
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .arg("repack")
- .arg(bootimage.display().to_string())
- .status()?;
- ensure!(status.success(), "magiskboot repack failed");
- new_boot = Some(workdir.join("new-boot.img"));
- }
-
- let new_boot = new_boot.unwrap();
-
- if image.is_some() {
- // if image is specified, write to output file
- let output_dir = std::env::current_dir()?;
- let now = chrono::Utc::now();
- let output_image = output_dir.join(format!(
- "kernelsu_restore_{}.img",
- now.format("%Y%m%d_%H%M%S")
- ));
-
- if from_backup || std::fs::rename(&new_boot, &output_image).is_err() {
- std::fs::copy(&new_boot, &output_image).context("copy out new boot failed")?;
- }
- println!("- Output file is written to");
- println!("- {}", output_image.display().to_string().trim_matches('"'));
- }
- if flash {
- if from_backup {
- println!("- Flashing new boot image from {}", new_boot.display());
- } else {
- println!("- Flashing new boot image");
- }
- flash_boot(&bootdevice, new_boot)?;
- }
- println!("- Done!");
- Ok(())
-}
-
-#[allow(clippy::too_many_arguments)]
-pub fn patch(
- image: Option,
- kernel: Option,
- kmod: Option,
- init: Option,
- ota: bool,
- flash: bool,
- out: Option,
- magiskboot: Option,
- kmi: Option,
-) -> Result<()> {
- let result = do_patch(image, kernel, kmod, init, ota, flash, out, magiskboot, kmi);
- if let Err(ref e) = result {
- println!("- Install Error: {e}");
- }
- result
-}
-
-#[allow(clippy::too_many_arguments)]
-fn do_patch(
- image: Option,
- kernel: Option,
- kmod: Option,
- init: Option,
- ota: bool,
- flash: bool,
- out: Option,
- magiskboot_path: Option,
- kmi: Option,
-) -> Result<()> {
- println!(include_str!("banner"));
-
- let patch_file = image.is_some();
-
- #[cfg(target_os = "android")]
- if !patch_file {
- ensure_gki_kernel()?;
- }
-
- let is_replace_kernel = kernel.is_some();
-
- if is_replace_kernel {
- ensure!(
- init.is_none() && kmod.is_none(),
- "init and module must not be specified."
- );
- }
-
- let tmpdir = tempdir::TempDir::new("KernelSU").context("create temp dir failed")?;
- let workdir = tmpdir.path();
-
- let kmi = if let Some(kmi) = kmi {
- kmi
- } else {
- get_current_kmi().context("Unknown KMI, please choose LKM manually")?
- };
-
- let skip_init = kmi.starts_with("android12-");
-
- let (bootimage, bootdevice) =
- find_boot_image(&image, skip_init, ota, is_replace_kernel, workdir)?;
-
- let bootimage = bootimage.display().to_string();
-
- // try extract magiskboot/bootctl
- let _ = assets::ensure_binaries(false);
-
- // extract magiskboot
- let magiskboot = find_magiskboot(magiskboot_path, workdir)?;
-
- if let Some(kernel) = kernel {
- std::fs::copy(kernel, workdir.join("kernel")).context("copy kernel from failed")?;
- }
-
- println!("- Preparing assets");
-
- let kmod_file = workdir.join("kernelsu.ko");
- if let Some(kmod) = kmod {
- std::fs::copy(kmod, kmod_file).context("copy kernel module failed")?;
- } else {
- // If kmod is not specified, extract from assets
- println!("- KMI: {kmi}");
- let name = format!("{kmi}_kernelsu.ko");
- assets::copy_assets_to_file(&name, kmod_file)
- .with_context(|| format!("Failed to copy {name}"))?;
- };
-
- let init_file = workdir.join("init");
- if let Some(init) = init {
- std::fs::copy(init, init_file).context("copy init failed")?;
- } else {
- assets::copy_assets_to_file("ksuinit", init_file).context("copy ksuinit failed")?;
- }
-
- // magiskboot unpack boot.img
- // magiskboot cpio ramdisk.cpio 'cp init init.real'
- // magiskboot cpio ramdisk.cpio 'add 0755 ksuinit init'
- // magiskboot cpio ramdisk.cpio 'add 0755 kernelsu.ko'
-
- println!("- Unpacking boot image");
- let status = Command::new(&magiskboot)
- .current_dir(workdir)
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .arg("unpack")
- .arg(&bootimage)
- .status()?;
- ensure!(status.success(), "magiskboot unpack failed");
-
- let no_ramdisk = !workdir.join("ramdisk.cpio").exists();
- let is_magisk_patched = is_magisk_patched(&magiskboot, workdir)?;
- ensure!(
- no_ramdisk || !is_magisk_patched,
- "Cannot work with Magisk patched image"
- );
-
- println!("- Adding KernelSU LKM");
- let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir)?;
-
- let mut need_backup = false;
- if !is_kernelsu_patched {
- // kernelsu.ko is not exist, backup init if necessary
- let status = do_cpio_cmd(&magiskboot, workdir, "exists init");
- if status.is_ok() {
- do_cpio_cmd(&magiskboot, workdir, "mv init init.real")?;
- }
-
- need_backup = flash;
- }
-
- do_cpio_cmd(&magiskboot, workdir, "add 0755 init init")?;
- do_cpio_cmd(&magiskboot, workdir, "add 0755 kernelsu.ko kernelsu.ko")?;
-
- #[cfg(target_os = "android")]
- if need_backup {
- if let Err(e) = do_backup(&magiskboot, workdir, &bootimage) {
- println!("- Backup stock image failed: {e}");
- }
- }
-
- println!("- Repacking boot image");
- // magiskboot repack boot.img
- let status = Command::new(&magiskboot)
- .current_dir(workdir)
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .arg("repack")
- .arg(&bootimage)
- .status()?;
- ensure!(status.success(), "magiskboot repack failed");
- let new_boot = workdir.join("new-boot.img");
-
- if patch_file {
- // if image is specified, write to output file
- let output_dir = out.unwrap_or(std::env::current_dir()?);
- let now = chrono::Utc::now();
- let output_image = output_dir.join(format!(
- "kernelsu_patched_{}.img",
- now.format("%Y%m%d_%H%M%S")
- ));
-
- if std::fs::rename(&new_boot, &output_image).is_err() {
- std::fs::copy(&new_boot, &output_image).context("copy out new boot failed")?;
- }
- println!("- Output file is written to");
- println!("- {}", output_image.display().to_string().trim_matches('"'));
- }
-
- if flash {
- println!("- Flashing new boot image");
- flash_boot(&bootdevice, new_boot)?;
-
- if ota {
- post_ota()?;
- }
- }
-
- println!("- Done!");
- Ok(())
-}
-
-#[cfg(target_os = "android")]
-fn calculate_sha1(file_path: impl AsRef) -> Result {
- use sha1::Digest;
- use std::io::Read;
- let mut file = std::fs::File::open(file_path.as_ref())?;
- let mut hasher = sha1::Sha1::new();
- let mut buffer = [0; 1024];
-
- loop {
- let n = file.read(&mut buffer)?;
- if n == 0 {
- break;
- }
- hasher.update(&buffer[..n]);
- }
-
- let result = hasher.finalize();
- Ok(format!("{:x}", result))
-}
-
-#[cfg(target_os = "android")]
-fn do_backup(magiskboot: &Path, workdir: &Path, image: &str) -> Result<()> {
- let sha1 = calculate_sha1(image)?;
- let filename = format!("{KSU_BACKUP_FILE_PREFIX}{sha1}");
-
- println!("- Backup stock boot image");
- // magiskboot cpio ramdisk.cpio 'add 0755 $BACKUP_FILENAME'
- let target = format!("{KSU_BACKUP_DIR}{filename}");
- std::fs::copy(image, &target).with_context(|| format!("backup to {target}"))?;
- std::fs::write(workdir.join(BACKUP_FILENAME), sha1.as_bytes()).context("write sha1")?;
- do_cpio_cmd(
- magiskboot,
- workdir,
- &format!("add 0755 {0} {0}", BACKUP_FILENAME),
- )?;
- println!("- Stock image has been backup to");
- println!("- {target}");
- Ok(())
-}
-
-#[cfg(target_os = "android")]
-fn clean_backup(sha1: &str) -> Result<()> {
- println!("- Clean up backup");
- let backup_name = format!("{}{}", KSU_BACKUP_FILE_PREFIX, sha1);
- let dir = std::fs::read_dir(defs::KSU_BACKUP_DIR)?;
- for entry in dir.flatten() {
- let path = entry.path();
- if !path.is_file() {
- continue;
- }
- if let Some(name) = path.file_name() {
- let name = name.to_string_lossy().to_string();
- if name != backup_name
- && name.starts_with(KSU_BACKUP_FILE_PREFIX)
- && std::fs::remove_file(path).is_ok()
- {
- println!("- removed {name}");
- }
- }
- }
- Ok(())
-}
-
-fn flash_boot(bootdevice: &Option, new_boot: PathBuf) -> Result<()> {
- let Some(bootdevice) = bootdevice else {
- bail!("boot device not found")
- };
- let status = Command::new("blockdev")
- .arg("--setrw")
- .arg(bootdevice)
- .status()?;
- ensure!(status.success(), "set boot device rw failed");
- dd(new_boot, bootdevice).context("flash boot failed")?;
- Ok(())
-}
-
-fn find_magiskboot(magiskboot_path: Option, workdir: &Path) -> Result {
- let magiskboot = {
- if which("magiskboot").is_ok() {
- let _ = assets::ensure_binaries(true);
- "magiskboot".into()
- } else {
- // magiskboot is not in $PATH, use builtin or specified one
- let magiskboot = if let Some(magiskboot_path) = magiskboot_path {
- std::fs::canonicalize(magiskboot_path)?
- } else {
- let magiskboot_path = workdir.join("magiskboot");
- assets::copy_assets_to_file("magiskboot", &magiskboot_path)
- .context("copy magiskboot failed")?;
- magiskboot_path
- };
- ensure!(magiskboot.exists(), "{magiskboot:?} is not exist");
- #[cfg(unix)]
- let _ = std::fs::set_permissions(&magiskboot, std::fs::Permissions::from_mode(0o755));
- magiskboot
- }
- };
- Ok(magiskboot)
-}
-
-fn find_boot_image(
- image: &Option,
- skip_init: bool,
- ota: bool,
- is_replace_kernel: bool,
- workdir: &Path,
-) -> Result<(PathBuf, Option)> {
- let bootimage;
- let mut bootdevice = None;
- if let Some(ref image) = *image {
- ensure!(image.exists(), "boot image not found");
- bootimage = std::fs::canonicalize(image)?;
- } else {
- if cfg!(not(target_os = "android")) {
- println!("- Current OS is not android, refusing auto bootimage/bootdevice detection");
- bail!("please specify a boot image");
- }
- let mut slot_suffix =
- utils::getprop("ro.boot.slot_suffix").unwrap_or_else(|| String::from(""));
-
- if !slot_suffix.is_empty() && ota {
- if slot_suffix == "_a" {
- slot_suffix = "_b".to_string()
- } else {
- slot_suffix = "_a".to_string()
- }
- };
-
- let init_boot_exist =
- Path::new(&format!("/dev/block/by-name/init_boot{slot_suffix}")).exists();
- let boot_partition = if !is_replace_kernel && init_boot_exist && !skip_init {
- format!("/dev/block/by-name/init_boot{slot_suffix}")
- } else {
- format!("/dev/block/by-name/boot{slot_suffix}")
- };
-
- println!("- Bootdevice: {boot_partition}");
- let tmp_boot_path = workdir.join("boot.img");
-
- dd(&boot_partition, &tmp_boot_path)?;
-
- ensure!(tmp_boot_path.exists(), "boot image not found");
-
- bootimage = tmp_boot_path;
- bootdevice = Some(boot_partition);
- };
- Ok((bootimage, bootdevice))
-}
-
-fn post_ota() -> Result<()> {
- use crate::defs::ADB_DIR;
- use assets::BOOTCTL_PATH;
- let status = Command::new(BOOTCTL_PATH).arg("hal-info").status()?;
- if !status.success() {
- return Ok(());
- }
-
- let current_slot = Command::new(BOOTCTL_PATH)
- .arg("get-current-slot")
- .output()?
- .stdout;
- let current_slot = String::from_utf8(current_slot)?;
- let current_slot = current_slot.trim();
- let target_slot = if current_slot == "0" { 1 } else { 0 };
-
- Command::new(BOOTCTL_PATH)
- .arg(format!("set-active-boot-slot {target_slot}"))
- .status()?;
-
- let post_fs_data = std::path::Path::new(ADB_DIR).join("post-fs-data.d");
- utils::ensure_dir_exists(&post_fs_data)?;
- let post_ota_sh = post_fs_data.join("post_ota.sh");
-
- let sh_content = format!(
- r###"
-{BOOTCTL_PATH} mark-boot-successful
-rm -f {BOOTCTL_PATH}
-rm -f /data/adb/post-fs-data.d/post_ota.sh
-"###
- );
-
- std::fs::write(&post_ota_sh, sh_content)?;
- #[cfg(unix)]
- std::fs::set_permissions(post_ota_sh, std::fs::Permissions::from_mode(0o755))?;
-
- Ok(())
-}
diff --git a/userspace/ksud/src/cli.rs b/userspace/ksud/src/cli.rs
deleted file mode 100644
index cd96a360..00000000
--- a/userspace/ksud/src/cli.rs
+++ /dev/null
@@ -1,392 +0,0 @@
-use anyhow::{Ok, Result};
-use clap::Parser;
-use std::path::PathBuf;
-
-#[cfg(target_os = "android")]
-use android_logger::Config;
-#[cfg(target_os = "android")]
-use log::LevelFilter;
-
-use crate::{apk_sign, assets, debug, defs, init_event, ksucalls, module, utils};
-
-/// KernelSU userspace cli
-#[derive(Parser, Debug)]
-#[command(author, version = defs::VERSION_NAME, about, long_about = None)]
-struct Args {
- #[command(subcommand)]
- command: Commands,
-}
-
-#[derive(clap::Subcommand, Debug)]
-enum Commands {
- /// Manage KernelSU modules
- Module {
- #[command(subcommand)]
- command: Module,
- },
-
- /// Trigger `post-fs-data` event
- PostFsData,
-
- /// Trigger `service` event
- Services,
-
- /// Trigger `boot-complete` event
- BootCompleted,
-
- /// Install KernelSU userspace component to system
- Install {
- #[arg(long, default_value = None)]
- magiskboot: Option,
- },
-
- /// Uninstall KernelSU modules and itself(LKM Only)
- Uninstall {
- /// magiskboot path, if not specified, will search from $PATH
- #[arg(long, default_value = None)]
- magiskboot: Option,
- },
-
- /// SELinux policy Patch tool
- Sepolicy {
- #[command(subcommand)]
- command: Sepolicy,
- },
-
- /// Manage App Profiles
- Profile {
- #[command(subcommand)]
- command: Profile,
- },
-
- /// Patch boot or init_boot images to apply KernelSU
- BootPatch {
- /// boot image path, if not specified, will try to find the boot image automatically
- #[arg(short, long)]
- boot: Option,
-
- /// kernel image path to replace
- #[arg(short, long)]
- kernel: Option,
-
- /// LKM module path to replace, if not specified, will use the builtin one
- #[arg(short, long)]
- module: Option,
-
- /// init to be replaced
- #[arg(short, long, requires("module"))]
- init: Option,
-
- /// will use another slot when boot image is not specified
- #[arg(short = 'u', long, default_value = "false")]
- ota: bool,
-
- /// Flash it to boot partition after patch
- #[arg(short, long, default_value = "false")]
- flash: bool,
-
- /// output path, if not specified, will use current directory
- #[arg(short, long, default_value = None)]
- out: Option,
-
- /// magiskboot path, if not specified, will search from $PATH
- #[arg(long, default_value = None)]
- magiskboot: Option,
-
- /// KMI version, if specified, will use the specified KMI
- #[arg(long, default_value = None)]
- kmi: Option,
- },
-
- /// Restore boot or init_boot images patched by KernelSU
- BootRestore {
- /// boot image path, if not specified, will try to find the boot image automatically
- #[arg(short, long)]
- boot: Option,
-
- /// Flash it to boot partition after patch
- #[arg(short, long, default_value = "false")]
- flash: bool,
-
- /// magiskboot path, if not specified, will search from $PATH
- #[arg(long, default_value = None)]
- magiskboot: Option,
- },
-
- /// Show boot information
- BootInfo {
- #[command(subcommand)]
- command: BootInfo,
- },
- /// For developers
- Debug {
- #[command(subcommand)]
- command: Debug,
- },
-}
-
-#[derive(clap::Subcommand, Debug)]
-enum BootInfo {
- /// show current kmi version
- CurrentKmi,
-
- /// show supported kmi versions
- SupportedKmi,
-}
-
-#[derive(clap::Subcommand, Debug)]
-enum Debug {
- /// Set the manager app, kernel CONFIG_KSU_DEBUG should be enabled.
- SetManager {
- /// manager package name
- #[arg(default_value_t = String::from("me.weishu.kernelsu"))]
- apk: String,
- },
-
- /// Get apk size and hash
- GetSign {
- /// apk path
- apk: String,
- },
-
- /// Root Shell
- Su {
- /// switch to gloabl mount namespace
- #[arg(short, long, default_value = "false")]
- global_mnt: bool,
- },
-
- /// Get kernel version
- Version,
-
- Mount,
-
- /// Copy sparse file
- Xcp {
- /// source file
- src: String,
- /// destination file
- dst: String,
- /// punch hole
- #[arg(short, long, default_value = "false")]
- punch_hole: bool,
- },
-
- /// For testing
- Test,
-}
-
-#[derive(clap::Subcommand, Debug)]
-enum Sepolicy {
- /// Patch sepolicy
- Patch {
- /// sepolicy statements
- sepolicy: String,
- },
-
- /// Apply sepolicy from file
- Apply {
- /// sepolicy file path
- file: String,
- },
-
- /// Check if sepolicy statement is supported/valid
- Check {
- /// sepolicy statements
- sepolicy: String,
- },
-}
-
-#[derive(clap::Subcommand, Debug)]
-enum Module {
- /// Install module
- Install {
- /// module zip file path
- zip: String,
- },
-
- /// Uninstall module
- Uninstall {
- /// module id
- id: String,
- },
-
- /// enable module
- Enable {
- /// module id
- id: String,
- },
-
- /// disable module
- Disable {
- // module id
- id: String,
- },
-
- /// list all modules
- List,
-
- /// Shrink module image size
- Shrink,
-}
-
-#[derive(clap::Subcommand, Debug)]
-enum Profile {
- /// get root profile's selinux policy of
- GetSepolicy {
- /// package name
- package: String,
- },
-
- /// set root profile's selinux policy of to
- SetSepolicy {
- /// package name
- package: String,
- /// policy statements
- policy: String,
- },
-
- /// get template of
- GetTemplate {
- /// template id
- id: String,
- },
-
- /// set template of to
- SetTemplate {
- /// template id
- id: String,
- /// template string
- template: String,
- },
-
- /// delete template of
- DeleteTemplate {
- /// template id
- id: String,
- },
-
- /// list all templates
- ListTemplates,
-}
-
-pub fn run() -> Result<()> {
- #[cfg(target_os = "android")]
- android_logger::init_once(
- Config::default()
- .with_max_level(LevelFilter::Trace) // limit log level
- .with_tag("KernelSU"), // logs will show under mytag tag
- );
-
- #[cfg(not(target_os = "android"))]
- env_logger::init();
-
- // the kernel executes su with argv[0] = "su" and replace it with us
- let arg0 = std::env::args().next().unwrap_or_default();
- if arg0 == "su" || arg0 == "/system/bin/su" {
- return crate::su::root_shell();
- }
-
- let cli = Args::parse();
-
- log::info!("command: {:?}", cli.command);
-
- let result = match cli.command {
- Commands::PostFsData => init_event::on_post_data_fs(),
- Commands::BootCompleted => init_event::on_boot_completed(),
-
- Commands::Module { command } => {
- #[cfg(any(target_os = "linux", target_os = "android"))]
- {
- utils::switch_mnt_ns(1)?;
- utils::unshare_mnt_ns()?;
- }
- match command {
- Module::Install { zip } => module::install_module(&zip),
- Module::Uninstall { id } => module::uninstall_module(&id),
- Module::Enable { id } => module::enable_module(&id),
- Module::Disable { id } => module::disable_module(&id),
- Module::List => module::list_modules(),
- Module::Shrink => module::shrink_ksu_images(),
- }
- }
- Commands::Install { magiskboot } => utils::install(magiskboot),
- Commands::Uninstall { magiskboot } => utils::uninstall(magiskboot),
- Commands::Sepolicy { command } => match command {
- Sepolicy::Patch { sepolicy } => crate::sepolicy::live_patch(&sepolicy),
- Sepolicy::Apply { file } => crate::sepolicy::apply_file(file),
- Sepolicy::Check { sepolicy } => crate::sepolicy::check_rule(&sepolicy),
- },
- Commands::Services => init_event::on_services(),
- Commands::Profile { command } => match command {
- Profile::GetSepolicy { package } => crate::profile::get_sepolicy(package),
- Profile::SetSepolicy { package, policy } => {
- crate::profile::set_sepolicy(package, policy)
- }
- Profile::GetTemplate { id } => crate::profile::get_template(id),
- Profile::SetTemplate { id, template } => crate::profile::set_template(id, template),
- Profile::DeleteTemplate { id } => crate::profile::delete_template(id),
- Profile::ListTemplates => crate::profile::list_templates(),
- },
-
- Commands::Debug { command } => match command {
- Debug::SetManager { apk } => debug::set_manager(&apk),
- Debug::GetSign { apk } => {
- let sign = apk_sign::get_apk_signature(&apk)?;
- println!("size: {:#x}, hash: {}", sign.0, sign.1);
- Ok(())
- }
- Debug::Version => {
- println!("Kernel Version: {}", ksucalls::get_version());
- Ok(())
- }
- Debug::Su { global_mnt } => crate::su::grant_root(global_mnt),
- Debug::Mount => init_event::mount_modules_systemlessly(defs::MODULE_DIR),
- Debug::Xcp {
- src,
- dst,
- punch_hole,
- } => {
- utils::copy_sparse_file(src, dst, punch_hole)?;
- Ok(())
- }
- Debug::Test => assets::ensure_binaries(false),
- },
-
- Commands::BootPatch {
- boot,
- init,
- kernel,
- module,
- ota,
- flash,
- out,
- magiskboot,
- kmi,
- } => crate::boot_patch::patch(boot, kernel, module, init, ota, flash, out, magiskboot, kmi),
-
- Commands::BootInfo { command } => match command {
- BootInfo::CurrentKmi => {
- let kmi = crate::boot_patch::get_current_kmi()?;
- println!("{}", kmi);
- // return here to avoid printing the error message
- return Ok(());
- }
- BootInfo::SupportedKmi => {
- let kmi = crate::assets::list_supported_kmi()?;
- kmi.iter().for_each(|kmi| println!("{}", kmi));
- return Ok(());
- }
- },
- Commands::BootRestore {
- boot,
- magiskboot,
- flash,
- } => crate::boot_patch::restore(boot, magiskboot, flash),
- };
-
- if let Err(e) = &result {
- log::error!("Error: {:?}", e);
- }
- result
-}
diff --git a/userspace/ksud/src/debug.rs b/userspace/ksud/src/debug.rs
deleted file mode 100644
index 8ff851d3..00000000
--- a/userspace/ksud/src/debug.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-use anyhow::{ensure, Context, Ok, Result};
-use std::{
- path::{Path, PathBuf},
- process::Command,
-};
-
-const KERNEL_PARAM_PATH: &str = "/sys/module/kernelsu";
-
-fn read_u32(path: &PathBuf) -> Result {
- let content = std::fs::read_to_string(path)?;
- let content = content.trim();
- let content = content.parse::()?;
- Ok(content)
-}
-
-fn set_kernel_param(uid: u32) -> Result<()> {
- let kernel_param_path = Path::new(KERNEL_PARAM_PATH).join("parameters");
-
- let ksu_debug_manager_uid = kernel_param_path.join("ksu_debug_manager_uid");
- let before_uid = read_u32(&ksu_debug_manager_uid)?;
- std::fs::write(&ksu_debug_manager_uid, uid.to_string())?;
- let after_uid = read_u32(&ksu_debug_manager_uid)?;
-
- println!("set manager uid: {before_uid} -> {after_uid}");
-
- Ok(())
-}
-
-#[cfg(target_os = "android")]
-fn get_pkg_uid(pkg: &str) -> Result {
- // stat /data/data/
- let uid = rustix::fs::stat(format!("/data/data/{pkg}"))
- .with_context(|| format!("stat /data/data/{}", pkg))?
- .st_uid;
- Ok(uid)
-}
-
-pub fn set_manager(pkg: &str) -> Result<()> {
- ensure!(
- Path::new(KERNEL_PARAM_PATH).exists(),
- "CONFIG_KSU_DEBUG is not enabled"
- );
-
- #[cfg(target_os = "android")]
- let uid = get_pkg_uid(pkg)?;
- #[cfg(not(target_os = "android"))]
- let uid = 0;
- set_kernel_param(uid)?;
- // force-stop it
- let _ = Command::new("am").args(["force-stop", pkg]).status();
- Ok(())
-}
diff --git a/userspace/ksud/src/defs.rs b/userspace/ksud/src/defs.rs
deleted file mode 100644
index c4b9fc3f..00000000
--- a/userspace/ksud/src/defs.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-use const_format::concatcp;
-
-pub const ADB_DIR: &str = "/data/adb/";
-pub const WORKING_DIR: &str = concatcp!(ADB_DIR, "ksu/");
-pub const BINARY_DIR: &str = concatcp!(WORKING_DIR, "bin/");
-pub const LOG_DIR: &str = concatcp!(WORKING_DIR, "log/");
-
-pub const PROFILE_DIR: &str = concatcp!(WORKING_DIR, "profile/");
-pub const PROFILE_SELINUX_DIR: &str = concatcp!(PROFILE_DIR, "selinux/");
-pub const PROFILE_TEMPLATE_DIR: &str = concatcp!(PROFILE_DIR, "templates/");
-
-pub const KSURC_PATH: &str = concatcp!(WORKING_DIR, ".ksurc");
-pub const KSU_OVERLAY_SOURCE: &str = "KSU";
-pub const DAEMON_PATH: &str = concatcp!(ADB_DIR, "ksud");
-pub const MAGISKBOOT_PATH: &str = concatcp!(BINARY_DIR, "magiskboot");
-
-#[cfg(target_os = "android")]
-pub const DAEMON_LINK_PATH: &str = concatcp!(BINARY_DIR, "ksud");
-
-pub const MODULE_DIR: &str = concatcp!(ADB_DIR, "modules/");
-pub const MODULE_IMG: &str = concatcp!(WORKING_DIR, "modules.img");
-pub const MODULE_UPDATE_IMG: &str = concatcp!(WORKING_DIR, "modules_update.img");
-
-pub const MODULE_UPDATE_TMP_IMG: &str = concatcp!(WORKING_DIR, "update_tmp.img");
-
-// warning: this directory should not change, or you need to change the code in module_installer.sh!!!
-pub const MODULE_UPDATE_TMP_DIR: &str = concatcp!(ADB_DIR, "modules_update/");
-
-pub const SYSTEM_RW_DIR: &str = concatcp!(MODULE_DIR, ".rw/");
-
-pub const TEMP_DIR: &str = "/debug_ramdisk";
-pub const TEMP_DIR_LEGACY: &str = "/sbin";
-
-pub const MODULE_WEB_DIR: &str = "webroot";
-pub const DISABLE_FILE_NAME: &str = "disable";
-pub const UPDATE_FILE_NAME: &str = "update";
-pub const REMOVE_FILE_NAME: &str = "remove";
-pub const SKIP_MOUNT_FILE_NAME: &str = "skip_mount";
-
-pub const VERSION_CODE: &str = include_str!(concat!(env!("OUT_DIR"), "/VERSION_CODE"));
-pub const VERSION_NAME: &str = include_str!(concat!(env!("OUT_DIR"), "/VERSION_NAME"));
-
-pub const KSU_BACKUP_DIR: &str = WORKING_DIR;
-pub const KSU_BACKUP_FILE_PREFIX: &str = "ksu_backup_";
-pub const BACKUP_FILENAME: &str = "stock_image.sha1";
diff --git a/userspace/ksud/src/init_event.rs b/userspace/ksud/src/init_event.rs
deleted file mode 100644
index 7107ff74..00000000
--- a/userspace/ksud/src/init_event.rs
+++ /dev/null
@@ -1,305 +0,0 @@
-use anyhow::{bail, Context, Result};
-use log::{info, warn};
-use std::{collections::HashMap, path::Path};
-
-use crate::module::prune_modules;
-use crate::{
- assets, defs, ksucalls, mount, restorecon,
- utils::{self, ensure_clean_dir},
-};
-
-fn mount_partition(partition_name: &str, lowerdir: &Vec) -> Result<()> {
- if lowerdir.is_empty() {
- warn!("partition: {partition_name} lowerdir is empty");
- return Ok(());
- }
-
- let partition = format!("/{partition_name}");
-
- // if /partition is a symlink and linked to /system/partition, then we don't need to overlay it separately
- if Path::new(&partition).read_link().is_ok() {
- warn!("partition: {partition} is a symlink");
- return Ok(());
- }
-
- let mut workdir = None;
- let mut upperdir = None;
- let system_rw_dir = Path::new(defs::SYSTEM_RW_DIR);
- if system_rw_dir.exists() {
- workdir = Some(system_rw_dir.join(partition_name).join("workdir"));
- upperdir = Some(system_rw_dir.join(partition_name).join("upperdir"));
- }
-
- mount::mount_overlay(&partition, lowerdir, workdir, upperdir)
-}
-
-pub fn mount_modules_systemlessly(module_dir: &str) -> Result<()> {
- // construct overlay mount params
- let dir = std::fs::read_dir(module_dir);
- let Ok(dir) = dir else {
- bail!("open {} failed", defs::MODULE_DIR);
- };
-
- let mut system_lowerdir: Vec = Vec::new();
-
- let partition = vec!["vendor", "product", "system_ext", "odm", "oem"];
- let mut partition_lowerdir: HashMap> = HashMap::new();
- for ele in &partition {
- partition_lowerdir.insert((*ele).to_string(), Vec::new());
- }
-
- for entry in dir.flatten() {
- let module = entry.path();
- if !module.is_dir() {
- continue;
- }
- let disabled = module.join(defs::DISABLE_FILE_NAME).exists();
- if disabled {
- info!("module: {} is disabled, ignore!", module.display());
- continue;
- }
- let skip_mount = module.join(defs::SKIP_MOUNT_FILE_NAME).exists();
- if skip_mount {
- info!("module: {} skip_mount exist, skip!", module.display());
- continue;
- }
-
- let module_system = Path::new(&module).join("system");
- if module_system.is_dir() {
- system_lowerdir.push(format!("{}", module_system.display()));
- }
-
- for part in &partition {
- // if /partition is a mountpoint, we would move it to $MODPATH/$partition when install
- // otherwise it must be a symlink and we don't need to overlay!
- let part_path = Path::new(&module).join(part);
- if part_path.is_dir() {
- if let Some(v) = partition_lowerdir.get_mut(*part) {
- v.push(format!("{}", part_path.display()));
- }
- }
- }
- }
-
- // mount /system first
- if let Err(e) = mount_partition("system", &system_lowerdir) {
- warn!("mount system failed: {:#}", e);
- }
-
- // mount other partitions
- for (k, v) in partition_lowerdir {
- if let Err(e) = mount_partition(&k, &v) {
- warn!("mount {k} failed: {:#}", e);
- }
- }
-
- Ok(())
-}
-
-pub fn on_post_data_fs() -> Result<()> {
- ksucalls::report_post_fs_data();
-
- utils::umask(0);
-
- #[cfg(unix)]
- let _ = catch_bootlog("logcat", vec!["logcat"]);
- #[cfg(unix)]
- let _ = catch_bootlog("dmesg", vec!["dmesg", "-w"]);
-
- if utils::has_magisk() {
- warn!("Magisk detected, skip post-fs-data!");
- return Ok(());
- }
-
- let safe_mode = crate::utils::is_safe_mode();
-
- if safe_mode {
- // we should still mount modules.img to `/data/adb/modules` in safe mode
- // becuase we may need to operate the module dir in safe mode
- warn!("safe mode, skip common post-fs-data.d scripts");
- } else {
- // Then exec common post-fs-data scripts
- if let Err(e) = crate::module::exec_common_scripts("post-fs-data.d", true) {
- warn!("exec common post-fs-data scripts failed: {}", e);
- }
- }
-
- let module_update_img = defs::MODULE_UPDATE_IMG;
- let module_img = defs::MODULE_IMG;
- let module_dir = defs::MODULE_DIR;
- let module_update_flag = Path::new(defs::WORKING_DIR).join(defs::UPDATE_FILE_NAME);
-
- // modules.img is the default image
- let mut target_update_img = &module_img;
-
- // we should clean the module mount point if it exists
- ensure_clean_dir(module_dir)?;
-
- assets::ensure_binaries(true).with_context(|| "Failed to extract bin assets")?;
-
- if Path::new(module_update_img).exists() {
- if module_update_flag.exists() {
- // if modules_update.img exists, and the the flag indicate this is an update
- // this make sure that if the update failed, we will fallback to the old image
- // if we boot succeed, we will rename the modules_update.img to modules.img #on_boot_complete
- target_update_img = &module_update_img;
- // And we should delete the flag immediately
- std::fs::remove_file(module_update_flag)?;
- } else {
- // if modules_update.img exists, but the flag not exist, we should delete it
- std::fs::remove_file(module_update_img)?;
- }
- }
-
- if !Path::new(target_update_img).exists() {
- return Ok(());
- }
-
- // we should always mount the module.img to module dir
- // becuase we may need to operate the module dir in safe mode
- info!("mount module image: {target_update_img} to {module_dir}");
- mount::AutoMountExt4::try_new(target_update_img, module_dir, false)
- .with_context(|| "mount module image failed".to_string())?;
-
- // tell kernel that we've mount the module, so that it can do some optimization
- ksucalls::report_module_mounted();
-
- // if we are in safe mode, we should disable all modules
- if safe_mode {
- warn!("safe mode, skip post-fs-data scripts and disable all modules!");
- if let Err(e) = crate::module::disable_all_modules() {
- warn!("disable all modules failed: {}", e);
- }
- return Ok(());
- }
-
- if let Err(e) = prune_modules() {
- warn!("prune modules failed: {}", e);
- }
-
- if let Err(e) = restorecon::restorecon() {
- warn!("restorecon failed: {}", e);
- }
-
- // load sepolicy.rule
- if crate::module::load_sepolicy_rule().is_err() {
- warn!("load sepolicy.rule failed");
- }
-
- if let Err(e) = crate::profile::apply_sepolies() {
- warn!("apply root profile sepolicy failed: {}", e);
- }
-
- // mount temp dir
- if let Err(e) = mount::mount_tmpfs(utils::get_tmp_path()) {
- warn!("do temp dir mount failed: {}", e);
- }
-
- // exec modules post-fs-data scripts
- // TODO: Add timeout
- if let Err(e) = crate::module::exec_stage_script("post-fs-data", true) {
- warn!("exec post-fs-data scripts failed: {}", e);
- }
-
- // load system.prop
- if let Err(e) = crate::module::load_system_prop() {
- warn!("load system.prop failed: {}", e);
- }
-
- // mount module systemlessly by overlay
- if let Err(e) = mount_modules_systemlessly(module_dir) {
- warn!("do systemless mount failed: {}", e);
- }
-
- run_stage("post-mount", true);
-
- std::env::set_current_dir("/").with_context(|| "failed to chdir to /")?;
-
- Ok(())
-}
-
-fn run_stage(stage: &str, block: bool) {
- utils::umask(0);
-
- if utils::has_magisk() {
- warn!("Magisk detected, skip {stage}");
- return;
- }
-
- if crate::utils::is_safe_mode() {
- warn!("safe mode, skip {stage} scripts");
- return;
- }
-
- if let Err(e) = crate::module::exec_common_scripts(&format!("{stage}.d"), block) {
- warn!("Failed to exec common {stage} scripts: {e}");
- }
- if let Err(e) = crate::module::exec_stage_script(stage, block) {
- warn!("Failed to exec {stage} scripts: {e}");
- }
-}
-
-pub fn on_services() -> Result<()> {
- info!("on_services triggered!");
- run_stage("service", false);
-
- Ok(())
-}
-
-pub fn on_boot_completed() -> Result<()> {
- ksucalls::report_boot_complete();
- info!("on_boot_completed triggered!");
- let module_update_img = Path::new(defs::MODULE_UPDATE_IMG);
- let module_img = Path::new(defs::MODULE_IMG);
- if module_update_img.exists() {
- // this is a update and we successfully booted
- if std::fs::rename(module_update_img, module_img).is_err() {
- warn!("Failed to rename images, copy it now.",);
- utils::copy_sparse_file(module_update_img, module_img, false)
- .with_context(|| "Failed to copy images")?;
- std::fs::remove_file(module_update_img).with_context(|| "Failed to remove image!")?;
- }
- }
-
- run_stage("boot-completed", false);
-
- Ok(())
-}
-
-#[cfg(unix)]
-fn catch_bootlog(logname: &str, command: Vec<&str>) -> Result<()> {
- use std::os::unix::process::CommandExt;
- use std::process::Stdio;
-
- let logdir = Path::new(defs::LOG_DIR);
- utils::ensure_dir_exists(logdir)?;
- let bootlog = logdir.join(format!("{logname}.log"));
- let oldbootlog = logdir.join(format!("{logname}.old.log"));
-
- if bootlog.exists() {
- std::fs::rename(&bootlog, oldbootlog)?;
- }
-
- let bootlog = std::fs::File::create(bootlog)?;
-
- let mut args = vec!["-s", "9", "30s"];
- args.extend_from_slice(&command);
- // timeout -s 9 30s logcat > boot.log
- let result = unsafe {
- std::process::Command::new("timeout")
- .process_group(0)
- .pre_exec(|| {
- utils::switch_cgroups();
- Ok(())
- })
- .args(args)
- .stdout(Stdio::from(bootlog))
- .spawn()
- };
-
- if let Err(e) = result {
- warn!("Failed to start logcat: {:#}", e);
- }
-
- Ok(())
-}
diff --git a/userspace/ksud/src/installer.sh b/userspace/ksud/src/installer.sh
deleted file mode 100644
index 40138ae3..00000000
--- a/userspace/ksud/src/installer.sh
+++ /dev/null
@@ -1,446 +0,0 @@
-#!/system/bin/sh
-############################################
-# KernelSU installer script
-# mostly from module_installer.sh
-# and util_functions.sh in Magisk
-############################################
-
-umask 022
-
-ui_print() {
- if $BOOTMODE; then
- echo "$1"
- else
- echo -e "ui_print $1\nui_print" >> /proc/self/fd/$OUTFD
- fi
-}
-
-toupper() {
- echo "$@" | tr '[:lower:]' '[:upper:]'
-}
-
-grep_cmdline() {
- local REGEX="s/^$1=//p"
- { echo $(cat /proc/cmdline)$(sed -e 's/[^"]//g' -e 's/""//g' /proc/cmdline) | xargs -n 1; \
- sed -e 's/ = /=/g' -e 's/, /,/g' -e 's/"//g' /proc/bootconfig; \
- } 2>/dev/null | sed -n "$REGEX"
-}
-
-grep_prop() {
- local REGEX="s/$1=//p"
- shift
- local FILES=$@
- [ -z "$FILES" ] && FILES='/system/build.prop'
- cat $FILES 2>/dev/null | dos2unix | sed -n "$REGEX" | head -n 1 | xargs
-}
-
-grep_get_prop() {
- local result=$(grep_prop $@)
- if [ -z "$result" ]; then
- # Fallback to getprop
- getprop "$1"
- else
- echo $result
- fi
-}
-
-is_mounted() {
- grep -q " $(readlink -f $1) " /proc/mounts 2>/dev/null
- return $?
-}
-
-abort() {
- ui_print "$1"
- $BOOTMODE || recovery_cleanup
- [ ! -z $MODPATH ] && rm -rf $MODPATH
- rm -rf $TMPDIR
- exit 1
-}
-
-print_title() {
- local len line1len line2len bar
- line1len=$(echo -n $1 | wc -c)
- line2len=$(echo -n $2 | wc -c)
- len=$line2len
- [ $line1len -gt $line2len ] && len=$line1len
- len=$((len + 2))
- bar=$(printf "%${len}s" | tr ' ' '*')
- ui_print "$bar"
- ui_print " $1 "
- [ "$2" ] && ui_print " $2 "
- ui_print "$bar"
-}
-
-check_sepolicy() {
- /data/adb/ksud sepolicy check "$1"
- return $?
-}
-
-######################
-# Environment Related
-######################
-
-setup_flashable() {
- ensure_bb
- $BOOTMODE && return
- if [ -z $OUTFD ] || readlink /proc/$$/fd/$OUTFD | grep -q /tmp; then
- # We will have to manually find out OUTFD
- for FD in `ls /proc/$$/fd`; do
- if readlink /proc/$$/fd/$FD | grep -q pipe; then
- if ps | grep -v grep | grep -qE " 3 $FD |status_fd=$FD"; then
- OUTFD=$FD
- break
- fi
- fi
- done
- fi
- recovery_actions
-}
-
-ensure_bb() {
- :
-}
-
-recovery_actions() {
- :
-}
-
-recovery_cleanup() {
- :
-}
-
-#######################
-# Installation Related
-#######################
-
-# find_block [partname...]
-find_block() {
- local BLOCK DEV DEVICE DEVNAME PARTNAME UEVENT
- for BLOCK in "$@"; do
- DEVICE=`find /dev/block \( -type b -o -type c -o -type l \) -iname $BLOCK | head -n 1` 2>/dev/null
- if [ ! -z $DEVICE ]; then
- readlink -f $DEVICE
- return 0
- fi
- done
- # Fallback by parsing sysfs uevents
- for UEVENT in /sys/dev/block/*/uevent; do
- DEVNAME=`grep_prop DEVNAME $UEVENT`
- PARTNAME=`grep_prop PARTNAME $UEVENT`
- for BLOCK in "$@"; do
- if [ "$(toupper $BLOCK)" = "$(toupper $PARTNAME)" ]; then
- echo /dev/block/$DEVNAME
- return 0
- fi
- done
- done
- # Look just in /dev in case we're dealing with MTD/NAND without /dev/block devices/links
- for DEV in "$@"; do
- DEVICE=`find /dev \( -type b -o -type c -o -type l \) -maxdepth 1 -iname $DEV | head -n 1` 2>/dev/null
- if [ ! -z $DEVICE ]; then
- readlink -f $DEVICE
- return 0
- fi
- done
- return 1
-}
-
-# setup_mntpoint
-setup_mntpoint() {
- local POINT=$1
- [ -L $POINT ] && mv -f $POINT ${POINT}_link
- if [ ! -d $POINT ]; then
- rm -f $POINT
- mkdir -p $POINT
- fi
-}
-
-# mount_name
-mount_name() {
- local PART=$1
- local POINT=$2
- local FLAG=$3
- setup_mntpoint $POINT
- is_mounted $POINT && return
- # First try mounting with fstab
- mount $FLAG $POINT 2>/dev/null
- if ! is_mounted $POINT; then
- local BLOCK=$(find_block $PART)
- mount $FLAG $BLOCK $POINT || return
- fi
- ui_print "- Mounting $POINT"
-}
-
-# mount_ro_ensure
-mount_ro_ensure() {
- # We handle ro partitions only in recovery
- $BOOTMODE && return
- local PART=$1
- local POINT=$2
- mount_name "$PART" $POINT '-o ro'
- is_mounted $POINT || abort "! Cannot mount $POINT"
-}
-
-mount_partitions() {
- # Check A/B slot
- SLOT=`grep_cmdline androidboot.slot_suffix`
- if [ -z $SLOT ]; then
- SLOT=`grep_cmdline androidboot.slot`
- [ -z $SLOT ] || SLOT=_${SLOT}
- fi
- [ -z $SLOT ] || ui_print "- Current boot slot: $SLOT"
-
- # Mount ro partitions
- if is_mounted /system_root; then
- umount /system 2&>/dev/null
- umount /system_root 2&>/dev/null
- fi
- mount_ro_ensure "system$SLOT app$SLOT" /system
- if [ -f /system/init -o -L /system/init ]; then
- SYSTEM_ROOT=true
- setup_mntpoint /system_root
- if ! mount --move /system /system_root; then
- umount /system
- umount -l /system 2>/dev/null
- mount_ro_ensure "system$SLOT app$SLOT" /system_root
- fi
- mount -o bind /system_root/system /system
- else
- SYSTEM_ROOT=false
- grep ' / ' /proc/mounts | grep -qv 'rootfs' || grep -q ' /system_root ' /proc/mounts && SYSTEM_ROOT=true
- fi
- # /vendor is used only on some older devices for recovery AVBv1 signing so is not critical if fails
- [ -L /system/vendor ] && mount_name vendor$SLOT /vendor '-o ro'
- $SYSTEM_ROOT && ui_print "- Device is system-as-root"
-
- # Mount sepolicy rules dir locations in recovery (best effort)
- if ! $BOOTMODE; then
- mount_name "cache cac" /cache
- mount_name metadata /metadata
- mount_name persist /persist
- fi
-}
-
-api_level_arch_detect() {
- API=$(grep_get_prop ro.build.version.sdk)
- ABI=$(grep_get_prop ro.product.cpu.abi)
- if [ "$ABI" = "x86" ]; then
- ARCH=x86
- ABI32=x86
- IS64BIT=false
- elif [ "$ABI" = "arm64-v8a" ]; then
- ARCH=arm64
- ABI32=armeabi-v7a
- IS64BIT=true
- elif [ "$ABI" = "x86_64" ]; then
- ARCH=x64
- ABI32=x86
- IS64BIT=true
- else
- ARCH=arm
- ABI=armeabi-v7a
- ABI32=armeabi-v7a
- IS64BIT=false
- fi
-}
-
-#################
-# Module Related
-#################
-
-set_perm() {
- chown $2:$3 $1 || return 1
- chmod $4 $1 || return 1
- local CON=$5
- [ -z $CON ] && CON=u:object_r:system_file:s0
- chcon $CON $1 || return 1
-}
-
-set_perm_recursive() {
- find $1 -type d 2>/dev/null | while read dir; do
- set_perm $dir $2 $3 $4 $6
- done
- find $1 -type f -o -type l 2>/dev/null | while read file; do
- set_perm $file $2 $3 $5 $6
- done
-}
-
-mktouch() {
- mkdir -p ${1%/*} 2>/dev/null
- [ -z $2 ] && touch $1 || echo $2 > $1
- chmod 644 $1
-}
-
-mark_remove() {
- mkdir -p ${1%/*} 2>/dev/null
- mknod $1 c 0 0
- chmod 644 $1
-}
-
-mark_replace() {
- # REPLACE must be directory!!!
- # https://docs.kernel.org/filesystems/overlayfs.html#whiteouts-and-opaque-directories
- mkdir -p $1 2>/dev/null
- setfattr -n trusted.overlay.opaque -v y $1
- chmod 644 $1
-}
-
-request_size_check() {
- reqSizeM=`du -ms "$1" | cut -f1`
-}
-
-request_zip_size_check() {
- reqSizeM=`unzip -l "$1" | tail -n 1 | awk '{ print int(($1 - 1) / 1048576 + 1) }'`
-}
-
-boot_actions() { return; }
-
-# Require ZIPFILE to be set
-is_legacy_script() {
- unzip -l "$ZIPFILE" install.sh | grep -q install.sh
- return $?
-}
-
-handle_partition() {
- # if /system/vendor is a symlink, we need to move it out of $MODPATH/system, otherwise it will be overlayed
- # if /system/vendor is a normal directory, it is ok to overlay it and we don't need to overlay it separately.
- if [ ! -e $MODPATH/system/$1 ]; then
- # no partition found
- return;
- fi
-
- if [ -L "/system/$1" ] && [ "$(readlink -f /system/$1)" = "/$1" ]; then
- ui_print "- Handle partition /$1"
- # we create a symlink if module want to access $MODPATH/system/$1
- # but it doesn't always work(ie. write it in post-fs-data.sh would fail because it is readonly)
- mv -f $MODPATH/system/$1 $MODPATH/$1 && ln -sf ../$1 $MODPATH/system/$1
- fi
-}
-
-# Require OUTFD, ZIPFILE to be set
-install_module() {
- rm -rf $TMPDIR
- mkdir -p $TMPDIR
- chcon u:object_r:system_file:s0 $TMPDIR
- cd $TMPDIR
-
- mount_partitions
- api_level_arch_detect
-
- # Setup busybox and binaries
- if $BOOTMODE; then
- boot_actions
- else
- recovery_actions
- fi
-
- # Extract prop file
- unzip -o "$ZIPFILE" module.prop -d $TMPDIR >&2
- [ ! -f $TMPDIR/module.prop ] && abort "! Unable to extract zip file!"
-
- local MODDIRNAME=modules
- $BOOTMODE && MODDIRNAME=modules_update
- local MODULEROOT=$NVBASE/$MODDIRNAME
- MODID=`grep_prop id $TMPDIR/module.prop`
- MODNAME=`grep_prop name $TMPDIR/module.prop`
- MODAUTH=`grep_prop author $TMPDIR/module.prop`
- MODPATH=$MODULEROOT/$MODID
-
- # Create mod paths
- rm -rf $MODPATH
- mkdir -p $MODPATH
-
- if is_legacy_script; then
- unzip -oj "$ZIPFILE" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2
-
- # Load install script
- . $TMPDIR/install.sh
-
- # Callbacks
- print_modname
- on_install
-
- [ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh
- $SKIPMOUNT && touch $MODPATH/skip_mount
- $PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop
- cp -af $TMPDIR/module.prop $MODPATH/module.prop
- $POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh
- $LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh
-
- ui_print "- Setting permissions"
- set_permissions
- else
- print_title "$MODNAME" "by $MODAUTH"
- print_title "Powered by KernelSU"
-
- unzip -o "$ZIPFILE" customize.sh -d $MODPATH >&2
-
- if ! grep -q '^SKIPUNZIP=1$' $MODPATH/customize.sh 2>/dev/null; then
- ui_print "- Extracting module files"
- unzip -o "$ZIPFILE" -x 'META-INF/*' -d $MODPATH >&2
-
- # Default permissions
- set_perm_recursive $MODPATH 0 0 0755 0644
- set_perm_recursive $MODPATH/system/bin 0 2000 0755 0755
- set_perm_recursive $MODPATH/system/xbin 0 2000 0755 0755
- set_perm_recursive $MODPATH/system/system_ext/bin 0 2000 0755 0755
- set_perm_recursive $MODPATH/system/vendor 0 2000 0755 0755 u:object_r:vendor_file:s0
- fi
-
- # Load customization script
- [ -f $MODPATH/customize.sh ] && . $MODPATH/customize.sh
- fi
-
- # Handle replace folders
- for TARGET in $REPLACE; do
- ui_print "- Replace target: $TARGET"
- mark_replace $MODPATH$TARGET
- done
-
- # Handle remove files
- for TARGET in $REMOVE; do
- ui_print "- Remove target: $TARGET"
- mark_remove $MODPATH$TARGET
- done
-
- handle_partition vendor
- handle_partition system_ext
- handle_partition product
-
- if $BOOTMODE; then
- mktouch $NVBASE/modules/$MODID/update
- rm -rf $NVBASE/modules/$MODID/remove 2>/dev/null
- rm -rf $NVBASE/modules/$MODID/disable 2>/dev/null
- cp -af $MODPATH/module.prop $NVBASE/modules/$MODID/module.prop
- fi
-
- # Remove stuff that doesn't belong to modules and clean up any empty directories
- rm -rf \
- $MODPATH/system/placeholder $MODPATH/customize.sh \
- $MODPATH/README.md $MODPATH/.git*
- rmdir -p $MODPATH 2>/dev/null
-
- cd /
- $BOOTMODE || recovery_cleanup
- rm -rf $TMPDIR
-
- ui_print "- Done"
-}
-
-##########
-# Presets
-##########
-
-# Detect whether in boot mode
-[ -z $BOOTMODE ] && ps | grep zygote | grep -qv grep && BOOTMODE=true
-[ -z $BOOTMODE ] && ps -A 2>/dev/null | grep zygote | grep -qv grep && BOOTMODE=true
-[ -z $BOOTMODE ] && BOOTMODE=false
-
-NVBASE=/data/adb
-TMPDIR=/dev/tmp
-POSTFSDATAD=$NVBASE/post-fs-data.d
-SERVICED=$NVBASE/service.d
-
-# Some modules dependents on this
-export MAGISK_VER=25.2
-export MAGISK_VER_CODE=25200
diff --git a/userspace/ksud/src/ksucalls.rs b/userspace/ksud/src/ksucalls.rs
deleted file mode 100644
index 596df545..00000000
--- a/userspace/ksud/src/ksucalls.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-const EVENT_POST_FS_DATA: u64 = 1;
-const EVENT_BOOT_COMPLETED: u64 = 2;
-const EVENT_MODULE_MOUNTED: u64 = 3;
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn get_version() -> i32 {
- rustix::process::ksu_get_version()
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
-pub fn get_version() -> i32 {
- 0
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-fn report_event(event: u64) {
- rustix::process::ksu_report_event(event)
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
-fn report_event(_event: u64) {}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn check_kernel_safemode() -> bool {
- rustix::process::ksu_check_kernel_safemode()
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
-pub fn check_kernel_safemode() -> bool {
- false
-}
-
-pub fn report_post_fs_data() {
- report_event(EVENT_POST_FS_DATA);
-}
-
-pub fn report_boot_complete() {
- report_event(EVENT_BOOT_COMPLETED);
-}
-
-pub fn report_module_mounted() {
- report_event(EVENT_MODULE_MOUNTED);
-}
diff --git a/userspace/ksud/src/main.rs b/userspace/ksud/src/main.rs
deleted file mode 100644
index 3b517205..00000000
--- a/userspace/ksud/src/main.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-mod apk_sign;
-mod assets;
-mod boot_patch;
-mod cli;
-mod debug;
-mod defs;
-mod init_event;
-mod ksucalls;
-mod module;
-mod mount;
-mod profile;
-mod restorecon;
-mod sepolicy;
-mod su;
-mod utils;
-
-fn main() -> anyhow::Result<()> {
- cli::run()
-}
diff --git a/userspace/ksud/src/module.rs b/userspace/ksud/src/module.rs
deleted file mode 100644
index ac3ff213..00000000
--- a/userspace/ksud/src/module.rs
+++ /dev/null
@@ -1,709 +0,0 @@
-#[allow(clippy::wildcard_imports)]
-use crate::utils::*;
-use crate::{
- assets, defs, ksucalls, mount,
- restorecon::{restore_syscon, setsyscon},
- sepolicy, utils,
-};
-
-use anyhow::{anyhow, bail, ensure, Context, Result};
-use const_format::concatcp;
-use is_executable::is_executable;
-use java_properties::PropertiesIter;
-use log::{info, warn};
-
-use std::fs::OpenOptions;
-use std::{
- collections::HashMap,
- env::var as env_var,
- fs::{remove_dir_all, remove_file, set_permissions, File, Permissions},
- io::Cursor,
- path::{Path, PathBuf},
- process::{Command, Stdio},
- str::FromStr,
-};
-use zip_extensions::zip_extract_file_to_memory;
-
-#[cfg(unix)]
-use std::os::unix::{fs::MetadataExt, prelude::PermissionsExt, process::CommandExt};
-
-const INSTALLER_CONTENT: &str = include_str!("./installer.sh");
-const INSTALL_MODULE_SCRIPT: &str = concatcp!(
- INSTALLER_CONTENT,
- "\n",
- "install_module",
- "\n",
- "exit 0",
- "\n"
-);
-
-fn exec_install_script(module_file: &str) -> Result<()> {
- let realpath = std::fs::canonicalize(module_file)
- .with_context(|| format!("realpath: {module_file} failed"))?;
-
- let result = Command::new(assets::BUSYBOX_PATH)
- .args(["sh", "-c", INSTALL_MODULE_SCRIPT])
- .env("ASH_STANDALONE", "1")
- .env(
- "PATH",
- format!(
- "{}:{}",
- env_var("PATH").unwrap(),
- defs::BINARY_DIR.trim_end_matches('/')
- ),
- )
- .env("KSU", "true")
- .env("KSU_KERNEL_VER_CODE", ksucalls::get_version().to_string())
- .env("KSU_VER", defs::VERSION_NAME)
- .env("KSU_VER_CODE", defs::VERSION_CODE)
- .env("OUTFD", "1")
- .env("ZIPFILE", realpath)
- .status()?;
- ensure!(result.success(), "Failed to install module script");
- Ok(())
-}
-
-// becuase we use something like A-B update
-// we need to update the module state after the boot_completed
-// if someone(such as the module) install a module before the boot_completed
-// then it may cause some problems, just forbid it
-fn ensure_boot_completed() -> Result<()> {
- // ensure getprop sys.boot_completed == 1
- if getprop("sys.boot_completed").as_deref() != Some("1") {
- bail!("Android is Booting!");
- }
- Ok(())
-}
-
-fn mark_update() -> Result<()> {
- ensure_file_exists(concatcp!(defs::WORKING_DIR, defs::UPDATE_FILE_NAME))
-}
-
-fn mark_module_state(module: &str, flag_file: &str, create_or_delete: bool) -> Result<()> {
- let module_state_file = Path::new(defs::MODULE_DIR).join(module).join(flag_file);
- if create_or_delete {
- ensure_file_exists(module_state_file)
- } else {
- if module_state_file.exists() {
- std::fs::remove_file(module_state_file)?;
- }
- Ok(())
- }
-}
-
-fn foreach_module(active_only: bool, mut f: impl FnMut(&Path) -> Result<()>) -> Result<()> {
- let modules_dir = Path::new(defs::MODULE_DIR);
- let dir = std::fs::read_dir(modules_dir)?;
- for entry in dir.flatten() {
- let path = entry.path();
- if !path.is_dir() {
- warn!("{} is not a directory, skip", path.display());
- continue;
- }
-
- if active_only && path.join(defs::DISABLE_FILE_NAME).exists() {
- info!("{} is disabled, skip", path.display());
- continue;
- }
- if active_only && path.join(defs::REMOVE_FILE_NAME).exists() {
- warn!("{} is removed, skip", path.display());
- continue;
- }
-
- f(&path)?;
- }
-
- Ok(())
-}
-
-fn foreach_active_module(f: impl FnMut(&Path) -> Result<()>) -> Result<()> {
- foreach_module(true, f)
-}
-
-fn check_image(img: &str) -> Result<()> {
- let result = Command::new("e2fsck")
- .args(["-yf", img])
- .stdout(Stdio::piped())
- .status()
- .with_context(|| format!("Failed to exec e2fsck {img}"))?;
- let code = result.code();
- // 0 or 1 is ok
- // 0: no error
- // 1: file system errors corrected
- // https://man7.org/linux/man-pages/man8/e2fsck.8.html
- // ensure!(
- // code == Some(0) || code == Some(1),
- // "Failed to check image, e2fsck exit code: {}",
- // code.unwrap_or(-1)
- // );
- info!("e2fsck exit code: {}", code.unwrap_or(-1));
- Ok(())
-}
-
-pub fn load_sepolicy_rule() -> Result<()> {
- foreach_active_module(|path| {
- let rule_file = path.join("sepolicy.rule");
- if !rule_file.exists() {
- return Ok(());
- }
- info!("load policy: {}", &rule_file.display());
-
- if sepolicy::apply_file(&rule_file).is_err() {
- warn!("Failed to load sepolicy.rule for {}", &rule_file.display());
- }
- Ok(())
- })?;
-
- Ok(())
-}
-
-fn exec_script>(path: T, wait: bool) -> Result<()> {
- info!("exec {}", path.as_ref().display());
-
- let mut command = &mut Command::new(assets::BUSYBOX_PATH);
- #[cfg(unix)]
- {
- command = command.process_group(0);
- command = unsafe {
- command.pre_exec(|| {
- // ignore the error?
- switch_cgroups();
- Ok(())
- })
- };
- }
- command = command
- .current_dir(path.as_ref().parent().unwrap())
- .arg("sh")
- .arg(path.as_ref())
- .env("ASH_STANDALONE", "1")
- .env("KSU", "true")
- .env("KSU_KERNEL_VER_CODE", ksucalls::get_version().to_string())
- .env("KSU_VER_CODE", defs::VERSION_CODE)
- .env("KSU_VER", defs::VERSION_NAME)
- .env(
- "PATH",
- format!(
- "{}:{}",
- env_var("PATH").unwrap(),
- defs::BINARY_DIR.trim_end_matches('/')
- ),
- );
-
- let result = if wait {
- command.status().map(|_| ())
- } else {
- command.spawn().map(|_| ())
- };
- result.map_err(|err| anyhow!("Failed to exec {}: {}", path.as_ref().display(), err))
-}
-
-pub fn exec_stage_script(stage: &str, block: bool) -> Result<()> {
- foreach_active_module(|module| {
- let script_path = module.join(format!("{stage}.sh"));
- if !script_path.exists() {
- return Ok(());
- }
-
- exec_script(&script_path, block)
- })?;
-
- Ok(())
-}
-
-pub fn exec_common_scripts(dir: &str, wait: bool) -> Result<()> {
- let script_dir = Path::new(defs::ADB_DIR).join(dir);
- if !script_dir.exists() {
- info!("{} not exists, skip", script_dir.display());
- return Ok(());
- }
-
- let dir = std::fs::read_dir(&script_dir)?;
- for entry in dir.flatten() {
- let path = entry.path();
-
- if !is_executable(&path) {
- warn!("{} is not executable, skip", path.display());
- continue;
- }
-
- exec_script(path, wait)?;
- }
-
- Ok(())
-}
-
-pub fn load_system_prop() -> Result<()> {
- foreach_active_module(|module| {
- let system_prop = module.join("system.prop");
- if !system_prop.exists() {
- return Ok(());
- }
- info!("load {} system.prop", module.display());
-
- // resetprop -n --file system.prop
- Command::new(assets::RESETPROP_PATH)
- .arg("-n")
- .arg("--file")
- .arg(&system_prop)
- .status()
- .with_context(|| format!("Failed to exec {}", system_prop.display()))?;
-
- Ok(())
- })?;
-
- Ok(())
-}
-
-pub fn prune_modules() -> Result<()> {
- foreach_module(false, |module| {
- remove_file(module.join(defs::UPDATE_FILE_NAME)).ok();
-
- if !module.join(defs::REMOVE_FILE_NAME).exists() {
- return Ok(());
- }
-
- info!("remove module: {}", module.display());
-
- let uninstaller = module.join("uninstall.sh");
- if uninstaller.exists() {
- if let Err(e) = exec_script(uninstaller, true) {
- warn!("Failed to exec uninstaller: {}", e);
- }
- }
-
- if let Err(e) = remove_dir_all(module) {
- warn!("Failed to remove {}: {}", module.display(), e);
- }
-
- Ok(())
- })?;
-
- Ok(())
-}
-
-fn create_module_image(image: &str, image_size: u64, journal_size: u64) -> Result<()> {
- File::create(image)
- .context("Failed to create ext4 image file")?
- .set_len(image_size)
- .context("Failed to truncate ext4 image")?;
-
- // format the img to ext4 filesystem
- let result = Command::new("mkfs.ext4")
- .arg("-J")
- .arg(format!("size={journal_size}"))
- .arg(image)
- .stdout(Stdio::piped())
- .output()?;
- ensure!(
- result.status.success(),
- "Failed to format ext4 image: {}",
- String::from_utf8(result.stderr).unwrap()
- );
- check_image(image)?;
- Ok(())
-}
-fn _install_module(zip: &str) -> Result<()> {
- ensure_boot_completed()?;
-
- // print banner
- println!(include_str!("banner"));
-
- assets::ensure_binaries(false).with_context(|| "Failed to extract assets")?;
-
- // first check if workding dir is usable
- ensure_dir_exists(defs::WORKING_DIR).with_context(|| "Failed to create working dir")?;
- ensure_dir_exists(defs::BINARY_DIR).with_context(|| "Failed to create bin dir")?;
-
- // read the module_id from zip, if faild if will return early.
- let mut buffer: Vec = Vec::new();
- let entry_path = PathBuf::from_str("module.prop")?;
- let zip_path = PathBuf::from_str(zip)?;
- let zip_path = zip_path.canonicalize()?;
- zip_extract_file_to_memory(&zip_path, &entry_path, &mut buffer)?;
-
- let mut module_prop = HashMap::new();
- PropertiesIter::new_with_encoding(Cursor::new(buffer), encoding_rs::UTF_8).read_into(
- |k, v| {
- module_prop.insert(k, v);
- },
- )?;
- info!("module prop: {:?}", module_prop);
-
- let Some(module_id) = module_prop.get("id") else {
- bail!("module id not found in module.prop!");
- };
- let module_id = module_id.trim();
-
- let modules_img = Path::new(defs::MODULE_IMG);
- let modules_update_img = Path::new(defs::MODULE_UPDATE_IMG);
- let module_update_tmp_dir = defs::MODULE_UPDATE_TMP_DIR;
-
- let modules_img_exist = modules_img.exists();
- let modules_update_img_exist = modules_update_img.exists();
-
- // prepare the tmp module img
- let tmp_module_img = defs::MODULE_UPDATE_TMP_IMG;
- let tmp_module_path = Path::new(tmp_module_img);
- if tmp_module_path.exists() {
- std::fs::remove_file(tmp_module_path)?;
- }
-
- let zip_uncompressed_size = get_zip_uncompressed_size(zip)?;
-
- info!(
- "zip uncompressed size: {}",
- humansize::format_size(zip_uncompressed_size, humansize::DECIMAL)
- );
-
- println!("- Preparing image");
- println!(
- "- Module size: {}",
- humansize::format_size(zip_uncompressed_size, humansize::DECIMAL)
- );
-
- let sparse_image_size = 1 << 40; // 1T
- let journal_size = 8; // 8M
- if !modules_img_exist && !modules_update_img_exist {
- // if no modules and modules_update, it is brand new installation, we should create a new img
- // create a tmp module img and mount it to modules_update
- info!("Creating brand new module image");
- create_module_image(tmp_module_img, sparse_image_size, journal_size)?;
- } else if modules_update_img_exist {
- // modules_update.img exists, we should use it as tmp img
- info!("Using existing modules_update.img as tmp image");
- utils::copy_sparse_file(modules_update_img, tmp_module_img, true).with_context(|| {
- format!(
- "Failed to copy {} to {}",
- modules_update_img.display(),
- tmp_module_img
- )
- })?;
- } else {
- // modules.img exists, we should use it as tmp img
- info!("Using existing modules.img as tmp image");
-
- #[cfg(unix)]
- let blksize = std::fs::metadata(defs::MODULE_DIR)?.blksize();
- #[cfg(not(unix))]
- let blksize = 0;
- // legacy image, it's block size is 1024 with unlimited journal size
- if blksize == 1024 {
- println!("- Legacy image, migrating to new format, please be patient...");
- create_module_image(tmp_module_img, sparse_image_size, journal_size)?;
- let _dontdrop =
- mount::AutoMountExt4::try_new(tmp_module_img, module_update_tmp_dir, true)
- .with_context(|| format!("Failed to mount {tmp_module_img}"))?;
- utils::copy_module_files(defs::MODULE_DIR, module_update_tmp_dir)
- .with_context(|| "Failed to migrate module files".to_string())?;
- } else {
- utils::copy_sparse_file(modules_img, tmp_module_img, true)
- .with_context(|| "Failed to copy module image".to_string())?;
-
- if std::fs::metadata(tmp_module_img)?.len() < sparse_image_size {
- // truncate the file to new size
- OpenOptions::new()
- .write(true)
- .open(tmp_module_img)
- .context("Failed to open ext4 image")?
- .set_len(sparse_image_size)
- .context("Failed to truncate ext4 image")?;
-
- // resize the image to new size
- check_image(tmp_module_img)?;
- Command::new("resize2fs")
- .arg(tmp_module_img)
- .stdout(Stdio::piped())
- .status()?;
- }
- }
- }
-
- // ensure modules_update exists
- ensure_dir_exists(module_update_tmp_dir)?;
-
- // mount the modules_update.img to mountpoint
- println!("- Mounting image");
-
- let _dontdrop = mount::AutoMountExt4::try_new(tmp_module_img, module_update_tmp_dir, true)?;
-
- info!("mounted {} to {}", tmp_module_img, module_update_tmp_dir);
-
- setsyscon(module_update_tmp_dir)?;
-
- let module_dir = format!("{module_update_tmp_dir}/{module_id}");
- ensure_clean_dir(&module_dir)?;
- info!("module dir: {}", module_dir);
-
- // unzip the image and move it to modules_update/ dir
- let file = File::open(zip)?;
- let mut archive = zip::ZipArchive::new(file)?;
- archive.extract(&module_dir)?;
-
- // set permission and selinux context for $MOD/system
- let module_system_dir = PathBuf::from(module_dir).join("system");
- if module_system_dir.exists() {
- #[cfg(unix)]
- set_permissions(&module_system_dir, Permissions::from_mode(0o755))?;
- restore_syscon(&module_system_dir)?;
- }
-
- exec_install_script(zip)?;
-
- info!("rename {tmp_module_img} to {}", defs::MODULE_UPDATE_IMG);
- // all done, rename the tmp image to modules_update.img
- if std::fs::rename(tmp_module_img, defs::MODULE_UPDATE_IMG).is_err() {
- warn!("Rename image failed, try copy it.");
- utils::copy_sparse_file(tmp_module_img, defs::MODULE_UPDATE_IMG, true)
- .with_context(|| "Failed to copy image.".to_string())?;
- let _ = std::fs::remove_file(tmp_module_img);
- }
-
- mark_update()?;
-
- info!("Module install successfully!");
-
- Ok(())
-}
-
-pub fn install_module(zip: &str) -> Result<()> {
- let result = _install_module(zip);
- if let Err(ref e) = result {
- // error happened, do some cleanup!
- let _ = std::fs::remove_file(defs::MODULE_UPDATE_TMP_IMG);
- let _ = mount::umount_dir(defs::MODULE_UPDATE_TMP_DIR);
- println!("- Error: {e}");
- }
- result
-}
-
-fn update_module(update_dir: &str, id: &str, func: F) -> Result<()>
-where
- F: Fn(&str, &str) -> Result<()>,
-{
- ensure_boot_completed()?;
-
- let modules_img = Path::new(defs::MODULE_IMG);
- let modules_update_img = Path::new(defs::MODULE_UPDATE_IMG);
- let modules_update_tmp_img = Path::new(defs::MODULE_UPDATE_TMP_IMG);
- if !modules_update_img.exists() && !modules_img.exists() {
- bail!("Please install module first!");
- } else if modules_update_img.exists() {
- info!(
- "copy {} to {}",
- modules_update_img.display(),
- modules_update_tmp_img.display()
- );
- utils::copy_sparse_file(modules_update_img, modules_update_tmp_img, true)?;
- } else {
- info!(
- "copy {} to {}",
- modules_img.display(),
- modules_update_tmp_img.display()
- );
- utils::copy_sparse_file(modules_img, modules_update_tmp_img, true)?;
- }
-
- // ensure modules_update dir exist
- ensure_clean_dir(update_dir)?;
-
- // mount the modules_update img
- let _dontdrop = mount::AutoMountExt4::try_new(defs::MODULE_UPDATE_TMP_IMG, update_dir, true)?;
-
- // call the operation func
- let result = func(id, update_dir);
-
- if let Err(e) = std::fs::rename(modules_update_tmp_img, defs::MODULE_UPDATE_IMG) {
- warn!("Rename image failed: {e}, try copy it.");
- utils::copy_sparse_file(modules_update_tmp_img, defs::MODULE_UPDATE_IMG, true)
- .with_context(|| "Failed to copy image.".to_string())?;
- let _ = std::fs::remove_file(modules_update_tmp_img);
- }
-
- mark_update()?;
-
- result
-}
-
-pub fn uninstall_module(id: &str) -> Result<()> {
- update_module(defs::MODULE_UPDATE_TMP_DIR, id, |mid, update_dir| {
- let dir = Path::new(update_dir);
- ensure!(dir.exists(), "No module installed");
-
- // iterate the modules_update dir, find the module to be removed
- let dir = std::fs::read_dir(dir)?;
- for entry in dir.flatten() {
- let path = entry.path();
- let module_prop = path.join("module.prop");
- if !module_prop.exists() {
- continue;
- }
- let content = std::fs::read(module_prop)?;
- let mut module_id: String = String::new();
- PropertiesIter::new_with_encoding(Cursor::new(content), encoding_rs::UTF_8).read_into(
- |k, v| {
- if k.eq("id") {
- module_id = v;
- }
- },
- )?;
- if module_id.eq(mid) {
- let remove_file = path.join(defs::REMOVE_FILE_NAME);
- File::create(remove_file).with_context(|| "Failed to create remove file.")?;
- break;
- }
- }
-
- // santity check
- let target_module_path = format!("{update_dir}/{mid}");
- let target_module = Path::new(&target_module_path);
- if target_module.exists() {
- let remove_file = target_module.join(defs::REMOVE_FILE_NAME);
- if !remove_file.exists() {
- File::create(remove_file).with_context(|| "Failed to create remove file.")?;
- }
- }
-
- let _ = mark_module_state(id, defs::REMOVE_FILE_NAME, true);
-
- Ok(())
- })
-}
-
-fn _enable_module(module_dir: &str, mid: &str, enable: bool) -> Result<()> {
- let src_module_path = format!("{module_dir}/{mid}");
- let src_module = Path::new(&src_module_path);
- ensure!(src_module.exists(), "module: {} not found!", mid);
-
- let disable_path = src_module.join(defs::DISABLE_FILE_NAME);
- if enable {
- if disable_path.exists() {
- std::fs::remove_file(&disable_path).with_context(|| {
- format!("Failed to remove disable file: {}", &disable_path.display())
- })?;
- }
- } else {
- ensure_file_exists(disable_path)?;
- }
-
- let _ = mark_module_state(mid, defs::DISABLE_FILE_NAME, !enable);
-
- Ok(())
-}
-
-pub fn enable_module(id: &str) -> Result<()> {
- update_module(defs::MODULE_UPDATE_TMP_DIR, id, |mid, update_dir| {
- _enable_module(update_dir, mid, true)
- })
-}
-
-pub fn disable_module(id: &str) -> Result<()> {
- update_module(defs::MODULE_UPDATE_TMP_DIR, id, |mid, update_dir| {
- _enable_module(update_dir, mid, false)
- })
-}
-
-pub fn disable_all_modules() -> Result<()> {
- mark_all_modules(defs::DISABLE_FILE_NAME)
-}
-
-pub fn uninstall_all_modules() -> Result<()> {
- mark_all_modules(defs::REMOVE_FILE_NAME)
-}
-
-fn mark_all_modules(flag_file: &str) -> Result<()> {
- // we assume the module dir is already mounted
- let dir = std::fs::read_dir(defs::MODULE_DIR)?;
- for entry in dir.flatten() {
- let path = entry.path();
- let flag = path.join(flag_file);
- if let Err(e) = ensure_file_exists(flag) {
- warn!("Failed to mark module: {}: {}", path.display(), e);
- }
- }
-
- Ok(())
-}
-
-fn _list_modules(path: &str) -> Vec> {
- // first check enabled modules
- let dir = std::fs::read_dir(path);
- let Ok(dir) = dir else {
- return Vec::new();
- };
-
- let mut modules: Vec> = Vec::new();
-
- for entry in dir.flatten() {
- let path = entry.path();
- info!("path: {}", path.display());
- let module_prop = path.join("module.prop");
- if !module_prop.exists() {
- continue;
- }
- let content = std::fs::read(&module_prop);
- let Ok(content) = content else {
- warn!("Failed to read file: {}", module_prop.display());
- continue;
- };
- let mut module_prop_map: HashMap = HashMap::new();
- let encoding = encoding_rs::UTF_8;
- let result =
- PropertiesIter::new_with_encoding(Cursor::new(content), encoding).read_into(|k, v| {
- module_prop_map.insert(k, v);
- });
-
- if !module_prop_map.contains_key("id") || module_prop_map["id"].is_empty() {
- if let Some(id) = entry.file_name().to_str() {
- info!("Use dir name as module id: {}", id);
- module_prop_map.insert("id".to_owned(), id.to_owned());
- } else {
- info!("Failed to get module id: {:?}", module_prop);
- continue;
- }
- }
-
- // Add enabled, update, remove flags
- let enabled = !path.join(defs::DISABLE_FILE_NAME).exists();
- let update = path.join(defs::UPDATE_FILE_NAME).exists();
- let remove = path.join(defs::REMOVE_FILE_NAME).exists();
- let web = path.join(defs::MODULE_WEB_DIR).exists();
-
- module_prop_map.insert("enabled".to_owned(), enabled.to_string());
- module_prop_map.insert("update".to_owned(), update.to_string());
- module_prop_map.insert("remove".to_owned(), remove.to_string());
- module_prop_map.insert("web".to_owned(), web.to_string());
-
- if result.is_err() {
- warn!("Failed to parse module.prop: {}", module_prop.display());
- continue;
- }
- modules.push(module_prop_map);
- }
-
- modules
-}
-
-pub fn list_modules() -> Result<()> {
- let modules = _list_modules(defs::MODULE_DIR);
- println!("{}", serde_json::to_string_pretty(&modules)?);
- Ok(())
-}
-
-pub fn shrink_image(img: &str) -> Result<()> {
- check_image(img)?;
- Command::new("resize2fs")
- .arg("-M")
- .arg(img)
- .stdout(Stdio::piped())
- .status()?;
- Ok(())
-}
-
-pub fn shrink_ksu_images() -> Result<()> {
- shrink_image(defs::MODULE_IMG)?;
- if Path::new(defs::MODULE_UPDATE_IMG).exists() {
- shrink_image(defs::MODULE_UPDATE_IMG)?;
- }
- Ok(())
-}
diff --git a/userspace/ksud/src/mount.rs b/userspace/ksud/src/mount.rs
deleted file mode 100644
index 11be898b..00000000
--- a/userspace/ksud/src/mount.rs
+++ /dev/null
@@ -1,327 +0,0 @@
-use anyhow::{anyhow, bail, Ok, Result};
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-use anyhow::Context;
-#[cfg(any(target_os = "linux", target_os = "android"))]
-use rustix::{fd::AsFd, fs::CWD, mount::*};
-
-use crate::defs::KSU_OVERLAY_SOURCE;
-use log::{info, warn};
-#[cfg(any(target_os = "linux", target_os = "android"))]
-use procfs::process::Process;
-use std::path::Path;
-use std::path::PathBuf;
-
-pub struct AutoMountExt4 {
- target: String,
- auto_umount: bool,
-}
-
-impl AutoMountExt4 {
- #[cfg(any(target_os = "linux", target_os = "android"))]
- pub fn try_new(source: &str, target: &str, auto_umount: bool) -> Result {
- mount_ext4(source, target)?;
- Ok(Self {
- target: target.to_string(),
- auto_umount,
- })
- }
-
- #[cfg(not(any(target_os = "linux", target_os = "android")))]
- pub fn try_new(_src: &str, _mnt: &str, _auto_umount: bool) -> Result {
- unimplemented!()
- }
-
- #[cfg(any(target_os = "linux", target_os = "android"))]
- pub fn umount(&self) -> Result<()> {
- unmount(self.target.as_str(), UnmountFlags::DETACH)?;
- Ok(())
- }
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-impl Drop for AutoMountExt4 {
- fn drop(&mut self) {
- log::info!(
- "AutoMountExt4 drop: {}, auto_umount: {}",
- self.target,
- self.auto_umount
- );
- if self.auto_umount {
- let _ = self.umount();
- }
- }
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn mount_ext4(source: impl AsRef, target: impl AsRef) -> Result<()> {
- let new_loopback = loopdev::LoopControl::open()?
- .next_free()
- .with_context(|| "Failed to alloc loop")?;
- new_loopback
- .with()
- .attach(source)
- .with_context(|| "Failed to attach loop")?;
- let lo = new_loopback.path().ok_or(anyhow!("no loop"))?;
- if let Result::Ok(fs) = fsopen("ext4", FsOpenFlags::FSOPEN_CLOEXEC) {
- let fs = fs.as_fd();
- fsconfig_set_string(fs, "source", lo)?;
- fsconfig_create(fs)?;
- let mount = fsmount(fs, FsMountFlags::FSMOUNT_CLOEXEC, MountAttrFlags::empty())?;
- move_mount(
- mount.as_fd(),
- "",
- CWD,
- target.as_ref(),
- MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH,
- )?;
- } else {
- mount(lo, target.as_ref(), "ext4", MountFlags::empty(), "")?;
- }
- Ok(())
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn umount_dir(src: impl AsRef) -> Result<()> {
- unmount(src.as_ref(), UnmountFlags::empty())
- .with_context(|| format!("Failed to umount {}", src.as_ref().display()))?;
- Ok(())
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn mount_overlayfs(
- lower_dirs: &[String],
- lowest: &str,
- upperdir: Option,
- workdir: Option,
- dest: impl AsRef,
-) -> Result<()> {
- let lowerdir_config = lower_dirs
- .iter()
- .map(|s| s.as_ref())
- .chain(std::iter::once(lowest))
- .collect::>()
- .join(":");
- info!(
- "mount overlayfs on {:?}, lowerdir={}, upperdir={:?}, workdir={:?}",
- dest.as_ref(),
- lowerdir_config,
- upperdir,
- workdir
- );
-
- let upperdir = upperdir
- .filter(|up| up.exists())
- .map(|e| e.display().to_string());
- let workdir = workdir
- .filter(|wd| wd.exists())
- .map(|e| e.display().to_string());
-
- let result = (|| {
- let fs = fsopen("overlay", FsOpenFlags::FSOPEN_CLOEXEC)?;
- let fs = fs.as_fd();
- fsconfig_set_string(fs, "lowerdir", &lowerdir_config)?;
- if let (Some(upperdir), Some(workdir)) = (&upperdir, &workdir) {
- fsconfig_set_string(fs, "upperdir", upperdir)?;
- fsconfig_set_string(fs, "workdir", workdir)?;
- }
- fsconfig_set_string(fs, "source", KSU_OVERLAY_SOURCE)?;
- fsconfig_create(fs)?;
- let mount = fsmount(fs, FsMountFlags::FSMOUNT_CLOEXEC, MountAttrFlags::empty())?;
- move_mount(
- mount.as_fd(),
- "",
- CWD,
- dest.as_ref(),
- MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH,
- )
- })();
-
- if let Err(e) = result {
- warn!("fsopen mount failed: {:#}, fallback to mount", e);
- let mut data = format!("lowerdir={lowerdir_config}");
- if let (Some(upperdir), Some(workdir)) = (upperdir, workdir) {
- data = format!("{data},upperdir={upperdir},workdir={workdir}");
- }
- mount(
- KSU_OVERLAY_SOURCE,
- dest.as_ref(),
- "overlay",
- MountFlags::empty(),
- data,
- )?;
- }
- Ok(())
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn mount_tmpfs(dest: impl AsRef) -> Result<()> {
- info!("mount tmpfs on {}", dest.as_ref().display());
- if let Result::Ok(fs) = fsopen("tmpfs", FsOpenFlags::FSOPEN_CLOEXEC) {
- let fs = fs.as_fd();
- fsconfig_set_string(fs, "source", KSU_OVERLAY_SOURCE)?;
- fsconfig_create(fs)?;
- let mount = fsmount(fs, FsMountFlags::FSMOUNT_CLOEXEC, MountAttrFlags::empty())?;
- move_mount(
- mount.as_fd(),
- "",
- CWD,
- dest.as_ref(),
- MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH,
- )?;
- } else {
- mount(
- KSU_OVERLAY_SOURCE,
- dest.as_ref(),
- "tmpfs",
- MountFlags::empty(),
- "",
- )?;
- }
- Ok(())
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn bind_mount(from: impl AsRef, to: impl AsRef) -> Result<()> {
- info!(
- "bind mount {} -> {}",
- from.as_ref().display(),
- to.as_ref().display()
- );
- if let Result::Ok(tree) = open_tree(
- CWD,
- from.as_ref(),
- OpenTreeFlags::OPEN_TREE_CLOEXEC
- | OpenTreeFlags::OPEN_TREE_CLONE
- | OpenTreeFlags::AT_RECURSIVE,
- ) {
- move_mount(
- tree.as_fd(),
- "",
- CWD,
- to.as_ref(),
- MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH,
- )?;
- } else {
- mount(
- from.as_ref(),
- to.as_ref(),
- "",
- MountFlags::BIND | MountFlags::REC,
- "",
- )?;
- }
- Ok(())
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-fn mount_overlay_child(
- mount_point: &str,
- relative: &String,
- module_roots: &Vec,
- stock_root: &String,
-) -> Result<()> {
- if !module_roots
- .iter()
- .any(|lower| Path::new(&format!("{lower}{relative}")).exists())
- {
- return bind_mount(stock_root, mount_point);
- }
- if !Path::new(&stock_root).is_dir() {
- return Ok(());
- }
- let mut lower_dirs: Vec = vec![];
- for lower in module_roots {
- let lower_dir = format!("{lower}{relative}");
- let path = Path::new(&lower_dir);
- if path.is_dir() {
- lower_dirs.push(lower_dir);
- } else if path.exists() {
- // stock root has been blocked by this file
- return Ok(());
- }
- }
- if lower_dirs.is_empty() {
- return Ok(());
- }
- // merge modules and stock
- if let Err(e) = mount_overlayfs(&lower_dirs, stock_root, None, None, mount_point) {
- warn!("failed: {:#}, fallback to bind mount", e);
- bind_mount(stock_root, mount_point)?;
- }
- Ok(())
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn mount_overlay(
- root: &String,
- module_roots: &Vec,
- workdir: Option,
- upperdir: Option,
-) -> Result<()> {
- info!("mount overlay for {}", root);
- std::env::set_current_dir(root).with_context(|| format!("failed to chdir to {root}"))?;
- let stock_root = ".";
-
- // collect child mounts before mounting the root
- let mounts = Process::myself()?
- .mountinfo()
- .with_context(|| "get mountinfo")?;
- let mut mount_seq = mounts
- .0
- .iter()
- .filter(|m| {
- m.mount_point.starts_with(root) && !Path::new(&root).starts_with(&m.mount_point)
- })
- .map(|m| m.mount_point.to_str())
- .collect::>();
- mount_seq.sort();
- mount_seq.dedup();
-
- mount_overlayfs(module_roots, root, upperdir, workdir, root)
- .with_context(|| "mount overlayfs for root failed")?;
- for mount_point in mount_seq.iter() {
- let Some(mount_point) = mount_point else {
- continue;
- };
- let relative = mount_point.replacen(root, "", 1);
- let stock_root: String = format!("{stock_root}{relative}");
- if !Path::new(&stock_root).exists() {
- continue;
- }
- if let Err(e) = mount_overlay_child(mount_point, &relative, module_roots, &stock_root) {
- warn!(
- "failed to mount overlay for child {}: {:#}, revert",
- mount_point, e
- );
- umount_dir(root).with_context(|| format!("failed to revert {root}"))?;
- bail!(e);
- }
- }
- Ok(())
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
-pub fn mount_ext4(_src: &str, _target: &str, _autodrop: bool) -> Result<()> {
- unimplemented!()
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
-pub fn umount_dir(_src: &str) -> Result<()> {
- unimplemented!()
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
-pub fn mount_overlay(
- _root: &String,
- _module_roots: &Vec,
- _workdir: Option,
- _upperdir: Option,
-) -> Result<()> {
- unimplemented!()
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
-pub fn mount_tmpfs(_dest: impl AsRef) -> Result<()> {
- unimplemented!()
-}
diff --git a/userspace/ksud/src/profile.rs b/userspace/ksud/src/profile.rs
deleted file mode 100644
index 21574448..00000000
--- a/userspace/ksud/src/profile.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-use crate::utils::ensure_dir_exists;
-use crate::{defs, sepolicy};
-use anyhow::{Context, Result};
-use std::path::Path;
-
-pub fn set_sepolicy(pkg: String, policy: String) -> Result<()> {
- ensure_dir_exists(defs::PROFILE_SELINUX_DIR)?;
- let policy_file = Path::new(defs::PROFILE_SELINUX_DIR).join(pkg);
- std::fs::write(&policy_file, policy)?;
- sepolicy::apply_file(&policy_file)?;
- Ok(())
-}
-
-pub fn get_sepolicy(pkg: String) -> Result<()> {
- let policy_file = Path::new(defs::PROFILE_SELINUX_DIR).join(pkg);
- let policy = std::fs::read_to_string(policy_file)?;
- println!("{policy}");
- Ok(())
-}
-
-// ksud doesn't guarteen the correctness of template, it just save
-pub fn set_template(id: String, template: String) -> Result<()> {
- ensure_dir_exists(defs::PROFILE_TEMPLATE_DIR)?;
- let template_file = Path::new(defs::PROFILE_TEMPLATE_DIR).join(id);
- std::fs::write(template_file, template)?;
- Ok(())
-}
-
-pub fn get_template(id: String) -> Result<()> {
- let template_file = Path::new(defs::PROFILE_TEMPLATE_DIR).join(id);
- let template = std::fs::read_to_string(template_file)?;
- println!("{template}");
- Ok(())
-}
-
-pub fn delete_template(id: String) -> Result<()> {
- let template_file = Path::new(defs::PROFILE_TEMPLATE_DIR).join(id);
- std::fs::remove_file(template_file)?;
- Ok(())
-}
-
-pub fn list_templates() -> Result<()> {
- let templates = std::fs::read_dir(defs::PROFILE_TEMPLATE_DIR);
- let Ok(templates) = templates else {
- return Ok(());
- };
- for template in templates {
- let template = template?;
- let template = template.file_name();
- if let Some(template) = template.to_str() {
- println!("{template}");
- };
- }
- Ok(())
-}
-
-pub fn apply_sepolies() -> Result<()> {
- let path = Path::new(defs::PROFILE_SELINUX_DIR);
- if !path.exists() {
- log::info!("profile sepolicy dir not exists.");
- return Ok(());
- }
-
- let sepolicies =
- std::fs::read_dir(path).with_context(|| "profile sepolicy dir open failed.".to_string())?;
- for sepolicy in sepolicies {
- let Ok(sepolicy) = sepolicy else {
- log::info!("profile sepolicy dir read failed.");
- continue;
- };
- let sepolicy = sepolicy.path();
- if sepolicy::apply_file(&sepolicy).is_ok() {
- log::info!("profile sepolicy applied: {:?}", sepolicy);
- } else {
- log::info!("profile sepolicy apply failed: {:?}", sepolicy);
- }
- }
- Ok(())
-}
diff --git a/userspace/ksud/src/restorecon.rs b/userspace/ksud/src/restorecon.rs
deleted file mode 100644
index 152a7c5e..00000000
--- a/userspace/ksud/src/restorecon.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-use crate::defs;
-use anyhow::Result;
-use jwalk::{Parallelism::Serial, WalkDir};
-use std::path::Path;
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-use anyhow::{Context, Ok};
-#[cfg(any(target_os = "linux", target_os = "android"))]
-use extattr::{lsetxattr, Flags as XattrFlags};
-
-pub const SYSTEM_CON: &str = "u:object_r:system_file:s0";
-pub const ADB_CON: &str = "u:object_r:adb_data_file:s0";
-pub const UNLABEL_CON: &str = "u:object_r:unlabeled:s0";
-
-const SELINUX_XATTR: &str = "security.selinux";
-
-pub fn lsetfilecon>(path: P, con: &str) -> Result<()> {
- #[cfg(any(target_os = "linux", target_os = "android"))]
- lsetxattr(&path, SELINUX_XATTR, con, XattrFlags::empty()).with_context(|| {
- format!(
- "Failed to change SELinux context for {}",
- path.as_ref().display()
- )
- })?;
- Ok(())
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn lgetfilecon>(path: P) -> Result {
- let con = extattr::lgetxattr(&path, SELINUX_XATTR).with_context(|| {
- format!(
- "Failed to get SELinux context for {}",
- path.as_ref().display()
- )
- })?;
- let con = String::from_utf8_lossy(&con);
- Ok(con.to_string())
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn setsyscon>(path: P) -> Result<()> {
- lsetfilecon(path, SYSTEM_CON)
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
-pub fn setsyscon>(path: P) -> Result<()> {
- unimplemented!()
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
-pub fn lgetfilecon>(path: P) -> Result {
- unimplemented!()
-}
-
-pub fn restore_syscon>(dir: P) -> Result<()> {
- for dir_entry in WalkDir::new(dir).parallelism(Serial) {
- if let Some(path) = dir_entry.ok().map(|dir_entry| dir_entry.path()) {
- setsyscon(&path)?;
- }
- }
- Ok(())
-}
-
-fn restore_syscon_if_unlabeled>(dir: P) -> Result<()> {
- for dir_entry in WalkDir::new(dir).parallelism(Serial) {
- if let Some(path) = dir_entry.ok().map(|dir_entry| dir_entry.path()) {
- if let anyhow::Result::Ok(con) = lgetfilecon(&path) {
- if con == UNLABEL_CON || con.is_empty() {
- lsetfilecon(&path, SYSTEM_CON)?;
- }
- }
- }
- }
- Ok(())
-}
-
-pub fn restorecon() -> Result<()> {
- lsetfilecon(defs::DAEMON_PATH, ADB_CON)?;
- restore_syscon_if_unlabeled(defs::MODULE_DIR)?;
- Ok(())
-}
diff --git a/userspace/ksud/src/sepolicy.rs b/userspace/ksud/src/sepolicy.rs
deleted file mode 100644
index 581c416a..00000000
--- a/userspace/ksud/src/sepolicy.rs
+++ /dev/null
@@ -1,738 +0,0 @@
-use anyhow::{bail, Result};
-use derive_new::new;
-use nom::{
- branch::alt,
- bytes::complete::{tag, take_while, take_while1, take_while_m_n},
- character::{
- complete::{space0, space1},
- is_alphanumeric,
- },
- combinator::map,
- sequence::Tuple,
- IResult, Parser,
-};
-use std::{path::Path, vec};
-
-type SeObject<'a> = Vec<&'a str>;
-
-fn is_sepolicy_char(c: char) -> bool {
- is_alphanumeric(c as u8) || c == '_' || c == '-'
-}
-
-fn parse_single_word(input: &str) -> IResult<&str, &str> {
- take_while1(is_sepolicy_char).parse(input)
-}
-
-fn parse_bracket_objs(input: &str) -> IResult<&str, SeObject> {
- let (input, (_, words, _)) = (
- tag("{"),
- take_while_m_n(1, 100, |c: char| is_sepolicy_char(c) || c.is_whitespace()),
- tag("}"),
- )
- .parse(input)?;
- Ok((input, words.split_whitespace().collect()))
-}
-
-fn parse_single_obj(input: &str) -> IResult<&str, SeObject> {
- let (input, word) = take_while1(is_sepolicy_char).parse(input)?;
- Ok((input, vec![word]))
-}
-
-fn parse_star(input: &str) -> IResult<&str, SeObject> {
- let (input, _) = tag("*").parse(input)?;
- Ok((input, vec!["*"]))
-}
-
-// 1. a single sepolicy word
-// 2. { obj1 obj2 obj3 ...}
-// 3. *
-fn parse_seobj(input: &str) -> IResult<&str, SeObject> {
- let (input, strs) = alt((parse_single_obj, parse_bracket_objs, parse_star)).parse(input)?;
- Ok((input, strs))
-}
-
-fn parse_seobj_no_star(input: &str) -> IResult<&str, SeObject> {
- let (input, strs) = alt((parse_single_obj, parse_bracket_objs)).parse(input)?;
- Ok((input, strs))
-}
-
-trait SeObjectParser<'a> {
- fn parse(input: &'a str) -> IResult<&'a str, Self>
- where
- Self: Sized;
-}
-
-#[derive(Debug, PartialEq, Eq, new)]
-struct NormalPerm<'a> {
- op: &'a str,
- source: SeObject<'a>,
- target: SeObject<'a>,
- class: SeObject<'a>,
- perm: SeObject<'a>,
-}
-
-#[derive(Debug, PartialEq, Eq, new)]
-struct XPerm<'a> {
- op: &'a str,
- source: SeObject<'a>,
- target: SeObject<'a>,
- class: SeObject<'a>,
- operation: &'a str,
- perm_set: &'a str,
-}
-
-#[derive(Debug, PartialEq, Eq, new)]
-struct TypeState<'a> {
- op: &'a str,
- stype: SeObject<'a>,
-}
-
-#[derive(Debug, PartialEq, Eq, new)]
-struct TypeAttr<'a> {
- stype: SeObject<'a>,
- sattr: SeObject<'a>,
-}
-
-#[derive(Debug, PartialEq, Eq, new)]
-struct Type<'a> {
- name: &'a str,
- attrs: SeObject<'a>,
-}
-
-#[derive(Debug, PartialEq, Eq, new)]
-struct Attr<'a> {
- name: &'a str,
-}
-
-#[derive(Debug, PartialEq, Eq, new)]
-struct TypeTransition<'a> {
- source: &'a str,
- target: &'a str,
- class: &'a str,
- default_type: &'a str,
- object_name: Option<&'a str>,
-}
-
-#[derive(Debug, PartialEq, Eq, new)]
-struct TypeChange<'a> {
- op: &'a str,
- source: &'a str,
- target: &'a str,
- class: &'a str,
- default_type: &'a str,
-}
-
-#[derive(Debug, PartialEq, Eq, new)]
-struct GenFsCon<'a> {
- fs_name: &'a str,
- partial_path: &'a str,
- fs_context: &'a str,
-}
-
-#[derive(Debug)]
-enum PolicyStatement<'a> {
- // "allow *source_type *target_type *class *perm_set"
- // "deny *source_type *target_type *class *perm_set"
- // "auditallow *source_type *target_type *class *perm_set"
- // "dontaudit *source_type *target_type *class *perm_set"
- NormalPerm(NormalPerm<'a>),
-
- // "allowxperm *source_type *target_type *class operation xperm_set"
- // "auditallowxperm *source_type *target_type *class operation xperm_set"
- // "dontauditxperm *source_type *target_type *class operation xperm_set"
- XPerm(XPerm<'a>),
-
- // "permissive ^type"
- // "enforce ^type"
- TypeState(TypeState<'a>),
-
- // "type type_name ^(attribute)"
- Type(Type<'a>),
-
- // "typeattribute ^type ^attribute"
- TypeAttr(TypeAttr<'a>),
-
- // "attribute ^attribute"
- Attr(Attr<'a>),
-
- // "type_transition source_type target_type class default_type (object_name)"
- TypeTransition(TypeTransition<'a>),
-
- // "type_change source_type target_type class default_type"
- // "type_member source_type target_type class default_type"
- TypeChange(TypeChange<'a>),
-
- // "genfscon fs_name partial_path fs_context"
- GenFsCon(GenFsCon<'a>),
-}
-
-impl<'a> SeObjectParser<'a> for NormalPerm<'a> {
- fn parse(input: &'a str) -> IResult<&str, Self> {
- let (input, op) = alt((
- tag("allow"),
- tag("deny"),
- tag("auditallow"),
- tag("dontaudit"),
- ))(input)?;
-
- let (input, _) = space0(input)?;
- let (input, source) = parse_seobj(input)?;
- let (input, _) = space0(input)?;
- let (input, target) = parse_seobj(input)?;
- let (input, _) = space0(input)?;
- let (input, class) = parse_seobj(input)?;
- let (input, _) = space0(input)?;
- let (input, perm) = parse_seobj(input)?;
- Ok((input, NormalPerm::new(op, source, target, class, perm)))
- }
-}
-
-impl<'a> SeObjectParser<'a> for XPerm<'a> {
- fn parse(input: &'a str) -> IResult<&'a str, Self> {
- let (input, op) = alt((
- tag("allowxperm"),
- tag("auditallowxperm"),
- tag("dontauditxperm"),
- ))(input)?;
-
- let (input, _) = space0(input)?;
- let (input, source) = parse_seobj(input)?;
- let (input, _) = space0(input)?;
- let (input, target) = parse_seobj(input)?;
- let (input, _) = space0(input)?;
- let (input, class) = parse_seobj(input)?;
- let (input, _) = space0(input)?;
- let (input, operation) = parse_single_word(input)?;
- let (input, _) = space0(input)?;
- let (input, perm_set) = parse_single_word(input)?;
-
- Ok((
- input,
- XPerm::new(op, source, target, class, operation, perm_set),
- ))
- }
-}
-
-impl<'a> SeObjectParser<'a> for TypeState<'a> {
- fn parse(input: &'a str) -> IResult<&'a str, Self> {
- let (input, op) = alt((tag("permissive"), tag("enforce")))(input)?;
-
- let (input, _) = space1(input)?;
- let (input, stype) = parse_seobj_no_star(input)?;
-
- Ok((input, TypeState::new(op, stype)))
- }
-}
-
-impl<'a> SeObjectParser<'a> for Type<'a> {
- fn parse(input: &'a str) -> IResult<&'a str, Self> {
- let (input, _) = tag("type")(input)?;
- let (input, _) = space1(input)?;
- let (input, name) = parse_single_word(input)?;
-
- if input.is_empty() {
- return Ok((input, Type::new(name, vec!["domain"]))); // default to domain
- }
-
- let (input, _) = space1(input)?;
- let (input, attrs) = parse_seobj_no_star(input)?;
-
- Ok((input, Type::new(name, attrs)))
- }
-}
-
-impl<'a> SeObjectParser<'a> for TypeAttr<'a> {
- fn parse(input: &'a str) -> IResult<&'a str, Self> {
- let (input, _) = alt((tag("typeattribute"), tag("attradd")))(input)?;
- let (input, _) = space1(input)?;
- let (input, stype) = parse_seobj_no_star(input)?;
- let (input, _) = space1(input)?;
- let (input, attr) = parse_seobj_no_star(input)?;
-
- Ok((input, TypeAttr::new(stype, attr)))
- }
-}
-
-impl<'a> SeObjectParser<'a> for Attr<'a> {
- fn parse(input: &'a str) -> IResult<&'a str, Self> {
- let (input, _) = tag("attribute")(input)?;
- let (input, _) = space1(input)?;
- let (input, attr) = parse_single_word(input)?;
-
- Ok((input, Attr::new(attr)))
- }
-}
-
-impl<'a> SeObjectParser<'a> for TypeTransition<'a> {
- fn parse(input: &'a str) -> IResult<&'a str, Self> {
- let (input, _) = alt((tag("type_transition"), tag("name_transition")))(input)?;
- let (input, _) = space1(input)?;
- let (input, source) = parse_single_word(input)?;
- let (input, _) = space1(input)?;
- let (input, target) = parse_single_word(input)?;
- let (input, _) = space1(input)?;
- let (input, class) = parse_single_word(input)?;
- let (input, _) = space1(input)?;
- let (input, default) = parse_single_word(input)?;
-
- if input.is_empty() {
- return Ok((
- input,
- TypeTransition::new(source, target, class, default, None),
- ));
- }
-
- let (input, _) = space1(input)?;
- let (input, object) = parse_single_word(input)?;
-
- Ok((
- input,
- TypeTransition::new(source, target, class, default, Some(object)),
- ))
- }
-}
-
-impl<'a> SeObjectParser<'a> for TypeChange<'a> {
- fn parse(input: &'a str) -> IResult<&'a str, Self> {
- let (input, op) = alt((tag("type_change"), tag("type_member")))(input)?;
- let (input, _) = space1(input)?;
- let (input, source) = parse_single_word(input)?;
- let (input, _) = space1(input)?;
- let (input, target) = parse_single_word(input)?;
- let (input, _) = space1(input)?;
- let (input, class) = parse_single_word(input)?;
- let (input, _) = space1(input)?;
- let (input, default) = parse_single_word(input)?;
-
- Ok((input, TypeChange::new(op, source, target, class, default)))
- }
-}
-
-impl<'a> SeObjectParser<'a> for GenFsCon<'a> {
- fn parse(input: &'a str) -> IResult<&'a str, Self>
- where
- Self: Sized,
- {
- let (input, _) = tag("genfscon")(input)?;
- let (input, _) = space1(input)?;
- let (input, fs) = parse_single_word(input)?;
- let (input, _) = space1(input)?;
- let (input, path) = parse_single_word(input)?;
- let (input, _) = space1(input)?;
- let (input, context) = parse_single_word(input)?;
- Ok((input, GenFsCon::new(fs, path, context)))
- }
-}
-
-impl<'a> PolicyStatement<'a> {
- fn parse(input: &'a str) -> IResult<&'a str, Self> {
- let (input, _) = space0(input)?;
- let (input, statement) = alt((
- map(NormalPerm::parse, PolicyStatement::NormalPerm),
- map(XPerm::parse, PolicyStatement::XPerm),
- map(TypeState::parse, PolicyStatement::TypeState),
- map(Type::parse, PolicyStatement::Type),
- map(TypeAttr::parse, PolicyStatement::TypeAttr),
- map(Attr::parse, PolicyStatement::Attr),
- map(TypeTransition::parse, PolicyStatement::TypeTransition),
- map(TypeChange::parse, PolicyStatement::TypeChange),
- map(GenFsCon::parse, PolicyStatement::GenFsCon),
- ))(input)?;
- let (input, _) = space0(input)?;
- let (input, _) = take_while(|c| c == ';')(input)?;
- let (input, _) = space0(input)?;
- Ok((input, statement))
- }
-}
-
-fn parse_sepolicy<'a, 'b>(input: &'b str, strict: bool) -> Result>>
-where
- 'b: 'a,
-{
- let mut statements = vec![];
-
- for line in input.split(['\n', ';']) {
- if line.trim().is_empty() {
- continue;
- }
- if let Ok((_, statement)) = PolicyStatement::parse(line.trim()) {
- statements.push(statement);
- } else if strict {
- bail!("Failed to parse policy statement: {}", line)
- }
- }
- Ok(statements)
-}
-
-const SEPOLICY_MAX_LEN: usize = 128;
-
-const CMD_NORMAL_PERM: u32 = 1;
-const CMD_XPERM: u32 = 2;
-const CMD_TYPE_STATE: u32 = 3;
-const CMD_TYPE: u32 = 4;
-const CMD_TYPE_ATTR: u32 = 5;
-const CMD_ATTR: u32 = 6;
-const CMD_TYPE_TRANSITION: u32 = 7;
-const CMD_TYPE_CHANGE: u32 = 8;
-const CMD_GENFSCON: u32 = 9;
-
-#[derive(Debug, Default)]
-enum PolicyObject {
- All, // for "*", stand for all objects, and is NULL in ffi
- One([u8; SEPOLICY_MAX_LEN]),
- #[default]
- None,
-}
-
-impl TryFrom<&str> for PolicyObject {
- type Error = anyhow::Error;
- fn try_from(s: &str) -> Result {
- anyhow::ensure!(s.len() <= SEPOLICY_MAX_LEN, "policy object too long");
- if s == "*" {
- return Ok(PolicyObject::All);
- }
- let mut buf = [0u8; SEPOLICY_MAX_LEN];
- buf[..s.len()].copy_from_slice(s.as_bytes());
- Ok(PolicyObject::One(buf))
- }
-}
-
-/// atomic statement, such as: allow domain1 domain2:file1 read;
-/// normal statement would be expand to atomic statement, for example:
-/// allow domain1 domain2:file1 { read write }; would be expand to two atomic statement
-/// allow domain1 domain2:file1 read;allow domain1 domain2:file1 write;
-#[allow(clippy::too_many_arguments)]
-#[derive(Debug, new)]
-struct AtomicStatement {
- cmd: u32,
- subcmd: u32,
- sepol1: PolicyObject,
- sepol2: PolicyObject,
- sepol3: PolicyObject,
- sepol4: PolicyObject,
- sepol5: PolicyObject,
- sepol6: PolicyObject,
- sepol7: PolicyObject,
-}
-
-impl<'a> TryFrom<&'a NormalPerm<'a>> for Vec {
- type Error = anyhow::Error;
- fn try_from(perm: &'a NormalPerm<'a>) -> Result {
- let mut result = vec![];
- let subcmd = match perm.op {
- "allow" => 1,
- "deny" => 2,
- "auditallow" => 3,
- "dontaudit" => 4,
- _ => 0,
- };
- for &s in &perm.source {
- for &t in &perm.target {
- for &c in &perm.class {
- for &p in &perm.perm {
- result.push(AtomicStatement {
- cmd: CMD_NORMAL_PERM,
- subcmd,
- sepol1: s.try_into()?,
- sepol2: t.try_into()?,
- sepol3: c.try_into()?,
- sepol4: p.try_into()?,
- sepol5: PolicyObject::None,
- sepol6: PolicyObject::None,
- sepol7: PolicyObject::None,
- });
- }
- }
- }
- }
- Ok(result)
- }
-}
-
-impl<'a> TryFrom<&'a XPerm<'a>> for Vec {
- type Error = anyhow::Error;
- fn try_from(perm: &'a XPerm<'a>) -> Result {
- let mut result = vec![];
- let subcmd = match perm.op {
- "allowxperm" => 1,
- "auditallowxperm" => 2,
- "dontauditxperm" => 3,
- _ => 0,
- };
- for &s in &perm.source {
- for &t in &perm.target {
- for &c in &perm.class {
- result.push(AtomicStatement {
- cmd: CMD_XPERM,
- subcmd,
- sepol1: s.try_into()?,
- sepol2: t.try_into()?,
- sepol3: c.try_into()?,
- sepol4: perm.operation.try_into()?,
- sepol5: perm.perm_set.try_into()?,
- sepol6: PolicyObject::None,
- sepol7: PolicyObject::None,
- });
- }
- }
- }
- Ok(result)
- }
-}
-
-impl<'a> TryFrom<&'a TypeState<'a>> for Vec {
- type Error = anyhow::Error;
- fn try_from(perm: &'a TypeState<'a>) -> Result {
- let mut result = vec![];
- let subcmd = match perm.op {
- "permissive" => 1,
- "enforcing" => 2,
- _ => 0,
- };
- for &t in &perm.stype {
- result.push(AtomicStatement {
- cmd: CMD_TYPE_STATE,
- subcmd,
- sepol1: t.try_into()?,
- sepol2: PolicyObject::None,
- sepol3: PolicyObject::None,
- sepol4: PolicyObject::None,
- sepol5: PolicyObject::None,
- sepol6: PolicyObject::None,
- sepol7: PolicyObject::None,
- });
- }
- Ok(result)
- }
-}
-
-impl<'a> TryFrom<&'a Type<'a>> for Vec {
- type Error = anyhow::Error;
- fn try_from(perm: &'a Type<'a>) -> Result {
- let mut result = vec![];
- for &attr in &perm.attrs {
- result.push(AtomicStatement {
- cmd: CMD_TYPE,
- subcmd: 0,
- sepol1: perm.name.try_into()?,
- sepol2: attr.try_into()?,
- sepol3: PolicyObject::None,
- sepol4: PolicyObject::None,
- sepol5: PolicyObject::None,
- sepol6: PolicyObject::None,
- sepol7: PolicyObject::None,
- });
- }
- Ok(result)
- }
-}
-
-impl<'a> TryFrom<&'a TypeAttr<'a>> for Vec {
- type Error = anyhow::Error;
- fn try_from(perm: &'a TypeAttr<'a>) -> Result {
- let mut result = vec![];
- for &t in &perm.stype {
- for &attr in &perm.sattr {
- result.push(AtomicStatement {
- cmd: CMD_TYPE_ATTR,
- subcmd: 0,
- sepol1: t.try_into()?,
- sepol2: attr.try_into()?,
- sepol3: PolicyObject::None,
- sepol4: PolicyObject::None,
- sepol5: PolicyObject::None,
- sepol6: PolicyObject::None,
- sepol7: PolicyObject::None,
- });
- }
- }
- Ok(result)
- }
-}
-
-impl<'a> TryFrom<&'a Attr<'a>> for Vec {
- type Error = anyhow::Error;
- fn try_from(perm: &'a Attr<'a>) -> Result {
- let result = vec![AtomicStatement {
- cmd: CMD_ATTR,
- subcmd: 0,
- sepol1: perm.name.try_into()?,
- sepol2: PolicyObject::None,
- sepol3: PolicyObject::None,
- sepol4: PolicyObject::None,
- sepol5: PolicyObject::None,
- sepol6: PolicyObject::None,
- sepol7: PolicyObject::None,
- }];
- Ok(result)
- }
-}
-
-impl<'a> TryFrom<&'a TypeTransition<'a>> for Vec {
- type Error = anyhow::Error;
- fn try_from(perm: &'a TypeTransition<'a>) -> Result {
- let mut result = vec![];
- let obj = match perm.object_name {
- Some(obj) => obj.try_into()?,
- None => PolicyObject::None,
- };
- result.push(AtomicStatement {
- cmd: CMD_TYPE_TRANSITION,
- subcmd: 0,
- sepol1: perm.source.try_into()?,
- sepol2: perm.target.try_into()?,
- sepol3: perm.class.try_into()?,
- sepol4: perm.default_type.try_into()?,
- sepol5: obj,
- sepol6: PolicyObject::None,
- sepol7: PolicyObject::None,
- });
- Ok(result)
- }
-}
-
-impl<'a> TryFrom<&'a TypeChange<'a>> for Vec {
- type Error = anyhow::Error;
- fn try_from(perm: &'a TypeChange<'a>) -> Result {
- let mut result = vec![];
- let subcmd = match perm.op {
- "type_change" => 1,
- "type_member" => 2,
- _ => 0,
- };
- result.push(AtomicStatement {
- cmd: CMD_TYPE_CHANGE,
- subcmd,
- sepol1: perm.source.try_into()?,
- sepol2: perm.target.try_into()?,
- sepol3: perm.class.try_into()?,
- sepol4: perm.default_type.try_into()?,
- sepol5: PolicyObject::None,
- sepol6: PolicyObject::None,
- sepol7: PolicyObject::None,
- });
- Ok(result)
- }
-}
-
-impl<'a> TryFrom<&'a GenFsCon<'a>> for Vec {
- type Error = anyhow::Error;
- fn try_from(perm: &'a GenFsCon<'a>) -> Result {
- let result = vec![AtomicStatement {
- cmd: CMD_GENFSCON,
- subcmd: 0,
- sepol1: perm.fs_name.try_into()?,
- sepol2: perm.partial_path.try_into()?,
- sepol3: perm.fs_context.try_into()?,
- sepol4: PolicyObject::None,
- sepol5: PolicyObject::None,
- sepol6: PolicyObject::None,
- sepol7: PolicyObject::None,
- }];
- Ok(result)
- }
-}
-
-impl<'a> TryFrom<&'a PolicyStatement<'a>> for Vec {
- type Error = anyhow::Error;
- fn try_from(value: &'a PolicyStatement) -> Result {
- match value {
- PolicyStatement::NormalPerm(perm) => perm.try_into(),
- PolicyStatement::XPerm(perm) => perm.try_into(),
- PolicyStatement::TypeState(perm) => perm.try_into(),
- PolicyStatement::Type(perm) => perm.try_into(),
- PolicyStatement::TypeAttr(perm) => perm.try_into(),
- PolicyStatement::Attr(perm) => perm.try_into(),
- PolicyStatement::TypeTransition(perm) => perm.try_into(),
- PolicyStatement::TypeChange(perm) => perm.try_into(),
- PolicyStatement::GenFsCon(perm) => perm.try_into(),
- }
- }
-}
-
-////////////////////////////////////////////////////////////////
-/// for C FFI to call kernel interface
-///////////////////////////////////////////////////////////////
-
-#[derive(Debug)]
-#[repr(C)]
-struct FfiPolicy {
- cmd: u32,
- subcmd: u32,
- sepol1: *const libc::c_char,
- sepol2: *const libc::c_char,
- sepol3: *const libc::c_char,
- sepol4: *const libc::c_char,
- sepol5: *const libc::c_char,
- sepol6: *const libc::c_char,
- sepol7: *const libc::c_char,
-}
-
-fn to_c_ptr(pol: &PolicyObject) -> *const libc::c_char {
- match pol {
- PolicyObject::None | PolicyObject::All => std::ptr::null(),
- PolicyObject::One(s) => s.as_ptr().cast::(),
- }
-}
-
-impl From for FfiPolicy {
- fn from(policy: AtomicStatement) -> FfiPolicy {
- FfiPolicy {
- cmd: policy.cmd,
- subcmd: policy.subcmd,
- sepol1: to_c_ptr(&policy.sepol1),
- sepol2: to_c_ptr(&policy.sepol2),
- sepol3: to_c_ptr(&policy.sepol3),
- sepol4: to_c_ptr(&policy.sepol4),
- sepol5: to_c_ptr(&policy.sepol5),
- sepol6: to_c_ptr(&policy.sepol6),
- sepol7: to_c_ptr(&policy.sepol7),
- }
- }
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-fn apply_one_rule<'a>(statement: &'a PolicyStatement<'a>, strict: bool) -> Result<()> {
- let policies: Vec = statement.try_into()?;
-
- for policy in policies {
- if !rustix::process::ksu_set_policy(&FfiPolicy::from(policy)) {
- log::warn!("apply rule: {:?} failed.", statement);
- if strict {
- return Err(anyhow::anyhow!("apply rule {:?} failed.", statement));
- }
- }
- }
-
- Ok(())
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
-fn apply_one_rule<'a>(_statement: &'a PolicyStatement<'a>, _strict: bool) -> Result<()> {
- unimplemented!()
-}
-
-pub fn live_patch(policy: &str) -> Result<()> {
- let result = parse_sepolicy(policy.trim(), false)?;
- for statement in result {
- println!("{statement:?}");
- apply_one_rule(&statement, false)?;
- }
- Ok(())
-}
-
-pub fn apply_file>(path: P) -> Result<()> {
- let input = std::fs::read_to_string(path)?;
- live_patch(&input)
-}
-
-pub fn check_rule(policy: &str) -> Result<()> {
- let path = Path::new(policy);
- let policy = if path.exists() {
- std::fs::read_to_string(path)?
- } else {
- policy.to_string()
- };
- parse_sepolicy(policy.trim(), true)?;
- Ok(())
-}
diff --git a/userspace/ksud/src/su.rs b/userspace/ksud/src/su.rs
deleted file mode 100644
index b19bf7a2..00000000
--- a/userspace/ksud/src/su.rs
+++ /dev/null
@@ -1,301 +0,0 @@
-use anyhow::{Ok, Result};
-use getopts::Options;
-use std::env;
-#[cfg(unix)]
-use std::os::unix::process::CommandExt;
-use std::path::PathBuf;
-use std::{ffi::CStr, process::Command};
-
-use crate::{
- defs,
- utils::{self, umask},
-};
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-use rustix::{
- process::getuid,
- thread::{set_thread_res_gid, set_thread_res_uid, Gid, Uid},
-};
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn grant_root(global_mnt: bool) -> Result<()> {
- const KERNEL_SU_OPTION: u32 = 0xDEAD_BEEF;
- const CMD_GRANT_ROOT: u64 = 0;
-
- let mut result: u32 = 0;
- unsafe {
- #[allow(clippy::cast_possible_wrap)]
- libc::prctl(
- KERNEL_SU_OPTION as i32, // supposed to overflow
- CMD_GRANT_ROOT,
- 0,
- 0,
- std::ptr::addr_of_mut!(result).cast::(),
- );
- }
-
- anyhow::ensure!(result == KERNEL_SU_OPTION, "grant root failed");
- let mut command = std::process::Command::new("sh");
- let command = unsafe {
- command.pre_exec(move || {
- if global_mnt {
- let _ = utils::switch_mnt_ns(1);
- let _ = utils::unshare_mnt_ns();
- }
- std::result::Result::Ok(())
- })
- };
- // add /data/adb/ksu/bin to PATH
- #[cfg(any(target_os = "linux", target_os = "android"))]
- add_path_to_env(defs::BINARY_DIR)?;
- Err(command.exec().into())
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
-pub fn grant_root(_global_mnt: bool) -> Result<()> {
- unimplemented!("grant_root is only available on android");
-}
-
-fn print_usage(program: &str, opts: Options) {
- let brief = format!("KernelSU\n\nUsage: {program} [options] [-] [user [argument...]]");
- print!("{}", opts.usage(&brief));
-}
-
-fn set_identity(uid: u32, gid: u32, groups: &[u32]) {
- #[cfg(any(target_os = "linux", target_os = "android"))]
- {
- rustix::process::set_groups(
- groups
- .iter()
- .map(|g| unsafe { Gid::from_raw(*g) })
- .collect::>()
- .as_ref(),
- )
- .ok();
- let gid = unsafe { Gid::from_raw(gid) };
- let uid = unsafe { Uid::from_raw(uid) };
- set_thread_res_gid(gid, gid, gid).ok();
- set_thread_res_uid(uid, uid, uid).ok();
- }
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "android")))]
-pub fn root_shell() -> Result<()> {
- unimplemented!()
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn root_shell() -> Result<()> {
- // we are root now, this was set in kernel!
-
- use anyhow::anyhow;
- let env_args: Vec = std::env::args().collect();
- let program = env_args[0].clone();
- let args = env_args
- .iter()
- .position(|arg| arg == "-c")
- .map(|i| {
- let rest = env_args[i + 1..].to_vec();
- let mut new_args = env_args[..i].to_vec();
- new_args.push("-c".to_string());
- if !rest.is_empty() {
- new_args.push(rest.join(" "));
- }
- new_args
- })
- .unwrap_or_else(|| env_args.clone());
-
- let mut opts = Options::new();
- opts.optopt(
- "c",
- "command",
- "pass COMMAND to the invoked shell",
- "COMMAND",
- );
- opts.optflag("h", "help", "display this help message and exit");
- opts.optflag("l", "login", "pretend the shell to be a login shell");
- opts.optflag(
- "p",
- "preserve-environment",
- "preserve the entire environment",
- );
- opts.optflag(
- "s",
- "shell",
- "use SHELL instead of the default /system/bin/sh",
- );
- opts.optflag("v", "version", "display version number and exit");
- opts.optflag("V", "", "display version code and exit");
- opts.optflag(
- "M",
- "mount-master",
- "force run in the global mount namespace",
- );
- opts.optopt("g", "group", "Specify the primary group", "GROUP");
- opts.optmulti(
- "G",
- "supp-group",
- "Specify a supplementary group. The first specified supplementary group is also used as a primary group if the option -g is not specified.",
- "GROUP",
- );
-
- // Replace -cn with -z, -mm with -M for supporting getopt_long
- let args = args
- .into_iter()
- .map(|e| {
- if e == "-mm" {
- "-M".to_string()
- } else if e == "-cn" {
- "-z".to_string()
- } else {
- e
- }
- })
- .collect::>();
-
- let matches = match opts.parse(&args[1..]) {
- std::result::Result::Ok(m) => m,
- Err(f) => {
- println!("{f}");
- print_usage(&program, opts);
- std::process::exit(-1);
- }
- };
-
- if matches.opt_present("h") {
- print_usage(&program, opts);
- return Ok(());
- }
-
- if matches.opt_present("v") {
- println!("{}:KernelSU", defs::VERSION_NAME);
- return Ok(());
- }
-
- if matches.opt_present("V") {
- println!("{}", defs::VERSION_CODE);
- return Ok(());
- }
-
- let shell = matches.opt_str("s").unwrap_or("/system/bin/sh".to_string());
- let mut is_login = matches.opt_present("l");
- let preserve_env = matches.opt_present("p");
- let mount_master = matches.opt_present("M");
-
- let groups = matches
- .opt_strs("G")
- .into_iter()
- .map(|g| g.parse::().map_err(|_| anyhow!("Invalid GID: {}", g)))
- .collect::, _>>()?;
-
- // if -g provided, use it.
- let mut gid = matches
- .opt_str("g")
- .map(|g| g.parse::().map_err(|_| anyhow!("Invalid GID: {}", g)))
- .transpose()?;
-
- // otherwise, use the first gid of groups.
- if gid.is_none() && !groups.is_empty() {
- gid = Some(groups[0]);
- }
-
- // we've make sure that -c is the last option and it already contains the whole command, no need to construct it again
- let args = matches
- .opt_str("c")
- .map(|cmd| vec!["-c".to_string(), cmd])
- .unwrap_or_default();
-
- let mut free_idx = 0;
- if !matches.free.is_empty() && matches.free[free_idx] == "-" {
- is_login = true;
- free_idx += 1;
- }
-
- // use current uid if no user specified, these has been done in kernel!
- let mut uid = getuid().as_raw();
- if free_idx < matches.free.len() {
- let name = &matches.free[free_idx];
- uid = unsafe {
- #[cfg(target_arch = "aarch64")]
- let pw = libc::getpwnam(name.as_ptr()).as_ref();
- #[cfg(target_arch = "x86_64")]
- let pw = libc::getpwnam(name.as_ptr() as *const i8).as_ref();
-
- match pw {
- Some(pw) => pw.pw_uid,
- None => name.parse::().unwrap_or(0),
- }
- }
- }
-
- // if there is no gid provided, use uid.
- let gid = gid.unwrap_or(uid);
- // https://github.com/topjohnwu/Magisk/blob/master/native/src/su/su_daemon.cpp#L408
- let arg0 = if is_login { "-" } else { &shell };
-
- let mut command = &mut Command::new(&shell);
-
- if !preserve_env {
- // This is actually incorrect, i don't know why.
- // command = command.env_clear();
-
- let pw = unsafe { libc::getpwuid(uid).as_ref() };
-
- if let Some(pw) = pw {
- let home = unsafe { CStr::from_ptr(pw.pw_dir) };
- let pw_name = unsafe { CStr::from_ptr(pw.pw_name) };
-
- let home = home.to_string_lossy();
- let pw_name = pw_name.to_string_lossy();
-
- command = command
- .env("HOME", home.as_ref())
- .env("USER", pw_name.as_ref())
- .env("LOGNAME", pw_name.as_ref())
- .env("SHELL", &shell);
- }
- }
-
- // add /data/adb/ksu/bin to PATH
- #[cfg(any(target_os = "linux", target_os = "android"))]
- add_path_to_env(defs::BINARY_DIR)?;
-
- // when KSURC_PATH exists and ENV is not set, set ENV to KSURC_PATH
- if PathBuf::from(defs::KSURC_PATH).exists() && env::var("ENV").is_err() {
- command = command.env("ENV", defs::KSURC_PATH);
- }
-
- // escape from the current cgroup and become session leader
- // WARNING!!! This cause some root shell hang forever!
- // command = command.process_group(0);
- command = unsafe {
- command.pre_exec(move || {
- umask(0o22);
- utils::switch_cgroups();
-
- // switch to global mount namespace
- #[cfg(any(target_os = "linux", target_os = "android"))]
- if mount_master {
- let _ = utils::switch_mnt_ns(1);
- let _ = utils::unshare_mnt_ns();
- }
-
- set_identity(uid, gid, &groups);
-
- std::result::Result::Ok(())
- })
- };
-
- command = command.args(args).arg0(arg0);
- Err(command.exec().into())
-}
-
-fn add_path_to_env(path: &str) -> Result<()> {
- let mut paths =
- env::var_os("PATH").map_or(Vec::new(), |val| env::split_paths(&val).collect::>());
- let new_path = PathBuf::from(path.trim_end_matches('/'));
- paths.push(new_path);
- let new_path_env = env::join_paths(paths)?;
- env::set_var("PATH", new_path_env);
- Ok(())
-}
diff --git a/userspace/ksud/src/utils.rs b/userspace/ksud/src/utils.rs
deleted file mode 100644
index 9bacfa36..00000000
--- a/userspace/ksud/src/utils.rs
+++ /dev/null
@@ -1,454 +0,0 @@
-use anyhow::{bail, Context, Error, Ok, Result};
-use std::{
- fs::{self, create_dir_all, remove_file, write, File, OpenOptions},
- io::{
- ErrorKind::{AlreadyExists, NotFound},
- Write,
- },
- path::Path,
- process::Command,
- sync::OnceLock,
-};
-
-use crate::{assets, boot_patch, defs, ksucalls, module, restorecon};
-use std::fs::metadata;
-#[allow(unused_imports)]
-use std::fs::{set_permissions, Permissions};
-#[cfg(unix)]
-use std::os::unix::prelude::PermissionsExt;
-
-use hole_punch::*;
-use std::io::{Read, Seek, SeekFrom};
-
-use jwalk::WalkDir;
-use std::path::PathBuf;
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-use rustix::{
- process,
- thread::{move_into_link_name_space, unshare, LinkNameSpaceType, UnshareFlags},
-};
-
-pub fn ensure_clean_dir(dir: impl AsRef) -> Result<()> {
- let path = dir.as_ref();
- log::debug!("ensure_clean_dir: {}", path.display());
- if path.exists() {
- log::debug!("ensure_clean_dir: {} exists, remove it", path.display());
- std::fs::remove_dir_all(path)?;
- }
- Ok(std::fs::create_dir_all(path)?)
-}
-
-pub fn ensure_file_exists