office-gobmx/desktop/unx/source/start.c
Caolán McNamara 36c2ce1344 cid#1608081 silence Overflowed array index write
Change-Id: I40d4207eafe46736a122e07c56f6db94cb517697
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177044
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
2024-11-22 20:34:25 +01:00

888 lines
24 KiB
C

/* -*- 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 <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;
ssize_t n = write(fd, rtl_string_getStr(pOut), nLen);
bResult = (n >= 0 && (size_t) n == nLen);
if ( bResult )
{
char resp[SAL_N_ELEMENTS("InternalIPC::ProcessingDone")];
n = read(fd, resp, SAL_N_ELEMENTS(resp));
bResult = n == 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 */
// coverity[ tainted_data_return : FALSE ] version 2023.12.2
ssize_t nThisRead = read(child_info_get_status_fd(info),
pBuffer + nNotProcessed, BUFFER_LEN - nNotProcessed);
if (nThisRead < 0)
{
if (errno == EINTR)
return ProgressContinue;
return ProgressExit;
}
nRead = nThisRead + 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;
rtl_uString_newFromAscii(&pEnvName, "LD_LIBRARY_PATH");
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';
}
if (newpath[0] != '\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) {
int SigTermSucceded = 0;
oslProcessInfo info;
info.Size = sizeof(oslProcessInfo);
// forward SIGTERM to soffice.bin and give it a chance to semi-gracefully exit
// enough to remove named pipe
if (osl_getProcessInfo(g_pProcess, osl_Process_IDENTIFIER, &info) == osl_Process_E_None) {
TimeValue delay = { 1, 0 }; // 1 sec
SigTermSucceded = kill(info.Ident, SIGTERM) == 0 &&
osl_joinProcessWithTimeout(g_pProcess, &delay) == osl_Process_E_None;
}
// didn't work, SIGKILL instead
if (!SigTermSucceded) {
osl_terminateProcess(g_pProcess); // uses SIGKILL to terminate soffice.bin
osl_joinProcess(g_pProcess);
}
}
_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[27]; // 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: */