-2

A follow up of this post: Shell script does not run java, wrong parameters

I've created a program in java which reads the console, and react accordingly. Now I want this program constantly run, and read data what has been entered, but this maschine has only a barcode reader as an input. When I run the program manually, it works correctly, but I cannot make it automated. I need this, because it won't have a keyboard or a monitor. When it runs as a service, it doesn't take any input, and /proc/[procid]/fd/0 always gives permission denied.

How can I run this java program, that it always restarts itself, and able to read the input from the barcode reader?

The Barcode reader acts as a Generic 104 buttons PC, Right-AltGr, No compose key.

kry
  • 113
  • 6
  • What type of input does the barcode reader act as? a keyboard? More details on which one you are using might offer better advice. – Michael Daffin Sep 19 '17 at 08:39
  • Yes, sorry. I'm not sure which details are useful and which are not. It gives it's id, the read barcode as a string, and then a newline (\10\13 if I remember correctly. It behaves as it hits and enter after each message.) – kry Sep 19 '17 at 08:41
  • What exactly reading the console from a Java program means? Maybe you mean that your Java program is reading from its stdin (which is not the same in general). You should give a simple Java program -similar to yours- in your question (or at least put a link to the source code of your Java program) – Basile Starynkevitch Sep 19 '17 at 09:01
  • Are you sure that the barcoder acts like a English keyboard? Can you reconfigure the layout of that keyboard (e.g. with dpkg-reconfigure keyboard-configuration)? You should read more documentation about your barcode reader! – Basile Starynkevitch Sep 19 '17 at 09:09
  • Without much more information about that barcode reader (what model), the drivers involved, the configuration of the computer, the specific Java program, that question is unclear and too broad. – Basile Starynkevitch Sep 19 '17 at 09:11
  • It works normally when I use it as an English keyboard. When I use Hungarian, it gives there characters that are Hungarian where the English keys should be. (For example, ö instead 0, ü instead -). – kry Sep 19 '17 at 09:11
  • What does it have to do with the reader? It's just like using a computer with a keyboard without a monitor. Except the input is much more limited. – kry Sep 19 '17 at 09:12
  • Do you use any specific driver? – Basile Starynkevitch Sep 19 '17 at 09:13
  • No, I use the one coming with the default install. – kry Sep 19 '17 at 09:31
  • You are lacking general know-how about Linux and Unix. Take a few days to read good books (e.g. Advanced Linux Programming....) before coding any single additional line – Basile Starynkevitch Sep 19 '17 at 09:36
  • 1
    He means the scanner acts like a generic keyboard - basically typing out the character of the barcode scanned. Not an uncommon way for barcode readers to act. As far as linux is concerned it is a usb keyboard, no special drivers required. His application works when run in a terminal but not when disconnected from stdin - which is what his question is about. – Michael Daffin Sep 19 '17 at 09:40

2 Answers2

1

You have two main ways to tackle this.

Redirect a stdin from a tty to your application

By default systems boot to tty1, you can disable the getty running on that tty and hijack its input for your on purpose. First disable the getty on the system

sudo systemctl stop getty@tty1.service
sudo systemctl disable getty@tty1.service

You should do this from an ssh session or another getty or you will lose your login. You didn't mention your system, but with systemd this is the way - consult your distros documentation if this does not work for you

Now we need to create a wrapper script that contains your application to redirect /dev/tty1 to stdin of your program (the </dev/tty1 at the end): /usr/local/bin/rxtxcomm

#!/bin/bash
/usr/bin/java -Djava.library.path=/usr/lib/jni \
  -cp /usr/share/java/RXTXcomm.jar -jar '/foo/bar.jar' </dev/tty1

And make it executable with:

sudo chmod +x /usr/local/bin/rxtxcomm

Then update your service file to run this script instead. Restart the service and it should attach its stdin to /dev/tty1.

You can try it manually by running the above command in another tty or ssh session, but you need to run it as root (or changes the permissions on the tty). Note that with this solution you have to be on tty1 for it to capture any input (alt+ctrl+F1 on most systems). Also, to do this you must be root (which service files are by default) or the user you run as must have access to read from the tty directly.

Read directly from /dev/input/

Almost all devices in linux are available as files inside /dev. Keyboards are available in /dev/input/. You can modify your program to instead read directly from these files - the can be read from like any files but produce binary data so it is a little more work to get the characters typed.

Here is a short java example taken from this stack overflow question.

// replace path with path from your system
DataInputStream in = new DataInputStream(
    new FileInputStream("/dev/input/by-id/usb-0430_0005-event-kbd"));
String map = "    abcdefghijlkmnopqrstuvwxyz                                                                                                                                                                                                                                                                ";
// sizeof(struct timeval) = 16
byte[] timeval = new byte[16];
short type, code;
int value;
while (true) {
    in.readFully(timeval);
    type = in.readShort();
    code = in.readShort();
    value = in.readInt();
    System.out.printf("%04x %04x %08x %c\n", type, code, value, 
                                             map.charAt(value>>>24));
}

This method has the advantage of attaching to a specific keyboard - so you can attach another keyboard without interfering with the script. Which can be useful for debugging the system. It also means you do not need to disable a tty or forced to be on a specific tty for the application to work. You are still required to run as root however, or changes the permissions of the devices so another user has direct access to it.

  • I tried to run the first one, but now the java doesn't even start running. I also tried adding exec into the shell script. -bash: /dev/tty1: Permission denied – kry Sep 19 '17 at 09:29
  • Did you run it as root? Did it error at all? You should not need exec in the script. Do you already have something running on tty1 (alt+ctrl+F1 to switch to that tty)? – Michael Daffin Sep 19 '17 at 09:32
  • -bash: /dev/tty1: Permission denied you need to run it as root to attach to a tty like this. Or changes the permissions on /dev/tty1 to allow your user to read from it. – Michael Daffin Sep 19 '17 at 09:32
  • I've done it as root. At least with sudo. Do I need to log in as root? – kry Sep 19 '17 at 09:34
  • O, did you make the script executable? – Michael Daffin Sep 19 '17 at 09:35
  • I've added 777 permissions to it. – kry Sep 19 '17 at 09:39
  • Did you run the script as root? or did you add sudo inside the script - the latter will not work. You need to run the entire script as root sudo /usr/local/bin/rxtxcomm for the redirect to work inside it. – Michael Daffin Sep 19 '17 at 09:42
  • I added a sudo. Will check running as a toor. Oooh, it works, even across the room. :D Okay, the only thing it needs now is to run it as a script, so I don't need to start the program each time after restart. – kry Sep 19 '17 at 09:43
  • And I can't upvote posts or edit my comments, because I don't have enough reputation. I've added a sudo su - as the second line of the shell script, but it's still not running. – kry Sep 19 '17 at 09:50
  • Like in the previous question - just replace the command in the service file with the path to the wrapper script we created. – Michael Daffin Sep 19 '17 at 09:51
  • I did, it's now ExecStart=/usr/local/bin/rxtxcomm.sh And now the whole thing froze from the daemon-reload, be right back. And I lost it, not even restart works anymore. :( – kry Sep 19 '17 at 09:55
  • Okay, it's working again. Apparently I can not write sudo su - into a bash script, but how exactly do I run it now as a root? https://askubuntu.com/questions/167847/how-to-run-bash-script-as-root-with-no-password I changed it's owner to root, and gave it permissions, but it's still not running. :( – kry Sep 19 '17 at 10:13
  • Systemd will run things as root by default, no need to do anything special, you should just be able to leave sudo out of the script and ExecStart line completely. – Michael Daffin Sep 19 '17 at 10:24
  • Currently it's ExecStart=/usr/local/bin/rxtxcomm.sh, and the script has only one line (and a shebang), which starts with the /usr/bin/java. At this moment, the script does not run. I added an exec in front of the script, but it's still not working. – kry Sep 19 '17 at 10:28
  • Wrote a new shell script that uses exec sudo, and run it in root crontab each minute. Now it works as intended (altough, have to wait about a minute after start to run normally, but it's a minor setback). – kry Sep 19 '17 at 12:23
0

You may want to have your program started at power on time.

How to do that depends upon the init program used by your Unix or Linux system (e.g. some systems are using systemd others are using some sysvinit)

If crond is started on your system, consider some @reboot entry in your crontab(5)

How can I run this java program, that it always restarts itself, and able to read the input from the barcode reader?

A better way is to write a good enough program that does not stop unwillingly. Otherwise, wrap it into some shell script that would restart it on failure.

You need to understand how the barcode reader is viewed from Linux. Probably it is some character device, perhaps some tty... See tty(4), stty(1), agetty(8), termios(3), kbd_mode(1) and read the Tty demystified.

See also this

When it runs as a service, it doesn't take any input, and /proc/[procid]/fd/0 always gives permission denied.

Because in that case stdin is not a terminal (or the keyboard, or your barcode reader). You should perhaps redirect it.

Of course programs started at power on (thru init, systemd, crontab, ...) or in batch mode (with at or batch or even nohup) don't have the same execution environment as your interactive command line (different file descriptors, different environ(7)....). You either need to take that into account when coding these programs, or code some wrapping shell script setting things well (redirecting stdin, stdout, stderr; export-ing some important variables)

PS. I recommend taking a few days to read more about Linux (e.g. Advanced Linux Programming, From Power Up To Bash Prompt, Introduction to Linux, Understanding and Using systemd, Bash beginners Guide) and operating systems (e.g. Operating Systems : Three Easy Pieces) before coding any single line of Java or some script.