27 August 2014

Jailing Java

Just a short post today. Aside from all the other distressing things happening in my life I've recently learned I'm getting kicked out of my apartment. Joy. I'll keep blogging to keep me sane, but they might not be as technical or in-depth as some of my other series.

Have you looked at your homedir lately? Cluttered with dotfiles, isn't it? If you don't know what a 'dotfile' is, look at your home files with ls ~/ ... now look again with ls -a ~/ . Quite a difference, right? In theory we have some modern XDG standards that will take a lot of that clutter and put them in ~/.config, ~/.local, and ~/.cache but that requires the programs to adhere to the XDG spec. Since we're in The Year Of The Linux Desktop we're actually in an exciting time where we are seeing a lot of developers making software (including games!) for Linux without actually being in the ecosystem from the start. So a lot of them aren't necessarily using Linux day-to-day. They aren't aware of how your homedir can get littered with crap from software that doesn't understand that ~/ is not the same as "My Documents" on other operating systems.

Mine Craft, Mine

Let's look at Minecraft. It's been pretty good when it comes to Linux, because it's mostly using Java and is readily portable. It stores its configuration and savegames in your home directory under ~/.minecraft. This isn't terrible, and it's nice to see more games on Linux, but I prefer to keep my homedir free of particularly large files so it's easier to back up my super-important files. Savegames can get pretty big these days, and it'd be nice to keep the .minecraft stuff along with the launcher jar file and the server jar file and all the other stuff related to Minecraft in one place. I generally make a directory outside of my homedir to keep the big stuff like games and music and video, not only to keep my actual home size down but to remove the ecryptfs overhead for the game data.

I already used a small script to launch Minecraft, so at first I thought all I'd need to do would be to change the special $HOME environment variable to point somewhere else.
cd "$(dirname "$0")"
export HOME="$(pwd)/home"
Sadly, Minecraft is too crafty for us. It looks like Java provides it with my actual home directory, presumably based on my /etc/passwd entry. I'm not about to tamper with that stuff, so how can we fool Java into thinking my "home" is somewhere else? A bit of research yields the -Duser.home="$HOME" argument to java. That will override what Java reports to Minecraft, so when Minecraft drops its .minecraft dir, it'll be where we want it to go.

Here's my launch script:-

# Go to the directory where this script is located. Everything is relative from there.
cd "$(dirname "$0")"
export HOME="$(pwd)/home"
echo "Rehoming to $HOME"
mkdir -p "$HOME"

# Certain programs have in the past given me a small amount of trouble with Minecraft.
#killall npviewer.bin
#killall pulseaudio

# Minecraft doesn't get along with ibus for some reason.
# I've since switched to fcitx but I'll play it safe.
export XMODIFIERS=''

cd client/
java -Duser.home="$HOME" -jar Minecraft.jar
and here's how my files are structured:-
james@jin(): /machine/garden/java/MinecraftVanilla.mcbottle
$ tree -a -L 3 .
├── client
│   └── Minecraft.jar
├── home
│   ├── .config
│   │   └── pulse
│   ├── .java
│   │   └── fonts
│   ├── .minecraft
│   │   ├── assets
│   │   ├── launcher.jar
│   │   ├── launcher.pack.lzma
│   │   ├── launcher_profiles.json
│   │   ├── libraries
│   │   └── versions
│   ├── minecraft-latest
│   │   ├── hs_err_pid8351.log
│   │   ├── logs
│   │   ├── options.txt
│   │   ├── resourcepacks
│   │   ├── saves
│   │   ├── screenshots
│   │   └── servers.dat
│   └── .nv
│       └── GLCache
├── minecraftbottle.sh
├── saves -> home/minecraft-latest/saves/
├── server
│   └── minecraft_server.1.7.9.jar
└── status.py
As you can see, by using the -Duser.home switch we've made home/.minecraft successfully, but a side effect of our export HOME= line means that a few other files get created there. .nv is apparently set up by my use of the nvidia driver. .java is obvious. "minecraft-latest" is a result of me experimenting with the new "profiles" option to the launcher - which I'll get to in a moment. And we have our good friend PulseAudio making a .config/pulse/cookie file for some important pulseaudio related thing.

Things That Go Wrong

But I have to mention that it was not always so. I first tried this script on my old Ubuntu 12.04 machine, and that version of Pulse was not nearly as cooperative. No, it expected to find a ~/.pulse/ directory to store cookies and sockets and all sorts. To further infuriate me, it wouldn't find the sound server properly if our rehomed Minecraft .pulse did not match the .pulse in my actual home directory. To add insult to injury, I couldn't even symlink the Minecraft one to my real ~/.pulse dir, because a bug caused Pulse to think that the directory wasn't secure enough if it was looking at a symlink. GAAAAH! Happily, since updating to 14.04, it is better behaved and uses the standard ~/.config/ area without fuss.

The other issue is this fancy new Minecraft profile system. It's a pretty neat way to keep track of multiple Minecraft versions, yes - but the path you give it for storing the profile must be an absolute path. If you try to give it a relative path, it gets converted and stored as absolute. This is a bit annoying for me, as I wanted to do this whole "Minecraft Bottle" thing as a way to easily move my Minecraft between machines, and experiment with mods like Terrafirmacraft. Keep it in mind if you use the profile system.

Anyway, it works now that we've upgraded to a less dumb version of Pulseaudio, and it's quite fascinating to see how many dotfiles get created just by a single program invocation. It may be a good idea to bottle up more games and applications like this, if only to untangle the mess that is $HOME/.

No comments:

Post a Comment