diff --git a/chameleon-server/src/main/java/com/chameleonvision/Main.java b/chameleon-server/src/main/java/com/chameleonvision/Main.java index 7223da8df..a34d92244 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/Main.java +++ b/chameleon-server/src/main/java/com/chameleonvision/Main.java @@ -3,6 +3,7 @@ package com.chameleonvision; import com.chameleonvision.config.ConfigManager; import com.chameleonvision.network.NetworkManager; import com.chameleonvision.util.Platform; +import com.chameleonvision.util.ShellExec; import com.chameleonvision.util.Utilities; import com.chameleonvision.vision.VisionManager; import com.chameleonvision.web.Server; @@ -22,6 +23,7 @@ public class Main { private static final String NT_CLIENTMODESERVER_KEY = "--nt-client-server"; // expects String representing an IP address (hostnames will be rejected!) private static final String NETWORK_MANAGE_KEY = "--unmanage-network"; // no args for this setting private static final String IGNORE_ROOT_KEY = "--ignore-root"; // no args for this setting + private static final String UPDATE_FILE_PERMISSIONS = "--update-perms"; // no args for this setting, exits program after running private static final String TEST_MODE_KEY = "--cv-development"; private static final int DEFAULT_PORT = 5800; @@ -63,6 +65,7 @@ public class Main { case NT_SERVERMODE_KEY: case NETWORK_MANAGE_KEY: case IGNORE_ROOT_KEY: + case UPDATE_FILE_PERMISSIONS: case TEST_MODE_KEY: // nothing break; @@ -93,6 +96,19 @@ public class Main { case IGNORE_ROOT_KEY: ignoreRoot = true; break; + case UPDATE_FILE_PERMISSIONS: + if (!Platform.getCurrentPlatform().isWindows()) { + System.out.print("Fixing file permissions..."); + try { + new ShellExec().executeBashCommand("sudo chmod -R 0777 " + ConfigManager.SettingsPath.toString()); + System.out.println("Done. Exiting."); + } catch (IOException e) { + System.err.println("Failed to fix file permissions, exiting."); + } + System.exit(0); + } else { + System.out.println("Cannot change file permissions on windows, exiting."); + } case TEST_MODE_KEY: testMode = true; break; diff --git a/chameleon-server/src/main/java/com/chameleonvision/config/ConfigManager.java b/chameleon-server/src/main/java/com/chameleonvision/config/ConfigManager.java index 3003b6d02..5452618a2 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/config/ConfigManager.java +++ b/chameleon-server/src/main/java/com/chameleonvision/config/ConfigManager.java @@ -1,7 +1,10 @@ package com.chameleonvision.config; +import com.chameleonvision.Main; +import com.chameleonvision.util.Platform; import com.chameleonvision.util.ProgramDirectoryUtilities; import com.chameleonvision.util.JacksonHelper; +import com.chameleonvision.util.ShellExec; import com.chameleonvision.vision.pipeline.CVPipelineSettings; import java.io.File; @@ -16,7 +19,7 @@ import java.util.List; public class ConfigManager { private ConfigManager() {} - static final Path SettingsPath = Paths.get(ProgramDirectoryUtilities.getProgramDirectory(), "settings"); + public static final Path SettingsPath = Paths.get(ProgramDirectoryUtilities.getProgramDirectory(), "settings"); private static final Path settingsFilePath = Paths.get(SettingsPath.toString(), "settings.json"); private static final LinkedHashMap cameraConfigs = new LinkedHashMap<>(); @@ -33,6 +36,9 @@ public class ConfigManager { System.err.println("Failed to create settings folder: " + SettingsPath.toString()); } Files.createDirectory(SettingsPath); + if (!Platform.getCurrentPlatform().isWindows()) { + new ShellExec().executeBashCommand("sudo chmod -R 0777 " + SettingsPath.toString()); + } } catch (IOException e) { if(!(e instanceof java.nio.file.FileAlreadyExistsException)) e.printStackTrace(); diff --git a/chameleon-server/src/main/java/com/chameleonvision/util/ShellExec.java b/chameleon-server/src/main/java/com/chameleonvision/util/ShellExec.java index f0fa0f1cd..60856cf79 100644 --- a/chameleon-server/src/main/java/com/chameleonvision/util/ShellExec.java +++ b/chameleon-server/src/main/java/com/chameleonvision/util/ShellExec.java @@ -19,6 +19,43 @@ public class ShellExec { this.readError = readError; } + /** + * Execute a bash command. We can handle complex bash commands including + * multiple executions (; | && ||), quotes, expansions ($), escapes (\), e.g.: + * "cd /abc/def; mv ghi 'older ghi '$(whoami)" + * @param command + * @return true if bash got started, but your command may have failed. + */ + public int executeBashCommand(String command) throws IOException { + boolean wait = true; + boolean success = false; + Runtime r = Runtime.getRuntime(); + // Use bash -c so we can handle things like multi commands separated by ; and + // things like quotes, $, |, and \. My tests show that command comes as + // one argument to bash, so we do not need to quote it to make it one thing. + // Also, exec may object if it does not have an executable file as the first thing, + // so having bash here makes it happy provided bash is installed and in path. + String[] commands = {"bash", "-c", command}; + + Process process = r.exec(commands); + + // Consume streams, older jvm's had a memory leak if streams were not read, + // some other jvm+OS combinations may block unless streams are consumed. + errorGobbler = new StreamGobbler(process.getErrorStream(), readError); + outputGobbler = new StreamGobbler(process.getInputStream(), readOutput); + errorGobbler.start(); + outputGobbler.start(); + + exitCode = 0; + if (wait) { + try { + process.waitFor(); + exitCode = process.exitValue(); + } catch (InterruptedException ignored) { } + } + return exitCode; + } + /** * Execute a command in current folder, and wait for process to end * @param command command ("c:/some/folder/script.bat" or "some/folder/script.sh")