summaryrefslogtreecommitdiffstats
path: root/desktop/unx/source/start.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--desktop/unx/source/start.c873
1 files changed, 873 insertions, 0 deletions
diff --git a/desktop/unx/source/start.c b/desktop/unx/source/start.c
new file mode 100644
index 000000000..e3e5441bf
--- /dev/null
+++ b/desktop/unx/source/start.c
@@ -0,0 +1,873 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <config_java.h>
+
+#include <signal.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <string.h>
+#include <errno.h>
+
+#include <desktop/exithelper.h>
+#include <osl/process.h>
+#include <osl/thread.h>
+#include <rtl/bootstrap.h>
+#include <rtl/digest.h>
+#include <rtl/process.h>
+#include <rtl/ustrbuf.h>
+#include <sal/main.h>
+
+#include "args.h"
+#include "pagein.h"
+#include "splashx.h"
+
+#define PIPEDEFAULTPATH "/tmp"
+#define PIPEALTERNATEPATH "/var/tmp"
+
+/* Easier conversions: rtl_uString to rtl_String */
+static rtl_String *ustr_to_str(rtl_uString *pStr)
+{
+ rtl_String *pOut = NULL;
+
+ rtl_uString2String(&pOut, rtl_uString_getStr(pStr),
+ rtl_uString_getLength(pStr), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS);
+
+ return pOut;
+}
+
+/* Easier conversions: char * to rtl_uString */
+static rtl_uString *charp_to_ustr(const char *pStr)
+{
+ rtl_uString *pOut = NULL;
+
+ rtl_string2UString(&pOut, pStr, strlen(pStr), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS);
+
+ return pOut;
+}
+
+typedef struct {
+ int status_fd;
+ oslProcess child;
+} ChildInfo;
+
+static int
+child_info_get_status_fd(ChildInfo const *info)
+{
+ return info->status_fd;
+}
+
+static void
+child_info_destroy(ChildInfo *info)
+{
+ close (info->status_fd);
+ osl_freeProcessHandle (info->child);
+ free (info);
+}
+
+static ChildInfo * child_spawn(Args *args, sal_Bool bAllArgs, sal_Bool bWithStatus)
+{
+ rtl_uString *pApp = NULL, *pTmp = NULL;
+ rtl_uString **ppArgs;
+ sal_uInt32 nArgs, i;
+ ChildInfo *info;
+ int status_pipe[2];
+ oslProcessError nError;
+
+ info = calloc (1, sizeof (ChildInfo));
+
+ /* create pipe */
+ if (pipe(status_pipe) < 0)
+ {
+ fprintf(stderr, "ERROR: no file handles\n");
+ exit(1);
+ }
+ info->status_fd = status_pipe[0];
+
+ /* application name */
+ rtl_uString_newFromAscii(&pApp, "file://");
+ rtl_uString_newConcat(&pApp, pApp, args->pAppPath);
+ rtl_uString_newFromAscii(&pTmp, "soffice.bin");
+ rtl_uString_newConcat(&pApp, pApp, pTmp);
+ rtl_uString_release(pTmp);
+ pTmp = NULL;
+
+ /* copy args */
+ nArgs = bAllArgs ? args->nArgsTotal : args->nArgsEnv;
+ ppArgs = (rtl_uString **)calloc(nArgs + 1, sizeof(rtl_uString*));
+ for (i = 0; i < nArgs; ++i)
+ ppArgs[i] = args->ppArgs[i];
+
+ if(bWithStatus)
+ {
+ char buffer[64];
+
+ /* add the pipe arg */
+ snprintf(buffer, 63, "--splash-pipe=%d", status_pipe[1]);
+ rtl_uString_newFromAscii( &pTmp, buffer );
+ ppArgs[nArgs] = pTmp;
+ ++nArgs;
+ }
+
+ /* start the main process */
+ nError = osl_executeProcess(pApp, ppArgs, nArgs,
+ osl_Process_NORMAL,
+ NULL,
+ NULL,
+ NULL, 0,
+ &info->child );
+
+ if (pTmp)
+ rtl_uString_release(pTmp);
+ free (ppArgs);
+
+ if (nError != osl_Process_E_None)
+ {
+ fprintf(stderr, "ERROR %d forking process\n", nError);
+ rtl_uString_release(pApp);
+ _exit (1);
+ }
+
+ rtl_uString_release(pApp);
+ close( status_pipe[1] );
+
+ return info;
+}
+
+static sal_Bool child_exited_wait(ChildInfo *info, sal_Bool bShortWait)
+{
+ TimeValue t = { 0, 250 /* ms */ * 1000 * 1000 };
+ if (!bShortWait)
+ t.Seconds = 1024;
+
+ return osl_joinProcessWithTimeout(info->child, &t) != osl_Process_E_TimedOut;
+}
+
+static int child_get_exit_code(ChildInfo *info)
+{
+ oslProcessInfo inf;
+
+ inf.Code = -1;
+ inf.Size = sizeof(inf);
+
+ if (osl_getProcessInfo(info->child, osl_Process_EXITCODE, &inf) != osl_Process_E_None)
+ {
+ fprintf(stderr, "Warning: failed to fetch libreoffice exit status\n");
+ return -1;
+ }
+
+ return inf.Code;
+}
+
+typedef enum { ProgressContinue, ProgressRestart, ProgressExit } ProgressStatus;
+
+/* Path of the application, with trailing slash. */
+static rtl_uString *get_app_path(const char *pAppExec)
+{
+ char pRealPath[PATH_MAX];
+ rtl_uString *pResult;
+ sal_Int32 len;
+ char* dummy;
+
+ char *pOrigPath = strdup(pAppExec);
+ char *pPath = dirname(pOrigPath);
+
+ dummy = realpath(pPath, pRealPath);
+ (void)dummy;
+ pResult = charp_to_ustr(pRealPath);
+ free(pOrigPath);
+
+ len = rtl_uString_getLength(pResult);
+ if (len > 0 && rtl_uString_getStr(pResult)[len - 1] != '/')
+ {
+ rtl_uString *pSlash = NULL;
+ rtl_uString_newFromAscii(&pSlash, "/");
+ rtl_uString_newConcat(&pResult, pResult, pSlash);
+ rtl_uString_release(pSlash);
+ }
+
+ return pResult;
+}
+
+/* Compute the OOo md5 hash from 'pText' */
+static rtl_uString *get_md5hash(rtl_uString *pText)
+{
+ rtl_uString *pResult = NULL;
+ sal_Int32 nCapacity = 100;
+ unsigned char *pData = NULL;
+ sal_uInt32 nSize = 0;
+ rtlDigest digest;
+ sal_uInt32 md5_key_len = 0;
+ sal_uInt8* md5_buf = NULL;
+ sal_uInt32 i = 0;
+
+ if ( !pText )
+ return NULL;
+
+ pData = (unsigned char *)rtl_uString_getStr(pText);
+ nSize = rtl_uString_getLength(pText) * sizeof(sal_Unicode);
+ if (!pData)
+ return NULL;
+
+ digest = rtl_digest_create(rtl_Digest_AlgorithmMD5);
+ if (!digest)
+ return NULL;
+
+ md5_key_len = rtl_digest_queryLength(digest);
+ md5_buf = (sal_uInt8 *)calloc(md5_key_len, sizeof(sal_uInt8));
+
+ rtl_digest_init(digest, pData , nSize);
+ rtl_digest_update(digest, pData, nSize);
+ rtl_digest_get(digest, md5_buf, md5_key_len);
+ rtl_digest_destroy(digest);
+
+ /* create hex-value string from the MD5 value to keep
+ the string size minimal */
+ rtl_uString_new_WithLength(&pResult, nCapacity);
+ for (; i < md5_key_len; ++i)
+ {
+ char val[3];
+ snprintf(val, 3, "%x", md5_buf[i]); /* sic! we ignore some of the 0's */
+
+ rtl_uStringbuffer_insert_ascii(&pResult, &nCapacity, rtl_uString_getLength(pResult),
+ val, strlen(val));
+ }
+
+ /* cleanup */
+ free(md5_buf);
+
+ return pResult;
+}
+
+/* Construct the pipe name */
+static rtl_uString *get_pipe_path(rtl_uString *pAppPath)
+{
+ rtl_uString *pPath = NULL, *pTmp = NULL, *pUserInstallation = NULL;
+ rtl_uString *pResult = NULL, *pBasePath = NULL, *pAbsUserInstallation = NULL;
+ rtlBootstrapHandle handle;
+ rtl_uString *pMd5hash = NULL;
+ sal_Unicode pUnicode[RTL_USTR_MAX_VALUEOFINT32];
+
+ /* setup bootstrap filename */
+ rtl_uString_newFromAscii(&pPath, "file://");
+ rtl_uString_newConcat(&pPath, pPath, pAppPath);
+ rtl_uString_newConcat(&pPath, pPath, pTmp);
+ rtl_uString_newFromAscii(&pTmp, SAL_CONFIGFILE("bootstrap"));
+ rtl_uString_newConcat(&pPath, pPath, pTmp);
+
+ /* read userinstallation value */
+ handle = rtl_bootstrap_args_open(pPath);
+
+ rtl_uString_newFromAscii(&pTmp, "UserInstallation");
+ rtl_bootstrap_get_from_handle(handle, pTmp, &pUserInstallation, NULL);
+
+ rtl_bootstrap_args_close(handle);
+
+ /* turn it into an absolute path - unwinding symlinks etc. */
+ if (osl_getProcessWorkingDir(&pBasePath) ||
+ osl_getAbsoluteFileURL(pBasePath, pUserInstallation, &pAbsUserInstallation))
+ rtl_uString_newFromString(&pAbsUserInstallation, pUserInstallation);
+
+ /* create the pipe name */
+ pMd5hash = get_md5hash(pAbsUserInstallation);
+ if (!pMd5hash)
+ rtl_uString_new(&pMd5hash);
+
+ if (access(PIPEDEFAULTPATH, W_OK) == 0)
+ {
+ rtl_uString_newFromAscii(&pResult, PIPEDEFAULTPATH);
+ }
+ else if (access(PIPEALTERNATEPATH, W_OK) == 0)
+ {
+ rtl_uString_newFromAscii(&pResult, PIPEALTERNATEPATH);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: no valid pipe path found.\n");
+ exit(1);
+ }
+
+ rtl_uString_newFromAscii(&pTmp, "/OSL_PIPE_");
+ rtl_uString_newConcat(&pResult, pResult, pTmp);
+
+ rtl_ustr_valueOfInt32(pUnicode, (int)getuid(), 10);
+ rtl_uString_newFromStr(&pTmp, pUnicode);
+ rtl_uString_newConcat(&pResult, pResult, pTmp);
+
+ rtl_uString_newFromAscii(&pTmp, "_SingleOfficeIPC_");
+ rtl_uString_newConcat(&pResult, pResult, pTmp);
+
+ rtl_uString_newConcat(&pResult, pResult, pMd5hash);
+
+ /* cleanup */
+ rtl_uString_release(pMd5hash);
+ rtl_uString_release(pPath);
+ rtl_uString_release(pTmp);
+
+ if (pBasePath)
+ rtl_uString_release(pBasePath);
+
+ rtl_uString_release(pUserInstallation);
+ rtl_uString_release(pAbsUserInstallation);
+
+ return pResult;
+}
+
+/* Get fd of the pipe of the already running OOo. */
+static int connect_pipe(rtl_uString *pPipePath)
+{
+ int fd;
+ size_t len;
+ struct sockaddr_un addr;
+
+ rtl_String *pPipeStr = ustr_to_str(pPipePath);
+
+ memset(&addr, 0, sizeof(addr));
+
+ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ return fd;
+
+ (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, rtl_string_getStr(pPipeStr), sizeof(addr.sun_path) - 1);
+ rtl_string_release(pPipeStr);
+
+/* cut / paste from osl's pipe.c */
+#if defined(FREEBSD)
+ len = SUN_LEN(&addr);
+#else
+ len = sizeof(addr);
+#endif
+
+ if (connect(fd, (struct sockaddr *)&addr, len) < 0)
+ {
+ close(fd);
+ fd = -1;
+ }
+ return fd;
+}
+
+/* Escape: "," -> "\\,", "\0" -> "\\0", "\\" -> "\\\\" */
+static rtl_uString *escape_path(rtl_uString const *pToEscape)
+{
+ rtl_uString *pBuffer = NULL;
+ sal_Int32 nCapacity = 1000;
+ sal_Int32 i = 0;
+ sal_Int32 nEscapeLength = rtl_uString_getLength(pToEscape);
+
+ rtl_uString_new_WithLength(&pBuffer, nCapacity);
+
+ for (; i < nEscapeLength; ++i)
+ {
+ sal_Unicode c = pToEscape->buffer[i];
+ switch (c)
+ {
+ case '\0':
+ rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ RTL_CONSTASCII_STRINGPARAM("\\0"));
+ break;
+ case ',':
+ rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ RTL_CONSTASCII_STRINGPARAM("\\,"));
+ break;
+ case '\\':
+ rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ RTL_CONSTASCII_STRINGPARAM("\\\\"));
+ break;
+ default:
+ rtl_uStringbuffer_insert(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ &c, 1);
+ }
+ }
+
+ return pBuffer;
+}
+
+/* Send args to the LO instance (using the 'fd' file descriptor) */
+static sal_Bool send_args(int fd, rtl_uString const *pCwdPath)
+{
+ rtl_uString *pBuffer = NULL, *pTmp = NULL;
+ sal_Int32 nCapacity = 1000;
+ rtl_String *pOut = NULL;
+ sal_Bool bResult;
+ size_t nLen;
+ rtl_uString *pEscapedCwdPath = escape_path(pCwdPath);
+ sal_uInt32 nArg = 0;
+ sal_uInt32 nArgCount = rtl_getAppCommandArgCount();
+
+ rtl_uString_new_WithLength(&pBuffer, nCapacity);
+ rtl_uString_new(&pTmp);
+
+ rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ RTL_CONSTASCII_STRINGPARAM("InternalIPC::Arguments"));
+
+ if (rtl_uString_getLength(pEscapedCwdPath))
+ {
+ rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ RTL_CONSTASCII_STRINGPARAM("1"));
+
+ rtl_uStringbuffer_insert(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ rtl_uString_getStr(pEscapedCwdPath),
+ rtl_uString_getLength(pEscapedCwdPath));
+ }
+ else
+ {
+ rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ RTL_CONSTASCII_STRINGPARAM("0"));
+ }
+
+ for (nArg = 0; nArg < nArgCount; ++nArg)
+ {
+ rtl_uString *pEscapedTmp = NULL;
+ rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ ",", 1);
+
+ rtl_getAppCommandArg(nArg, &pTmp);
+
+ pEscapedTmp = escape_path(pTmp);
+
+ rtl_uStringbuffer_insert(&pBuffer, &nCapacity,
+ rtl_uString_getLength(pBuffer),
+ rtl_uString_getStr(pEscapedTmp),
+ rtl_uString_getLength(pEscapedTmp));
+
+ rtl_uString_release(pEscapedTmp);
+ }
+
+ if (!rtl_convertUStringToString(
+ &pOut, rtl_uString_getStr(pBuffer),
+ rtl_uString_getLength(pBuffer), RTL_TEXTENCODING_UTF8,
+ (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+ | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
+ {
+ fprintf(stderr, "ERROR: cannot convert arguments to UTF-8\n");
+ exit(1);
+ }
+
+ nLen = rtl_string_getLength(pOut) + 1;
+ bResult = (write(fd, rtl_string_getStr(pOut), nLen) == (ssize_t) nLen);
+
+ if ( bResult )
+ {
+ char resp[SAL_N_ELEMENTS("InternalIPC::ProcessingDone")];
+ ssize_t n = read(fd, resp, SAL_N_ELEMENTS(resp));
+ bResult = n == (ssize_t) SAL_N_ELEMENTS(resp)
+ && (memcmp(
+ resp, "InternalIPC::ProcessingDone",
+ SAL_N_ELEMENTS(resp))
+ == 0);
+ }
+
+ /* cleanup */
+ rtl_uString_release(pEscapedCwdPath);
+ rtl_uString_release(pBuffer);
+ rtl_uString_release(pTmp);
+ rtl_string_release(pOut);
+
+ return bResult;
+}
+
+
+#define BUFFER_LEN 255
+
+/* Read the percent to show in splash. */
+static ProgressStatus read_percent(ChildInfo const *info, int *pPercent)
+{
+ static char pBuffer[BUFFER_LEN + 1];
+ static char *pNext = pBuffer;
+ static ssize_t nRead = 0;
+
+ char *pBegin;
+ char *pIter;
+ char c;
+
+ /* from the last call */
+ int nNotProcessed = nRead - (pNext - pBuffer);
+ if (nNotProcessed >= BUFFER_LEN)
+ return ProgressContinue;
+
+ memmove(pBuffer, pNext, nNotProcessed);
+
+ /* read data */
+ nRead = read(child_info_get_status_fd(info),
+ pBuffer + nNotProcessed, BUFFER_LEN - nNotProcessed);
+
+ if (nRead < 0)
+ {
+ if (errno == EINTR)
+ return ProgressContinue;
+
+ return ProgressExit;
+ }
+
+ nRead += nNotProcessed;
+ pBuffer[nRead] = '\0';
+
+ /* skip old data */
+ pBegin = pBuffer;
+ pNext = pBuffer;
+ for (pIter = pBuffer; *pIter; ++pIter)
+ {
+ if (*pIter == '\n')
+ {
+ pBegin = pNext;
+ pNext = pIter + 1;
+ }
+ }
+
+ if (!strncasecmp(pBegin, "end", 3))
+ return ProgressExit;
+ else if (!strncasecmp(pBegin, "restart", 7))
+ return ProgressRestart;
+ else if (sscanf(pBegin, "%d%c", pPercent, &c) == 2 && c == '%')
+ return ProgressContinue;
+
+ /* unexpected - let's exit the splash to be safe */
+ return ProgressExit;
+}
+
+/* Simple system check. */
+static void system_checks(void)
+{
+#ifdef LINUX
+ struct stat buf;
+
+ /* check proc is mounted - lots of things fail otherwise */
+ if (stat("/proc/version", &buf) != 0)
+ {
+ fprintf(stderr, "ERROR: /proc not mounted - LibreOffice is unlikely to work well if at all\n");
+ exit(1);
+ }
+#endif
+}
+
+static void exec_pagein (Args *args)
+{
+ rtl_String * path = ustr_to_str(args->pAppPath);
+ pagein_execute(rtl_string_getStr(path), "pagein-common");
+
+ if (args->pPageinType)
+ pagein_execute(rtl_string_getStr(path), args->pPageinType);
+
+ rtl_string_release(path);
+}
+
+#if HAVE_FEATURE_JAVA
+
+static void extend_library_path(const char *new_element)
+{
+ rtl_uString *pEnvName=NULL, *pOrigEnvVar=NULL, *pNewEnvVar=NULL;
+ const char *pathname;
+#ifdef AIX
+ pathname = "LIBPATH";
+#else
+ pathname = "LD_LIBRARY_PATH";
+#endif
+
+ rtl_uString_newFromAscii(&pEnvName, pathname);
+ rtl_uString_newFromAscii(&pNewEnvVar, new_element);
+
+ osl_getEnvironment(pEnvName, &pOrigEnvVar);
+ if (pOrigEnvVar && pOrigEnvVar->length)
+ {
+ rtl_uString *pDelim = NULL;
+ rtl_uString_newFromAscii(&pDelim, ":");
+ rtl_uString_newConcat(&pNewEnvVar, pNewEnvVar, pDelim);
+ rtl_uString_newConcat(&pNewEnvVar, pNewEnvVar, pOrigEnvVar);
+ rtl_uString_release(pDelim);
+ }
+
+ osl_setEnvironment(pEnvName, pNewEnvVar);
+
+ if (pOrigEnvVar)
+ rtl_uString_release(pOrigEnvVar);
+
+ rtl_uString_release(pNewEnvVar);
+ rtl_uString_release(pEnvName);
+}
+
+static void exec_javaldx(Args *args)
+{
+ char newpath[4096];
+ sal_uInt32 nArgs;
+ rtl_uString *pApp;
+ rtl_uString **ppArgs;
+ rtl_uString *pTmp, *pTmp2;
+
+ oslProcess javaldx = NULL;
+ oslFileHandle fileOut = NULL;
+ oslProcessError err;
+
+ ppArgs = (rtl_uString **)calloc(args->nArgsEnv + 2, sizeof(rtl_uString*));
+
+ for (nArgs = 0; nArgs < args->nArgsEnv; ++nArgs)
+ ppArgs[nArgs] = args->ppArgs[nArgs];
+
+ /* Use absolute path to redirectrc */
+ pTmp = NULL;
+ rtl_uString_newFromAscii(&pTmp, "-env:INIFILENAME=vnd.sun.star.pathname:");
+ rtl_uString_newConcat(&pTmp, pTmp, args->pAppPath);
+ pTmp2 = NULL;
+ rtl_uString_newFromAscii(&pTmp2, "redirectrc");
+ rtl_uString_newConcat(&pTmp, pTmp, pTmp2);
+ ppArgs[nArgs] = pTmp;
+ rtl_uString_release (pTmp2);
+ nArgs++;
+
+ /* And also to javaldx */
+ pApp = NULL;
+ rtl_uString_newFromAscii(&pApp, "file://");
+ rtl_uString_newConcat(&pApp, pApp, args->pAppPath);
+ pTmp = NULL;
+ rtl_uString_newFromAscii(&pTmp, "javaldx");
+ rtl_uString_newConcat(&pApp, pApp, pTmp);
+ rtl_uString_release(pTmp);
+
+ err = osl_executeProcess_WithRedirectedIO(pApp, ppArgs, nArgs,
+ osl_Process_NORMAL,
+ NULL, // security
+ NULL, // work dir
+ NULL, 0,
+ &javaldx, // process handle
+ NULL,
+ &fileOut,
+ NULL);
+
+ rtl_uString_release(ppArgs[nArgs-1]);
+ rtl_uString_release(pApp);
+ free(ppArgs);
+
+ if(err != osl_Process_E_None)
+ {
+ fprintf (stderr, "Warning: failed to launch javaldx - java may not function correctly\n");
+
+ if (javaldx)
+ osl_freeProcessHandle(javaldx);
+ if (fileOut)
+ osl_closeFile(fileOut);
+ return;
+ }
+ else
+ {
+ char *chomp;
+ sal_uInt64 bytes_read;
+
+ /* Magically osl_readLine doesn't work with pipes with E_SPIPE - so be this lame instead: */
+ while (osl_readFile (fileOut, newpath, SAL_N_ELEMENTS (newpath), &bytes_read) == osl_File_E_INTR);
+
+ if (bytes_read <= 0)
+ {
+ fprintf (stderr, "Warning: failed to read path from javaldx\n");
+
+ if (javaldx)
+ osl_freeProcessHandle(javaldx);
+
+ if (fileOut)
+ osl_closeFile(fileOut);
+
+ return;
+ }
+
+ newpath[bytes_read] = '\0';
+
+ if ((chomp = strstr (newpath, "\n")))
+ *chomp = '\0';
+ }
+
+ extend_library_path(newpath);
+
+ if (javaldx)
+ osl_freeProcessHandle(javaldx);
+
+ if (fileOut)
+ osl_closeFile(fileOut);
+}
+
+#endif
+
+// has to be a global :(
+static oslProcess * volatile g_pProcess = NULL;
+
+static void sigterm_handler(int ignored)
+{
+ (void) ignored;
+
+ if (g_pProcess)
+ osl_terminateProcess(g_pProcess); // forward signal to soffice.bin
+
+ _exit(255);
+}
+
+
+SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
+{
+ sal_Bool bSentArgs = sal_False;
+ const char* pUsePlugin;
+ rtl_uString *pPipePath = NULL;
+ Args *args;
+ int status = 0;
+ struct splash* splash = NULL;
+ struct sigaction sigpipe_action;
+ struct sigaction sigterm_action;
+
+ /* turn SIGPIPE into an error */
+ memset(&sigpipe_action, 0, sizeof(struct sigaction));
+ sigpipe_action.sa_handler = SIG_IGN;
+ sigemptyset(&sigpipe_action.sa_mask);
+ sigaction(SIGPIPE, &sigpipe_action, NULL);
+ memset(&sigterm_action, 0, sizeof(struct sigaction));
+ sigterm_action.sa_handler = &sigterm_handler;
+ sigemptyset(&sigterm_action.sa_mask);
+ sigaction(SIGTERM, &sigterm_action, NULL);
+
+ args = args_parse();
+ args->pAppPath = get_app_path(argv[0]);
+ if (!args->pAppPath)
+ {
+ fprintf(stderr, "ERROR: Can't read app link\n");
+ exit(1);
+ }
+
+#ifndef ENABLE_QUICKSTART_LIBPNG
+ /* we can't load and render it anyway */
+ args->bInhibitSplash = sal_True;
+#endif
+
+ pUsePlugin = getenv("SAL_USE_VCLPLUGIN");
+ if (pUsePlugin && !strcmp(pUsePlugin, "svp"))
+ args->bInhibitSplash = sal_True;
+
+ if (!args->bInhibitPipe && !getenv("LIBO_FLATPAK"))
+ {
+ int fd = 0;
+ pPipePath = get_pipe_path(args->pAppPath);
+
+ if ((fd=connect_pipe(pPipePath)) >= 0)
+ {
+ // Wait for answer
+ char resp[strlen("InternalIPC::SendArguments") + 1];
+ ssize_t n = read(fd, resp, SAL_N_ELEMENTS(resp));
+ if (n == (ssize_t) SAL_N_ELEMENTS(resp) &&
+ (memcmp(resp, "InternalIPC::SendArguments",
+ SAL_N_ELEMENTS(resp) - 1) == 0))
+ {
+ rtl_uString *pCwdPath = NULL;
+ osl_getProcessWorkingDir(&pCwdPath);
+
+ // Then send args
+ bSentArgs = send_args(fd, pCwdPath);
+ }
+
+ close(fd);
+ }
+ }
+
+ if (!bSentArgs)
+ {
+ /* we have to prepare for, and exec the binary */
+ int nPercent = 0;
+ ChildInfo *info;
+ sal_Bool bAllArgs = sal_True;
+ sal_Bool bShortWait, bRestart;
+
+ /* sanity check pieces */
+ system_checks();
+
+ /* load splash image and create window */
+ if (!args->bInhibitSplash)
+ splash = splash_create(args->pAppPath, argc, argv);
+
+ /* pagein */
+ if (!args->bInhibitPagein)
+ exec_pagein(args);
+
+ /* javaldx */
+#if HAVE_FEATURE_JAVA
+ if (!args->bInhibitJavaLdx)
+ exec_javaldx (args);
+#endif
+
+ do
+ {
+ bRestart = sal_False;
+
+ /* fast updates if we have somewhere to update it to */
+ bShortWait = splash ? sal_True : sal_False;
+
+ /* Periodically update the splash & the percent according
+ to what status_fd says, poll quickly only while starting */
+ info = child_spawn (args, bAllArgs, bShortWait);
+ g_pProcess = info->child;
+
+ while (!child_exited_wait(info, bShortWait))
+ {
+ ProgressStatus eResult;
+
+ splash_draw_progress(splash, nPercent);
+ eResult = read_percent(info, &nPercent);
+
+ if (eResult != ProgressContinue)
+ {
+ splash_destroy(splash);
+ splash = NULL;
+ bShortWait = sal_False;
+ }
+ }
+
+ status = child_get_exit_code(info);
+ g_pProcess = NULL; // reset
+
+ switch (status)
+ {
+ case EXITHELPER_CRASH_WITH_RESTART: // re-start with just -env: parameters
+ bRestart = sal_True;
+ bAllArgs = sal_False;
+ break;
+ case EXITHELPER_NORMAL_RESTART: // re-start with all arguments
+ bRestart = sal_True;
+ bAllArgs = sal_True;
+ break;
+ default:
+ break;
+ }
+
+ child_info_destroy(info);
+ } while (bRestart);
+ }
+
+ /* cleanup */
+ if (pPipePath)
+ rtl_uString_release(pPipePath);
+
+ args_free(args);
+
+ return status;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */