Error in function createSettingsDocument (elements.cxx) when using a libreoffice command
When I run the following script as a root user, the powerpoint file converts to a pdf. When I run the following script as a non root user or a user on my web server I get the errors below. When searching for a solution on this issue, I found a lot of references to the solution having to do with a .config file or a .libreoffice file. I don't believe I have these files. I installed libreoffice using apt-get install libreoffice.
This is the .php file I am executing:
exec("libreoffice --headless --invisible --convert-to pdf ./general.pptx 2>&1", $output, $return);
print_r($output);
This is the result for a non root user:
Array
(
[0] => [Java framework] Error in function createSettingsDocument (elements.cxx).
[1] => javaldx failed!
[2] => Warning: failed to read path from javaldx
)
Solution 1:
I solved my issue by adding this:
export HOME=/tmp &&
at the beginning, e.g:
export HOME=/tmp && libreoffice --headless --invisible --convert-to pdf ./general.pptx 2>&1
That worked for me on Ubuntu 16.04, and as shell_exec()
in PHP
Solution 2:
After some googling and checking source code I can explain what is the root cause of locking subsequent libreoffice instances, running from the same user account. First of all it looks like intentional behavior since all running instances share the same cache and config dirs and could smash it when using it in a non-synchronized way. All running instances when started synchronize with each other via /tmp/OSL_blabla unix socket. Here are related bug reports where this socket file is mentioned ( https://bugzilla.redhat.com/show_bug.cgi?id=666603 https://bz.apache.org/ooo/show_bug.cgi?id=55154 ).
You can look closer into source code to see how the name of the socket file is determined and how instances are synchronized: https://code.woboq.org/libreoffice/libreoffice/desktop/unx/source/start.c.html#get_pipe_path and https://code.woboq.org/libreoffice/libreoffice/desktop/unx/source/start.c.html#connect_pipe
Getting pipe name is quite complex. They first detect 'bootstraprc' file name, open it and read variable 'UserInstallation' from there (https://wiki.openoffice.org/wiki/Bootstraprc). bootstraprc location is distribution specific, in my case (OracleLinux 7.5) it is here "/usr/lib64/libreoffice/program/bootstraprc":
[ErrorReport]
ErrorReportPort=80
ErrorReportServer=report.libreoffice.org
[Bootstrap]
InstallMode=<installmode>
ProductKey=LibreOffice 5.3
UserInstallation=$SYSUSERCONFIG/libreoffice/4
In Linux $SYSUSERCONFIG is a "$HOME/.config". Then they get 'md5' sum from config file path location and use it to determine socket location. So config file location maps to socket name. You should only change config dir path for multiple instances so they would not lock. BUT config dir is not the only place where you could get lock or data smash. There are other libs (like libGL) that use shared cache ($HOME/.cache/mesa)
You can check which libs try to read which environment variable with 'ltrace':
ltrace -e getenv -f sh -c "libreoffice --headless --convert-to pdf ./general.pptx"
You can see that all libs dependent on 'HOME' dir, so it's easier to change it before running multiple instances. Just make it unique for each run (and not '/tmp' for all, which limits us to run only 2 concurrent converters but not more).
I would advice to make temp path each time you need to convert and remove it just after conversion, which can be done with simple wrapper '/usr/bin/libreoffice_run_many':
#!/bin/sh
dir=`mktemp -d`
if [ -d $dir ]; then
HOME=$dir
export HOME
libreoffice $@
rm -Rf $dir
fi
Then just call wrapper instead of 'libreoffice':
exec("/usr/bin/libreoffice_run_many --headless --invisible --convert-to pdf ./general.pptx 2>&1", $output, $return);
print_r($output);