GNU/Linux


Monkey Problems

Recently, we tried to user monkeyrunner on an Ubuntu 18.04 LTS. We installed Android Studio through snap and we setup the Android SDK in ~/Andoid. monkeyrunner was installed in ~/Android/Sdk/tools/bin. To our immeasurable disappointment we found out that when we tried to execute monkeyrunner, it would give the following error:

$ ./monkeyrunner
-Djava.ext.dirs=/home/tux/Android/Sdk/tools/lib:/home/tux/Android/Sdk/tools/lib/x86_64 is not supported. Use -classpath instead.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

At first, we had no idea what that meant, so we used file command on monkeyrunner and we found out that monkeyrunner is a bash script.

$ file monkeyrunner
monkeyrunner: POSIX shell script, ASCII text executable

After reading the code, we read the following at the last lines:

#need to use "java.ext.dirs" because "-jar" causes classpath to be ignored
#might need more memory, e.g. -Xmx128M
exec java -Xmx128M $os_opts $java_debug -Djava.ext.dirs="$frameworkdir:$swtpath" -Djava.library.path="$libdir" -Dcom.android.monkeyrunner.bindir="$progdir" -jar "$jarpath" "[email protected]"

First thing we did was to find the java version that was used, since the command that was giving the problem was that. We found out that we had version 11.

$ java -version
openjdk version "11.0.6" 2020-01-14
OpenJDK Runtime Environment (build 11.0.6+10-post-Ubuntu-1ubuntu118.04.1)
OpenJDK 64-Bit Server VM (build 11.0.6+10-post-Ubuntu-1ubuntu118.04.1, mixed mode, sharing)

After reading a bit, we found out that after Java version 8 the command line directive -Djava.ext.dirs it was deprecated and the recommendation to use -classpath was added. In the past, java.ext.dirs was used to instruct the JRE from where to load additional class and jar files. Since we had Java version 11 we had to try the recommendation to remove the -Djava.ext.dirs directive and use -classpath instead. So, we edited the file monkeyrunner and changed the last line as follows:

exec java -Xmx128M $os_opts $java_debug -classpath "$frameworkdir/*:$swtpath" -Djava.library.path="$libdir" -Dcom.android.monkeyrunner.bindir="$progdir" -jar "$jarpath" "[email protected]"

We tried executing the newly updated monkeyrunner again, only to hit another wall!

$ ./monkeyrunner
Exception in thread "main" java.lang.NoClassDefFoundError: com/android/chimpchat/ChimpChat
at com.android.monkeyrunner.MonkeyRunnerStarter.(MonkeyRunnerStarter.java:60)
at com.android.monkeyrunner.MonkeyRunnerStarter.main(MonkeyRunnerStarter.java:188)
Caused by: java.lang.ClassNotFoundException: com.android.chimpchat.ChimpChat
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
… 2 more

It turns out that when you use the -jar directive, JRE will ignore the -classpath directive and so it will again not be able to load any external class or jar files…

Solution

Instead of reinventing the wheel (We tried, we failed, it was painful. Still worth the shot!) we decided to install Java version 8 on Ubuntu 18.04 LTS side by side with Java version 11 and just used that.

First, we checked the list of installed jvm on our machine using the following command:

update-java-alternatives --list;

Where we got the following:

$ update-java-alternatives --list
java-1.11.0-openjdk-amd64 1111 /usr/lib/jvm/java-1.11.0-openjdk-amd64
java-1.8.0-openjdk-amd64 1081 /usr/lib/jvm/java-1.8.0-openjdk-amd64

It turned out we already had Java version 8 but if we didn’t we would install it as follows:

sudo apt install openjdk-8-jdk;

and then it would again appear in the list mentioned above.

Then, we switched to the Java version 8 using the following command and selecting the appropriate option:

sudo update-alternatives --config java;

$ sudo update-alternatives --config java
[sudo] password for tux:
There are 2 choices for the alternative java (providing /usr/bin/java).
Selection Path Priority Status
0 /usr/lib/jvm/java-11-openjdk-amd64/bin/java 1111 auto mode
1 /usr/lib/jvm/java-11-openjdk-amd64/bin/java 1111 manual mode
2 /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java 1081 manual mode
Press to keep the current choice[*], or type selection number: 2
update-alternatives: using /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java to provide /usr/bin/java (java) in manual mode

After switching Java to Version 8 monkeyrunner was working as expected!!

Advertisements

How to temporarily open MySQL / MariaDB port on CentOS 7 firewall

Recently, we came across a CentOS 7 that was executing MariaDB (MySQL) server. The Database Administrators needed a way to open to the port and allow connections to the SQL server from outside the machine.
As they did not have a specific IP from which they would connect, we provided the following solution.

To temporarily open port 3306

firewall-cmd --add-port=3306/tcp;

To close the port 3306 (method A)

firewall-cmd --remove-port=3306/tcp;

or reload firewalld which will cause it to loose all changes that are not permanent (method B)

firewall-cmd  --reload;

firewalld (Dynamic Firewall Manager) tool provides a dynamically managed firewall. The tool enables network/firewall zones to define the trust level of network connections and/or interfaces. It has support both for IPv4 and IPv6 firewall settings. Also, it supports Ethernet bridges and allow you to separate between runtime and permanent configuration options. Finally, it supports an interface for services or applications to add firewall rules directly.


GNU/Linux: How to give access to a subfolder to a user where the user does not have execute permission over the parent folder

On GNU/Linux, you can traverse a directory if and only if you have execute permission on the whole path that you are going to use to access it. This rule applies a limitation to scenarios where for some reason you want to give execute access to a certain user on a subfolder but you do not want to enable the execute permission on the all the folders in the path.

In order to access the folder theFolder in the path /folderA/folderB/theFolder, if you are on the same level as folderA (or higher) you need to have execute permission both on folderA and folderA/folderB additionally to the permissions needed on theFolder. On another scenario if you are located in the same level as folderB (and you have execute rights to it) even if you do not have the execute rights to folder folderA you would still be able to access theFolder as your whole path (which is a relative path in this scenario) skips folderA. This feature is due to the fact that in GNU/Linux that the path that you use to access a folder determines your access constraints. In cases where the user does not have execute access to the whole path, creating symbolic links for them will not help you give them access. The kernel will still go through the access rights of the whole path that the symlink describes and it will act accordingly.

A hack-ish solution around this issue is to use mount to remount a part of the file hierarchy somewhere else using the bind parameter. For example: if we needed to give access to a user to the folder theFolder that resides in /folderA/folderB/theFolder without enabling execute rights on folderA nor /folderA/folderB we could execute the following command in a folder where that user already has execute access in (for example in the user’s home folder).

sudo mount --bind /folderA/folderB/theFolder finallyTheFolder;

Notes:

  • This solution circumvents security, be sure to think things through before implementing it
  • This solution ‘escapes’ normal good practices so it could lead to software bugs on your behalf
  • The bind will not persist after a reboot
  • To make this change permanent, you will need to add a configuration line in /etc/fstab
  • If the directory that you wish to bind contains mounted file systems, these file systems will not be transferred to the target. The mount points will appear as empty directories.

Compiling DJI Onboard-SDK: error: ‘fd_set’ does not name a type

While compiling the DJI Onboard SDK on a Fedora GNU/Linux we got the following error:

[ 41%] Building CXX object osdk-core/CMakeFiles/djiosdk-core.dir/platform/linux/src/linux_serial_device.cpp.o
In file included from Onboard-SDK/osdk-core/platform/linux/src/linux_serial_device.cpp:33:0:
Onboard-SDK/osdk-core/platform/linux/inc/linux_serial_device.hpp:97:3: error: ‘fd_set’ does not name a type; did you mean ‘tzset’?
 fd_set m_serial_fd_set;
 ^~~~~~
 tzset
In file included from /usr/include/sys/types.h:197:0,
 from /usr/include/stdlib.h:279,
 from /usr/include/c++/7/cstdlib:75,
 from /usr/include/c++/7/bits/stl_algo.h:59,
 from /usr/include/c++/7/algorithm:62,
 from Onboard-SDK/osdk-core/platform/linux/src/linux_serial_device.cpp:34:
Onboard-SDK/osdk-core/platform/linux/src/linux_serial_device.cpp: In member function ‘int DJI::OSDK::LinuxSerialDevice::_serialStart(const char*, int)’:
Onboard-SDK/osdk-core/platform/linux/src/linux_serial_device.cpp:330:14: error: ‘m_serial_fd_set’ was not declared in this scope
 FD_ZERO(&m_serial_fd_set);
 ^
Onboard-SDK/osdk-core/platform/linux/src/linux_serial_device.cpp:330:14: note: suggested alternative: ‘m_serial_fd’
Onboard-SDK/osdk-core/platform/linux/src/linux_serial_device.cpp:331:26: error: ‘m_serial_fd_set’ was not declared in this scope
 FD_SET(m_serial_fd, &m_serial_fd_set);
 ^
Onboard-SDK/osdk-core/platform/linux/src/linux_serial_device.cpp:331:26: note: suggested alternative: ‘m_serial_fd’
make[2]: *** [osdk-core/CMakeFiles/djiosdk-core.dir/build.make:735: osdk-core/CMakeFiles/djiosdk-core.dir/platform/linux/src/linux_serial_device.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:86: osdk-core/CMakeFiles/djiosdk-core.dir/all] Error 2
make: *** [Makefile:130: all] Error 2

To resolve this, we added to the file Onboard-SDK/osdk-core/platform/linux/inc/linux_serial_device.hpp the following include directive right after line 37 (which contained #define LINUXSERIALDEVICE_H):

#include <sys/select.h>

Then, we issued make again which terminated successfully.

Source: https://github.com/dji-sdk/Onboard-SDK

Compilation Commands:

git clone https://github.com/dji-sdk/Onboard-SDK;

cd Onboard-SDK;

mkdir build;

cd build;

cmake ..;

#Modify the file Onboard-SDK/osdk-core/platform/linux/inc/linux_serial_device.hpp and add #include <sys/select.h> at the top

make all;

# Something

# Make profit


Linux on life issues

Why can GNU/Linux users always have love ?

Because they can install it from the repositories!

$ love
 bash: love: command not found...
 Install package 'love' to provide command 'love'? [N/y] y

What is the opinion of your PC on love ?

That is love is not something appropriate!

#When you do not have the love package installed, you will get the following message
$ whatis love
 love: nothing appropriate.