Загрузка данных
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
public static class KWriteLauncher
{
[DllImport("libc")]
private static extern uint geteuid();
public static void OpenKWriteAsSudoUser(string filePath)
{
if (string.IsNullOrWhiteSpace(filePath))
throw new ArgumentException("Путь к файлу не указан.", nameof(filePath));
string fullPath = Path.GetFullPath(filePath);
if (!File.Exists(fullPath))
throw new FileNotFoundException("Файл не найден.", fullPath);
if (geteuid() != 0)
{
StartKWriteDirect(fullPath);
return;
}
string? sudoUser = Environment.GetEnvironmentVariable("SUDO_USER");
string? sudoUid = Environment.GetEnvironmentVariable("SUDO_UID");
if (string.IsNullOrWhiteSpace(sudoUser) || string.IsNullOrWhiteSpace(sudoUid))
{
throw new InvalidOperationException(
"Приложение запущено от root, но SUDO_USER/SUDO_UID не найдены."
);
}
string home = GetHomeDirectory(sudoUser)
?? throw new InvalidOperationException($"Не удалось определить HOME пользователя {sudoUser}.");
string runtimeDir = $"/run/user/{sudoUid}";
string dbusAddress = $"unix:path={runtimeDir}/bus";
if (!Directory.Exists(runtimeDir))
{
throw new InvalidOperationException(
$"Не найден {runtimeDir}. Пользователь {sudoUser} должен быть залогинен в графическую сессию."
);
}
string display = Environment.GetEnvironmentVariable("DISPLAY") ?? ":0";
string? waylandDisplay = Environment.GetEnvironmentVariable("WAYLAND_DISPLAY");
string? xAuthority = Environment.GetEnvironmentVariable("XAUTHORITY");
if (string.IsNullOrWhiteSpace(xAuthority))
{
string defaultXauthority = Path.Combine(home, ".Xauthority");
if (File.Exists(defaultXauthority))
xAuthority = defaultXauthority;
}
var psi = new ProcessStartInfo
{
FileName = "runuser",
UseShellExecute = false,
CreateNoWindow = true
};
psi.ArgumentList.Add("-u");
psi.ArgumentList.Add(sudoUser);
psi.ArgumentList.Add("--");
psi.ArgumentList.Add("env");
psi.ArgumentList.Add($"HOME={home}");
psi.ArgumentList.Add($"USER={sudoUser}");
psi.ArgumentList.Add($"LOGNAME={sudoUser}");
psi.ArgumentList.Add($"XDG_RUNTIME_DIR={runtimeDir}");
psi.ArgumentList.Add($"DBUS_SESSION_BUS_ADDRESS={dbusAddress}");
psi.ArgumentList.Add($"DISPLAY={display}");
AddEnvIfExists(psi, "XDG_SESSION_TYPE");
AddEnvIfExists(psi, "XDG_CURRENT_DESKTOP");
AddEnvIfExists(psi, "KDE_FULL_SESSION");
AddEnvIfExists(psi, "KDE_SESSION_VERSION");
AddEnvIfExists(psi, "QT_QPA_PLATFORM");
if (!string.IsNullOrWhiteSpace(waylandDisplay))
psi.ArgumentList.Add($"WAYLAND_DISPLAY={waylandDisplay}");
if (!string.IsNullOrWhiteSpace(xAuthority))
psi.ArgumentList.Add($"XAUTHORITY={xAuthority}");
psi.ArgumentList.Add("kwrite");
// Обычный путь, не admin://
psi.ArgumentList.Add(fullPath);
Process? process = Process.Start(psi);
// Не вызываем WaitForExit().
// Приложение продолжит работу сразу после запуска KWrite.
process?.Dispose();
}
private static void StartKWriteDirect(string fullPath)
{
var psi = new ProcessStartInfo
{
FileName = "kwrite",
UseShellExecute = false,
CreateNoWindow = true
};
psi.ArgumentList.Add(fullPath);
Process? process = Process.Start(psi);
process?.Dispose();
}
private static void AddEnvIfExists(ProcessStartInfo psi, string name)
{
string? value = Environment.GetEnvironmentVariable(name);
if (!string.IsNullOrWhiteSpace(value))
psi.ArgumentList.Add($"{name}={value}");
}
private static string? GetHomeDirectory(string userName)
{
foreach (string line in File.ReadLines("/etc/passwd"))
{
if (line.StartsWith(userName + ":", StringComparison.Ordinal))
{
string[] parts = line.Split(':');
if (parts.Length >= 6)
return parts[5];
}
}
return null;
}
}