[platform] revising startup-time system directory tests

- dropping obsolete file lock test
- postponing the no-exec test as it is not critical (IDEA-331084)

GitOrigin-RevId: e304fae08f82dedb896d24836869a3a3dd7bee15
This commit is contained in:
Roman Shevchenko
2023-09-07 08:16:27 +00:00
committed by intellij-monorepo-bot
parent b229aa0d48
commit acddd1bba5
4 changed files with 27 additions and 62 deletions
@@ -926,6 +926,7 @@ shell.env.loading.failed={0} has failed to load the environment from ''{1}''. \
Integration with tools that rely on environment variables may work incorrectly.
shell.env.loading.learn.more=Learn more
temp.dir.exec.failed=The IDE cannot execute a test script in the temporary directory ''{0}''. Some things may work incorrectly.
temp.dir.env.invalid=Environment variable ''{0}'' points to a non-existing directory (''{1}''). Some things may work incorrectly.
unsupported.windows=This version of Windows is no longer supported. Some features may not work correctly. Please use Windows 10 1809 or newer.
@@ -51,13 +51,10 @@ import java.io.IOException
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
import java.lang.management.ManagementFactory
import java.nio.channels.FileChannel
import java.nio.file.Files
import java.nio.file.InvalidPathException
import java.nio.file.Path
import java.nio.file.StandardOpenOption
import java.nio.file.attribute.PosixFileAttributeView
import java.nio.file.attribute.PosixFilePermission
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.*
@@ -69,6 +66,7 @@ import java.util.logging.ConsoleHandler
import java.util.logging.Level
import javax.swing.*
import kotlin.coroutines.CoroutineContext
import kotlin.io.path.deleteIfExists
import kotlin.system.exitProcess
internal const val IDE_STARTED: String = "------------------------------------------------------ IDE STARTED ------------------------------------------------------"
@@ -491,48 +489,22 @@ private suspend fun doCheckSystemDirs(configPath: Path, systemPath: Path): Boole
listOf(
async {
checkDirectory(directory = configPath,
kind = "Config",
property = PathManager.PROPERTY_CONFIG_PATH,
checkWrite = true,
checkLock = true,
checkExec = false)
checkDirectory(configPath, kind = "Config", property = PathManager.PROPERTY_CONFIG_PATH, checkWrite = true)
},
async {
checkDirectory(directory = systemPath,
kind = "System",
property = PathManager.PROPERTY_SYSTEM_PATH,
checkWrite = true,
checkLock = true,
checkExec = false)
checkDirectory(systemPath, kind = "System", property = PathManager.PROPERTY_SYSTEM_PATH, checkWrite = true)
},
async {
checkDirectory(directory = logPath,
kind = "Log",
property = PathManager.PROPERTY_LOG_PATH,
checkWrite = !logPath.startsWith(systemPath),
checkLock = false,
checkExec = false)
checkDirectory(logPath, kind = "Log", property = PathManager.PROPERTY_LOG_PATH, checkWrite = true)
},
async {
checkDirectory(directory = tempPath,
kind = "Temp",
property = PathManager.PROPERTY_SYSTEM_PATH,
checkWrite = !tempPath.startsWith(systemPath),
checkLock = false,
checkExec = SystemInfoRt.isUnix && !SystemInfoRt.isMac)
checkDirectory(tempPath, kind = "Temp", property = PathManager.PROPERTY_SYSTEM_PATH, checkWrite = !tempPath.startsWith(systemPath))
}
).awaitAll().all { it }
}
}
private fun checkDirectory(directory: Path,
kind: String,
property: String,
checkWrite: Boolean,
checkLock: Boolean,
checkExec: Boolean): Boolean {
private fun checkDirectory(directory: Path, kind: String, property: String, checkWrite: Boolean): Boolean {
var problem = "bootstrap.error.message.check.ide.directory.problem.cannot.create.the.directory"
var reason = "bootstrap.error.message.check.ide.directory.possible.reason.path.is.incorrect"
var tempFile: Path? = null
@@ -542,33 +514,11 @@ private fun checkDirectory(directory: Path,
reason = "bootstrap.error.message.check.ide.directory.possible.reason.directory.is.read.only.or.the.user.lacks.necessary.permissions"
Files.createDirectories(directory)
}
if (checkWrite || checkLock || checkExec) {
if (checkWrite) {
problem = "bootstrap.error.message.check.ide.directory.problem.the.ide.cannot.create.a.temporary.file.in.the.directory"
reason = "bootstrap.error.message.check.ide.directory.possible.reason.directory.is.read.only.or.the.user.lacks.necessary.permissions"
tempFile = directory.resolve("ij${Random().nextInt(Int.MAX_VALUE)}.tmp")
Files.writeString(tempFile, "#!/bin/sh\nexit 0", StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)
if (checkLock) {
problem = "bootstrap.error.message.check.ide.directory.problem.the.ide.cannot.create.a.lock.in.directory"
reason = "bootstrap.error.message.check.ide.directory.possible.reason.the.directory.is.located.on.a.network.disk"
FileChannel.open(tempFile, EnumSet.of(StandardOpenOption.WRITE)).use { channel ->
channel.tryLock().use { lock ->
if (lock == null) {
throw IOException("File is locked")
}
}
}
}
else if (checkExec) {
problem = "bootstrap.error.message.check.ide.directory.problem.the.ide.cannot.execute.test.script"
reason = "bootstrap.error.message.check.ide.directory.possible.reason.partition.is.mounted.with.no.exec.option"
Files.getFileAttributeView(tempFile!!, PosixFileAttributeView::class.java)
.setPermissions(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE))
val exitCode = ProcessBuilder(tempFile.toAbsolutePath().toString()).start().waitFor()
if (exitCode != 0) {
throw IOException("Unexpected exit value: $exitCode")
}
}
}
return true
}
@@ -29,6 +29,7 @@ import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.NlsContexts
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.SystemInfoRt
import com.intellij.openapi.util.io.NioFiles
import com.intellij.platform.ide.CoreUiCoroutineScopeHolder
import com.intellij.platform.ide.customization.ExternalProductResourceUrls
import com.intellij.util.SystemProperties
@@ -45,6 +46,7 @@ import java.nio.file.FileStore
import java.nio.file.Files
import java.nio.file.InvalidPathException
import java.nio.file.Path
import java.util.concurrent.TimeUnit
import kotlin.system.exitProcess
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
@@ -61,6 +63,7 @@ internal suspend fun startSystemHealthMonitor() {
checkEnvironment()
withContext(Dispatchers.IO) {
checkSignalBlocking()
checkTempDirSanity()
checkTempDirEnvVars()
checkAncientOs()
}
@@ -280,6 +283,21 @@ private fun checkSignalBlocking() {
}
}
private fun checkTempDirSanity() {
if (SystemInfoRt.isUnix && !SystemInfoRt.isMac) {
try {
val probe = Files.createTempFile(Path.of(PathManager.getTempPath()), "ij-exec-check-", ".sh")
NioFiles.setExecutable(probe)
val process = ProcessBuilder(probe.toString()).start()
if (!process.waitFor(1, TimeUnit.MINUTES)) throw IOException("${probe} timed out")
if (process.exitValue() != 0) throw IOException("${probe} returned ${process.exitValue()}")
}
catch (e: Exception) {
showNotification("temp.dir.exec.failed", suppressable = false, action = null, shorten(PathManager.getTempPath()))
}
}
}
private fun checkTempDirEnvVars() {
val envVars = if (SystemInfoRt.isWindows) sequenceOf("TMP", "TEMP") else sequenceOf("TMPDIR")
for (name in envVars) {
@@ -297,7 +315,7 @@ private fun checkTempDirEnvVars() {
}
private fun checkAncientOs() {
if (SystemInfo.isWindows) {
if (SystemInfoRt.isWindows) {
val buildNumber = SystemInfo.getWinBuildNumber()
if (buildNumber != null && buildNumber < 10000) { // 10 1507 = 10240, Server 2016 = 14393
showNotification("unsupported.windows", suppressable = true, null)
@@ -31,13 +31,9 @@ bootstrap.error.title.configuration.wizard.failed=Configuration Wizard Failed
bootstrap.error.message.check.ide.directory.problem.cannot.create.the.directory=The IDE cannot create the directory.
bootstrap.error.message.check.ide.directory.problem.the.ide.cannot.create.a.temporary.file.in.the.directory=The IDE cannot create a temporary file in the directory.
bootstrap.error.message.check.ide.directory.problem.the.ide.cannot.create.a.lock.in.directory=The IDE cannot create a lock file in the directory.
bootstrap.error.message.check.ide.directory.problem.the.ide.cannot.execute.test.script=The IDE cannot execute a test script in the directory.
bootstrap.error.message.check.ide.directory.possible.reason.path.is.incorrect=Possible reason: path is incorrect.
bootstrap.error.message.check.ide.directory.possible.reason.directory.is.read.only.or.the.user.lacks.necessary.permissions=Possible reason: parent directory is read-only or the user lacks necessary permissions.
bootstrap.error.message.check.ide.directory.possible.reason.the.directory.is.located.on.a.network.disk=Possible reason: the directory is located on a network disk.
bootstrap.error.message.check.ide.directory.possible.reason.partition.is.mounted.with.no.exec.option=Possible reason: the partition is mounted with 'no exec' option.
bootstrap.error.title.jetbrains.marketplace.boot.failure=JetBrains Marketplace Boot Failure