Bump version to 6.4-15
[LibreOffice.git] / desktop / unx / source / start.c
blobe3e5441bf97e9af94d8d00dfa1f8844e95ed6391
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <config_java.h>
12 #include <signal.h>
13 #include <unistd.h>
14 #include <limits.h>
15 #include <stdlib.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <sys/socket.h>
19 #include <arpa/inet.h>
20 #include <sys/un.h>
21 #include <sys/poll.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <libgen.h>
25 #include <string.h>
26 #include <errno.h>
28 #include <desktop/exithelper.h>
29 #include <osl/process.h>
30 #include <osl/thread.h>
31 #include <rtl/bootstrap.h>
32 #include <rtl/digest.h>
33 #include <rtl/process.h>
34 #include <rtl/ustrbuf.h>
35 #include <sal/main.h>
37 #include "args.h"
38 #include "pagein.h"
39 #include "splashx.h"
41 #define PIPEDEFAULTPATH "/tmp"
42 #define PIPEALTERNATEPATH "/var/tmp"
44 /* Easier conversions: rtl_uString to rtl_String */
45 static rtl_String *ustr_to_str(rtl_uString *pStr)
47 rtl_String *pOut = NULL;
49 rtl_uString2String(&pOut, rtl_uString_getStr(pStr),
50 rtl_uString_getLength(pStr), osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS);
52 return pOut;
55 /* Easier conversions: char * to rtl_uString */
56 static rtl_uString *charp_to_ustr(const char *pStr)
58 rtl_uString *pOut = NULL;
60 rtl_string2UString(&pOut, pStr, strlen(pStr), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS);
62 return pOut;
65 typedef struct {
66 int status_fd;
67 oslProcess child;
68 } ChildInfo;
70 static int
71 child_info_get_status_fd(ChildInfo const *info)
73 return info->status_fd;
76 static void
77 child_info_destroy(ChildInfo *info)
79 close (info->status_fd);
80 osl_freeProcessHandle (info->child);
81 free (info);
84 static ChildInfo * child_spawn(Args *args, sal_Bool bAllArgs, sal_Bool bWithStatus)
86 rtl_uString *pApp = NULL, *pTmp = NULL;
87 rtl_uString **ppArgs;
88 sal_uInt32 nArgs, i;
89 ChildInfo *info;
90 int status_pipe[2];
91 oslProcessError nError;
93 info = calloc (1, sizeof (ChildInfo));
95 /* create pipe */
96 if (pipe(status_pipe) < 0)
98 fprintf(stderr, "ERROR: no file handles\n");
99 exit(1);
101 info->status_fd = status_pipe[0];
103 /* application name */
104 rtl_uString_newFromAscii(&pApp, "file://");
105 rtl_uString_newConcat(&pApp, pApp, args->pAppPath);
106 rtl_uString_newFromAscii(&pTmp, "soffice.bin");
107 rtl_uString_newConcat(&pApp, pApp, pTmp);
108 rtl_uString_release(pTmp);
109 pTmp = NULL;
111 /* copy args */
112 nArgs = bAllArgs ? args->nArgsTotal : args->nArgsEnv;
113 ppArgs = (rtl_uString **)calloc(nArgs + 1, sizeof(rtl_uString*));
114 for (i = 0; i < nArgs; ++i)
115 ppArgs[i] = args->ppArgs[i];
117 if(bWithStatus)
119 char buffer[64];
121 /* add the pipe arg */
122 snprintf(buffer, 63, "--splash-pipe=%d", status_pipe[1]);
123 rtl_uString_newFromAscii( &pTmp, buffer );
124 ppArgs[nArgs] = pTmp;
125 ++nArgs;
128 /* start the main process */
129 nError = osl_executeProcess(pApp, ppArgs, nArgs,
130 osl_Process_NORMAL,
131 NULL,
132 NULL,
133 NULL, 0,
134 &info->child );
136 if (pTmp)
137 rtl_uString_release(pTmp);
138 free (ppArgs);
140 if (nError != osl_Process_E_None)
142 fprintf(stderr, "ERROR %d forking process\n", nError);
143 rtl_uString_release(pApp);
144 _exit (1);
147 rtl_uString_release(pApp);
148 close( status_pipe[1] );
150 return info;
153 static sal_Bool child_exited_wait(ChildInfo *info, sal_Bool bShortWait)
155 TimeValue t = { 0, 250 /* ms */ * 1000 * 1000 };
156 if (!bShortWait)
157 t.Seconds = 1024;
159 return osl_joinProcessWithTimeout(info->child, &t) != osl_Process_E_TimedOut;
162 static int child_get_exit_code(ChildInfo *info)
164 oslProcessInfo inf;
166 inf.Code = -1;
167 inf.Size = sizeof(inf);
169 if (osl_getProcessInfo(info->child, osl_Process_EXITCODE, &inf) != osl_Process_E_None)
171 fprintf(stderr, "Warning: failed to fetch libreoffice exit status\n");
172 return -1;
175 return inf.Code;
178 typedef enum { ProgressContinue, ProgressRestart, ProgressExit } ProgressStatus;
180 /* Path of the application, with trailing slash. */
181 static rtl_uString *get_app_path(const char *pAppExec)
183 char pRealPath[PATH_MAX];
184 rtl_uString *pResult;
185 sal_Int32 len;
186 char* dummy;
188 char *pOrigPath = strdup(pAppExec);
189 char *pPath = dirname(pOrigPath);
191 dummy = realpath(pPath, pRealPath);
192 (void)dummy;
193 pResult = charp_to_ustr(pRealPath);
194 free(pOrigPath);
196 len = rtl_uString_getLength(pResult);
197 if (len > 0 && rtl_uString_getStr(pResult)[len - 1] != '/')
199 rtl_uString *pSlash = NULL;
200 rtl_uString_newFromAscii(&pSlash, "/");
201 rtl_uString_newConcat(&pResult, pResult, pSlash);
202 rtl_uString_release(pSlash);
205 return pResult;
208 /* Compute the OOo md5 hash from 'pText' */
209 static rtl_uString *get_md5hash(rtl_uString *pText)
211 rtl_uString *pResult = NULL;
212 sal_Int32 nCapacity = 100;
213 unsigned char *pData = NULL;
214 sal_uInt32 nSize = 0;
215 rtlDigest digest;
216 sal_uInt32 md5_key_len = 0;
217 sal_uInt8* md5_buf = NULL;
218 sal_uInt32 i = 0;
220 if ( !pText )
221 return NULL;
223 pData = (unsigned char *)rtl_uString_getStr(pText);
224 nSize = rtl_uString_getLength(pText) * sizeof(sal_Unicode);
225 if (!pData)
226 return NULL;
228 digest = rtl_digest_create(rtl_Digest_AlgorithmMD5);
229 if (!digest)
230 return NULL;
232 md5_key_len = rtl_digest_queryLength(digest);
233 md5_buf = (sal_uInt8 *)calloc(md5_key_len, sizeof(sal_uInt8));
235 rtl_digest_init(digest, pData , nSize);
236 rtl_digest_update(digest, pData, nSize);
237 rtl_digest_get(digest, md5_buf, md5_key_len);
238 rtl_digest_destroy(digest);
240 /* create hex-value string from the MD5 value to keep
241 the string size minimal */
242 rtl_uString_new_WithLength(&pResult, nCapacity);
243 for (; i < md5_key_len; ++i)
245 char val[3];
246 snprintf(val, 3, "%x", md5_buf[i]); /* sic! we ignore some of the 0's */
248 rtl_uStringbuffer_insert_ascii(&pResult, &nCapacity, rtl_uString_getLength(pResult),
249 val, strlen(val));
252 /* cleanup */
253 free(md5_buf);
255 return pResult;
258 /* Construct the pipe name */
259 static rtl_uString *get_pipe_path(rtl_uString *pAppPath)
261 rtl_uString *pPath = NULL, *pTmp = NULL, *pUserInstallation = NULL;
262 rtl_uString *pResult = NULL, *pBasePath = NULL, *pAbsUserInstallation = NULL;
263 rtlBootstrapHandle handle;
264 rtl_uString *pMd5hash = NULL;
265 sal_Unicode pUnicode[RTL_USTR_MAX_VALUEOFINT32];
267 /* setup bootstrap filename */
268 rtl_uString_newFromAscii(&pPath, "file://");
269 rtl_uString_newConcat(&pPath, pPath, pAppPath);
270 rtl_uString_newConcat(&pPath, pPath, pTmp);
271 rtl_uString_newFromAscii(&pTmp, SAL_CONFIGFILE("bootstrap"));
272 rtl_uString_newConcat(&pPath, pPath, pTmp);
274 /* read userinstallation value */
275 handle = rtl_bootstrap_args_open(pPath);
277 rtl_uString_newFromAscii(&pTmp, "UserInstallation");
278 rtl_bootstrap_get_from_handle(handle, pTmp, &pUserInstallation, NULL);
280 rtl_bootstrap_args_close(handle);
282 /* turn it into an absolute path - unwinding symlinks etc. */
283 if (osl_getProcessWorkingDir(&pBasePath) ||
284 osl_getAbsoluteFileURL(pBasePath, pUserInstallation, &pAbsUserInstallation))
285 rtl_uString_newFromString(&pAbsUserInstallation, pUserInstallation);
287 /* create the pipe name */
288 pMd5hash = get_md5hash(pAbsUserInstallation);
289 if (!pMd5hash)
290 rtl_uString_new(&pMd5hash);
292 if (access(PIPEDEFAULTPATH, W_OK) == 0)
294 rtl_uString_newFromAscii(&pResult, PIPEDEFAULTPATH);
296 else if (access(PIPEALTERNATEPATH, W_OK) == 0)
298 rtl_uString_newFromAscii(&pResult, PIPEALTERNATEPATH);
300 else
302 fprintf(stderr, "ERROR: no valid pipe path found.\n");
303 exit(1);
306 rtl_uString_newFromAscii(&pTmp, "/OSL_PIPE_");
307 rtl_uString_newConcat(&pResult, pResult, pTmp);
309 rtl_ustr_valueOfInt32(pUnicode, (int)getuid(), 10);
310 rtl_uString_newFromStr(&pTmp, pUnicode);
311 rtl_uString_newConcat(&pResult, pResult, pTmp);
313 rtl_uString_newFromAscii(&pTmp, "_SingleOfficeIPC_");
314 rtl_uString_newConcat(&pResult, pResult, pTmp);
316 rtl_uString_newConcat(&pResult, pResult, pMd5hash);
318 /* cleanup */
319 rtl_uString_release(pMd5hash);
320 rtl_uString_release(pPath);
321 rtl_uString_release(pTmp);
323 if (pBasePath)
324 rtl_uString_release(pBasePath);
326 rtl_uString_release(pUserInstallation);
327 rtl_uString_release(pAbsUserInstallation);
329 return pResult;
332 /* Get fd of the pipe of the already running OOo. */
333 static int connect_pipe(rtl_uString *pPipePath)
335 int fd;
336 size_t len;
337 struct sockaddr_un addr;
339 rtl_String *pPipeStr = ustr_to_str(pPipePath);
341 memset(&addr, 0, sizeof(addr));
343 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
344 return fd;
346 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
348 addr.sun_family = AF_UNIX;
349 strncpy(addr.sun_path, rtl_string_getStr(pPipeStr), sizeof(addr.sun_path) - 1);
350 rtl_string_release(pPipeStr);
352 /* cut / paste from osl's pipe.c */
353 #if defined(FREEBSD)
354 len = SUN_LEN(&addr);
355 #else
356 len = sizeof(addr);
357 #endif
359 if (connect(fd, (struct sockaddr *)&addr, len) < 0)
361 close(fd);
362 fd = -1;
364 return fd;
367 /* Escape: "," -> "\\,", "\0" -> "\\0", "\\" -> "\\\\" */
368 static rtl_uString *escape_path(rtl_uString const *pToEscape)
370 rtl_uString *pBuffer = NULL;
371 sal_Int32 nCapacity = 1000;
372 sal_Int32 i = 0;
373 sal_Int32 nEscapeLength = rtl_uString_getLength(pToEscape);
375 rtl_uString_new_WithLength(&pBuffer, nCapacity);
377 for (; i < nEscapeLength; ++i)
379 sal_Unicode c = pToEscape->buffer[i];
380 switch (c)
382 case '\0':
383 rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
384 rtl_uString_getLength(pBuffer),
385 RTL_CONSTASCII_STRINGPARAM("\\0"));
386 break;
387 case ',':
388 rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
389 rtl_uString_getLength(pBuffer),
390 RTL_CONSTASCII_STRINGPARAM("\\,"));
391 break;
392 case '\\':
393 rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
394 rtl_uString_getLength(pBuffer),
395 RTL_CONSTASCII_STRINGPARAM("\\\\"));
396 break;
397 default:
398 rtl_uStringbuffer_insert(&pBuffer, &nCapacity,
399 rtl_uString_getLength(pBuffer),
400 &c, 1);
404 return pBuffer;
407 /* Send args to the LO instance (using the 'fd' file descriptor) */
408 static sal_Bool send_args(int fd, rtl_uString const *pCwdPath)
410 rtl_uString *pBuffer = NULL, *pTmp = NULL;
411 sal_Int32 nCapacity = 1000;
412 rtl_String *pOut = NULL;
413 sal_Bool bResult;
414 size_t nLen;
415 rtl_uString *pEscapedCwdPath = escape_path(pCwdPath);
416 sal_uInt32 nArg = 0;
417 sal_uInt32 nArgCount = rtl_getAppCommandArgCount();
419 rtl_uString_new_WithLength(&pBuffer, nCapacity);
420 rtl_uString_new(&pTmp);
422 rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
423 rtl_uString_getLength(pBuffer),
424 RTL_CONSTASCII_STRINGPARAM("InternalIPC::Arguments"));
426 if (rtl_uString_getLength(pEscapedCwdPath))
428 rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
429 rtl_uString_getLength(pBuffer),
430 RTL_CONSTASCII_STRINGPARAM("1"));
432 rtl_uStringbuffer_insert(&pBuffer, &nCapacity,
433 rtl_uString_getLength(pBuffer),
434 rtl_uString_getStr(pEscapedCwdPath),
435 rtl_uString_getLength(pEscapedCwdPath));
437 else
439 rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
440 rtl_uString_getLength(pBuffer),
441 RTL_CONSTASCII_STRINGPARAM("0"));
444 for (nArg = 0; nArg < nArgCount; ++nArg)
446 rtl_uString *pEscapedTmp = NULL;
447 rtl_uStringbuffer_insert_ascii(&pBuffer, &nCapacity,
448 rtl_uString_getLength(pBuffer),
449 ",", 1);
451 rtl_getAppCommandArg(nArg, &pTmp);
453 pEscapedTmp = escape_path(pTmp);
455 rtl_uStringbuffer_insert(&pBuffer, &nCapacity,
456 rtl_uString_getLength(pBuffer),
457 rtl_uString_getStr(pEscapedTmp),
458 rtl_uString_getLength(pEscapedTmp));
460 rtl_uString_release(pEscapedTmp);
463 if (!rtl_convertUStringToString(
464 &pOut, rtl_uString_getStr(pBuffer),
465 rtl_uString_getLength(pBuffer), RTL_TEXTENCODING_UTF8,
466 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
467 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
469 fprintf(stderr, "ERROR: cannot convert arguments to UTF-8\n");
470 exit(1);
473 nLen = rtl_string_getLength(pOut) + 1;
474 bResult = (write(fd, rtl_string_getStr(pOut), nLen) == (ssize_t) nLen);
476 if ( bResult )
478 char resp[SAL_N_ELEMENTS("InternalIPC::ProcessingDone")];
479 ssize_t n = read(fd, resp, SAL_N_ELEMENTS(resp));
480 bResult = n == (ssize_t) SAL_N_ELEMENTS(resp)
481 && (memcmp(
482 resp, "InternalIPC::ProcessingDone",
483 SAL_N_ELEMENTS(resp))
484 == 0);
487 /* cleanup */
488 rtl_uString_release(pEscapedCwdPath);
489 rtl_uString_release(pBuffer);
490 rtl_uString_release(pTmp);
491 rtl_string_release(pOut);
493 return bResult;
497 #define BUFFER_LEN 255
499 /* Read the percent to show in splash. */
500 static ProgressStatus read_percent(ChildInfo const *info, int *pPercent)
502 static char pBuffer[BUFFER_LEN + 1];
503 static char *pNext = pBuffer;
504 static ssize_t nRead = 0;
506 char *pBegin;
507 char *pIter;
508 char c;
510 /* from the last call */
511 int nNotProcessed = nRead - (pNext - pBuffer);
512 if (nNotProcessed >= BUFFER_LEN)
513 return ProgressContinue;
515 memmove(pBuffer, pNext, nNotProcessed);
517 /* read data */
518 nRead = read(child_info_get_status_fd(info),
519 pBuffer + nNotProcessed, BUFFER_LEN - nNotProcessed);
521 if (nRead < 0)
523 if (errno == EINTR)
524 return ProgressContinue;
526 return ProgressExit;
529 nRead += nNotProcessed;
530 pBuffer[nRead] = '\0';
532 /* skip old data */
533 pBegin = pBuffer;
534 pNext = pBuffer;
535 for (pIter = pBuffer; *pIter; ++pIter)
537 if (*pIter == '\n')
539 pBegin = pNext;
540 pNext = pIter + 1;
544 if (!strncasecmp(pBegin, "end", 3))
545 return ProgressExit;
546 else if (!strncasecmp(pBegin, "restart", 7))
547 return ProgressRestart;
548 else if (sscanf(pBegin, "%d%c", pPercent, &c) == 2 && c == '%')
549 return ProgressContinue;
551 /* unexpected - let's exit the splash to be safe */
552 return ProgressExit;
555 /* Simple system check. */
556 static void system_checks(void)
558 #ifdef LINUX
559 struct stat buf;
561 /* check proc is mounted - lots of things fail otherwise */
562 if (stat("/proc/version", &buf) != 0)
564 fprintf(stderr, "ERROR: /proc not mounted - LibreOffice is unlikely to work well if at all\n");
565 exit(1);
567 #endif
570 static void exec_pagein (Args *args)
572 rtl_String * path = ustr_to_str(args->pAppPath);
573 pagein_execute(rtl_string_getStr(path), "pagein-common");
575 if (args->pPageinType)
576 pagein_execute(rtl_string_getStr(path), args->pPageinType);
578 rtl_string_release(path);
581 #if HAVE_FEATURE_JAVA
583 static void extend_library_path(const char *new_element)
585 rtl_uString *pEnvName=NULL, *pOrigEnvVar=NULL, *pNewEnvVar=NULL;
586 const char *pathname;
587 #ifdef AIX
588 pathname = "LIBPATH";
589 #else
590 pathname = "LD_LIBRARY_PATH";
591 #endif
593 rtl_uString_newFromAscii(&pEnvName, pathname);
594 rtl_uString_newFromAscii(&pNewEnvVar, new_element);
596 osl_getEnvironment(pEnvName, &pOrigEnvVar);
597 if (pOrigEnvVar && pOrigEnvVar->length)
599 rtl_uString *pDelim = NULL;
600 rtl_uString_newFromAscii(&pDelim, ":");
601 rtl_uString_newConcat(&pNewEnvVar, pNewEnvVar, pDelim);
602 rtl_uString_newConcat(&pNewEnvVar, pNewEnvVar, pOrigEnvVar);
603 rtl_uString_release(pDelim);
606 osl_setEnvironment(pEnvName, pNewEnvVar);
608 if (pOrigEnvVar)
609 rtl_uString_release(pOrigEnvVar);
611 rtl_uString_release(pNewEnvVar);
612 rtl_uString_release(pEnvName);
615 static void exec_javaldx(Args *args)
617 char newpath[4096];
618 sal_uInt32 nArgs;
619 rtl_uString *pApp;
620 rtl_uString **ppArgs;
621 rtl_uString *pTmp, *pTmp2;
623 oslProcess javaldx = NULL;
624 oslFileHandle fileOut = NULL;
625 oslProcessError err;
627 ppArgs = (rtl_uString **)calloc(args->nArgsEnv + 2, sizeof(rtl_uString*));
629 for (nArgs = 0; nArgs < args->nArgsEnv; ++nArgs)
630 ppArgs[nArgs] = args->ppArgs[nArgs];
632 /* Use absolute path to redirectrc */
633 pTmp = NULL;
634 rtl_uString_newFromAscii(&pTmp, "-env:INIFILENAME=vnd.sun.star.pathname:");
635 rtl_uString_newConcat(&pTmp, pTmp, args->pAppPath);
636 pTmp2 = NULL;
637 rtl_uString_newFromAscii(&pTmp2, "redirectrc");
638 rtl_uString_newConcat(&pTmp, pTmp, pTmp2);
639 ppArgs[nArgs] = pTmp;
640 rtl_uString_release (pTmp2);
641 nArgs++;
643 /* And also to javaldx */
644 pApp = NULL;
645 rtl_uString_newFromAscii(&pApp, "file://");
646 rtl_uString_newConcat(&pApp, pApp, args->pAppPath);
647 pTmp = NULL;
648 rtl_uString_newFromAscii(&pTmp, "javaldx");
649 rtl_uString_newConcat(&pApp, pApp, pTmp);
650 rtl_uString_release(pTmp);
652 err = osl_executeProcess_WithRedirectedIO(pApp, ppArgs, nArgs,
653 osl_Process_NORMAL,
654 NULL, // security
655 NULL, // work dir
656 NULL, 0,
657 &javaldx, // process handle
658 NULL,
659 &fileOut,
660 NULL);
662 rtl_uString_release(ppArgs[nArgs-1]);
663 rtl_uString_release(pApp);
664 free(ppArgs);
666 if(err != osl_Process_E_None)
668 fprintf (stderr, "Warning: failed to launch javaldx - java may not function correctly\n");
670 if (javaldx)
671 osl_freeProcessHandle(javaldx);
672 if (fileOut)
673 osl_closeFile(fileOut);
674 return;
676 else
678 char *chomp;
679 sal_uInt64 bytes_read;
681 /* Magically osl_readLine doesn't work with pipes with E_SPIPE - so be this lame instead: */
682 while (osl_readFile (fileOut, newpath, SAL_N_ELEMENTS (newpath), &bytes_read) == osl_File_E_INTR);
684 if (bytes_read <= 0)
686 fprintf (stderr, "Warning: failed to read path from javaldx\n");
688 if (javaldx)
689 osl_freeProcessHandle(javaldx);
691 if (fileOut)
692 osl_closeFile(fileOut);
694 return;
697 newpath[bytes_read] = '\0';
699 if ((chomp = strstr (newpath, "\n")))
700 *chomp = '\0';
703 extend_library_path(newpath);
705 if (javaldx)
706 osl_freeProcessHandle(javaldx);
708 if (fileOut)
709 osl_closeFile(fileOut);
712 #endif
714 // has to be a global :(
715 static oslProcess * volatile g_pProcess = NULL;
717 static void sigterm_handler(int ignored)
719 (void) ignored;
721 if (g_pProcess)
722 osl_terminateProcess(g_pProcess); // forward signal to soffice.bin
724 _exit(255);
728 SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
730 sal_Bool bSentArgs = sal_False;
731 const char* pUsePlugin;
732 rtl_uString *pPipePath = NULL;
733 Args *args;
734 int status = 0;
735 struct splash* splash = NULL;
736 struct sigaction sigpipe_action;
737 struct sigaction sigterm_action;
739 /* turn SIGPIPE into an error */
740 memset(&sigpipe_action, 0, sizeof(struct sigaction));
741 sigpipe_action.sa_handler = SIG_IGN;
742 sigemptyset(&sigpipe_action.sa_mask);
743 sigaction(SIGPIPE, &sigpipe_action, NULL);
744 memset(&sigterm_action, 0, sizeof(struct sigaction));
745 sigterm_action.sa_handler = &sigterm_handler;
746 sigemptyset(&sigterm_action.sa_mask);
747 sigaction(SIGTERM, &sigterm_action, NULL);
749 args = args_parse();
750 args->pAppPath = get_app_path(argv[0]);
751 if (!args->pAppPath)
753 fprintf(stderr, "ERROR: Can't read app link\n");
754 exit(1);
757 #ifndef ENABLE_QUICKSTART_LIBPNG
758 /* we can't load and render it anyway */
759 args->bInhibitSplash = sal_True;
760 #endif
762 pUsePlugin = getenv("SAL_USE_VCLPLUGIN");
763 if (pUsePlugin && !strcmp(pUsePlugin, "svp"))
764 args->bInhibitSplash = sal_True;
766 if (!args->bInhibitPipe && !getenv("LIBO_FLATPAK"))
768 int fd = 0;
769 pPipePath = get_pipe_path(args->pAppPath);
771 if ((fd=connect_pipe(pPipePath)) >= 0)
773 // Wait for answer
774 char resp[strlen("InternalIPC::SendArguments") + 1];
775 ssize_t n = read(fd, resp, SAL_N_ELEMENTS(resp));
776 if (n == (ssize_t) SAL_N_ELEMENTS(resp) &&
777 (memcmp(resp, "InternalIPC::SendArguments",
778 SAL_N_ELEMENTS(resp) - 1) == 0))
780 rtl_uString *pCwdPath = NULL;
781 osl_getProcessWorkingDir(&pCwdPath);
783 // Then send args
784 bSentArgs = send_args(fd, pCwdPath);
787 close(fd);
791 if (!bSentArgs)
793 /* we have to prepare for, and exec the binary */
794 int nPercent = 0;
795 ChildInfo *info;
796 sal_Bool bAllArgs = sal_True;
797 sal_Bool bShortWait, bRestart;
799 /* sanity check pieces */
800 system_checks();
802 /* load splash image and create window */
803 if (!args->bInhibitSplash)
804 splash = splash_create(args->pAppPath, argc, argv);
806 /* pagein */
807 if (!args->bInhibitPagein)
808 exec_pagein(args);
810 /* javaldx */
811 #if HAVE_FEATURE_JAVA
812 if (!args->bInhibitJavaLdx)
813 exec_javaldx (args);
814 #endif
818 bRestart = sal_False;
820 /* fast updates if we have somewhere to update it to */
821 bShortWait = splash ? sal_True : sal_False;
823 /* Periodically update the splash & the percent according
824 to what status_fd says, poll quickly only while starting */
825 info = child_spawn (args, bAllArgs, bShortWait);
826 g_pProcess = info->child;
828 while (!child_exited_wait(info, bShortWait))
830 ProgressStatus eResult;
832 splash_draw_progress(splash, nPercent);
833 eResult = read_percent(info, &nPercent);
835 if (eResult != ProgressContinue)
837 splash_destroy(splash);
838 splash = NULL;
839 bShortWait = sal_False;
843 status = child_get_exit_code(info);
844 g_pProcess = NULL; // reset
846 switch (status)
848 case EXITHELPER_CRASH_WITH_RESTART: // re-start with just -env: parameters
849 bRestart = sal_True;
850 bAllArgs = sal_False;
851 break;
852 case EXITHELPER_NORMAL_RESTART: // re-start with all arguments
853 bRestart = sal_True;
854 bAllArgs = sal_True;
855 break;
856 default:
857 break;
860 child_info_destroy(info);
861 } while (bRestart);
864 /* cleanup */
865 if (pPipePath)
866 rtl_uString_release(pPipePath);
868 args_free(args);
870 return status;
873 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */