Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending command to java -jar using stdin via /proc/{pid}/fd/0

I'm trying to send a command to a minecraft server jar using /proc/{pid}/fd/0 but the server does not execute the command.

To replicate what I'm trying to do you can do this on a Debian based machine (possibly other Linux distributuions aswell).

What I use to test this:

  • Ubuntu 14.04
  • minecraft_server.jar (testing with 1.8)
  • OpenJDK Runtime Environment (installed with default-jre-headless)

First console:

$ java -jar minecraft_server.jar nogui

Response: [ ... server starts and waiting for input]

say hi

Response: [19:52:23] [Server thread/INFO]: [Server] hi

Second console:

Now when i switch to the second console, with the server still running in the first i write:

echo "say hi2" >> /proc/$(pidof java)/fd/0

Everything looks well until I switch back to the first console. I can see the text "say hi2" but the server hasn't recognized it. I can write another command in the first console again and it is as if the text inputted from the second console hasn't even existed.

Why is this? And more importantly, how do I use /proc/{pid}/fd/0 in a proper way to send commands to a java jar file?

I don't know if this is some kind of Java-thing that I'm not aware of, if I can use some flag or something when executing the server, or if it's the server jar itself that is the problem..

I'm aware that you can use screen, tail -f or some kind of server wrapper to accomplish this, but that's not what I'm after. I would like to send a command using this method, in some kind of way.

like image 318
Joel Bergroth Avatar asked Nov 05 '14 19:11

Joel Bergroth


1 Answers

It's not a Java thing. What you are trying is simply not doable.

Test it like this:

Console1:

 $ cat

This will basically echo anything you type on it as soon as you hit "return".

Console2: Find the process number of your cat command. Let's say it's NNN. Do:

$ echo Something > /proc/NNN/fd/0

Switch back to Console1. You'll see "Something" on the console output, but it's not echoed.

Why? Do

$ ls -l /proc/NNN/fd

And you may understand. All three descriptors, 0 for stdin, 1 for stdout and 2 for stderr are actually symbolic links, and all point to the same pseudoterminal slave (pts) device, which is the pts associated with your first terminal.

So basically, when you write to it, you actually write to the console output, not to its input. If you read from that file, you could steal some of the input that was supposed to go to the process in the first console (you are racing for this input). That's how a character device works.

The documentation for /proc says that:

/proc/[pid]/fd/

This is a subdirectory containing one entry for each file which the process has open, named by its file descriptor, and which is a symbolic link to the actual file. Thus, 0 is standard input, 1 standard output, 2 standard error, and so on.

So these are not the actual file descriptors opened by the process. They are just links to files (or in this case, character devices) with names that indicate which descriptor they are attached to in the given process. Their main duty is to tell you whether the process has redirected its file descriptors or has opened any new ones, and which resources they point to.

But if you want an alternative way of doing this, you can use a fifo - a named pipe.

Create a fifo by doing:

$ mkfifo myfifo

Run your java program:

$ java -jar minecraft_server.jar nogui < myfifo

Open another console. write

$ cat > myfifo

Now start typing things. Switch to the first console. You'll see your server executing your commands.

Mind your end-of-files, though. Several processes can write to the same fifo, but as soon as the last one closes it, your server will receive an EOF on its standard input.

like image 115
RealSkeptic Avatar answered Oct 11 '22 17:10

RealSkeptic