|
17 | 17 | */ |
18 | 18 | package org.jackhuang.hmcl; |
19 | 19 |
|
| 20 | +import org.jackhuang.hmcl.setting.SambaException; |
| 21 | +import org.jackhuang.hmcl.setting.SettingsManager; |
20 | 22 | import org.jackhuang.hmcl.util.FileSaver; |
21 | 23 | import org.jackhuang.hmcl.util.SelfDependencyPatcher; |
22 | 24 | import org.jackhuang.hmcl.util.SwingUtils; |
23 | 25 | import org.jackhuang.hmcl.java.JavaRuntime; |
24 | 26 | import org.jackhuang.hmcl.util.io.FileUtils; |
25 | 27 | import org.jackhuang.hmcl.util.io.JarUtils; |
| 28 | +import org.jackhuang.hmcl.util.platform.CommandBuilder; |
26 | 29 | import org.jackhuang.hmcl.util.platform.OperatingSystem; |
27 | 30 |
|
28 | 31 | import javax.swing.JOptionPane; |
| 32 | +import java.awt.Toolkit; |
| 33 | +import java.awt.datatransfer.StringSelection; |
29 | 34 | import java.io.IOException; |
30 | 35 | import java.lang.invoke.MethodHandle; |
31 | 36 | import java.lang.invoke.MethodHandles; |
32 | 37 | import java.lang.invoke.MethodType; |
33 | 38 | import java.nio.file.Files; |
34 | 39 | import java.nio.file.Path; |
| 40 | +import java.nio.file.Paths; |
| 41 | +import java.util.ArrayList; |
35 | 42 | import java.util.concurrent.CancellationException; |
36 | 43 |
|
37 | 44 | import static org.jackhuang.hmcl.util.logging.Logger.LOG; |
@@ -65,6 +72,17 @@ public static void main(String[] args) { |
65 | 72 | addEnableNativeAccess(); |
66 | 73 | enableUnsafeMemoryAccess(); |
67 | 74 |
|
| 75 | + try { |
| 76 | + SettingsManager.init(); |
| 77 | + } catch (SambaException e) { |
| 78 | + showWarning(i18n("fatal.samba")); |
| 79 | + } catch (IOException e) { |
| 80 | + LOG.error("Failed to load config", e); |
| 81 | + checkConfigOwner(); |
| 82 | + SwingUtils.showErrorDialog(i18n("fatal.config_loading_failure", SettingsManager.localConfigDirectory())); |
| 83 | + EntryPoint.exit(1); |
| 84 | + } |
| 85 | + |
68 | 86 | Launcher.main(args); |
69 | 87 | } |
70 | 88 |
|
@@ -225,15 +243,8 @@ private static void verifyJavaFX() { |
225 | 243 |
|
226 | 244 | private static void checkWine() { |
227 | 245 | if (OperatingSystem.isRunningUnderWine()) { |
228 | | - SwingUtils.initLookAndFeel(); |
229 | 246 | LOG.warning("HMCL is running under Wine or its distributions!"); |
230 | | - |
231 | | - int result = JOptionPane.showOptionDialog(null, i18n("fatal.wine_warning"), i18n("message.warning"), JOptionPane.OK_CANCEL_OPTION, |
232 | | - JOptionPane.WARNING_MESSAGE, null, null, null); |
233 | | - |
234 | | - if (result == JOptionPane.CANCEL_OPTION || result == JOptionPane.CLOSED_OPTION) { |
235 | | - exit(1); |
236 | | - } |
| 247 | + showWarning(i18n("fatal.wine_warning")); |
237 | 248 | } |
238 | 249 | } |
239 | 250 |
|
@@ -273,6 +284,70 @@ private static void enableUnsafeMemoryAccess() { |
273 | 284 | } |
274 | 285 | } |
275 | 286 |
|
| 287 | + private static void checkConfigOwner() { |
| 288 | + if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) |
| 289 | + return; |
| 290 | + |
| 291 | + String userName = System.getProperty("user.name"); |
| 292 | + Path configDirectory = SettingsManager.localConfigDirectory(); |
| 293 | + if (!Files.exists(configDirectory)) { |
| 294 | + return; |
| 295 | + } |
| 296 | + |
| 297 | + String owner; |
| 298 | + try { |
| 299 | + owner = Files.getOwner(configDirectory).getName(); |
| 300 | + } catch (IOException ioe) { |
| 301 | + LOG.warning("Failed to get file owner", ioe); |
| 302 | + return; |
| 303 | + } |
| 304 | + |
| 305 | + if (Files.isWritable(configDirectory) || userName.equals("root") || userName.equals(owner)) |
| 306 | + return; |
| 307 | + |
| 308 | + ArrayList<String> files = new ArrayList<>(); |
| 309 | + files.add(configDirectory.toString()); |
| 310 | + if (Files.exists(Metadata.HMCL_USER_HOME)) |
| 311 | + files.add(Metadata.HMCL_USER_HOME.toString()); |
| 312 | + |
| 313 | + Path mcDir = Paths.get(".minecraft").toAbsolutePath().normalize(); |
| 314 | + if (Files.exists(mcDir)) |
| 315 | + files.add(mcDir.toString()); |
| 316 | + |
| 317 | + String command = new CommandBuilder().addAll("sudo", "chown", "-R", userName).addAll(files).toString(); |
| 318 | + SwingUtils.initLookAndFeel(); |
| 319 | + |
| 320 | + Object[] options = {i18n("button.copy_and_exit"), i18n("button.cancel")}; |
| 321 | + int result = JOptionPane.showOptionDialog(null, |
| 322 | + i18n("fatal.config_loading_failure.unix", owner, command), |
| 323 | + i18n("message.error"), |
| 324 | + JOptionPane.DEFAULT_OPTION, |
| 325 | + JOptionPane.ERROR_MESSAGE, |
| 326 | + null, |
| 327 | + options, |
| 328 | + options[0]); |
| 329 | + |
| 330 | + if (result == 0) { |
| 331 | + try { |
| 332 | + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(command), null); |
| 333 | + } catch (Throwable e) { |
| 334 | + LOG.warning("Failed to copy command to clipboard", e); |
| 335 | + } |
| 336 | + } |
| 337 | + EntryPoint.exit(1); |
| 338 | + } |
| 339 | + |
| 340 | + private static void showWarning(String message) { |
| 341 | + SwingUtils.initLookAndFeel(); |
| 342 | + |
| 343 | + int result = JOptionPane.showOptionDialog(null, message, i18n("message.warning"), JOptionPane.OK_CANCEL_OPTION, |
| 344 | + JOptionPane.WARNING_MESSAGE, null, null, null); |
| 345 | + |
| 346 | + if (result == JOptionPane.CANCEL_OPTION || result == JOptionPane.CLOSED_OPTION) { |
| 347 | + exit(1); |
| 348 | + } |
| 349 | + } |
| 350 | + |
276 | 351 | /** |
277 | 352 | * Indicates that a fatal error has occurred, and that the application cannot start. |
278 | 353 | */ |
|
0 commit comments